Android 音频源码分析——音频设备切换(插入耳机)

Posted zpy_公众号_码农修仙儿

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 音频源码分析——音频设备切换(插入耳机)相关的知识,希望对你有一定的参考价值。

源码分析基于android9.0

通常带线耳机分类

  • 模拟耳机
    平时常用的3.5mm或6.3mm接口耳机,接收模拟信号(音频数据需要先处理,转码成pcm格式)
    android中模拟耳机由WiredAccessoryManager获取上报的事件,调用AudioService.setWiredDeviceConnectionState传递信息给Audioservice,更新设备信息。
  • 数字耳机
    例如USB Type-c耳机,接收数字信号(音频数据不需要解码成pcm,由耳机进行转换)
    Android中由UsbAlsaManager负责usb音频设备连接断开事件,调用AudioService.setWiredDeviceConnectionState传递信息给AudioService。

使用扬声器播放音乐,此时插入耳机,则音乐切换从耳机播放出。这里以插入数字耳机为例分析下音频设备切换流程。

一、Framework层

当设备插入usb 耳机,UsbHostManager会接收到usb设备事件调用usbDeviceAdded函数,调到UsbAlsaManager.usbDeviceAdded函数。

UsbAlsaManager.java

void usbDeviceAdded(String deviceAddress, UsbDevice usbDevice,
        UsbDescriptorParser parser) {
    //...
    if (hasInput || hasOutput) {
        
        UsbAlsaDevice alsaDevice =
                    new UsbAlsaDevice(mAudioService, cardRec.getCardNum(), 0 /*device*/,
                                      deviceAddress, hasOutput, hasInput,
                                      isInputHeadset, isOutputHeadset);
            if (alsaDevice != null) {
                alsaDevice.setDeviceNameAndDescription(
                          cardRec.getCardName(), cardRec.getCardDescription());
                mAlsaDevices.add(0, alsaDevice);
                selectAlsaDevice(alsaDevice);
            }
    }
}

private synchronized void selectAlsaDevice(UsbAlsaDevice alsaDevice) {
    //.......
    mSelectedDevice = alsaDevice;
    alsaDevice.start();
}
  • 创建UsbAlsaDevice,并设置信息;
  • 设置为mSelectedDevice;
  • 调用UsbAlsaDevice start,更新设备连接状态;

接着看UsbAlsaDevice start

public synchronized void start() {
    mSelected = true;
    mInputState = 0;
    mOutputState = 0;
    startJackDetect();
    updateWiredDeviceConnectionState(true);
}

public synchronized void updateWiredDeviceConnectionState(boolean enable) {
    //.......
     if (mHasOutput) {
         mAudioService.setWiredDeviceConnectionState(device, outputState,
                                                                alsaCardDeviceString,
                                                                mDeviceName, TAG);
     }
    
    if (mHasInput) {
        mAudioService.setWiredDeviceConnectionState(
                            device, inputState, alsaCardDeviceString,
                            mDeviceName, TAG);
    }
}

调用AudioService,设置设备连接状态。

AudioService

接下来分析AudioService中流程

public void setWiredDeviceConnectionState(int type, int state, String address, String name,
        String caller) {
    synchronized (mConnectedDevices) {
        if (DEBUG_DEVICES) {
            Slog.i(TAG, "setWiredDeviceConnectionState(" + state + " nm: " + name + " addr:"
                    + address + ")");
        }
        int delay = checkSendBecomingNoisyIntent(type, state, AudioSystem.DEVICE_NONE);
        queueMsgUnderWakeLock(mAudioHandler,
                MSG_SET_WIRED_DEVICE_CONNECTION_STATE,
                0 /* arg1 unused */,
                0 /* arg2 unused */,
                new WiredDeviceConnectionState(type, state, address, name, caller),
                delay);
    }
}

发送Message消息,由AudioHandler处理

public void handleMessage(Message msg) {
	switch (msg.what) {
        case MSG_SET_WIRED_DEVICE_CONNECTION_STATE:
            {   WiredDeviceConnectionState connectState =
                (WiredDeviceConnectionState)msg.obj;
             mDeviceLogger.log(new WiredDevConnectEvent(connectState));
             onSetWiredDeviceConnectionState(connectState.mType, connectState.mState,
                                             connectState.mAddress, connectState.mName, connectState.mCaller);
             mAudioEventWakeLock.release();
            }
            break;
    }
}

