【问题标题】:Capturing audio data and save to raw PCM file in AudioFlinger在 AudioFlinger 中捕获音频数据并保存到原始 PCM 文件
【发布时间】:2019-10-06 05:30:48
【问题描述】:

经过一番研究,我发现这是可以在Android的libaudioflinger中捕获音频数据的。

我认为音频数据正在这里写入 HAL:

ssize_t framesWritten = mNormalSink->write((char *)mSinkBuffer + offset, count);

完整代码:https://android.googlesource.com/platform/frameworks/av/+/lollipop-release/services/audioflinger/Threads.cpp#2118

所以,我想将 mSinkBuffer + 偏移量保存到一个文件中(我预计它将是原始 PCM 音频文件)。我使用这些流将其写入文件:

std::ofstream audioData ("/data/audiodata.raw", std::fstream::app);
audioData.write((char *)mSinkBuffer + offset, count);
audioData.close();

文件写入成功,里面有数据。 但是,当我使用 aplay 或 ffplay 播放 PCM 文件(audiodata.raw)时,我听到的唯一声音就是噪音。

aplay -t raw -c 2 -f S16_LE -r 48000 audiodata.raw

我担心 aplay 的配置。所以我打印了一些 libaudioflinger 的日志:

10-07 10:14:54.575  1300  1366 I AudioFlinger: I/O handle: 13
10-07 10:14:54.575  1300  1366 I AudioFlinger: Standby: no
10-07 10:14:54.575  1300  1366 I AudioFlinger: Sample rate: 48000 Hz
10-07 10:14:54.575  1300  1366 I AudioFlinger: HAL frame count: 512
10-07 10:14:54.575  1300  1366 I AudioFlinger: HAL format: 0x1 (AUDIO_FORMAT_PCM_16_BIT)
10-07 10:14:54.575  1300  1366 I AudioFlinger: HAL buffer size: 2048 bytes
10-07 10:14:54.575  1300  1366 I AudioFlinger: Channel count: 2
10-07 10:14:54.575  1300  1366 I AudioFlinger: Channel mask: 0x00000003 (front-left, front-right)
10-07 10:14:54.575  1300  1366 I AudioFlinger: Processing format: 0x5 (AUDIO_FORMAT_PCM_FLOAT)
10-07 10:14:54.576  1300  1366 I AudioFlinger: Processing frame size: 8 bytes
10-07 10:14:54.576  1300  1366 I AudioFlinger: Pending config events:
10-07 10:14:54.576  1300  1366 I AudioFlinger:  none
10-07 10:14:54.576  1300  1366 I AudioFlinger: Output device: 0x2 (AUDIO_DEVICE_OUT_SPEAKER)
10-07 10:14:54.576  1300  1366 I AudioFlinger: Input device: 0 (AUDIO_DEVICE_NONE)
10-07 10:14:54.576  1300  1366 I AudioFlinger: Audio source: 0 (default)

我不知道我做错了什么。请帮帮我!

谢谢你!

【问题讨论】:

    标签: android c++ audio pcm audioflinger


    【解决方案1】:

    以追加|二进制方式打开文件

    std::ofstream audioData("/data/audiodata.raw", std::fstream::app | std::fstream::binary);

    二进制 - 二进制 - 操作以二进制模式而不是文本模式执行。

    原始 PCM 缓冲区应以二进制模式写入。

    请检查代码以了解字节数和计数之间的差异 (添加了一些cmets供参考,希望能解决你的问题)

    if (mNormalSink != 0) {
    
        /* Count is the number of Frames or sample written != bytes  */
        const size_t count = mBytesRemaining / mFrameSize;
    
        ATRACE_BEGIN("write");
        // update the setpoint when AudioFlinger::mScreenState changes
        uint32_t screenState = AudioFlinger::mScreenState;
        if (screenState != mScreenState) {
            mScreenState = screenState;
            MonoPipe *pipe = (MonoPipe *)mPipeSink.get();
            if (pipe != NULL) {
                pipe->setAvgFrames((mScreenState & 1) ?
                        (pipe->maxFrames() * 7) / 8 : mNormalFrameCount * 2);
            }
        }
        ssize_t framesWritten = mNormalSink->write((char *)mSinkBuffer + offset, count);
    
        ATRACE_END();
        if (framesWritten > 0) {
            bytesWritten = framesWritten * mFrameSize;
            // std::ofstream audioData ("/data/audiodata.raw", std::fstream::binary);
            /* File write or stream write is the number of bytes written to the file */
            audioData.write((char *)mSinkBuffer + offset, bytesWritten);
            // audioData.close();
        } else {
            bytesWritten = framesWritten;
        }
    // otherwise use the HAL / AudioStreamOut directly
    }
    

    Audacity - 打开原始文件

    文件 -> 导入 -> 原始数据

    选择原始文件路径

    根据您附加的原始文件。

    使用这些设置

    编码:32 位浮点数

    字节顺序:小端序

    声道:2声道(立体声)

    起始偏移量:0

    进口数量:100

    采样率:48000

    文件播放正常,没有任何故障/噪音。

    【讨论】:

    • 感谢您的评论!不幸的是,当我尝试播放它时,它仍然只包含噪音。你还有什么想法吗?
    • 你能在大胆(导入选项)中打开原始文件并检查波形或音频数据是否存在。每次执行获得的计数大小是多少?
    • 我只能导入 > 原始数据。如果我使用 std::fstream::binary ,那么除了噪音我什么也听不到。如果我只使用 std::fstream::app,我可以听到一些有噪音的音乐。
    • 并且,计数为 1024
    • 你能不能只尝试二进制模式,在开始时打开文件1次,然后在程序结束时关闭它。你不需要使用附加模式。
    【解决方案2】:

    当您必须播放原始文件时,您必须对声音帧使用编解码器格式,例如 wav 或 mp3 等。尝试将原始数据传递到 winmm 中定义的 wav WAVEFORMAT 并从可以通过 C++ 中的 WAVEFORMAT 类型打开和关闭。

    【讨论】:

    • 实际上,原始文件仅包含音频数据。这就是为什么我必须为 aplay 指定采样率、通道等才能播放文件的原因。不像 WAV,它有一个标题来定义那些需要的信息。
    猜你喜欢
    • 2012-04-28
    • 1970-01-01
    • 2016-05-11
    • 1970-01-01
    • 1970-01-01
    • 2015-12-28
    • 2012-11-14
    • 1970-01-01
    • 2019-09-24
    相关资源
    最近更新 更多