Audio Device Strategy 音频设备输出、输入 选择 基于7.0 代码

news/2024/11/29 8:45:36/

存档,不想留本地了,没啥含量 都在Enginee.cpp里写着呢

1. 输出选择

整体流程

  1. 首先我们会获取当前存在的设备集合availableOutputDevices

  2. 然后根据传入的strategty类型进行匹配选择

  3. 在选择之前会先检测是否处于特殊情况下(如通话中)

  4. 最后按照优先级匹配设备。

关于音频设备选择的策略定义在AudioPolicyManager中的getDeviceForStrategy()方法,会根据当时设备的状态和连接设备选择最合适的设备,具体实现在frameworks/av/services/audiopolicy/enginedefault/src/Engine.cpp中。

以下注释解释很清楚,参数为strategy和fromCache,如果fromCache = true,则从mDeviceForStrategy[]选择,否则继续往下走。

mDeviceForStrategy[NUM_STRATEGIES] 是一个数组。

frameworks/av/services/audiopolicy/common/include/RoutingStrategy.henum routing_strategy {STRATEGY_MEDIA,STRATEGY_PHONE,STRATEGY_SONIFICATION,STRATEGY_SONIFICATION_RESPECTFUL,STRATEGY_DTMF,STRATEGY_ENFORCED_AUDIBLE,STRATEGY_TRANSMITTED_THROUGH_SPEAKER,STRATEGY_ACCESSIBILITY,STRATEGY_REROUTING,NUM_STRATEGIES
}; 

frameworks/av/services/audiopolicy/managerdefault/AudioPolicyManager.h

virtual audio_devices_t getDeviceForStrategy(routing_strategy strategy,bool fromCache); 

1.1 AudioPolicyManager.cpp中的具体实现

frameworks/av/services/audiopolicy/managerdefault/AudioPolicyManager.cpp

