Я использую oboe для воспроизведения звуков в моей библиотеке ndk, и я использую OpenSL с расширениями Android для декодирования файлов wav в PCM.Декодированные подписанные 16-битные PCM сохраняются в памяти (std::forward_list<int16_t>
), а затем они отправляются в поток гобой через обратный вызов.Звук, который я слышу из своего телефона, похож на оригинальный wav-файл с уровнем громкости, однако «качество» такого звука отсутствует - оно лопается и потрескивает.
Я предполагаю, что отправляю PCM ваудио поток в неправильном порядке или формате (частота дискретизации?).Как я могу использовать OpenSL-декодирование с аудио-потоком oboe?
Для декодирования файлов в PCM я использую AndroidSimpleBufferQueue в качестве приемника и AndroidFD с AAssetManager в качестве источника:
// Loading asset
AAsset* asset = AAssetManager_open(manager, path, AASSET_MODE_UNKNOWN);
off_t start, length;
int fd = AAsset_openFileDescriptor(asset, &start, &length);
AAsset_close(asset);
// Creating audio source
SLDataLocator_AndroidFD loc_fd = { SL_DATALOCATOR_ANDROIDFD, fd, start, length };
SLDataFormat_MIME format_mime = { SL_DATAFORMAT_MIME, NULL, SL_CONTAINERTYPE_UNSPECIFIED };
SLDataSource audio_source = { &loc_fd, &format_mime };
// Creating audio sink
SLDataLocator_AndroidSimpleBufferQueue loc_bq = { SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 1 };
SLDataFormat_PCM pcm = {
.formatType = SL_DATAFORMAT_PCM,
.numChannels = 2,
.samplesPerSec = SL_SAMPLINGRATE_44_1,
.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_16,
.containerSize = SL_PCMSAMPLEFORMAT_FIXED_16,
.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT,
.endianness = SL_BYTEORDER_LITTLEENDIAN
};
SLDataSink sink = { &loc_bq, &pcm };
А затем я регистрирую обратный вызов, ставлю в очередь буферы и перемещаю PCM из буфера в хранилище, пока это не будет сделано.
ПРИМЕЧАНИЕ: wavаудиофайл также 2-канальный со знаком 16 бит 44,1 Гц PCM
Моя конфигурация потока гобоя такая же:
AudioStreamBuilder builder;
builder.setChannelCount(2);
builder.setSampleRate(44100);
builder.setCallback(this);
builder.setFormat(AudioFormat::I16);
builder.setPerformanceMode(PerformanceMode::LowLatency);
builder.setSharingMode(SharingMode::Exclusive);
Рендеринг аудио работает так:
// Oboe stream callback
audio_engine::onAudioReady(AudioStream* self, void* audio_data, int32_t num_frames) {
auto stream = static_cast<int16_t*>(audio_data);
sound->render(stream, num_frames);
}
// Sound::render method
sound::render(int16_t* audio_data, int32_t num_frames) {
auto iter = pcm_data.begin();
std::advance(iter, cur_frame);
const int32_t rem_size = std::min(num_frames, size - cur_frame);
for(int32_t i = 0; i < rem_size; ++i, std::next(iter), ++cur_frame) {
audio_data[i] += *iter;
}
}