在audiotrack java层和native层还有audio hal中dump pcm

(69条消息) [RK3288][Android6.0] Audio播放时的pcm数据dump思路_Kris Fei's blog-CSDN博客

(69条消息) android framework层dump pcm数据的方法_和大伙儿去乘凉-CSDN博客

1.

dump pcm数据是音频工程师经常用的的debug手段,这里总结下在framework层dump数据的位置

dump 数据的方法,方法3的dump_out_data

FILE *fp1 = fopen("/data/audio_spk.pcm", "a+");
 if (fp1) {
         int flen = fwrite((char *)buffer, 1, bytes, fp1);
           fclose(fp1);
   }

2.AudioTrack的processAudioBuffer函数

应用层如果是callback的形式可以在此函数中dump
nsecs_t AudioTrack::processAudioBuffer()

具体dump位置如下,在EVENT_MORE_DATA的event回调之后

。。。。。。
       size_t reqSize = audioBuffer.size;
        mCbf(EVENT_MORE_DATA, mUserData, &audioBuffer);
        size_t writtenSize = audioBuffer.size;
 
        // Sanity check on returned size
        if (ssize_t(writtenSize) < 0 || writtenSize > reqSize) {
            ALOGE("EVENT_MORE_DATA requested %zu bytes but callback returned %zd bytes",
                    reqSize, ssize_t(writtenSize));
            return NS_NEVER;
        }

        FILE *fp1 = fopen("/data/cb16.pcm", "a+");
		 if (fp1) {
				fwrite((char *)audioBuffer.raw, 1, writtenSize, fp1);
				fclose(fp1);
			}


。。。。。。。


3.AudioFlinger的PlaybackThread::threadLoop_write函数内 mNormalSink->write((char *)mSinkBuffer + offset, count);之后

