Android AudioTrack getPlaybackHeadPosition всегда возвращает 0 - PullRequest
0 голосов
/ 21 февраля 2019

Я пишу код, который намеревается взять файл Wave и записать его в AudioTrack в режиме потока.Это минимальный жизнеспособный тест для обеспечения работы потокового режима AudioTrack.

Но как только я записываю некоторый буфер аудио в AudioTrack, а затем вызываю play (), метод getPlaybackHeadPosition () постоянно возвращает 0.

РЕДАКТИРОВАТЬ: если я игнорирую проверку доступных кадров и просто постоянно записываю буферы в AudioTrack, метод записи возвращает 0 (после первой записи в буфер), указывая, что он просто не записывал больше аудио.Поэтому кажется, что AudioTrack просто не хочет начинать воспроизведение.

Мой код правильно заполняет аудиотрек.Метод play не выдает никаких исключений, поэтому я не уверен, что происходит не так.

При пошаговом выполнении кода все на моем конце именно так, как я его ожидаю, поэтому я думаю, что у меня естьAudioTrack настроен неправильно.

Я работаю на эмуляторе, но я не думаю, что это должно быть проблемой.

Класс WavFile, который я использую, является проверенным классом, который у меня работает и надежно работает во многих проектах Java, он протестирован для правильной работы.

Соблюдайте следующую запись журнала, котораяфрагмент из большей части кода.Эта запись в журнал никогда не выполняется ...

                if (headPosition > 0)
                    Log.e("headPosition is greater than zero!!");

..

public static void writeToAudioTrackStream(final WavFile wave) 
    {
    Log.e("writeToAudioTrackStream");

    Thread thread = new Thread()
    {
        public void run()
        {
            try {

                final float[] data = wave.getData();
                int format = -1;

                if (wave.getChannel() == 1)
                    format = AudioFormat.CHANNEL_OUT_MONO;
                else if (wave.getChannel() == 2)
                    format = AudioFormat.CHANNEL_OUT_STEREO;
                else
                    throw new RuntimeException("writeToAudioTrackStatic() - unsupported number of channels value = "+wave.getChannel());

                final int bufferSizeInFrames = 2048;
                final int bytesPerSmp = wave.getBytesPerSmp();
                final int bufferSizeInBytes = bufferSizeInFrames * bytesPerSmp * wave.getChannel();

                AudioTrack audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, wave.getSmpRate(),
                        format,
                        AudioFormat.ENCODING_PCM_FLOAT,
                        bufferSizeInBytes,
                        AudioTrack.MODE_STREAM);

                int index = 0;
                float[] buffer = new float[bufferSizeInFrames * wave.getChannel()];
                boolean started = false;
                int framesWritten = 0;

                while (index < data.length) {

                    // calculate the available space in the buffer
                    int headPosition = audioTrack.getPlaybackHeadPosition();
                    if (headPosition > 0)
                        Log.e("headPosition is greater than zero!!");
                    int framesInBuffer = framesWritten - headPosition;
                    int availableFrames = bufferSizeInFrames - framesInBuffer;

                    // once the buffer has no space, the prime is done, so start playing
                    if (availableFrames == 0) {
                        if (!started) {
                            audioTrack.play();
                            started = true;
                        }
                        continue;
                    }

                    int endOffset = availableFrames * wave.getChannel();

                    for (int i = 0; i < endOffset; i++)
                        buffer[i] = data[index + i];

                    int samplesWritten = audioTrack.write(buffer , 0 , endOffset , AudioTrack.WRITE_BLOCKING);

                    // could return error values
                    if (samplesWritten < 0)
                        throw new RuntimeException("AudioTrack write error.");

                    framesWritten += samplesWritten / wave.getChannel();
                    index = endOffset;
                }
            }
            catch (Exception e) {
                Log.e(e.toString());
            }     
        }
    };

    thread.start();
}

1 Ответ

0 голосов
/ 23 февраля 2019

В соответствии с документацией ,

Для переносимости приложение должно заполнить путь данных до максимально допустимого значения путем записи данных, пока метод write () не вернет короткий счетчик передачи,Это позволяет немедленно начать play () и уменьшает вероятность опустошения.

При строгом чтении это может противоречить предыдущему утверждению:

... Вы можете при желании заполнить путь к данным перед вызовом play (), написав до bufferSizeInBytes ...

(выделено мной), но намерениедостаточно ясно: сначала вы должны написать короткую запись.

Это только начало игры.Когда это произойдет, вы можете использовать getPlaybackHeadPosition(), чтобы определить, когда больше свободного места.Я успешно использовал эту технику в своем собственном коде, на многих различных устройствах / уровнях API.

В качестве отступления: вы должны быть готовы к тому, что getPlaybackHeadPosition() изменится только большими шагами (если я правильно помню,это getMinBufferSize()/2).Это максимальное разрешение, доступное в системе;onMarkerReached() не может быть лучше.

...