以下逻辑均涉及getDeviceForStrategy的调用
  • void AudioPolicyManager::setPhoneState(audio_mode_t state)

  • audio_io_handle_t AudioPolicyManager::getOutput(audio_stream_type_t stream —)

  • status_t AudioPolicyManager::getOutputForAttr

  • status_t AudioPolicyManager::startOutput(

  • status_t AudioPolicyManager::getStreamVolumeIndex(audio_stream_type_t stream,int *index audio_devices_t device)

  • audio_io_handle_t AudioPolicyManager::getOutputForEffect(const effect_descriptor_t *desc)

  • void AudioPolicyManager::checkStrategyRoute(routing_strategy strategy, audio_io_handle_t ouptutToSkip)

  • status_t AudioPolicyManager::connectAudioSource(const sp& sourceDesc){

  • void AudioPolicyManager::checkStrategyRoute(routing_strategy strategy,audio_io_handle_t ouptutToSkip){

  • void AudioPolicyManager::checkOutputForStrategy(routing_strategy strategy)

  • audio_devices_t AudioPolicyManager::getNewOutputDevice(const sp& outputDesc, bool fromCache)

  • audio_devices_t AudioPolicyManager::getDevicesForStream(audio_stream_type_t stream) {

  • void AudioPolicyManager::updateDevicesAndOutputs()

  • uint32_t AudioPolicyManager::checkDeviceMuteStrategies(sp

  • float AudioPolicyManager::computeVolume(audio_stream_type_t stream,

  • void AudioPolicyManager::handleIncallSonification(audio_stream_type_t stream,bool starting, bool stateChange)

  • status_t AudioPolicyManager::setDeviceConnectionStateInt(audio_devices_t device,

audio_devices_t AudioPolicyManager::getDeviceForStrategy(routing_strategy strategy,bool fromCache) {// Routing// see if we have an explicit route// scan the whole RouteMap, for each entry, convert the stream type to a strategy// (getStrategy(stream)).// if the strategy from the stream type in the RouteMap is the same as the argument above,// and activity count is non-zero// the device = the device from the descriptor in the RouteMap, and exit.for (size_t routeIndex = 0; routeIndex < mOutputRoutes.size(); routeIndex++) {sp<SessionRoute> route = mOutputRoutes.valueAt(routeIndex);routing_strategy routeStrategy = getStrategy(route->mStreamType); //仍旧调用getDeviceForStrategyif ((routeStrategy == strategy) && route->isActive()) {return route->mDeviceDescriptor->type();}}if (fromCache) {ALOGVV("getDeviceForStrategy() from cache strategy %d, device %x",strategy, mDeviceForStrategy[strategy]);return mDeviceForStrategy[strategy];}return mEngine->getDeviceForStrategy(strategy);
} 
具体实现在Engine.cpp中

frameworks/av/services/audiopolicy/enginedefault/src/Engine.cpp

routing_strategy Engine::getStrategyForStream(audio_stream_type_t stream) {// stream to strategy mappingswitch (stream) {case AUDIO_STREAM_VOICE_CALL:case AUDIO_STREAM_BLUETOOTH_SCO:return STRATEGY_PHONE;case AUDIO_STREAM_RING:case AUDIO_STREAM_ALARM:return STRATEGY_SONIFICATION;case AUDIO_STREAM_NOTIFICATION:return STRATEGY_SONIFICATION_RESPECTFUL;case AUDIO_STREAM_DTMF:return STRATEGY_DTMF;default:ALOGE("unknown stream type %d", stream);case AUDIO_STREAM_SYSTEM:// NOTE: SYSTEM stream uses MEDIA strategy because muting music and switching outputs// while key clicks are played produces a poor resultcase AUDIO_STREAM_MUSIC:return STRATEGY_MEDIA;case AUDIO_STREAM_ENFORCED_AUDIBLE:return STRATEGY_ENFORCED_AUDIBLE;case AUDIO_STREAM_TTS:return STRATEGY_TRANSMITTED_THROUGH_SPEAKER;case AUDIO_STREAM_ACCESSIBILITY:return STRATEGY_ACCESSIBILITY;case AUDIO_STREAM_REROUTING:return STRATEGY_REROUTING;}
} 
audio_devices_t Engine::getDeviceForStrategy(routing_strategy strategy) const {DeviceVector availableOutputDevices = mApmObserver->getAvailableOutputDevices();DeviceVector availableInputDevices = mApmObserver->getAvailableInputDevices();const SwAudioOutputCollection &outputs = mApmObserver->getOutputs();return getDeviceForStrategyInt(strategy, availableOutputDevices,availableInputDevices, outputs);
} 

1.2 针对STRATEGY_MEDIA分析,播放设备优先级如下

  • AUDIO_DEVICE_OUT_BLUETOOTH_A2DP
  • AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES(普通蓝牙耳机)
  • AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER(蓝牙小音箱) //此处属于setForceUse的强制插队 (if FORCE_SPEAKER)AUDIO_DEVICE_OUT_SPEAKER(扬声器)
  • AUDIO_DEVICE_OUT_WIRED_HEADPHONE(普通耳机,只能听,不能操控播放)
  • AUDIO_DEVICE_OUT_LINE
  • AUDIO_DEVICE_OUT_WIRED_HEADSET(线控耳机)
  • AUDIO_DEVICE_OUT_USB_HEADSET(USB耳机)
case STRATEGY_MEDIA: {uint32_t device2 = AUDIO_DEVICE_NONE;if (isInCall() && (device == AUDIO_DEVICE_NONE)) {  //针对通话// when in call, get the device for Phone strategydevice = getDeviceForStrategy(STRATEGY_PHONE);break;}if (strategy != STRATEGY_SONIFICATION) {//和提示做特别处理// no sonification on remote submix (e.g. WFD)if (availableOutputDevices.getDevice(AUDIO_DEVICE_OUT_REMOTE_SUBMIX,String8("0")) != 0) {device2 = availableOutputDevices.types() & AUDIO_DEVICE_OUT_REMOTE_SUBMIX;}}if (isInCall() && (strategy == STRATEGY_MEDIA)) {device = getDeviceForStrategyInt(STRATEGY_PHONE, availableOutputDevices, availableInputDevices, outputs);break;}if ((device2 == AUDIO_DEVICE_NONE) &&(mForceUse[AUDIO_POLICY_FORCE_FOR_MEDIA] != AUDIO_POLICY_FORCE_NO_BT_A2DP) &&(outputs.isA2dpOnPrimary() || (outputs.getA2dpOutput() != 0))) {device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP;   //A2DPif (device2 == AUDIO_DEVICE_NONE) {device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES; //蓝牙耳机}if (device2 == AUDIO_DEVICE_NONE) {device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER; //蓝牙音箱}}if ((device2 == AUDIO_DEVICE_NONE) &&(mForceUse[AUDIO_POLICY_FORCE_FOR_MEDIA] == AUDIO_POLICY_FORCE_SPEAKER)) {//如果force speker 扬声器 喇叭device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_SPEAKER;}if (device2 == AUDIO_DEVICE_NONE) {device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_WIRED_HEADPHONE; //普通有线耳机 不带麦克风}if (device2 == AUDIO_DEVICE_NONE) {device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_LINE;}if (device2 == AUDIO_DEVICE_NONE) {device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_WIRED_HEADSET; //带麦克风的有线耳机}if (device2 == AUDIO_DEVICE_NONE) {device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_USB_ACCESSORY;}if (device2 == AUDIO_DEVICE_NONE) {device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_USB_DEVICE;  //USB设备 }if (device2 == AUDIO_DEVICE_NONE) {device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET;}if ((strategy != STRATEGY_SONIFICATION) && (device == AUDIO_DEVICE_NONE)&& (device2 == AUDIO_DEVICE_NONE)) {// no sonification on aux digital (e.g. HDMI)device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_AUX_DIGITAL;}if ((device2 == AUDIO_DEVICE_NONE) &&(mForceUse[AUDIO_POLICY_FORCE_FOR_DOCK] == AUDIO_POLICY_FORCE_ANALOG_DOCK)&& (strategy != STRATEGY_SONIFICATION)) {device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET;}
#ifdef AUDIO_EXTN_AFE_PROXY_ENABLEDif ((strategy != STRATEGY_SONIFICATION) && (device == AUDIO_DEVICE_NONE)&& (device2 == AUDIO_DEVICE_NONE)) {// no sonification on WFD sinkdevice2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_PROXY;}
#endifif (device2 == AUDIO_DEVICE_NONE) {device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_SPEAKER; // 外放 扬声器 喇叭}int device3 = AUDIO_DEVICE_NONE;if (strategy == STRATEGY_MEDIA) {///如果arc,spdif,aux_line可用,赋值给device3// ARC, SPDIF and AUX_LINE can co-exist with others.device3 = availableOutputDevicesType & AUDIO_DEVICE_OUT_HDMI_ARC;device3 |= (availableOutputDevicesType & AUDIO_DEVICE_OUT_SPDIF);device3 |= (availableOutputDevicesType & AUDIO_DEVICE_OUT_AUX_LINE);}device2 |= device3;// device is DEVICE_OUT_SPEAKER if we come from case STRATEGY_SONIFICATION or// STRATEGY_ENFORCED_AUDIBLE, AUDIO_DEVICE_NONE otherwisedevice |= device2;// If hdmi system audio mode is on, remove speaker out of output list.if ((strategy == STRATEGY_MEDIA) &&(mForceUse[AUDIO_POLICY_FORCE_FOR_HDMI_SYSTEM_AUDIO] ==AUDIO_POLICY_FORCE_HDMI_SYSTEM_AUDIO_ENFORCED)) {device &= ~AUDIO_DEVICE_OUT_SPEAKER;}} break; 

2.输入选择

Audio Device Strategy 音频设备 输入选择 7.0

1.输入设备选择

1.1 MediaRecorder java层setAudioSource

以MediaRecorder为例,不考虑其他。setAudioSource设置输入源

 mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);// 设置麦克风 

frameworks/base/media/java/android/media/MediaRecorder.java

AudioSource共定义以下几种

/** Default audio source **/
public static final int DEFAULT = 0; //默认
/** Microphone audio source */
public static final int MIC = 1; //麦克
/** Voice call uplink (Tx) audio source */
public static final int VOICE_UPLINK = 2; //电话上行
/** Voice call downlink (Rx) audio source */
public static final int VOICE_DOWNLINK = 3; //电话下行
/** Voice call uplink + downlink audio source */
public static final int VOICE_CALL = 4;  //电话录音
/** Microphone audio source with same orientation as camera if available, the main*  device microphone otherwise */
public static final int CAMCORDER = 5;  //摄像头麦克
public static final int VOICE_RECOGNITION = 6; //语音识别
public static final int VOICE_COMMUNICATION = 7;//网络电话
public static final int REMOTE_SUBMIX = 8; //用于内录
public static final int UNPROCESSED = 9;  //未处理原始声音
@SystemApi
public static final int RADIO_TUNER = 1998; //广播
@SystemApi
public static final int HOTWORD = 1999; 

继续看MediaRecorder

public native void setAudioSource(int audio_source)throws IllegalStateException; 

通过JNI调用到mediarecorder.cpp

frameworks/base/media/jni/android_media_MediaRecorder.cpp

static void
android_media_MediaRecorder_setVideoSource(JNIEnv *env, jobject thiz, jint vs) {sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
} 

frameworks/av/media/libmedia/mediarecorder.cpp

status_t MediaRecorder::setAudioSource(int as){status_t ret = mMediaRecorder->setAudioSource(as);
} 

1.2 mMediaRecorder是谁

在看mMediaRecorder实例,是一个IMediaPlayerService 的service对象,调用了createMediaRecorder()

MediaRecorder::MediaRecorder(const String16& opPackageName) : mSurfaceMediaSource(NULL)
{const sp<IMediaPlayerService> service(getMediaPlayerService());if (service != NULL) {mMediaRecorder = service->createMediaRecorder(opPackageName);}
} 

frameworks/av/media/libmedia/IMediaPlayerService.cpp

下面就是明显的binder操作,BnMediaPlayerService 定义了如下

virtual sp<IMediaRecorder> createMediaRecorder(const String16 &opPackageName) {Parcel data, reply;data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());data.writeString16(opPackageName);remote()->transact(CREATE_MEDIA_RECORDER, data, &reply);return interface_cast<IMediaRecorder>(reply.readStrongBinder());
} 

MediaPlayerService继承BnMediaPlayerService

frameworks/av/media/libmediaplayerservice/MediaPlayerService.h

class MediaPlayerService : public BnMediaPlayerService 

这就通过binder来到了MediaRecorderClient,可知recorder对象就是MediaRecorderClient

frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp

sp<IMediaRecorder> MediaPlayerService::createMediaRecorder(const String16 &opPackageName){sp<MediaRecorderClient> recorder = new MediaRecorderClient(this, pid, opPackageName);return recorder;
} 

1.3 MediaRecorderClient.cpp的setAudioSource

到这里可以继续看setAudioSource了

frameworks/av/media/libmediaplayerservice/MediaRecorderClient.cpp

status_t MediaRecorderClient::setAudioSource(int as) {return mRecorder->setAudioSource((audio_source_t)as);
}
MediaRecorderBase      *mRecorder; 

mRecorder为MediaRecorderBase实例,StagefrightRecorder继承于MediaRecorderBase,这里继续看StagefrightRecorder

frameworks/av/media/libmediaplayerservice/StagefrightRecorder.cpp

struct StagefrightRecorder : public MediaRecorderBase {
status_t StagefrightRecorder::setAudioSource(audio_source_t as) {if (as == AUDIO_SOURCE_DEFAULT) {mAudioSource = AUDIO_SOURCE_MIC;} else {mAudioSource = as;}
}
} 

StagefrightRecorder中会根据mAudioSource去创建audioSource……

sp<MediaCodecSource> StagefrightRecorder::createAudioSource() {sp<AudioSource> audioSource = AVFactory::get()->createAudioSource(           
} 

frameworks/av/media/libavextensions/stagefright/AVFactory.cpp

AudioSource* AVFactory::createAudioSource(return new AudioSource(inputSource, opPackageName, sampleRate,channels, outSampleRate, clientUid, clientPid);
} 

AudioSource中有创建了AudioRecord

frameworks/av/media/libstagefright/AudioSource.cpp

mRecord = new AudioRecord(inputSource, sampleRate, AUDIO_FORMAT_PCM_16_BIT, 

以下代码在AudioRecord的构造方法中,inputsource是我们上边传入的参数。

frameworks/av/media/libmedia/AudioRecord.cpp

mStatus = set(inputSource, sampleRate, format, channelMask, frameCount, cbf, user,notificationFrames, false /*threadCanCallJava*/, sessionId, transferType, flags,uid, pid, pAttributes);//set方法       
set(){if (pAttributes == NULL) {mAttributes.source = inputSource;} 
} 

mAttributes应用在openRecord_l方法中,可以看到AudioSystem调用了getInputForAttr

status_t AudioRecord::openRecord_l(const Modulo<uint32_t> &epoch, const String16& opPackageName) {
status = AudioSystem::getInputForAttr(&mAttributes, &input,mSessionId,mClientPid,mClientUid,mSampleRate, mFormat, mChannelMask,mFlags, mSelectedDeviceId);
} 

frameworks/av/media/libmedia/AudioSystem.cpp

status_t AudioSystem::getInputForAttr(const audio_attributes_t *attr,) {const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();if (aps == 0) return NO_INIT;return aps->getInputForAttr(attr, input, session, pid, uid,samplingRate, format, channelMask, flags, selectedDeviceId);
} 

frameworks/av/media/libmedia/IAudioPolicyService.cpp

重点关注aps,是IAudioPolicyService。点进去发现又是binder

virtual status_t getInputForAttr(const audio_attributes_t *attr,){status_t status = remote()->transact(GET_INPUT_FOR_ATTR, data, &reply);} 

frameworks/av/services/audiopolicy/service/AudioPolicyService.h

class AudioPolicyService :public BinderService<AudioPolicyService>,public BnAudioPolicyService, 

AudioPolicyService 继承 BnAudioPolicyService,BnAudioPolicyService实现于 AudioPolicyInterface,AudioPolicyManager又继承AudioPolicyInterface。终于来到了AudioPolicyManager.cpp

1.4 AudioPolicyManager.cpp中的策略

frameworks/av/services/audiopolicy/managerdefault/AudioPolicyManager.cpp

device = getDeviceAndMixForInputSource(inputSource, &policyMix); 
*input = getInputForDevice(device, address, session, uid, inputSource,samplingRate, format, channelMask, flags,policyMix); 
audio_devices_t AudioPolicyManager::getDeviceForInputSource(audio_source_t inputSource) {for (size_t routeIndex = 0; routeIndex < mInputRoutes.size(); routeIndex++) {sp<SessionRoute> route = mInputRoutes.valueAt(routeIndex);if (inputSource == route->mSource && route->isActive()) {return route->mDeviceDescriptor->type();}}return mEngine->getDeviceForInputSource(inputSource);
} 
以下为具体策略

frameworks/av/services/audiopolicy/enginedefault/src/Engine.cpp

audio_devices_t Engine::getDeviceForInputSource(audio_source_t inputSource) const {const DeviceVector &availableOutputDevices = mApmObserver->getAvailableOutputDevices();const DeviceVector &availableInputDevices = mApmObserver->getAvailableInputDevices();const SwAudioOutputCollection &outputs = mApmObserver->getOutputs();audio_devices_t availableDeviceTypes = availableInputDevices.types() & ~AUDIO_DEVICE_BIT_IN;uint32_t device = AUDIO_DEVICE_NONE;switch (inputSource) {case AUDIO_SOURCE_VOICE_UPLINK:if (availableDeviceTypes & AUDIO_DEVICE_IN_VOICE_CALL) {device = AUDIO_DEVICE_IN_VOICE_CALL;break;}break;case AUDIO_SOURCE_DEFAULT:case AUDIO_SOURCE_MIC:if (availableDeviceTypes & AUDIO_DEVICE_IN_BLUETOOTH_A2DP) {  //A2DPdevice = AUDIO_DEVICE_IN_BLUETOOTH_A2DP;} else if ((mForceUse[AUDIO_POLICY_FORCE_FOR_RECORD] == AUDIO_POLICY_FORCE_BT_SCO) && //如果强制蓝牙 优先蓝牙耳机(availableDeviceTypes & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET)) {device = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET;} else if (availableDeviceTypes & AUDIO_DEVICE_IN_WIRED_HEADSET) {//有线蓝牙device = AUDIO_DEVICE_IN_WIRED_HEADSET;} else if (availableDeviceTypes & AUDIO_DEVICE_IN_USB_DEVICE) {//usbdevice = AUDIO_DEVICE_IN_USB_DEVICE;} else if (availableDeviceTypes & AUDIO_DEVICE_IN_BUILTIN_MIC) { //手机自带micdevice = AUDIO_DEVICE_IN_BUILTIN_MIC;}break;case AUDIO_SOURCE_VOICE_COMMUNICATION:// Allow only use of devices on primary input if in call and HAL does not support routing// to voice call path.if ((getPhoneState() == AUDIO_MODE_IN_CALL) &&(availableOutputDevices.types() & AUDIO_DEVICE_OUT_TELEPHONY_TX) == 0) {sp<AudioOutputDescriptor> primaryOutput = outputs.getPrimaryOutput();availableDeviceTypes =availableInputDevices.getDevicesFromHwModule(primaryOutput->getModuleHandle())& ~AUDIO_DEVICE_BIT_IN;}switch (mForceUse[AUDIO_POLICY_FORCE_FOR_COMMUNICATION]) {case AUDIO_POLICY_FORCE_BT_SCO:// if SCO device is requested but no SCO device is available, fall back to default caseif (availableDeviceTypes & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) {device = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET;break;}// FALL THROUGHdefault:    // FORCE_NONEif (availableDeviceTypes & AUDIO_DEVICE_IN_WIRED_HEADSET) {device = AUDIO_DEVICE_IN_WIRED_HEADSET;} else if (availableDeviceTypes & AUDIO_DEVICE_IN_USB_DEVICE) {device = AUDIO_DEVICE_IN_USB_DEVICE;} else if (availableDeviceTypes & AUDIO_DEVICE_IN_BUILTIN_MIC) {device = AUDIO_DEVICE_IN_BUILTIN_MIC;}break;case AUDIO_POLICY_FORCE_SPEAKER:if (availableDeviceTypes & AUDIO_DEVICE_IN_BACK_MIC) {device = AUDIO_DEVICE_IN_BACK_MIC;} else if (availableDeviceTypes & AUDIO_DEVICE_IN_BUILTIN_MIC) {device = AUDIO_DEVICE_IN_BUILTIN_MIC;}break;}break;case AUDIO_SOURCE_VOICE_RECOGNITION:case AUDIO_SOURCE_UNPROCESSED:case AUDIO_SOURCE_HOTWORD:if (mForceUse[AUDIO_POLICY_FORCE_FOR_RECORD] == AUDIO_POLICY_FORCE_BT_SCO &&availableDeviceTypes & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) {device = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET;} else if (availableDeviceTypes & AUDIO_DEVICE_IN_WIRED_HEADSET) {device = AUDIO_DEVICE_IN_WIRED_HEADSET;} else if (availableDeviceTypes & AUDIO_DEVICE_IN_USB_DEVICE) {device = AUDIO_DEVICE_IN_USB_DEVICE;} else if (availableDeviceTypes & AUDIO_DEVICE_IN_BUILTIN_MIC) {device = AUDIO_DEVICE_IN_BUILTIN_MIC;}break;case AUDIO_SOURCE_CAMCORDER:if (availableDeviceTypes & AUDIO_DEVICE_IN_BACK_MIC) {device = AUDIO_DEVICE_IN_BACK_MIC;} else if (availableDeviceTypes & AUDIO_DEVICE_IN_BUILTIN_MIC) {device = AUDIO_DEVICE_IN_BUILTIN_MIC;}break;case AUDIO_SOURCE_VOICE_DOWNLINK:case AUDIO_SOURCE_VOICE_CALL:if (availableDeviceTypes & AUDIO_DEVICE_IN_VOICE_CALL) {device = AUDIO_DEVICE_IN_VOICE_CALL;}break;case AUDIO_SOURCE_REMOTE_SUBMIX:if (availableDeviceTypes & AUDIO_DEVICE_IN_REMOTE_SUBMIX) {device = AUDIO_DEVICE_IN_REMOTE_SUBMIX;}break;case AUDIO_SOURCE_FM_TUNER:if (availableDeviceTypes & AUDIO_DEVICE_IN_FM_TUNER) {device = AUDIO_DEVICE_IN_FM_TUNER;}break;default:ALOGW("getDeviceForInputSource() invalid input source %d", inputSource);break;}if (device == AUDIO_DEVICE_NONE) {ALOGV("getDeviceForInputSource() no device found for source %d", inputSource);if (availableDeviceTypes & AUDIO_DEVICE_IN_STUB) {device = AUDIO_DEVICE_IN_STUB;}ALOGE_IF(device == AUDIO_DEVICE_NONE,"getDeviceForInputSource() no default device defined");}ALOGV("getDeviceForInputSource()input source %d, device %08x", inputSource, device);return device;
} 

Android-MediaRecorder之setAudioSource

[Android两种改变音频输出/入设备的方式

=


http://www.ppmy.cn/news/181302.html

相关文章

联想think system sr550信息

带外管理口 默认IP地址&#xff1a;192.168.70.125 默认用户名密码 USERID PASSW0RD 0是数字0 转载于:https://www.cnblogs.com/cnqfz/p/11410765.html

ThinkPad P1 Gen4 是否支持单条4T固态?

与一年前&#xff08;2022.4&#xff09;固态相比&#xff0c;固态每T的价格直接减半&#xff0c;估计是国产的加入&#xff0c;这对消费者绝对是好事&#xff0c;但长江存储居然没有4T的产品&#xff0c;至少现在没有找到&#xff0c;看着现在的价格可以购进 "英睿达&am…

t450加固态硬盘教程_联想thinkpad笔记本t450s拆机加装固态硬盘及内存图解

拆机需要松开8颗螺丝,后盖上的螺丝全部有防掉落设计(除电池下面的那颗螺丝外)。 联想thinkpad笔记本t450s拆机加装固态硬盘及内存图解 图三 原装正版win7,我已经把系统换成win10了。 联想thinkpad笔记本t450s拆机加装固态硬盘及内存图解 图四 联想thinkpad笔记本t450s---…

Lenovo笔记本BIOS详解

Lenovo笔记本电脑进入BIOS方式&#xff1a; 方式一&#xff1a;按下电源开关按钮开机后&#xff0c;连续不断敲击键盘上的F2按键&#xff08;频率&#xff1a;每秒1-2次&#xff09;&#xff1b; 方式二&#xff1a;按下电源开关按钮开机后&#xff0c;一边按下键盘左下角的Fn功…

p51 thinkpad 拆解_ThinkPad P51s固态硬盘加装指南(含拆机图)

原标题:ThinkPad P51s固态硬盘加装指南(含拆机图) ThinkPad P51s是一款定位功能强大、机身轻薄的移动工作站,在19.9mm的机身中承载着酷睿i7、专业图形显卡、32G大内存、固态+机械双硬盘等专属强大性能。 但是强大的性能意味着不菲的价格,很多专业工作者在购买P51s都会通过自…

ThinkPad T450s笔记本禁用触摸板

网上找了很多方法&#xff0c;联系客服没人接电话&#xff0c;无力吐槽。 打开控制面板之后我们找到“设备和打印机”选项&#xff0c;然后找到其中的“鼠标”&#xff0c;点击进入。 点击鼠标按钮之后&#xff0c;我们打开鼠标的属性&#xff0c;在里面有一个ThinkPad/ultra…

笔记本电脑的S0-S5的状态

笔记本电脑的S0-S5的状态 1、S1 >Standby。即指说系统处于低电源供应状态&#xff0c;在 windows or BIOS 中可设定萤幕讯号输出关闭、 硬碟停止运转进入待命状态、电源灯号处于闪烁状态。此时动一动滑鼠、按键盘任一键均可叫醒电脑。 2、S2 >Power Standby&#xff0c…

VS常用快捷键

VS常用快捷键 前言1. 常用调试快捷键2. 编辑快捷键3. 代码快捷键4. 窗口操作快捷键5. 项目快捷键结尾 前言 在实际开发过程中&#xff0c;熟悉掌握相关快捷键不仅可以减少手指运动&#xff0c;还可以提高开发效率。本文将详细介绍VS中的相关快捷键。 1. 常用调试快捷键 F6: …