Oboe / AAudio播放流中的欠载情况

时间:2018-11-26 10:05:27

标签: android audio android-ndk oboe

我正在开发一个Android应用,该应用处理的设备基本上是USB麦克风。我需要读取输入数据并进行处理。有时,我需要向设备发送数据(4个short *通道数,通常为2),并且该数据与输入无关。

我正在使用Oboe,并且我用于测试的所有电话都在下面使用AAudio。

阅读部分有效,但是当我尝试将数据写入输出流时,在logcat中收到以下警告,并且没有任何内容写入输出:

 W/AudioTrack: releaseBuffer() track 0x78e80a0400 disabled due to previous underrun, restarting

这是我的回叫:

oboe::DataCallbackResult
OboeEngine::onAudioReady(oboe::AudioStream *oboeStream, void *audioData, int32_t numFrames) {

    // check if there's data to write, agcData is a buffer previously allocated
    // and h2iaudio::getAgc() returns true if data's available
    if (h2iaudio::getAgc(this->agcData)) {

        // padding the buffer
        short* padPos = this->agcData+ 4 * playStream->getChannelCount();
        memset(padPos, 0,
            static_cast<size_t>((numFrames - 4) * playStream->getBytesPerFrame()));

        // write the data
        oboe::ResultWithValue<int32_t> result = 
            this->playStream->write(this->agcData, numFrames, 1);

        if (result != oboe::Result::OK){
            LOGE("Failed to create stream. Error: %s",
                oboe::convertToText(result.error()));
            return oboe::DataCallbackResult::Stop;
        }
    }else{
        // if there's nothing to write, write silence
        memset(this->agcData, 0,
            static_cast<size_t>(numFrames * playStream->getBytesPerFrame()));
    }

    // data processing here
    h2iaudio::processData(static_cast<short*>(audioData),
                          static_cast<size_t>(numFrames * oboeStream->getChannelCount()),
                          oboeStream->getSampleRate());

    return oboe::DataCallbackResult::Continue;
}

//...

oboe::AudioStreamBuilder *OboeEngine::setupRecordingStreamParameters(
  oboe::AudioStreamBuilder *builder) {

    builder->setCallback(this)
        ->setDeviceId(this->recordingDeviceId)
        ->setDirection(oboe::Direction::Input)
        ->setSampleRate(this->sampleRate)
        ->setChannelCount(this->inputChannelCount)
        ->setFramesPerCallback(1024);
    return setupCommonStreamParameters(builder);
}

setupRecordingStreamParameters所示,我正在将回调注册到输入流。在所有的Oboe示例中,回调都注册在输出流上,并且读取处于阻塞状态。这有重要性吗?如果没有,我需要向流中写入多少帧以避免欠载?

编辑 同时,我找到了欠款的来源。输出流读取的帧数量与输入流读取的帧数量不同(事后看来,这是合乎逻辑的),因此写入playStream->getFramesPerBurst()给定的帧数量解决了我的问题。这是我的新回调:

oboe::DataCallbackResult
OboeEngine::onAudioReady(oboe::AudioStream *oboeStream, void *audioData, int32_t numFrames) {
    int framesToWrite = playStream->getFramesPerBurst();

    memset(agcData, 0, static_cast<size_t>(framesToWrite * 
           this->playStream->getChannelCount()));
    h2iaudio::getAgc(agcData);

    oboe::ResultWithValue<int32_t> result = 
        this->playStream->write(agcData, framesToWrite, 0);

    if (result != oboe::Result::OK) {
        LOGE("Failed to write AGC data. Error: %s", 
             oboe::convertToText(result.error()));
    }

    // data processing here
    h2iaudio::processData(static_cast<short*>(audioData),
                          static_cast<size_t>(numFrames * oboeStream->getChannelCount()),
                          oboeStream->getSampleRate());

    return oboe::DataCallbackResult::Continue;
}

以这种方式工作,如果发现任何性能问题,我将更改附加了回调的流,现在,我将保持这种方式。

2 个答案:

答案 0 :(得分:3)

  

有时候,我需要向设备发送数据

您始终需要将数据写入输出。通常,您至少需要编写numFrames,甚至更多。如果没有任何要发送的有效数据,则写入零。 警告:在您的else块中,您正在调用memset(),但未写入流。

  

-> setFramesPerCallback(1024);

您具体需要1024吗?那是FFT的吗?如果没有,那么如果未指定FramesPerCallback,则AAudio可以更好地优化回调。

  

在所有的Oboe示例中,回调都注册在输出流上,   并且阅读受阻。这有重要性吗?

实际上,读取是非阻塞的。任何没有回调的流都应该是非阻塞的。使用timeoutNanos = 0。

如果要降低延迟,将输出流用于回调很重要。那是因为输出流只能通过回调而不是直接write()提供低等待时间模式。但是输入流通过回调和read()可以提供低延迟。

一旦流稳定,您就可以在每个回调中读取或写入相同数量的帧。但是在稳定之前,您可能需要读取或写入额外的帧。

使用输出回调,您应排空输入一段时间,以使其接近空。

使用输入回调,您应该在一段时间内填充输出,以使其接近满负荷运行。

  

write(this-> agcData,numFrames,1);

您的1纳秒超时非常小。但是双簧管仍然会阻塞。对于非阻塞模式,您应该将timeoutNanos设置为0。

答案 1 :(得分:0)

根据Oboe文档,在onAudioReady回调过程中,您必须将确切的numFrames帧直接直接写入* audioData指向的缓冲区中。而且,您不必调用Oboe的“写入”函数,而是自己填充缓冲区。

不确定getAgc()函数的工作方式,但也许可以为该函数提供指针audioData作为参数,以避免必须将数据再次从一个缓冲区复制到另一个缓冲区。 如果确实需要onAudioReady回调来请求相同数量的帧,则在使用以下方法构建AudioStream时必须设置该数字:

oboe::AudioStreamBuilder::setFramesPerCallback(int framesPerCallback)

在这里查看在onAudioReady回调期间不应执行的操作,您会发现双簧管写入功能被禁止: https://google.github.io/oboe/reference/classoboe_1_1_audio_stream_callback.html