AudioTrack: воспроизведение звука через Wi-Fi
У меня есть AudioTrack в моем приложении, которое настроено на режим Stream. Я хочу написать аудио, которое я получаю по беспроводному соединению. AudioTrack объявляется следующим образом:
mPlayer = new AudioTrack(STREAM_TYPE,
FREQUENCY,
CHANNEL_CONFIG_OUT,
AUDIO_ENCODING,
PLAYER_CAPACITY,
PLAY_MODE);
Если параметры определены следующим образом:
private static final int FREQUENCY = 8000,
CHANNEL_CONFIG_OUT = AudioFormat.CHANNEL_OUT_MONO,
AUDIO_ENCODING = AudioFormat.ENCODING_PCM_16BIT,
PLAYER_CAPACITY = 2048,
STREAM_TYPE = AudioManager.STREAM_MUSIC,
PLAY_MODE = AudioTrack.MODE_STREAM;
Однако, когда я пишу данные в AudioTrack с помощью write(), он будет играть прерывистый... Вызов
byte[] audio = packet.getData();
mPlayer.write(audio, 0, audio.length);
создается всякий раз, когда пакет принимается по сетевому соединению. Кто-нибудь знает, почему это звучит странно? Может быть, это имеет какое-то отношение к самому Wi-Fi-соединению? Я так не думаю, поскольку звук не звучит ужасно, наоборот, когда я отправляю данные с телефона Android в другой источник через UDP. Звук тогда звучит полным, а не изменчивым... Так кто-нибудь имеет представление о том, почему это происходит?
Ответы
Ответ 1
Знаете ли вы, сколько байт в секунду вы получаете, среднее время между пакетами сравнивается и максимальное время между пакетами? Если нет, можете ли вы добавить код для его расчета?
Чтобы сохранить поток, вам необходимо усреднять 8000 выборок в секунду * 2 байта/образец = 16 000 байт в секунду.
Зазор более 2048 байт /(16000 байт в секунду) = 128 миллисекунд между входящими пакетами приведет к тому, что ваш поток будет работать сухим, а звук заикается.
Один из способов предотвратить увеличение размера буфера (PLAYER_CAPACITY). Более крупный буфер будет более способен обрабатывать изменения в размере и скорости входящего пакета. Стоимость дополнительной стабильности - это большая задержка при запуске воспроизведения, пока вы ждете, пока буфер не будет заполнен.
Ответ 2
Я частично решил его, поместив mPlayer.write(audio, 0, audio.length);
в свой собственный Thread
. Это отнимет часть изменчивости (из-за того, что запись является блокирующим вызовом), но она по-прежнему звучит порывисто после хорошей секунды или 2. У нее все еще есть значительная задержка в 2-3 секунды.
new Thread(){
public void run(){
byte[] audio = packet.getData();
mPlayer.write(audio, 0, audio.length);
}
}.start();
Просто анонимный Thread
, который теперь пишет...
У кого-нибудь есть идея, как решить эту проблему?
Edit:
После некоторой дополнительной проверки и отладки я заметил, что это проблема с getBuffer.
Я посмотрел на java-код AudioTrack и С++ код AudioTrack И я заметил, что он может отображаться только в коде на С++.
if (__builtin_expect(result!=NO_ERROR, false)) {
LOGW( "obtainBuffer timed out (is the CPU pegged?) "
"user=%08x, server=%08x", u, s);
mAudioTrack->start(); // FIXME: Wake up audioflinger
timeout = 1;
}
Я заметил, что в этом фрагменте кода есть FIXME
.: & Л; Но так или иначе, может ли кто-нибудь объяснить, как работает этот код на С++? У меня был некоторый опыт работы с ним, но он никогда не был таким сложным, как этот...
Изменить 2:
Я уже несколько раз пробовал разницу: разница в том, что я буферизую полученные данные, а затем, когда буфер заполнен некоторыми данными, он записывается в плеер. Тем не менее, игрок не отстает от потребления в течение нескольких циклов, затем появляется предупреждение obtainBuffer timed out (is the CPU pegged?)
, и нет никаких данных, написанных для игрока до тех пор, пока он не начнет возвращаться к жизни... После этого он будет постоянно получить данные, записанные на него, до тех пор, пока буфер не будет опустошен.
Другая небольшая разница заключается в том, что я передаю файл игроку сейчас. То есть, читая его в кусках, записывая эти куски в буфер. Это имитирует пакеты, принимаемые через Wi-Fi...
Я начинаю задаваться вопросом, является ли это просто проблемой ОС, которую имеет Android, и это не то, что я могу решить самостоятельно... У кого-нибудь есть идеи по этому поводу?
Изменить 3:
Я сделал больше тестов, но это не помогает мне дальше. Этот тест показывает мне, что я только задерживаюсь, когда впервые пытаюсь писать в AudioTrack. Это займет от 1 до 3 секунд. Я сделал это, используя следующий бит кода:
long beforeTime = Utilities.getCurrentTimeMillis(), afterTime = 0;
mPlayer.write(data, 0, data.length);
afterTime = Utilities.getCurrentTimeMillis();
Log.e("WriteToPlayerThread", "Writing a package took " + (afterTime - beforeTime) + " milliseconds");
Однако я получаю следующие результаты:
Изображение Logcat http://img810.imageshack.us/img810/3453/logcatimage.png
Они показывают, что изначальное отставание происходит в начале, после чего AudioTrack постоянно продолжает получать данные... Мне действительно нужно, чтобы этот фиксированный...