ssize_t AudioFlinger::PlaybackThread::threadLoop_write()
{
    LOG_HIST_TS();
    mInWrite = true;
    ssize_t bytesWritten;
    const size_t offset = mCurrentWriteLength - mBytesRemaining;
 
    // If an NBAIO sink is present, use it to write the normal mixer's submix
    if (mNormalSink != 0) {
 
        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;
#ifdef TEE_SINK
            mTee.write((char *)mSinkBuffer + offset, framesWritten);
#endif

4.hal中dump pcm数据 

out_write调 操作入参的 void* buffer 和长度 size_t bytes


static ssize_t out_write(struct audio_stream_out *stream, const void* buffer,
                         size_t bytes)
{
......
	//通过property来控制是否要dump pcm data
    property_get("media.audio.record", value, NULL);
    //
    prop_pcm = atoi(value);
    //非0的值决定要dump多少数据才停止,单位是M
    if (prop_pcm > 0) {
        dump_out_data(buffer, bytes, &prop_pcm);
    }
......


dump_out_data()实现

static void dump_out_data(const void* buffer,size_t bytes, int *size)
 {
    ALOGD("dump pcm file.");
    static FILE* fd;
    static int offset = 0;
    if(fd == NULL) {
        fd=fopen("/data/debug.pcm","wb+");
            if(fd == NULL) {
            ALOGD("DEBUG open /data/debug.pcm error =%d ,errno = %d",fd,errno);
            offset = 0;
        }
    }
    //写pcm数据
    fwrite(buffer,bytes,1,fd);
    offset += bytes;
    fflush(fd);
    //比如size是1,那么就是1M后停止dump数据
    if(offset >= (*size)*1024*1024) {
        *size = 0;
        fclose(fd);
        offset = 0;
        system("setprop media.audio.record 0");
        ALOGD("TEST playback pcmfile end");
    }
}

5.使用callback形式,在 AudioRecord::processAudioBuffer()的函数内EVENT_MORE_DATA的事件回调之后

 
        if (mRetryOnPartialBuffer) {
            mRetryOnPartialBuffer = false;
            if (avail < mRemainingFrames) {
                int64_t myns = ((mRemainingFrames - avail) *
                        1100000000LL) / mSampleRate;
                if (ns < 0 || myns < ns) {
                    ns = myns;
                }
                return ns;
            }
        }
 
        size_t reqSize = audioBuffer.size;
        mCbf(EVENT_MORE_DATA, mUserData, &audioBuffer);
        size_t readSize = audioBuffer.size;
 
	
		FILE *fp1 = fopen("/data/cb16.pcm", "a+");
		if (fp1) {
			fwrite((char *)audioBuffer.raw, 1, readSize, fp1);
			fclose(fp1);
		}

另外方法

1. dump audioflinger的数据
/frameworks/av/services/audioflinger/Tracks.cpp#getNextBuffer

// AudioBufferProvider interface
status_t AudioFlinger::PlaybackThread::Track::getNextBuffer(
        AudioBufferProvider::Buffer* buffer)
{
    ServerProxy::Buffer buf;
    size_t desiredFrames = buffer->frameCount;
    buf.mFrameCount = desiredFrames;
    status_t status = mServerProxy->obtainBuffer(&buf);
    buffer->frameCount = buf.mFrameCount;
    buffer->raw = buf.mRaw;
    if (buf.mFrameCount == 0) {
        mAudioTrackServerProxy->tallyUnderrunFrames(desiredFrames);
    } else {
        mAudioTrackServerProxy->tallyUnderrunFrames(0);
    }
    //JaychouNote: dump audio flinger data begin.
        int tmpFd = ::open("/data/misc/audio/dumpTrack.pcm", O_CREAT | O_WRONLY | O_APPEND, 0777);
        if ( tmpFd < 0 ) {
            ALOGE("Tracks.cpp Fail to open dumpTrack file");
        } else {
            ::write(tmpFd, buffer->raw, buffer->frameCount * TrackBase::mChannelCount * 2);
            ::close(tmpFd);
        }
        //JaychouNote: dump audio flinger data end.
    return status;
}

dump hal层的数据

/hardware/qcom/audio/hal/audio_hw.c#out_write

static ssize_t out_write(struct audio_stream_out *stream, const void *buffer,size_t bytes)
{
    struct stream_out *out = (struct stream_out *)stream;
    struct audio_device *adev = out->dev;
    ssize_t ret = 0;
    ......
    } else {
        if (out->pcm) {
            if (out->muted)
                memset((void *)buffer, 0, bytes);

            ALOGVV("%s: writing buffer (%d bytes) to pcm device", __func__, bytes);
        //JaychouNote: dump hal data begin.
    int tmpFd = open("/data/misc/audio/dumpTrack_hal.pcm", O_CREAT | O_WRONLY | O_APPEND, 0777);

    if ( tmpFd < 0 ) {
        ALOGE("Fail to open dumpTrack_hal file");
    } else {
        write(tmpFd, buffer, bytes);
        close(tmpFd);
    }
    //JaychouNote: dump hal data end.
            if (adev->adm_request_focus)
                adev->adm_request_focus(adev->adm_data, out->handle);

            if (out->usecase == USECASE_AUDIO_PLAYBACK_AFE_PROXY) {
                ret = pcm_mmap_write(out->pcm, (void *)buffer, bytes);
            }
            else
                ret = pcm_write(out->pcm, (void *)buffer, bytes);

            if (ret == 0)
                out->written += bytes / (out->config.channels * sizeof(short));

            if (adev->adm_abandon_focus)
                adev->adm_abandon_focus(adev->adm_data, out->handle);
        }
    }

exit:
    pthread_mutex_unlock(&out->lock);

    if (ret != 0) {
        if (out->pcm)
            ALOGE("%s: error %zu - %s", __func__, ret, pcm_get_error(out->pcm));
        out_standby(&out->stream.common);
        usleep(bytes * 1000000 / audio_stream_out_frame_size(stream) /
               out_get_sample_rate(&out->stream.common));
    }
    return bytes;
}

  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
AudioFlinger是Android平台上的一个系统服务,它主要负责管理所有的音频数据和音频设备,包括音频采集、音频处理、音频输出等。它与应用程序、音频设备驱动程序及硬件抽象HAL)进行交互,从而实现音频的输入、处理和输出。 与HAL的交互:AudioFlinger通过HAL与底音频硬件进行交互。HAL是一种硬件抽象,它为上AudioFlinger提供了一种与底音频硬件进行通信的标准接口。HAL可以根据不同的硬件平台、不同的设备需求等进行适配,并将这些信息提供给AudioFlinger。AudioFlinger可以通过HAL来控制不同的音频硬件设备,例如麦克风、扬声器等。 与应用程序的交互:应用程序可以通过Android提供的音频API调用AudioFlinger服务,从而控制音频的输入、处理和输出。例如,应用程序可以使用AudioRecord类来录制音频数据,使用AudioTrack类来播放音频数据。这些类都是通过与AudioFlinger进行交互来实现音频的输入和输出。 与音频设备驱动程序的交互:音频设备驱动程序是在HAL之下的一软件,它主要负责控制音频硬件设备的操作。AudioFlinger可以通过与音频设备驱动程序的交互来控制音频设备的采样率、位深度、声道数等属性,从而实现更加精细的音频处理。 总之,AudioFlinger是Android平台上非常重要的音频管理服务,它通过与HAL、应用程序和音频设备驱动程序进行交互,实现了音频的输入、处理和输出。这些交互的方式也为应用程序开发者提供了更加灵活的音频控制和处理方式

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值