接着看onSetWiredDeviceConnectionState函数

private void onSetWiredDeviceConnectionState(int device, int state, String address,
        String deviceName, String caller) {
    synchronized (mConnectedDevices) {
        if ((state == 0) && ((device & DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG) != 0)) {
            setBluetoothA2dpOnInt(true, "onSetWiredDeviceConnectionState state 0");
        }

        if (!handleDeviceConnection(state == 1, device, address, deviceName)) {
            // change of connection state failed, bailout
            return;
        }
        //..... 
    }
   
    sendDeviceConnectionIntent(device, state, address, deviceName);
    updateAudioRoutes(device, state);
}
  • 如果是设备拔出,则设置A2dp;
  • handleDeviceConnection 处理设备连接;
  • 发送广播、更新audio通路;

接着分析handleDeviceConnection

private boolean handleDeviceConnection(boolean connect, int device, String address,
        String deviceName) {
     synchronized (mConnectedDevices) {
            String deviceKey = makeDeviceListKey(device, address);
            DeviceListSpec deviceSpec = mConnectedDevices.get(deviceKey);
            boolean isConnected = deviceSpec != null;
            
            if (connect && !isConnected) {
                //连接 处理
                final int res = AudioSystem.setDeviceConnectionState(device,
                        AudioSystem.DEVICE_STATE_AVAILABLE, address, deviceName);
                if (res != AudioSystem.AUDIO_STATUS_OK) {
                    return false;
                }
                mConnectedDevices.put(deviceKey, new DeviceListSpec(device, deviceName, address));
                sendMsg(mAudioHandler, MSG_ACCESSORY_PLUG_MEDIA_UNMUTE, SENDMSG_QUEUE,
                        device, 0, null, 0);
                return true;
            } else if (!connect && isConnected) {
                //断开连接 处理
                AudioSystem.setDeviceConnectionState(device,
                        AudioSystem.DEVICE_STATE_UNAVAILABLE, address, deviceName);
                // always remove even if disconnection failed
                mConnectedDevices.remove(deviceKey);
                return true;
            }
        }
        return false;
}

调用AudioSystem.setDeviceConnectionState处理状态,连接或者断开连接都调用此流程,只是参数不同,连接对应DEVICE_STATE_AVAILABLE。

接着看AudioSystem

AudioSystem

AudioSystem.java

public static native int setDeviceConnectionState(int device, int state,
                                                  String device_address, String device_name);

setDeviceConnectionState为native方法,直接看jni对应实现

android_media_AudioSystem.cpp

static jint
android_media_AudioSystem_setDeviceConnectionState(JNIEnv *env, jobject thiz, jint device, jint state, jstring device_address, jstring device_name)
{
    const char *c_address = env->GetStringUTFChars(device_address, NULL);
    const char *c_name = env->GetStringUTFChars(device_name, NULL);
    int status = check_AudioSystem_Command(AudioSystem::setDeviceConnectionState(static_cast <audio_devices_t>(device),
                                          static_cast <audio_policy_dev_state_t>(state),
                                          c_address, c_name));
    env->ReleaseStringUTFChars(device_address, c_address);
    env->ReleaseStringUTFChars(device_name, c_name);
    return (jint) status;
}

这里继续向下追查

AudioSystem.cpp

status_t AudioSystem::setDeviceConnectionState(audio_devices_t device,
                                               audio_policy_dev_state_t state,
                                               const char *device_address,
                                               const char *device_name)
{
    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
    const char *address = "";
    const char *name = "";

    if (aps == 0) return PERMISSION_DENIED;

    if (device_address != NULL) {
        address = device_address;
    }
    if (device_name != NULL) {
        name = device_name;
    }
    return aps->setDeviceConnectionState(device, state, address, name);
}
  • 获取AudioPolicyService;
  • 快进程调用AudioPolicyService setDeviceConnectionState;

二、audioserver

