Я хочу записать аудиопоток микрофона, чтобы я мог делать в реальном времени DSP.Android-dev AudioRecord без блокировки или потоков
Я хочу сделать это, не используя нити и не имея .read()
блока, пока он ждет новых аудиоданных.
UPDATE/ANSWER: Это ошибка в Android. 4.2.2 все еще есть проблема, но 5.01 IS FIXED! Я не знаю, где этот разрыв, но это история.
ПРИМЕЧАНИЕ: Пожалуйста, не говорите «Просто используйте потоки». Нити в порядке, но это не о них, и разработчики Android, предназначенные для AudioRecord, могут быть полностью работоспособны без необходимости указывать темы и без меня иметь дело с блокировкой read(). Спасибо!
Вот что я нашел:
Когда объект AudioRecord инициализируется, он создает свой собственный внутренний буфер типа кольца. Когда .start()
называется, он начинает запись в указанный кольцевой буфер (или любой другой вид, что на самом деле.)
Когда .read()
называется, он читает либо половину BufferSize или указанное число байтов (в зависимости от того меньше), а затем возвращается.
Если во внутреннем буфере имеется более чем достаточно звуковых образцов, то read() мгновенно возвращает данные. Если пока недостаточно, то read() ждет, пока не появится, а затем вернется с данными.
.setRecordPositionUpdateListener()
может использоваться для установки слушателя, а .setPositionNotificationPeriod()
и .setNotificationMarkerPosition()
могут использоваться для установки Периода и положения уведомления соответственно.
Однако Слушатель, кажется, не быть не вызывается, если определенные требования не будут выполнены:
1: Период или позиция должна быть равна BufferSize/2 или (BufferSize/2) -1.
2: .read()
должен вызываться до периода или установки таймера начинает обратный отсчет - другими словами, после вызова .start()
затем также называют .read()
, и каждый раз, когда Слушатель называется, вызовите .read()
снова.
3: .read()
должен считывать по меньшей мере половину bufferSize каждый раз.
Таким образом, используя эти правила, я могу заставить обработчик обратного вызова/прослушивателя работать, но по какой-то причине чтения по-прежнему блокируются, и я не могу понять, как заставить Listener вызываться только при наличии полного чтения стоимость.
Если я настраиваю вид кнопки, чтобы щелкнуть, чтобы прочитать, тогда я могу нажать на нее, и если быстро нажать, прочитайте блоки. Но если я дождался заполнения звукового буфера, тогда первый нажатие будет мгновенным (чтение сразу вернется), но субклиентные быстрые нажатия блокируются, потому что read() должен ждать, я думаю.
Очень ценно будет любое понимание того, как я мог бы заставить Слушатель работать по назначению - таким образом, чтобы мой слушатель вызывался, когда есть достаточно данных для read() для немедленного возврата.
Ниже приведены части моего кода.
У меня есть несколько операторов журнала в моем коде, которые отправляют строки для logcat, что позволяет мне видеть, сколько времени занимает каждая команда, и именно так я знаю, что read() блокирует. (А кнопки в моем простом тесте приложении также очень собачий медленно реагируют, когда он читает несколько раз, но процессор не привязан.)
Спасибо, ~ Джесси
В моей OnCreate():
bufferSize=AudioRecord.getMinBufferSize(samplerate,AudioFormat.CHANNEL_CONFIGURATION_MONO,AudioFormat.ENCODING_PCM_16BIT)*4;
recorder = new AudioRecord (AudioSource.MIC,samplerate,AudioFormat.CHANNEL_CONFIGURATION_MONO,AudioFormat.ENCODING_PCM_16BIT,bufferSize);
recorder.setRecordPositionUpdateListener(mRecordListener);
recorder.setPositionNotificationPeriod(bufferSize/2);
//recorder.setNotificationMarkerPosition(bufferSize/2);
audioData = new short [bufferSize];
recorder.startRecording();
samplesread=recorder.read(audioData,0,bufferSize);//This triggers it to start doing the callback.
Тогда вот мой слушатель:
public OnRecordPositionUpdateListener mRecordListener = new OnRecordPositionUpdateListener()
{
public void onPeriodicNotification(AudioRecord recorder) //This one gets called every period.
{
Log.d("TimeTrack", "AAA");
samplesread=recorder.read(audioData,0,bufferSize);
Log.d("TimeTrack", "BBB");
//player.write(audioData, 0, samplesread);
//Log.d("TimeTrack", "CCC");
reads++;
}
@Override
public void onMarkerReached(AudioRecord recorder) //This one gets called only once -- when the marker is reached.
{
Log.d("TimeTrack", "AAA");
samplesread=recorder.read(audioData,0,bufferSize);
Log.d("TimeTrack", "BBB");
//player.write(audioData, 0, samplesread);
//Log.d("TimeTrack", "CCC");
}
};
UPDATE: Я попробовал это на Android 2.2.3, 2.3.4, 4.0.3 и теперь, в d все действуют одинаково. Также: есть ошибка на code.google об этом - одна запись началась в 2012 году кем-то другим, затем с начала 2013 года (я не знал о первом):
UPDATE 2016: Ahhhh finally после нескольких лет удивления, был ли это я или андроид, я наконец получил ответ! Я попробовал мой код выше на 4.2.2 и такую же проблему. Я пробовал код на 5.01, И ЭТО РАБОТАЕТ !!! И начальный вызов .read() НЕ нужен больше. Теперь, как только вызывается .setPositionNotificationPeriod() и .StartRecording(), mRecordListener() просто волшебным образом начинает получать вызов каждый раз, когда имеются данные , теперь, поэтому он больше не блокируется, так как обратный вызов не вызывается до после достаточно данные были записаны. Я не слушал данные, чтобы знать, правильно ли они записываются, но обратный вызов происходит так, как должен, и это не блокирует активность, как раньше!
http://code.google.com/p/android/issues/detail?id=53996
http://code.google.com/p/android/issues/detail?id=25138
Если люди, которые заботятся об этом журнале об ошибках и голосовать за и/или прокомментировать ошибка, возможно, он будет получать адрес рано от Google.
Я, вероятно, в конечном итоге просто создаю нить. Кажется, что Android больше глючит, чем улей и ничего не фиксируется (25 000 новых неуправляемых ошибок дефектов, датированные годами назад некоторые из них). В ответ на ваши вопросы я хотел избежать потоков, потому что я хотел избежать беспорядочных хаков и сделать это право, если бы мог. Похоже, этого не произойдет, поэтому лучше всего использовать самый чистый хак - это еще один поток. Темы велики - не поймите меня неправильно. В реальном времени я имею в виду приложение осциллографа или анализатор спектра и т. Д. Или играю audiotrk –