一、概述
采用Android TEE方案,支持dump AudioFlinger中各个链路中的音频数据。
支持DUMP的音频数据如下:
"aftee_Date_ThreadId_C_reason.wav" // RecordThread (从hal层取到的数据)
"aftee_Date_ThreadId_M_reason.wav" //MixerThread (NormalMixer后的数据)
"aftee_Date_ThreadId_F_reason.wav" // MixerThread (FastMixer后的数据)
"aftee_Date_ThreadId_TrackId_R_reason.wav" // RecordTrack(送给AudioRecord的数据)
"aftee_Date_ThreadId_TrackId_TrackName_T_reason.wav" // PlaybackTrack (AudioTrack写下来的数据)
二、准备工作
2.1 编译时设置
- 修改frameworks/av/services/audioflinger/Configuration.h,对 #define TEE_SINK 取消注释
- 重新编译 libaudioflinger.so
- 将 64与32位的 libaudioflinger.so 推送或同步到设备的 /system/lib
Android 9 也要编译 audioserver 推进车机
2.2 运行时设置
- 开启debug开关
getprop | grep ro.debuggable
确认输出是:[ro.debuggable]: [1]
- 创建文件目录
ls -ld /data/misc/audioserver,
确认输出是:drwx------ audioserver audioserver ... audioserver
如果目录不存在,请按如下方式创建:
mkdir /data/misc/audioserver
chown audioserver:audioserver/data/misc/audioserver
- 修改配置文件
echo af.tee=# > /data/local.prop
af.tee 的值是一个 0 到 7 之间的数字,表示几个位的总和(每个功能一个位)
1 = 输入
2 = FastMixer 输出
4 = 各音轨的 AudioRecord 和 AudioTrack
chmod 644 /data/local.prop
- 重启系统
三.测试和获取数据
- 播放音频
- dumpsys media.audio_flinger
- 在 dumpsys 输出中查找如下行:
tee copied to /data/misc/audioserver/20131010101147_2.wav
这是一个 PCM .wav 文件
- adb pull /data/misc/audioserver/*.wav 文件
四、截取位置代码分析
T 及 R 录音文件的截取位置:
// frameworks/av/services/audioflinger/Tracks.cpp
// AudioBufferProvider interface
// getNextBuffer() = 0;
// This implementation of releaseBuffer() is used by Track and RecordTrack
void AudioFlinger::ThreadBase::TrackBase::releaseBuffer(AudioBufferProvider::Buffer* buffer)
{
#ifdef TEE_SINK
mTee.write(buffer->raw, buffer->frameCount);
#endif
F录音文件的截取位置:
//frameworks/av/services/audioflinger/FastMixer.cpp
void FastMixer::onWork()
{
...
// if non-NULL, then duplicate write() to this non-blocking sink
#ifdef TEE_SINK
mTee.write(buffer, frameCount);
#endif
// FIXME write() is non-blocking and lock-free for a properly implemented NBAIO sink,
// but this code should be modified to handle both non-blocking and blocking sinks
dumpState->mWriteSequence++;
ATRACE_BEGIN("write");
ssize_t framesWritten = mOutputSink->write(buffer, frameCount);
ATRACE_END();
...
}
M录音文件的截取位置:
// frameworks/av/services/audioflinger/Threads.cpp
// shared by MIXER and DIRECT, overridden by DUPLICATING
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
} else {
bytesWritten = framesWritten;
}