回答这个问题前,首先找到是哪里调用了音频策略的选择设备的函数。
在前面分析中,可知道AUdioTrack的流程中——Android Audio:AudioTrack构造函数分析
有一个createTrack走到了音频策略选择。
PS:基于Android P源码分析,实习内容,分析不够准确,只供参考和自己学习。
frameworks\av\services\audioflinger\AudioFlinger.cpp
sp<IAudioTrack> AudioFlinger::createTrack(const CreateTrackInput& input,
CreateTrackOutput& output,
status_t *status)
{
sp<PlaybackThread::Track> track;
sp<TrackHandle> trackHandle;
sp<Client> client;
status_t lStatus;
audio_stream_type_t streamType;
audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE;
bool updatePid = (input.clientInfo.clientPid == -1);
const uid_t callingUid = IPCThreadState::self()->getCallingUid();
uid_t clientUid = input.clientInfo.clientUid;
if (!isTrustedCallingUid(callingUid)) {
ALOGW_IF(clientUid != callingUid,
"%s uid %d tried to pass itself off as %d",
__FUNCTION__, callingUid, clientUid);
clientUid = callingUid;
updatePid = true;
}
pid_t clientPid = input.clientInfo.clientPid;
if (updatePid) {
const pid_t callingPid = IPCThreadState::self()->getCallingPid();
ALOGW_IF(clientPid != -1 && clientPid != callingPid,
"%s uid %d pid %d tried to pass itself off as pid %d",
__func__, callingUid, callingPid, clientPid);
clientPid = callingPid;
}
audio_session_t sessionId = input.sessionId;
if (sessionId == AUDIO_SESSION_ALLOCATE) {
sessionId = (audio_session_t) newAudioUniqueId(AUDIO_UNIQUE_ID_USE_SESSION);
} else if (audio_unique_id_get_use(sessionId) != AUDIO_UNIQUE_ID_USE_SESSION) {
lStatus = BAD_VALUE;
goto Exit;
}
output.sessionId = sessionId;
output.outputId = AUDIO_IO_HANDLE_NONE;
output.selectedDeviceId = input.selectedDeviceId;
lStatus = AudioSystem::getOutputForAttr(&input.attr, &output.outputId, sessionId, &streamType,
clientPid, clientUid, &input.config, input.flags,
&output.selectedDeviceId, &portId);
if (lStatus != NO_ERROR || output.outputId == AUDIO_IO_HANDLE_NONE) {
ALOGE("createTrack() getOutputForAttr() return error %d or invalid output handle", lStatus);
goto Exit;
}
// client AudioTrack::set already implements AUDIO_STREAM_DEFAULT => AUDIO_STREAM_MUSIC,
// but if someone uses binder directly they could bypass that and cause us to crash
if (uint32_t(streamType) >= AUDIO_STREAM_CNT) {
ALOGE("createTrack() invalid stream type %d", streamType);
lStatus = BAD_VALUE;
goto Exit;
}
// further channel mask checks are performed by createTrack_l() depending on the thread type
if (!audio_is_output_channel(input.config.channel_mask)) {
ALOGE("createTrack() invalid channel mask %#x", input.config.channel_mask);
lStatus = BAD_VALUE;
goto Exit;
}
// further format checks are performed by createTrack_l() depending on the thread type
if ((!audio_is_valid_format(input.config.format)) &&
((property_get_bool("audio.aptx.aac_latm.decoder.enabled", false)) &&
(!(input.config.format == AUDIO_FORMAT_AAC_LATM_LC || input.config.format == AUDIO_FORMAT_APTX)))) {
ALOGE("createTrack() invalid format %#x", input.config.format);
lStatus = BAD_VALUE;
goto Exit;
}
{
Mutex::Autolock _l(mLock);
PlaybackThread *thread = checkPlaybackThread_l(output.outputId);
if (thread == NULL) {
ALOGE("no playback thread found for output handle %d", output.outputId);
lStatus = BAD_VALUE;
goto Exit;
}
client = registerPid(clientPid);
PlaybackThread *effectThread = NULL;
// check if an effect chain with the same session ID is present on another
// output thread and move it here.
for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
sp<PlaybackThread> t = mPlaybackThreads.valueAt(i);
if (mPlaybackThreads.keyAt(i) != output.outputId) {
uint32_t sessions = t->hasAudioSession(sessionId);
if (sessions & ThreadBase::EFFECT_SESSION) {
effectThread = t.get();
break;
}
}
}
ALOGV("createTrack() sessionId: %d", sessionId);
output.sampleRate = input.config.sample_rate;
output.frameCount = input.frameCount;
output.notificationFrameCount = input.notificationFrameCount;
output.flags = input.flags;
track = thread->createTrack_l(client, streamType, input.attr, &output.sampleRate,
input.config.format, input.config.channel_mask,
&output.frameCount, &output.notificationFrameCount,
input.notificationsPerBuffer, input.speed,
input.sharedBuffer, sessionId, &output.flags,
input.clientInfo.clientTid, clientUid, &lStatus, portId);
LOG_ALWAYS_FATAL_IF((lStatus == NO_ERROR) && (track == 0));
// we don't abort yet if lStatus != NO_ERROR; there is still work to be done regardless
output.afFrameCount = thread->frameCount();
output.afSampleRate = thread->sampleRate();
output.afLatencyMs = thread->latency();
// move effect chain to this output thread if an effect on same session was waiting
// for a track to be created
if (lStatus == NO_ERROR && effectThread != NULL) {
// no risk of deadlock because AudioFlinger::mLock is held
Mutex::Autolock _dl(thread->mLock);
Mutex::Autolock _sl(effectThread->mLock);
moveEffectChain_l(sessionId, effectThread, thread, true);
}
// Look for sync events awaiting for a session to be used.
for (size_t i = 0; i < mPendingSyncEvents.size(); i++) {
if (mPendingSyncEvents[i]->triggerSession() == sessionId) {
if (thread->isValidSyncEvent(mPendingSyncEvents[i])) {
if (lStatus == NO_ERROR) {
(void) track->setSyncEvent(