ringtone播放分析当播放音乐时,不同的的输出流会根据不同stragy,来选择输出设备,然后播放音乐。
下面开始分析,当选择要播放的音乐后,设备是如何设置的。
根据打印信息我们可以看到从文件AudioFlinger.cpp中 函数start开始设置输出设备
status_t AudioFlinger::PlaybackThread::Track::start()
{
……
if (!isOutputTrack() && state != ACTIVE && state != RESUMING) {
thread...
当播放音乐时,不同的的输出流会根据不同stragy,来选择输出设备,然后播放音乐。
下面开始
,当选择要播放的音乐后,设备是如何设置的。
根据打印信息我们可以看到从文件AudioFlinger.cpp中 函数start开始设置输出设备
status_t AudioFlinger::PlaybackThread::Track::start()
{
……
if (!isOutputTrack() && state != ACTIVE && state != RESUMING) {
thread->mLock.unlock();
status = AudioSystem::startOutput(thread->id(), (AudioSystem::stream_type)mStreamType,
mSessionId);
thread->mLock.lock();
}
……
}
然后AudioSystem::startOutput(……)调用的是文件AudioSystem.cpp中的
status_t AudioSystem::startOutput(audio_io_handle_t output,
AudioSystem::stream_type stream,
int session)
{
const sp
& aps = AudioSystem::get_audio_policy_service();
if (aps == 0) return PERMISSION_DENIED;
return aps->startOutput(output, stream, session);
}
然后根据打印信息可以看到aps->startOutput(output, stream, session);调用的是文件AudioYusuPolicyManager.cpp中的函数
status_t AudioYusuPolicyManager::startOutput(audio_io_handle_t output,
AudioSystem::stream_type stream,
int session)
{
LOGD("startOutput() output %d, stream %d, session %d", output, stream, session);
……
outputDesc->changeRefCount(stream, 1);
setOutputDevice(output, getNewDevice(output));
……
}
在函数AudioYusuPolicyManager::startOutput()中我们可以看到outputDesc->changeRefCount(stream, 1);先根据输出流调用changeRefCount()更新数组mRefCount[stream],然后早通过getNewDevice(output)获取新的设备。
uint32_t AudioYusuPolicyManager::getNewDevice(audio_io_handle_t output, bool fromCache)
{
uint32_t device = 0;
AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output);
if (isInCall() ||
outputDesc->isUsedByStrategy(STRATEGY_PHONE)) {
device = getDeviceForStrategy(STRATEGY_PHONE, fromCache);
} else if (outputDesc->isUsedByStrategy(STRATEGY_SONIFICATION)) {
device = getDeviceForStrategy(STRATEGY_SONIFICATION, fromCache);
} else if (outputDesc->isUsedByStrategy(STRATEGY_MEDIA)) {
device = getDeviceForStrategy(STRATEGY_MEDIA, fromCache);
} else if (outputDesc->isUsedByStrategy(STRATEGY_DTMF)) {
device = getDeviceForStrategy(STRATEGY_DTMF, fromCache);
}else if (outputDesc->isUsedByStrategy(STRATEGY_PRIPRIOTARY)) {
device = getDeviceForStrategy(STRATEGY_PRIPRIOTARY, fromCache);
}
LOGV("getNewDevice() selected device %x output= %d", device,output);
return device;
}
在isUsedByStrategy()中就是根据先前更新的数组mRefCount[stream],来判断是否是对应的输出流对应的策略,isUsedByStrategy具体对应的函数是strategyRefCount()
uint32_t AudioYusuPolicyManager::AudioOutputDescriptor::strategyRefCount(routing_strategy strategy)
{
uint32_t refCount = 0;
for (int i = 0; i < (int)AudioSystem::NUM_STREAM_TYPES; i++) {
if (getStrategy((AudioSystem::stream_type)i) == strategy) {
refCount += mRefCount[i];
}
}
return refCount;
}
根据输出流如果判断是当前对应的策略,则根据策略回去当前的设备device = getDeviceForStrategy(STRATEGY_*, fromCache);
uint32_t AudioYusuPolicyManager::getDeviceForStrategy(routing_strategy strategy, bool fromCache)
{
uint32_t device = 0;
LOGV("getDeviceForStrategy() from cache strategy %d, device %x mAvailableOutputDevices = %x" , strategy, mDeviceForStrategy[strategy],mAvailableOutputDevices);
if (fromCache) {
LOGV("getDeviceForStrategy() from cache strategy %d, device %x", strategy, mDeviceForStrategy[strategy]);
return mDeviceForStrategy[strategy];
}
switch (strategy) {
case STRATEGY_DTMF:……
case STRATEGY_PHONE:……
case STRATEGY_PRIPRIOTARY:……
case STRATEGY_SONIFICATION:
// If incall, just select the STRATEGY_PHONE device: The rest of the behavior is handled by
// handleIncallSonification().
if (isInCall()) {
device = getDeviceForStrategy(STRATEGY_PHONE, false);
break;
}
device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_SPEAKER;
if (device == 0) {
LOGE("getDeviceForStrategy() speaker device not found");
}
// The second device used for sonification is the same as the device used by media strategy
// FALL THROUGH
case STRATEGY_MEDIA: {
// modified by chipeng
//uint32_t device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_AUX_DIGITAL;
uint32_t device2 = 0;
#ifdef WITH_A2DP
if (mA2dpOutput != 0 && (!isInCall()) ) {
if (strategy == STRATEGY_SONIFICATION && !a2dpUsedForSonification()) {
break;
}
if (device2 == 0) {
device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP;
}
if (device2 == 0) {
device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
}
if (device2 == 0) {
device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
}
}
#endif
if (device2 == 0) {
device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE;
}
if (device2 == 0) {
device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADSET;
}
// move digital
if(device2 ==0){
device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_AUX_DIGITAL;
}
if (device2 == 0) {
device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_SPEAKER;
}
// device is DEVICE_OUT_SPEAKER if we come from case STRATEGY_SONIFICATION, 0 otherwise
device |= device2;
if (device == 0) {
LOGE("getDeviceForStrategy() speaker device not found");
}
} break;
……
}
}
当获取新的设备之后然后调用setOutputDevice(output, getNewDevice(output));设置输出流的输出设备。具体流程如下
start-> startOutput-> changeRefCount-> getNewDevice->setOutputDevice;
在分析问题时,我们根据打印信息发现当插入耳机后,硬件检测到了耳机的插入并设置成功, 我们在预览情景模式播放ringtone时发信根据输出流AudioSystem:RING的获取对应的策略是STRATEGY_SONIFICATION:(闹钟也是此策略)但是在此策略中,根据上面代码可以看出输出设备的设置是外放和耳机同时播放,这就是问题的根被原因。所以我们根据分析,修改了输出流AudioSystem:RING对应的策略。
具体修改内容如下:首先在AudioYusuPolicyManager.h中添加新的策略STRATEGY_RINGTONE
enum routing_strategy {
STRATEGY_MEDIA,
STRATEGY_PHONE,
STRATEGY_SONIFICATION,
STRATEGY_DTMF,
STRATEGY_PRIPRIOTARY,
STRATEGY_RINGTONE,//add by anxueyan
NUM_STRATEGIES
};
然后在文件AudioYusuPolicyManager.cpp中的函数getStrategy,修改输出流的策略。
AudioYusuPolicyManager::routing_strategy AudioYusuPolicyManager::getStrategy(
AudioSystem::stream_type stream) {
// stream to strategy mapping
switch (stream) {
case AudioSystem::VOICE_CALL:
case AudioSystem::BLUETOOTH_SCO:
return STRATEGY_PHONE;
case AudioSystem::RING:
return STRATEGY_RINGTONE; //add by anxueyan
case AudioSystem::NOTIFICATION:
case AudioSystem::ALARM:
case AudioSystem::ENFORCED_AUDIBLE:
return STRATEGY_SONIFICATION;
case AudioSystem::DTMF:
return STRATEGY_DTMF;
……
}
}
修改函数uint32_t AudioYusuPolicyManager::getNewDevice(audio_io_handle_t output, bool fromCache)
{
……
if (isInCall() ||
outputDesc->isUsedByStrategy(STRATEGY_PHONE)) {
device = getDeviceForStrategy(STRATEGY_PHONE, fromCache);
}
……
//add by anxueyan
else if (outputDesc->isUsedByStrategy(STRATEGY_RINGTONE)) {
device = getDeviceForStrategy(STRATEGY_RINGTONE, fromCache);
}
//end add
……
}
最后重点修改getDeviceForStrategy()函数,在case STRATEGY_SONIFICATION:之前添加内容如下
case STRATEGY_RINGTONE:
uint32_t device2 = 0;
// handleIncallSonification().
if (isInCall()) {
device = getDeviceForStrategy(STRATEGY_PHONE, false);
break;
}
if (device2 == 0) {
device2 = mAvailableOutputDevices&AudioSystem::DEVICE_OUT_WIRED_HEADPHONE;
}
if (device2 == 0) {
device2 =
mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADSET;
}
// move digital
if(device2 ==0){
device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_AUX_DIGITAL;
}
if (device2 == 0) {
device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_SPEAKER;
}
device |= device2;
if (device == 0) {
LOGE("getDeviceForStrategy() speaker device not found");
}
break;
添加内容之后,执行命令./mk lcsh73_gb new android 即可。
本文档为【ringtone播放分析】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑,
图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。
本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。
网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。