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, 
  • 6
    点赞
  • 56
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值