status_t AudioPolicyService::setDeviceConnectionState(audio_devices_t device,
                                                  audio_policy_dev_state_t state,
                                                  const char *device_address,
                                                  const char *device_name)
{
    if (mAudioPolicyManager == NULL) {
        return NO_INIT;
    }
    if (!settingsAllowed()) {
        return PERMISSION_DENIED;
    }
    if (state != AUDIO_POLICY_DEVICE_STATE_AVAILABLE &&
            state != AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE) {
        return BAD_VALUE;
    }

    ALOGV("setDeviceConnectionState()");
    Mutex::Autolock _l(mLock);
    AutoCallerClear acc;
    return mAudioPolicyManager->setDeviceConnectionState(device, state,
                                                         device_address, device_name);
}
  • 检查mAudioPolicyManager、权限、state;
  • 调用AudioPolicyManager对应setDeviceConnectionState;

AudioPolicyManager

setDeviceConnectionState调用setDeviceConnectionStateInt。

status_t AudioPolicyManager::setDeviceConnectionState(audio_devices_t device,
                                                      audio_policy_dev_state_t state,
                                                      const char *device_address,
                                                      const char *device_name)
{
    status_t status = setDeviceConnectionStateInt(device, state, device_address, device_name);
    nextAudioPortGeneration();
    return status;
}

