(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;
}