08.音频系统:第008课_项目实战2_多APP同时录音:第003节_修改代码支持多APP同时录音

该小节我们修改android系统源代码,让系统支持APP。先来回顾一下上一节的内容:
在这里插入图片描述
在源生的代码中,我们找到了其不能同时录制声音的原因:对于同一个声卡的录音通道(input),他对应一个或者对个RecordThread线程。如果我们能实现如下框架:
在这里插入图片描述
同一个声卡的input通道,对应一个RecordThread线程,然后RecordThread中包括多个Track,每个Track都对应一个应用程序。在RecordThread其本身是支持多个Track的。

我们先来看看源生代码是怎么做的:
APP:创建一个AudioRecord,通过其中set函数。最终导致1.RecordThread被创建。2.在RecordThread中创建一个Track。之后RecordThread会从硬件读取数据,然后写入到Track之中,通过共享内存,应用程序就能得到数据了。

现在我们要进行改进:1.先判断该输入通道是否已经有了RecordThread,如果有了则返回,否则进行创建。2.其上的输入通道就是APP要使用的通道,APP指定inputSource,然后AudiopolicyManager确定device(type,再找到吻合的profile,即input通道。流程如下:
在这里插入图片描述
那么怎么去判断input通道是否已经有了RecordThread线程呢?如下:
在这里插入图片描述
在上小节中提到,每个inout通道,都有对应的一个AudioInputDescriptor描述符,AudioInputDescriptor有一个或者多个成员为const sp mProfile,每个mProfile对应一个RecordThread。

我们打开AudioPolicyManager.cpp,其最终会调用到:

status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr,audio_io_handle_t *input,audio_session_t session,uid_t uid,uint32_t samplingRate,audio_format_t format,audio_channel_mask_t channelMask,audio_input_flags_t flags, audio_port_handle_t selectedDeviceId,input_type_t *inputType)
	/*找到input*/
	*input = getInputForDevice(device, address, session, uid, inputSource,samplingRate, format, channelMask, flags,policyMix);
		/*从所有的profile中,找到支持的profile,即应用程序需要的输入通道*/
		profile = getInputProfile(device, address,profileSamplingRate, profileFormat, profileChannelMask,profileFlags);

找到通道之后,添加我们需要修改的代码如下

    audio_config_t config = AUDIO_CONFIG_INITIALIZER;
    config.sample_rate = profileSamplingRate;
    config.channel_mask = profileChannelMask;
    config.format = profileFormat;
    
+	/* check wether have an AudioInputDescriptor use the same profile */
+	for (size_t input_index = 0; input_index < mInputs.size(); input_index++) {
+		sp<AudioInputDescriptor> desc;
+		desc = mInputs.valueAt(input_index);
+		if (desc->mProfile == profile) {
+			desc->mOpenRefCount++;        // 引用计数加1    
+			desc->mSessions.add(session); // session
+			return desc->mIoHandle;
+		}
+	}

status_t status = mpClientInterface->openInput(profile->getModuleHandle(),	

下面对我们添加的代码进行讲解:

	/* check wether have an AudioInputDescriptor use the same profile */
	for (size_t input_index = 0; input_index < mInputs.size(); input_index++) {
		sp<AudioInputDescriptor> desc;
		/*通过循环,取出每个AudioInputDescriptor*/
		desc = mInputs.valueAt(input_index);
		/*判断一下是不是我们想要的profile,如果是了,则代表去已经创建RecordThread线程改了*/
		if (desc->mProfile == profile) {
			desc->mOpenRefCount++;        // 引用计数加1    
			desc->mSessions.add(session); // session
			/*返回他的索引值*/
			return desc->mIoHandle;
		}
	}	

其上的session是什么?之前我们说应用程序录音时,会创建一个AudioRecord,AudioRecord会与RecordThread中的一个track对应,他们之间会存在一个联系,这个联系就是session。一个应用程序是可以创建多个AudioRecord的:
在这里插入图片描述
我们知道每个AudioRecord都会对应到RecordThread的track,这样一个APP则会对应一个RecordThread的多个track。session为一个不重复的整数。通过desc->mSessions.add(session),session会被添加到描述符之中。以后就能通过sp desc获得session,再根据session,可以找到应用程序的AudioRecord,也能找到RecordThread的track。

添加代码之后,重新编译,然后按照上小节博客,同时运行两个c++编写的录音程序即可。

猜你喜欢

转载自blog.csdn.net/weixin_43013761/article/details/89841952