status_t AudioPolicyManager::setDeviceConnectionStateInt(audio_devices_t device,
                                                         audio_policy_dev_state_t state,
                                                         const char *device_address,
                                                         const char *device_name)
{
        // connect/disconnect only 1 device at a time
    if (!audio_is_output_device(device) && !audio_is_input_device(device)) return BAD_VALUE;

    sp<DeviceDescriptor> devDesc =
            mHwModules.getDeviceDescriptor(device, device_address, device_name);

    // 处理输出设备
    if (audio_is_output_device(device)) {
        SortedVector <audio_io_handle_t> outputs;

        ssize_t index = mAvailableOutputDevices.indexOf(devDesc);

        // 在通过checkOutputsForDevice()打开或关闭任何输出之前,请保存打开的输出描述符的副本。 checkOutputForAllStrategies()将需要它
        mPreviousOutputs = mOutputs;
        switch (state)
        {
        // 处理输出设备连接
        case AUDIO_POLICY_DEVICE_STATE_AVAILABLE: {
            if (index >= 0) {
                return INVALID_OPERATION;
            }

            // register new device as available
            index = mAvailableOutputDevices.add(devDesc);
            if (index >= 0) {
                sp<HwModule> module = mHwModules.getModuleForDevice(device);
                if (module == 0) {
                    mAvailableOutputDevices.remove(devDesc);
                    return INVALID_OPERATION;
                }
                mAvailableOutputDevices[index]->attach(module);
            } else {
                return NO_MEMORY;
            }

            // Before checking outputs, broadcast connect event to allow HAL to retrieve dynamic
            // parameters on newly connected devices (instead of opening the outputs...)
            broadcastDeviceConnectionState(device, state, devDesc->mAddress);

            if (checkOutputsForDevice(devDesc, state, outputs, devDesc->mAddress) != NO_ERROR) {
                mAvailableOutputDevices.remove(devDesc);
                broadcastDeviceConnectionState(device, AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
                                               devDesc->mAddress);
                return INVALID_OPERATION;
            }
            // Propagate device availability to Engine
            mEngine->setDeviceConnectionState(devDesc, state);
            } break;
        // 处理输出设备断开连接
        case AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE: {
            //....
            } break;
        default:
            return BAD_VALUE;
        }

        // checkA2dpSuspend must run before checkOutputForAllStrategies so that A2DP
        // output is suspended before any tracks are moved to it
        checkA2dpSuspend();
        checkOutputForAllStrategies();
        // outputs must be closed after checkOutputForAllStrategies() is executed
        if (!outputs.isEmpty()) {
            for (audio_io_handle_t output : outputs) {
                sp<SwAudioOutputDescriptor> desc = mOutputs.valueFor(output);
                // close unused outputs after device disconnection or direct outputs that have been
                // opened by checkOutputsForDevice() to query dynamic parameters
                if ((state == AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE) ||
                        (((desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) != 0) &&
                         (desc->mDirectOpenCount == 0))) {
                    closeOutput(output);
                }
            }
            // check again after closing A2DP output to reset mA2dpSuspended if needed
            checkA2dpSuspend();
        }

        updateDevicesAndOutputs();
        if (mEngine->getPhoneState() == AUDIO_MODE_IN_CALL && hasPrimaryOutput()) {
            audio_devices_t newDevice = getNewOutputDevice(mPrimaryOutput, false /*fromCache*/);
            updateCallRouting(newDevice);
        }
        for (size_t i = 0; i < mOutputs.size(); i++) {
            sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
            if ((mEngine->getPhoneState() != AUDIO_MODE_IN_CALL) || (desc != mPrimaryOutput)) {
                audio_devices_t newDevice = getNewOutputDevice(desc, true /*fromCache*/);
                // do not force device change on duplicated output because if device is 0, it will
                // also force a device 0 for the two outputs it is duplicated to which may override
                // a valid device selection on those outputs.
                bool force = !desc->isDuplicated()
                        && (!device_distinguishes_on_address(device)
                                // always force when disconnecting (a non-duplicated device)
                                || (state == AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE));
                setOutputDevice(desc, newDevice, force, 0);
            }
        }

        if (state == AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE) {
            cleanUpForDevice(devDesc);
        }

        mpClientInterface->onAudioPortListUpdate();
        return NO_ERROR;
    }  // end if is output device

分析setDeviceConnectionStateInt

  • 注册新设备到mAvailableOutputDevices,并绑定其HWModules;
  • broadcastDeviceConnectionState 在检查outputs前,广播连接事件以允许hal在新连接的设备上检索动态参数(而不是打开输出);
  • checkOutputsForDevice 检查设备支持profile,并打开output,更新output参数;
  • checkA2dpSuspend 检查a2dp;
  • checkOutputForAllStrategies检查所有音频 strategy,并将不一致outputs,对应track置为无效;
  • closeOutput 设备断开连接或checkOutputsForDeivce中打开的direct outputs,则进行关闭。
  • updateDevicesAndOutputs 更新devices 和outputs;
  • setOutputDevice 设置输出设备;

1 checkOutputsForDevice

检查device的outputs。

status_t AudioPolicyManager::checkOutputsForDevice(const sp<DeviceDescriptor>& devDesc,
                                                   audio_policy_dev_state_t state,
                                                   SortedVector<audio_io_handle_t>& outputs,
                                                   const String8& address)
{
    //.........
    if (state == AUDIO_POLICY_DEVICE_STATE_AVAILABLE) {
        // first list already open outputs that can be routed to this device
        for (size_t i = 0; i < mOutputs.size(); i++) {
            desc = mOutputs.valueAt(i);
            if (!desc->isDuplicated() && (desc->supportedDevices() & device)) {
                if (!device_distinguishes_on_address(device)) {
                    outputs.add(mOutputs.keyAt(i));
                } else {
                    findIoHandlesByAddress(desc, device, address, outputs);
                }
            }
        }
        // then look for output profiles that can be routed to this device
        SortedVector< sp<IOProfile> > profiles;
        for (const auto& hwModule : mHwModules) {
            for (size_t j = 0; j < hwModule->getOutputProfiles().size(); j++) {
                sp<IOProfile> profile = hwModule->getOutputProfiles()[j];
                if (profile->supportDevice(device)) {
                    if (!device_distinguishes_on_address(device) ||
                            profile->supportDeviceAddress(address)) {
                        profiles.add(profile);
                    }
                }
            }
        }

        if (profiles.isEmpty() && outputs.isEmpty()) {
            return BAD_VALUE;
        }

        // open outputs for matching profiles if needed. Direct outputs are also opened to
        // query for dynamic parameters and will be closed later by setDeviceConnectionState()
        for (ssize_t profile_index = 0; profile_index < (ssize_t)profiles.size(); profile_index++) {
            //......

            desc = new SwAudioOutputDescriptor(profile, mpClientInterface);
            audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
            status_t status = desc->open(nullptr, device, address,
                                         AUDIO_STREAM_DEFAULT, AUDIO_OUTPUT_FLAG_NONE, &output);

            if (status == NO_ERROR) {
                // Here is where the out_set_parameters() for card & device gets called
                if (!address.isEmpty()) {
                    char *param = audio_device_address_to_parameter(device, address);
                    mpClientInterface->setParameters(output, String8(param));
                    free(param);
                }
                //....
        }

        if (profiles.isEmpty()) {
            return BAD_VALUE;
        }
    } else { // Disconnect
        // .....
    }
    return NO_ERROR;
}
  • 查找output是否支持该device,现在是扬声器对应primary,不支持usb device;
  • 查找该设备支持的output profile;
  • 根据profile创建SwAudioOutputDescriptor,并调用open函数,打开open output stream,创建PalybackThread子类(这里对于usb耳机,应该是OffloadThread);
  • 更新output的参数;

这里分析下desc->open流程

status_t SwAudioOutputDescriptor::open(const audio_config_t *config,
                                       audio_devices_t device,
                                       const String8& address,
                                       audio_stream_type_t stream,
                                       audio_output_flags_t flags,
                                       audio_io_handle_t *output)
{
    //......
    status_t status = mClientInterface->openOutput(mProfile->getModuleHandle(),
                                                   output,
                                                   &lConfig,
                                                   &mDevice,
                                                   address,
                                                   &mLatency,
                                                   mFlags);
}

status_t AudioPolicyService::AudioPolicyClient::openOutput(audio_module_handle_t module,
                                                           audio_io_handle_t *output,
                                                           audio_config_t *config,
                                                           audio_devices_t *devices,
                                                           const String8& address,
                                                           uint32_t *latencyMs,
                                                           audio_output_flags_t flags)
{
    sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
    if (af == 0) {
        return PERMISSION_DENIED;
    }
    return af->openOutput(module, output, config, devices, address, latencyMs, flags);
}

流程如下

SwAudioOutputDescriptor::open

——》AudioPolicyClient::openOutput

——》AudioFlinger::openOutput

——》AudioFlinger::openOutput_l

AudioFlinger openOutput_l函数

sp<AudioFlinger::ThreadBase> AudioFlinger::openOutput_l(audio_module_handle_t module,
                                                            audio_io_handle_t *output,
                                                            audio_config_t *config,
                                                            audio_devices_t devices,
                                                            const String8& address,
                                                            audio_output_flags_t flags)
{
    AudioHwDevice *outHwDev = findSuitableHwDev_l(module, devices);
    if (outHwDev == NULL) {
        return 0;
    }

    if (*output == AUDIO_IO_HANDLE_NONE) {
        *output = nextUniqueId(AUDIO_UNIQUE_ID_USE_OUTPUT);
    } else {
        return 0;
    }
    mHardwareStatus = AUDIO_HW_OUTPUT_OPEN;

    AudioStreamOut *outputStream = NULL;
    status_t status = outHwDev->openOutputStream(
            &outputStream,
            *output,
            devices,
            flags,
            config,
            address.string());

    mHardwareStatus = AUDIO_HW_IDLE;

    if (status == NO_ERROR) {
        if (flags & AUDIO_OUTPUT_FLAG_MMAP_NOIRQ) {
            sp<MmapPlaybackThread> thread =
                    new MmapPlaybackThread(this, *output, outHwDev, outputStream,
                                          devices, AUDIO_DEVICE_NONE, mSystemReady);
            mMmapThreads.add(*output, thread);
            return thread;
        } else {
            sp<PlaybackThread> thread;
            if (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
                thread = new OffloadThread(this, outputStream, *output, devices, mSystemReady);
            } else if ((flags & AUDIO_OUTPUT_FLAG_DIRECT)
                    || !isValidPcmSinkFormat(config->format)
                    || !isValidPcmSinkChannelMask(config->channel_mask)) {
            } else {
                thread = new MixerThread(this, outputStream, *output, devices, mSystemReady);
            }
            mPlaybackThreads.add(*output, thread);
            return thread;
        }
    }

    return 0;
}
  1. findSuitableHwDev_l 查找AudioHwDevice;
  2. outHwDev->openOutputStream 打开output stream;
  3. 根据flags创建thread,这里usb 耳机对应创建OffloadThread;

2 checkOutputForAllStrategies

checkOutputForAllStrategies针对所有strategy,调用checkOutputForStrategy函数处理。

void AudioPolicyManager::checkOutputForAllStrategies()
{
    if (mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) == AUDIO_POLICY_FORCE_SYSTEM_ENFORCED)
        checkOutputForStrategy(STRATEGY_ENFORCED_AUDIBLE);
    checkOutputForStrategy(STRATEGY_PHONE);
    if (mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) != AUDIO_POLICY_FORCE_SYSTEM_ENFORCED)
        checkOutputForStrategy(STRATEGY_ENFORCED_AUDIBLE);
    checkOutputForStrategy(STRATEGY_SONIFICATION);
    checkOutputForStrategy(STRATEGY_SONIFICATION_RESPECTFUL);
    checkOutputForStrategy(STRATEGY_ACCESSIBILITY);
    checkOutputForStrategy(STRATEGY_MEDIA);
    checkOutputForStrategy(STRATEGY_DTMF);
    checkOutputForStrategy(STRATEGY_REROUTING);
}

