Я пытаюсь воспроизвести аудиофайл в формате Raw (int16 PCM) в моем приложении для Android.Я следил и читал документацию / образцы Oboe, чтобы попытаться воспроизвести один из моих собственных аудиофайлов.
Размер аудиофайла, который мне нужно воспроизвести, составляет примерно 6 КБ или 1592 кадра (стерео).
Либо не воспроизводится звук, либо воспроизводится звук / джиттер при запуске (с различным выходным сигналом - см. Ниже)
Устранение неполадок
обновление Я переключился на число с плавающей точкой для очередей в буфере, вместо того, чтобы сохранять все в int16_t (и преобразовать обратно в int16_t, когда закончил), хотя теперь я вернулся к отсутствию звука.
Звук, кажется, либоиграть или играть при запуске (что неправильно).Звук должен воспроизводиться после нажатия кнопки «Пуск».
Когда приложение было реализовано только с int16_t, преждевременное звучание было относительно размера буфера.Если размер буфера меньше, чем аудиофайл, звук будет очень быстрым и обрезанным (более похожим на дрон при меньших размерах буфера).Кажется, что он больше размера необработанного аудио, он воспроизводится в цикле и становится тише при больших размерах буфера.Звук также станет «мягче» при нажатии кнопки запуска.Я даже не совсем уверен, что это означает, что воспроизводился необработанный звук, это могли быть случайные бессмысленные дрожания от Android.
При заполнении буферов поплавками и последующем преобразовании в int16_t,звук не воспроизводится.
(я пробовал запустить systrace, но, честно говоря, не знаю, что ищу)
- Поток открываетсяотлично.
- Размер буфера не может быть скорректирован в
createPlaybackStream()
(хотя каким-то образом он все равно устанавливает его в два раза больше размера пакета) - Поток запускается нормально.
- Сырые ресурсы загружаются нормально.
Реализация
Что я сейчас пытаюсь в сборщике:
- Настройка обратного вызована
this
или onAudioReady()
- Установка режима производительности на
LowLatency
- Установка режима совместного использования на
Exclusive
- Установка емкости буфера на (что угоднобольше, чем количество кадров в моем аудиофайле)
- Установка размера пакета (количество кадров на вызов back) to (что-либо равное или меньшее, чем емкость буфера / 2)
Я использую класс Player
и класс AAssetManager
из образца Rhythm Game здесь: https://github.com/google/oboe/blob/master/samples/RhythmGame. Я использую эти классы для загрузки своих ресурсов и воспроизведения звука.Player.renderAudio
записывает аудиоданные в выходной буфер.
Вот соответствующие методы из моего звукового движка:
void AudioEngine::createPlaybackStream() {
// // Load the RAW PCM data files into memory
std::shared_ptr<AAssetDataSource> soundSource(AAssetDataSource::newFromAssetManager(assetManager, "sound.raw", ChannelCount::Mono));
if (soundSource == nullptr) {
LOGE("Could not load source data for sound");
return;
}
sound = std::make_shared<Player>(soundSource);
AudioStreamBuilder builder;
builder.setCallback(this);
builder.setPerformanceMode(PerformanceMode::LowLatency);
builder.setSharingMode(SharingMode::Exclusive);
builder.setChannelCount(mChannelCount);
Result result = builder.openStream(&stream);
if (result == Result::OK && stream != nullptr) {
mSampleRate = stream->getSampleRate();
mFramesPerBurst = stream->getFramesPerBurst();
int channelCount = stream->getChannelCount();
if (channelCount != mChannelCount) {
LOGW("Requested %d channels but received %d", mChannelCount, channelCount);
}
// Set the buffer size to (burst size * 2) - this will give us the minimum possible latency while minimizing underruns
stream->setBufferSizeInFrames(mFramesPerBurst * 2);
if (setBufferSizeResult != Result::OK) {
LOGW("Failed to set buffer size. Error: %s", convertToText(setBufferSizeResult.error()));
}
// Start the stream - the dataCallback function will start being called
result = stream->requestStart();
if (result != Result::OK) {
LOGE("Error starting stream. %s", convertToText(result));
}
} else {
LOGE("Failed to create stream. Error: %s", convertToText(result));
}
}
DataCallbackResult AudioEngine::onAudioReady(AudioStream *audioStream, void *audioData, int32_t numFrames) {
int16_t *outputBuffer = static_cast<int16_t *>(audioData);
sound->renderAudio(outputBuffer, numFrames);
return DataCallbackResult::Continue;
}
// When the 'start' button is pressed, it calls this method with true
// There should be no sound on app start-up until this button is pressed
// Sound stops when 'stop' is pressed
setPlaying(bool isPlaying) {
sound->setPlaying(isPlaying);
}