1

我正在开发一个处理基本上是 USB 麦克风的设备的 Android 应用程序。我需要读取输入数据并进行处理。有时,我需要向设备发送数据(4 shorts * 通常为 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,我正在将回调注册到输入流。在所有双簧管示例中,回调都注册在输出流上,并且读取是阻塞的。这有重要性吗?如果不是,我需要向流中写入多少帧以避免欠载?

编辑 与此同时,我找到了不足的来源。输出流没有读取与输入流相同数量的帧(事后看来这似乎是合乎逻辑的),因此写入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;
}

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

4

2 回答 2

3

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

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

->setFramesPerCallback(1024);

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

在所有双簧管示例中,回调都注册在输出流上,并且读取是阻塞的。这有重要性吗?

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

如果您想要低延迟,则将输出流用于回调很重要。这是因为输出流只能提供带有回调的低延迟模式,而不能提供直接 write()s。但是输入流可以通过回调和 read() 提供低延迟。

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

使用输出回调,您应该将输入耗尽一段时间,以便它运行接近空。

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

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

您的 1 纳秒超时非常小。但双簧管仍然会挡住。对于非阻塞模式,您应该使用 0 的 timeoutNanos。

于 2018-11-28T00:57:04.843 回答
0

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

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

oboe::AudioStreamBuilder::setFramesPerCallback(int framesPerCallback)

看这里在onAudioReady回调期间不应该做的事情,你会发现双簧管写入功能被禁止: https ://google.github.io/oboe/reference/classoboe_1_1_audio_stream_callback.html

于 2019-10-04T05:21:20.180 回答