void AudioPolicyManager::checkOutputForStrategy(routing_strategy strategy)
{
    audio_devices_t oldDevice = getDeviceForStrategy(strategy, true /*fromCache*/);
    audio_devices_t newDevice = getDeviceForStrategy(strategy, false /*fromCache*/);
    SortedVector<audio_io_handle_t> srcOutputs = getOutputsForDevice(oldDevice, mPreviousOutputs);
    SortedVector<audio_io_handle_t> dstOutputs = getOutputsForDevice(newDevice, mOutputs);

    // also take into account external policy-related changes: add all outputs which are
    // associated with policies in the "before" and "after" output vectors
    for (size_t i = 0 ; i < mPreviousOutputs.size() ; i++) {
        const sp<SwAudioOutputDescriptor> desc = mPreviousOutputs.valueAt(i);
        if (desc != 0 && desc->mPolicyMix != NULL) {
            srcOutputs.add(desc->mIoHandle);
        }
    }
    for (size_t i = 0 ; i < mOutputs.size() ; i++) {
        const sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
        if (desc != 0 && desc->mPolicyMix != NULL) {
            dstOutputs.add(desc->mIoHandle);
        }
    }

    if (!vectorsEqual(srcOutputs,dstOutputs)) {
        // get maximum latency of all source outputs to determine the minimum mute time guaranteeing
        // audio from invalidated tracks will be rendered when unmuting
        uint32_t maxLatency = 0;
        for (audio_io_handle_t srcOut : srcOutputs) {
            sp<SwAudioOutputDescriptor> desc = mPreviousOutputs.valueFor(srcOut);
            if (desc != 0 && maxLatency < desc->latency()) {
                maxLatency = desc->latency();
            }
        }
        // mute strategy while moving tracks from one output to another
        for (audio_io_handle_t srcOut : srcOutputs) {
            sp<SwAudioOutputDescriptor> desc = mPreviousOutputs.valueFor(srcOut);
            if (desc != 0 && isStrategyActive(desc, strategy)) {
                setStrategyMute(strategy, true, desc);
                setStrategyMute(strategy, false, desc, maxLatency * LATENCY_MUTE_FACTOR, newDevice);
            }
            sp<AudioSourceDescriptor> source =
                    getSourceForStrategyOnOutput(srcOut, strategy);
            if (source != 0){
                connectAudioSource(source);
            }
        }

        // Move effects associated to this strategy from previous output to new output
        if (strategy == STRATEGY_MEDIA) {
            selectOutputForMusicEffects();
        }
        // Move tracks associated to this strategy from previous output to new output
        for (int i = 0; i < AUDIO_STREAM_FOR_POLICY_CNT; i++) {
            if (getStrategy((audio_stream_type_t)i) == strategy) {
                mpClientInterface->invalidateStream((audio_stream_type_t)i);
            }
        }
    }
}

