Android 5.1 Audio系统笔记:AudioRecord
Posted Mr.Biandan
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 5.1 Audio系统笔记:AudioRecord相关的知识,希望对你有一定的参考价值。
AudioRecord
- 前言
- AudioTrack
- 第一部分:AudioRecord创建
前言
还是绕不开录音部分,最近想了解一下重采样的内容,但是毫无头绪,硬着头皮先把AudioRecord熟悉一遍先。牵涉到audioflinger这块都是弯弯绕绕的,Are you ready ?
AudioTrack
AudioTrack,录音部分的核心,往简单的说无非以下几部分:
1、AudioRecord的创建:创建相应的线程
2、AudioRecord音频路由建立
3、开始读数据
第一部分:AudioRecord创建
从frameworks/base/media/java/android/media/AudioRecord.java开始
new AudioRecord();
//frameworks/base/core/jni/android_media_AudioRecord.cpp
public AudioRecord(AudioAttributes attributes, AudioFormat format, int bufferSizeInBytes,
int sessionId) throws IllegalArgumentException
1.标记mRecordingState为stoped状态;
2.获取一个MainLooper;
3.判断录音源是否是REMOTE_SUBMIX,有兴趣的童鞋可以深入研究;
4.重新获取rate与format参数,这里会根据AUDIO_FORMAT_HAS_PROPERTY_X来判断从哪里获取参数,而在之前的构造函数中,设置参数的时候已经标记了该标志位,所以这两个参数还是我们设置的;
5.调用audioParamCheck对参数再一次进行检查合法性;
6.获取声道数以及声道掩码,单声道掩码为0x10,双声道掩码为0x0c;
7.调用audioBuffSizeCheck检查最小缓冲区大小是否合法;
8. 调用native_setup的native函数 ,注意这里传过去的参数包括:指向自己的指针,录制源,rate,声道掩码,format,minBuffSize,session[];
9.标记mRecordingState为inited状态;
注:关于SessionId
一个Session就是一个会话,每个会话都有一个独一无二的Id来标识。该Id的最终管理在AudioFlinger中。
一个会话可以被多个AudioTrack对象和MediaPlayer共用。
共用一个Session的AudioTrack和MediaPlayer共享相同的AudioEffect(音效)
8.1 native_setup
//frameworks/base/core/jni/android_media_AudioRecord.cpp
static jint
android_media_AudioRecord_setup(JNIEnv *env, jobject thiz, jobject weak_this,
jobject jaa, jint sampleRateInHertz, jint channelMask,
// Java channel masks map directly to the native definition
jint audioFormat, jint buffSizeInBytes, jintArray jSession)
8.1.1.判断声道掩码是否合法,然后通过掩码计算出声道数;
8.1.2.由于最小缓冲区大小是采样帧数量*每个采样帧大小得出,每个采样帧大小为所有声道数所占的字节数,从而求出采样帧数量frameCount;
8.1.3.进行一系列的JNI处理录音源,以及把AudioRecord.java的指针绑定到lpCallbackData回调数据中,
这样就能把数据通过回调的方式通知到上层;
8.1.4.调用AudioRecord的set函数(lpRecorder->set),这里注意下flags,他的类型为audio_input_flags_t,
定义在system\\core\\include\\system\\audio.h中,
作为音频输入的标志,这里设置为AUDIO_INPUT_FLAG_NONE
typedef enum
AUDIO_INPUT_FLAG_NONE = 0x0, // no attributes
AUDIO_INPUT_FLAG_FAST = 0x1, // prefer an input that supports "fast tracks"
AUDIO_INPUT_FLAG_HW_HOTWORD = 0x2, // prefer an input that captures from hw hotword source
audio_input_flags_t;
8.1.5.把lpRecorder对象以及lpCallbackData回调保存到javaAudioRecordFields的相应字段中
8.1.4 set
frameworks\\av\\media\\libmedia\\AudioRecord.cpp
status_t AudioRecord::set(
audio_source_t inputSource,
uint32_t sampleRate,
audio_format_t format,
audio_channel_mask_t channelMask,
size_t frameCount,
callback_t cbf,
void* user,
uint32_t notificationFrames,
bool threadCanCallJava,
int sessionId,
transfer_type transferType,
audio_input_flags_t flags,
const audio_attributes_t* pAttributes)
8.1.4.1.在JNI中传递过来的参数:transferType为TRANSFER_DEFAULT,cbf!=null,threadCanCallJava=true,
所以mTransfer设置为TRANSFER_SYNC,他是决定如何从AudioRecord传输数据方式,后面会用到;
8.1.4.2.保存相关的参数,如录制源mAttributes.source,采样率mSampleRate,采样精度mFormat,
声道掩码mChannelMask,声道数mChannelCount,采样帧大小mFrameSize,采样帧数量mReqFrameCount,
通知帧计数mNotificationFramesReq,mSessionId在这里更新了,
音频输入标志mFlags还是之前的AUDIO_INPUT_FLAG_NONE
8.1.4.3.当cbf数据回调函数不为null时,开启一个录音线程AudioRecordThread;
8.1.4.4.调用openRecord_l(0)创建IAudioRecord对象;
8.1.4.5.如果建立失败,就销毁录音线程AudioRecordThread,否则更新参数;
8.1.4.4 创建IAudioRecord对象 openRecord_l
//frameworks\\av\\media\\libmedia\\AudioRecord.cpp
status_t AudioRecord::openRecord_l(size_t epoch)
8.1.4.4.1.获取IAudioFlinger对象,其通过binder和AudioFlinger通信,所以也就是相当于直接调用到AudioFlinger服务中了;
8.1.4.4.2.判断音频输入标志,是否需要清除AUDIO_INPUT_FLAG_FAST标志位,这里不需要,一直是AUDIO_INPUT_FLAG_NONE;
8.1.4.4.3.调用Audiosystem::getInputForAttr获取输入流的句柄input;
8.1.4.4.4.调用audioFlinger->openRecord创建IAudioRecord对象;
8.1.4.4.5.通过IMemory共享内存,获取录音数据;
8.1.4.4.6.更新AudioRecordClientProxy客户端代理的录音数据;
8.1.4.4.3 getInputForAttr
//frameworks\\av\\media\\libmedia\\AudioSystem.cpp
status_t AudioSystem::getInputForAttr(const audio_attributes_t *attr,
audio_io_handle_t *input,
audio_session_t session,
uint32_t samplingRate,
audio_format_t format,
audio_channel_mask_t channelMask,
audio_input_flags_t flags)
const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
if (aps == 0) return NO_INIT;
return aps->getInputForAttr(attr, input, session, samplingRate, format, channelMask, flags);
8.1.4.4.3.1 AudioPolicyService::getInputForAttr
frameworks\\av\\services\\audiopolicy\\AudioPolicyInterfaceImpl.cpp
status_t AudioPolicyService::getInputForAttr(const audio_attributes_t *attr,
audio_io_handle_t *input,
audio_session_t session,
uint32_t samplingRate,
audio_format_t format,
audio_channel_mask_t channelMask,
audio_input_flags_t flags)
8.1.4.4.3.1.1.对source为HOTWORD或FM_TUNER的录音源,判断是否具有相应的录音权限(根据应用进程号);
8.1.4.4.3.1.2.继续调用AudioPolicyManager的方法(AudioPolicyManager::getInputForAttr)获取input以及inputType;
8.1.4.4.3.1.3.检查应用是否具有该inputType的录音权限;
8.1.4.4.3.1.4.判断是否需要添加音效(audioPolicyEffects),需要则使用audioPolicyEffects->addInputEffects添加音效;
8.1.4.4.3.1.2 AudioPolicyManager::getInputForAttr
//frameworks\\av\\services\\audiopolicy\\AudioPolicyManager.cpp
status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr,
audio_io_handle_t *input,
audio_session_t session,
uint32_t samplingRate,
audio_format_t format,
audio_channel_mask_t channelMask,
audio_input_flags_t flags,
input_type_t *inputType)
8.1.4.4.3.1.2.1.调用getDeviceAndMixForInputSource函数获取policyMix设备以及对应的audio_device_t设备类型(device)
8.1.4.4.3.1.2.2.获取inputType的类型
8.1.4.4.3.1.2.3.更新channelMask,适配声道到输入源;
8.1.4.4.3.1.2.4.调用getInputProfile,根据传进来的采样率/精度/掩码等参数与获得的设备支持的Input Profile比较,
返回一个与设备Profile匹配的IOProfile对象,IOProfile是用来描述输出或输入流的能力,
策略管理器使用它来确定输出或输入是否适合于给定的用例, 相应地打开/关闭它,以及连接/断开音频轨道;
8.1.4.4.3.1.2.5.如果获取失败的话,则使用AUDIO_INPUT_FLAG_NONE再次获取一遍,如果依然失败,则return一个bad news;
8.1.4.4.3.1.2.6.继续调用mpClientInterface->openInput建立起输入流;
8.1.4.4.3.1.2.7.根据IOProfile对象构造AudioInputDescriptor,并绑定到input流中,最后更新AudioPortList;
8.1.4.4.3.1.2.1.调用getDeviceAndMixForInputSource
首先看下AudioPolicyManager.cpp::getInputForAttr()的第1步.获取policyMix设备以及对应的audio_device_t设备类型(device)
audio_devices_t AudioPolicyManager::getDeviceAndMixForInputSource(audio_source_t inputSource,
AudioMix **policyMix)
这里就是通过InputSource去获取相应的policyMix与audio_device_t设备类型了,
从这里也可以看出Android系统上对Audio设备的分类有多少种了。
类似AudioTrack的音频策略找到相应的设备类型,这里就是录音的策略了。
8.1.4.4.4 audioFlinger->openRecord
//frameworks\\av\\services\\audiopolicy\\AudioPolicyClientImpl.cpp
status_t AudioPolicyService::AudioPolicyClient::openInput(audio_module_handle_t module,
audio_io_handle_t *input,
audio_config_t *config,
audio_devices_t *device,
const String8& address,
audio_source_t source,
audio_input_flags_t flags)
sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
if (af == 0)
ALOGW("%s: could not get AudioFlinger", __func__);
return PERMISSION_DENIED;
return af->openInput(module, input, config, device, address, source, flags);
8.1.4.4.4.1 AudioFlinger::openInput
这里就调用到了AF端的openInput函数了
//frameworks\\av\\services\\audioflinger\\AudioFlinger.cpp
status_t AudioFlinger::openInput(audio_module_handle_t module,
audio_io_handle_t *input,
audio_config_t *config,
audio_devices_t *device,
const String8& address,
audio_source_t source,
audio_input_flags_t flags)
8.1.4.4.4.1.1.findSuitableHwDev_l中通过IOProfile中的module.handle与audio_device_t设备类型找到Hw模块;
8.1.4.4.4.1.2.调用HAL层inHwHal->open_input_stream打开输入流;
8.1.4.4.4.1.3.如果失败了,再继续调用一次;
8.1.4.4.4.1.4.根据inHwDev与inStream创建AudioStreamIn对象,如此,就建立起了一个输入流了,
AudioStreamIn定义在frameworks\\av\\services\\audioflinger\\AudioFlinger.h;
8.1.4.4.4.1.5.创建一个RecordThread线程,并把该线程加入到mRecordThreads线程中,
这个线程是在AudioRecord.cpp::set()函数中创建的;
8.1.4.4.4.1.2 调用HAL层 open_input_stream
//hardware\\aw\\audio\\tulip\\audio_hw.c
static int adev_open_input_stream(struct audio_hw_device *dev,
audio_io_handle_t handle,
audio_devices_t devices,
struct audio_config *config,
struct audio_stream_in **stream_in)
1.检查rate,format,channel参数是否支持;
2.给sunxi_stream_in输入流对象分配内存空间;
3.绑定相应参数的获取/设置方法;
4.为输入流创建buff空间:in->config.period_size *audio_stream_frame_size(&in->stream.common) * 8;
5.如果是AUDIO_DEVICE_IN_AF类型的设备的话,则对PcmManager做相应处理;
这个输入流对象会绑定到AF中的AudioStreamIn对象中,所以到这里,输入流对象就已经完全创建好了。
8.1.4.4.4.1.5 创建一个RecordThread线程
//frameworks\\av\\services\\audioflinger\\Threads.cpp
udioFlinger::RecordThread::RecordThread(const sp<AudioFlinger>& audioFlinger,
AudioStreamIn *input,
audio_io_handle_t id,
audio_devices_t outDevice,
audio_devices_t inDevice
#ifdef TEE_SINK
, const sp<NBAIO_Sink>& teeSink
#endif
) :
ThreadBase(audioFlinger, id, outDevice, inDevice, RECORD),
mInput(input), mActiveTracksGen(0), mRsmpInBuffer(NULL),
// mRsmpInFrames and mRsmpInFramesP2 are set by readInputParameters_l()
mRsmpInRear(0)
#ifdef TEE_SINK
, mTeeSink(teeSink)
#endif
, mReadOnlyHeap(new MemoryDealer(kRecordThreadReadOnlyHeapSize,
"RecordThreadRO", MemoryHeapBase::READ_ONLY))
// mFastCapture below
, mFastCaptureFutex(0)
// mInputSource
// mPipeSink
// mPipeSource
, mPipeFramesP2(0)
// mPipeMemory
// mFastCaptureNBLogWriter
, mFastTrackAvail(false)
1.调用readInputParameters_l函数把录音参数读取到线程空间中;
2.创建AudioStreamInSource对象,作为线程中间中的输入流,其实现是在frameworks\\av\\media\\libnbaio\\AudioStreamInSource.cpp
8.1.4.4 调用 thread->createRecordTrack_l创建IAudioRecord对象
sp<IAudioRecord> AudioFlinger::openRecord(
audio_io_handle_t input,
uint32_t sampleRate,
audio_format_t format,
audio_channel_mask_t channelMask,
size_t *frameCount,
IAudioFlinger::track_flags_t *flags,
pid_t tid,
int *sessionId,
size_t *notificationFrames,
sp<IMemory>& cblk,
sp<IMemory>& buffers,
status_t *status)
1.调用recordingAllowed检查录音权限;
2.判断参数是否非法;
3.调用checkRecordThread_l函数,根据input从AudioRecordThread线程中获取该input的RecordThread,在前面的分析中可以得知,这个RecordThread是在AudioFlinger.cpp::openInput函数中创建并添加到AudioRecordThread中的;
4.调用createRecordTrack_l方法创建一个RecordTrack对象,RecordThread::RecordTrack对象的作用是管理RecordThread中的音频数据;
5.通过SessionId获取是否存在effect chain,若有,则加到RecordThread中;
6.通过RecordTrack获取cblk以及buffers,他们就是CblkMemory以及BufferMemory;
7.根据recordTrack,创建RecordHandle对象,实现位置:frameworks\\av\\services\\audioflinger\\Tracks.cpp,也就完成了IAudioRecord对象的创建了,也就是说IAudioRecord的方法是在Tracks.cpp中实现的;
调用createRecordTrack_l方法创建一个RecordTrack对象
sp<AudioFlinger::RecordThread::RecordTrack> AudioFlinger::RecordThread::createRecordTrack_l(
const sp<AudioFlinger::Client>& client,
uint32_t sampleRate,
audio_format_t format,
audio_channel_mask_t channelMask,
size_t *pFrameCount,
int sessionId,
size_t *notificationFrames,
int uid,
IAudioFlinger::track_flags_t *flags,
pid_t tid,
status_t *status)
这个函数重要的一点就是重新计算了frameCount大小,然后根据新的参数创建了RecordTrack对象,然后return。
当应用层new AudioRecord时,系统建立起了输入流,并创建了RecordThread线程,现在录音的准备工作已经完成,就等待应用层开启录音了。
本文是整理得出:https://www.cnblogs.com/pngcui/p/10016538.html ,
然鹅是5.1的跟9.0千差万别。。。。。。。。。。。。下一篇基于Android9.0的,,,正在重新整理校验中。。。。
以上是关于Android 5.1 Audio系统笔记:AudioRecord的主要内容,如果未能解决你的问题,请参考以下文章
Android 9 Audio系统笔记:AudioRecord
Android 9 Audio系统笔记:AudioFlinger音频流处理流程
Android 9 Audio系统笔记:音量调节从CarAudioManager到tinyalsa