我正在尝试在我的android应用程序中播放Raw(int16 PCM)编码的音频文件。我一直在关注并阅读Oboe文档/样本,以尝试获取自己的音频文件之一。
我需要播放的音频文件大约为6kb或1592帧(立体声)。
要么没有声音播放,要么声音/抖动在启动时播放(输出变化-参见下面)
问题排查
更新 我现在改用float来进行缓冲区排队,而不是将所有内容都保留为int16_t(并在完成后转换回int16_t),尽管现在我没有声音了。
音频似乎没有播放或在启动时播放(这是错误的)。我按“开始”后,声音应该会播放。
仅使用int16_t实现应用程序时,声音过早与缓冲区大小有关。如果缓冲区大小小于音频文件,则声音会非常快并被剪切(缓冲区大小较小时,无人机更像无人机)。它比Raw音频大小大,看起来像是在循环播放,并且在更大的缓冲区大小时变得更安静。当按下开始按钮时,声音也会变得“更柔和”。我什至不能完全确定这意味着正在播放原始音频,这可能只是Android发出的随机废话。
用浮点数填充缓冲区,然后转换为int16_t时,不会播放音频。
(我曾尝试运行systrace,但老实说我不知道我在寻找什么)
createPlaybackStream()
中调整缓冲区大小(尽管仍将其设置为突发大小的两倍)实施
我目前正在构建器中尝试的操作
this
或onAudioReady()
LowLatency
Exclusive
我正在使用https://github.com/google/oboe/blob/master/samples/RhythmGame节奏游戏示例中的Player
类和AAssetManager
类。我正在使用这些类来加载资源并播放声音。 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);
}
答案 0 :(得分:1)
将缓冲区容量设置为(大于我的音频文件帧数)
您不需要设置缓冲区容量。这将自动为您设置在一个合理的水平。通常约为3000帧。请注意,缓冲区容量与缓冲区 size 不同,缓冲区默认值为2 * framesPerBurst。
将突发大小(每个回叫的帧数)设置为(等于或小于缓冲区容量/ 2的任何值)
再次,不要这样做。每次流需要更多音频数据时,都会调用onAudioReady
,并且numFrames
指示应提供多少帧。如果您使用的值与音频设备的本机突发大小的确切比率不正确(该值通常为128、192和240帧,具体取决于底层硬件),则覆盖此值,则可能会出现音频故障。
我已切换到浮点数进行缓冲区排队
您需要提供数据的格式由音频流确定,只有在打开该流后才能知道。您可以通过调用stream->getFormat()
来获得它。
在RhythmGame
示例(至少the version you're referring to)中,格式如下:
AAssetDataSource::newFromAssetManager
内部的浮点数(浮点数是任何一种信号处理的首选格式)onAudioReady
内1592帧(立体声)。
您说您的信号源是立体声,但您在此处将其指定为单声道:
std :: shared_ptr soundSource(AAssetDataSource :: newFromAssetManager(assetManager,“ sound.raw”,ChannelCount :: Mono));
毫无疑问,这将导致音频问题,因为AAssetDataSource
的{{1}}值是正确值的两倍。这将导致音频故障,因为您有一半的时间会随机播放系统内存中的部分。