checkOutputForStrategy对比先后的ouputs,如果不同进行下述处理

  • setStrategyMute 静音一定时间;
  • invalidateStream 将与当前策略有关的stream 从先前output移除,针对当前stream的Track设置为CBLK_INVALID,后续重新创建Track;

分析下 invalidateStream

status_t AudioFlinger::invalidateStream(audio_stream_type_t stream)
{
    Mutex::Autolock _l(mLock);

    for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
        PlaybackThread *thread = mPlaybackThreads.valueAt(i).get();
        thread->invalidateTracks(stream);
    }
    for (size_t i = 0; i < mMmapThreads.size(); i++) {
        mMmapThreads[i]->invalidateTracks(stream);
    }
    return NO_ERROR;
}

bool AudioFlinger::PlaybackThread::invalidateTracks_l(audio_stream_type_t streamType)
{
    bool trackMatch = false;
    size_t size = mTracks.size();
    for (size_t i = 0; i < size; i++) {
        sp<Track> t = mTracks[i];
        if (t->streamType() == streamType && t->isExternalTrack()) {
            t->invalidate();
            trackMatch = true;
        }
    }
    return trackMatch;
}

获取该stream对应的 PlaybackThread,将其包含的track 置为无效 CBLK_INVALID,扬声器对应track 则不能在进行播放了。后续根据新设备创建新的Track,进行播放。

3 closeOutput

对于设备断开连接或checkOutputsForDeivce中打开的direct outputs,则需要进行关闭。usb 耳机回打开 direct outputs,所以这里需要关闭outputs

这里分析下closeOutput流程

void AudioPolicyManager::closeOutput(audio_io_handle_t output)
{
    sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueFor(output);
    mPolicyMixes.closeOutput(outputDesc);

    // look for duplicated outputs connected to the output being removed.
    //..........

    outputDesc->close();

    removeOutput(output);
    mPreviousOutputs = mOutputs;
}

直接看 AudioFlinger

status_t AudioFlinger::closeOutput(audio_io_handle_t output)
{
    return closeOutput_nonvirtual(output);
}

status_t AudioFlinger::closeOutput_nonvirtual(audio_io_handle_t output)
{
    // keep strong reference on the playback thread so that
    // it is not destroyed while exit() is executed
    sp<PlaybackThread> playbackThread;
    sp<MmapPlaybackThread> mmapThread;
    {
        Mutex::Autolock _l(mLock);
        playbackThread = checkPlaybackThread_l(output);
        if (playbackThread != NULL) {
            if (playbackThread->type() == ThreadBase::MIXER) {
                for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
                    if (mPlaybackThreads.valueAt(i)->isDuplicating()) {
                        DuplicatingThread *dupThread =
                                (DuplicatingThread *)mPlaybackThreads.valueAt(i).get();
                        dupThread->removeOutputTrack((MixerThread *)playbackThread.get());
                    }
                }
            }


            mPlaybackThreads.removeItem(output);
            // save all effects to the default thread
            if (mPlaybackThreads.size()) {
                PlaybackThread *dstThread = checkPlaybackThread_l(mPlaybackThreads.keyAt(0));
                if (dstThread != NULL) {
                    // audioflinger lock is held so order of thread lock acquisition doesn't matter
                    Mutex::Autolock _dl(dstThread->mLock);
                    Mutex::Autolock _sl(playbackThread->mLock);
                    Vector< sp<EffectChain> > effectChains = playbackThread->getEffectChains_l();
                    for (size_t i = 0; i < effectChains.size(); i ++) {
                        moveEffectChain_l(effectChains[i]->sessionId(), playbackThread.get(),
                                dstThread, true);
                    }
                }
            }
        } else {
            mmapThread = (MmapPlaybackThread *)checkMmapThread_l(output);
            if (mmapThread == 0) {
                return BAD_VALUE;
            }
            mMmapThreads.removeItem(output);
            ALOGD("closing mmapThread %p", mmapThread.get());
        }
        const sp<AudioIoDescriptor> ioDesc = new AudioIoDescriptor();
        ioDesc->mIoHandle = output;
        ioConfigChanged(AUDIO_OUTPUT_CLOSED, ioDesc);
    }
    // The thread entity (active unit of execution) is no longer running here,
    // but the ThreadBase container still exists.

    if (playbackThread != 0) {
        playbackThread->exit();
        if (!playbackThread->isDuplicating()) {
            closeOutputFinish(playbackThread);
        }
    } else if (mmapThread != 0) {
        ALOGD("mmapThread exit()");
        mmapThread->exit();
        AudioStreamOut *out = mmapThread->clearOutput();
        ALOG_ASSERT(out != NULL, "out shouldn't be NULL");
        // from now on thread->mOutput is NULL
        delete out;
    }
    return NO_ERROR;
}
  1. PlaybackThread 删除 output;
  2. PlaybackThread 退出线程;

三、AudioTrack

AudioTrack 包含多个函数 如:start() processAudioBuffer getTimestamp_l getPosition等,都会检查flags 是否包含CBLK_INVALID状态,如果是此状态则调用restoreTrack_l重新创建Track,这样完成设备的切换,使用usb 耳机播放声音。

该流程暂不分析。

以上是关于Android 音频源码分析——音频设备切换(插入耳机)的主要内容,如果未能解决你的问题,请参考以下文章

Android 音频源码分析——音频设备切换(插入耳机)

Android 音频源码分析——音频设备切换(插入耳机)

Android 音频源码分析——AudioTrack设备选择

Android 音频源码分析——AudioTrack设备选择

Android 音频源码分析——音量调节流程

Android 音频源码分析——音量调节流程