最近遇到一个问题:插入带麦克风的USB摄像头,摄像头可以正常输出图像但是没有声音,跟踪了一下整个框架记录一下
先从kernel入手:
kernel/sound/usb/card.c
当插入USB麦克风,USB Core会通过注册的usb_audio_ids 匹配到usb_audio_probe()函数
static struct usb_device_id usb_audio_ids [] = {
#include "quirks-table.h"
{ .match_flags = (USB_DEVICE_ID_MATCH_INT_CLASS | USB_DEVICE_ID_MATCH_INT_SUBCLASS),
.bInterfaceClass = USB_CLASS_AUDIO,
.bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL },
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, usb_audio_ids);
/*
* entry point for linux usb interface
*/
static struct usb_driver usb_audio_driver = {
.name = "snd-usb-audio",
.probe = usb_audio_probe,
.disconnect = usb_audio_disconnect,
.suspend = usb_audio_suspend,
.resume = usb_audio_resume,
.id_table = usb_audio_ids,
.supports_autosuspend = 1,
};
static int usb_audio_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
struct snd_usb_audio *chip;
chip = snd_usb_audio_probe(interface_to_usbdev(intf), intf, id);
if (chip) {
usb_set_intfdata(intf, chip);
return 0;
} else
return -EIO;
}
snd_usb_audio_probe()函数会调用snd_usb_create_quirk()
static struct snd_usb_audio * snd_usb_audio_probe(struct usb_device *dev,struct usb_interface *intf,const struct usb_device_id *usb_id)
{
。。。。。。。。。。。。。。。。。。。
if (!chip->ctrl_intf)
chip->ctrl_intf = alts;
chip->txfr_quirk = 0;
err = 1; /* continue */
if (quirk && quirk->ifnum != QUIRK_NO_INTERFACE) {
/* need some special handlings */
if ((err = snd_usb_create_quirk(chip, intf, &usb_audio_driver, quirk)) < 0)
goto __error;
}
if (err > 0) {
/* create normal USB audio interfaces */
if (snd_usb_create_streams(chip, ifnum) < 0 ||
snd_usb_create_mixer(chip, ifnum, ignore_ctl_error) < 0) {
goto __error;
}
}
/* we are allowed to call snd_card_register() many times */
if (snd_card_register(chip->card) < 0) {
goto __error;
}
。。。。。。。。。。。。。。。。。。。。。。。。。。
}
int snd_usb_create_quirk(struct snd_usb_audio *chip,struct usb_interface *iface,struct usb_driver *driver,const struct snd_usb_audio_quirk *quirk)
{
typedef int (*quirk_func_t)(struct snd_usb_audio *,
struct usb_interface *,
struct usb_driver *,
const struct snd_usb_audio_quirk *);
static const quirk_func_t quirk_funcs[] = {
[QUIRK_IGNORE_INTERFACE] = ignore_interface_quirk,
[QUIRK_COMPOSITE] = create_composite_quirk,
[QUIRK_MIDI_STANDARD_INTERFACE] = create_any_midi_quirk,
[QUIRK_MIDI_FIXED_ENDPOINT] = create_any_midi_quirk,
[QUIRK_MIDI_YAMAHA] = create_any_midi_quirk,
[QUIRK_MIDI_MIDIMAN] = create_any_midi_quirk,
[QUIRK_MIDI_NOVATION] = create_any_midi_quirk,
[QUIRK_MIDI_RAW_BYTES] = create_any_midi_quirk,
[QUIRK_MIDI_EMAGIC] = create_any_midi_quirk,
[QUIRK_MIDI_CME] = create_any_midi_quirk,
[QUIRK_MIDI_AKAI] = create_any_midi_quirk,
[QUIRK_MIDI_FTDI] = create_any_midi_quirk,
[QUIRK_AUDIO_STANDARD_INTERFACE] = create_standard_audio_quirk,
[QUIRK_AUDIO_FIXED_ENDPOINT] = create_fixed_stream_quirk,
[QUIRK_AUDIO_EDIROL_UAXX] = create_uaxx_quirk,
[QUIRK_AUDIO_ALIGN_TRANSFER] = create_align_transfer_quirk,
[QUIRK_AUDIO_STANDARD_MIXER] = create_standard_mixer_quirk,
};
if (quirk->type < QUIRK_TYPE_COUNT) {
return quirk_funcs[quirk->type](chip, iface, driver, quirk);
} else {
snd_printd(KERN_ERR "invalid quirk type %d\n", quirk->type);
return -ENXIO;
}
}
static int create_uaxx_quirk(struct snd_usb_audio *chip,
struct usb_interface *iface,
struct usb_driver *driver,
const struct snd_usb_audio_quirk *quirk)
{
。。。。。。
err = snd_usb_add_audio_stream(chip, stream, fp);
。。。。。。
}
int snd_usb_add_audio_stream(struct snd_usb_audio *chip,
int stream,
struct audioformat *fp)
{
err = snd_pcm_new(chip->card, "USB Audio", chip->pcm_devs,
stream == SNDRV_PCM_STREAM_PLAYBACK ? 1 : 0,
stream == SNDRV_PCM_STREAM_PLAYBACK ? 0 : 1,
&pcm);
}
static int _snd_pcm_new(struct snd_card *card, const char *id, int device,
int playback_count, int capture_count, bool internal,
struct snd_pcm **rpcm)
{
struct snd_pcm *pcm;
int err;
static struct snd_device_ops ops = {
.dev_free = snd_pcm_dev_free,
.dev_register = snd_pcm_dev_register,
.dev_disconnect = snd_pcm_dev_disconnect,
};
if (snd_BUG_ON(!card))
return -ENXIO;
if (rpcm)
*rpcm = NULL;
pcm = kzalloc(sizeof(*pcm), GFP_KERNEL);
if (pcm == NULL) {
snd_printk(KERN_ERR "Cannot allocate PCM\n");
return -ENOMEM;
}
pcm->card = card;
pcm->device = device;
pcm->internal = internal;
}
static int snd_pcm_dev_register(struct snd_device *device)
{
int cidx, err;
struct snd_pcm_substream *substream;
struct snd_pcm_notify *notify;
char str[16];
struct snd_pcm *pcm;
struct device *dev;
if (snd_BUG_ON(!device || !device->device_data))
return -ENXIO;
pcm = device->device_data;
mutex_lock(®ister_mutex);
err = snd_pcm_add(pcm);
if (err) {
mutex_unlock(®ister_mutex);
return err;
}
for (cidx = 0; cidx < 2; cidx++) {
int devtype = -1;
if (pcm->streams[cidx].substream == NULL || pcm->internal)
continue;
switch (cidx) {
case SNDRV_PCM_STREAM_PLAYBACK:
sprintf(str, "pcmC%iD%ip", pcm->card->number, pcm->device);
devtype = SNDRV_DEVICE_TYPE_PCM_PLAYBACK;
break;
case SNDRV_PCM_STREAM_CAPTURE:
sprintf(str, "pcmC%iD%ic", pcm->card->number, pcm->device);
devtype = SNDRV_DEVICE_TYPE_PCM_CAPTURE;
break;
}
/* device pointer to use, pcm->dev takes precedence if
* it is assigned, otherwise fall back to card's device
* if possible */
dev = pcm->dev;
if (!dev)
dev = snd_card_get_device_link(pcm->card);
/* register pcm */
err = snd_register_device_for_dev(devtype, pcm->card,
pcm->device,
&snd_pcm_f_ops[cidx],
pcm, str, dev);
if (err < 0) {
list_del(&pcm->list);
mutex_unlock(®ister_mutex);
return err;
}
snd_add_device_sysfs_file(devtype, pcm->card, pcm->device,
&pcm_attrs);
for (substream = pcm->streams[cidx].substream; substream; substream = substream->next)
snd_pcm_timer_init(substream);
}
list_for_each_entry(notify, &snd_pcm_notify_list, list)
notify->n_register(pcm);
mutex_unlock(®ister_mutex);
return 0;
}
最终会在: /dev/snd/pcm* 创建出节点。
进入framework/base/services/usb/java/com/android/server/usb/UsbAlsaManager.java
private static final String ALSA_DIRECTORY = "/dev/snd/";
private final FileObserver mAlsaObserver = new FileObserver(ALSA_DIRECTORY,
FileObserver.CREATE | FileObserver.DELETE) {
public void onEvent(int event, String path) {
switch (event) {
case FileObserver.CREATE:
alsaFileAdded(path);
break;
case FileObserver.DELETE:
alsaFileRemoved(path);
break;
}
}
};
当/dev/snd/目录下有新的设备节点创建时调用:alsaFileAdded()
private void alsaFileAdded(String name) {
int type = AlsaDevice.TYPE_UNKNOWN;
int card = -1, device = -1;
if (name.startsWith("pcmC")) {
if (name.endsWith("p")) {
type = AlsaDevice.TYPE_PLAYBACK;
} else if (name.endsWith("c")) {
type = AlsaDevice.TYPE_CAPTURE;
}
} else if (name.startsWith("midiC")) {
type = AlsaDevice.TYPE_MIDI;
}
if (type != AlsaDevice.TYPE_UNKNOWN) {
try {
int c_index = name.indexOf('C');
int d_index = name.indexOf('D');
int end = name.length();
if (type == AlsaDevice.TYPE_PLAYBACK || type == AlsaDevice.TYPE_CAPTURE) {
// skip trailing 'p' or 'c'
end--;
}
card = Integer.parseInt(name.substring(c_index + 1, d_index));
device = Integer.parseInt(name.substring(d_index + 1, end));
} catch (Exception e) {
Slog.e(TAG, "Could not parse ALSA file name " + name, e);
return;
}
synchronized(mAlsaDevices) {
if (mAlsaDevices.get(name) == null) {
AlsaDevice alsaDevice = new AlsaDevice(type, card, device);
Slog.d(TAG, "Adding ALSA device " + alsaDevice);
mAlsaDevices.put(name, alsaDevice);
mAlsaDevices.notifyAll();
}
}
}
}
最后会调到:usbDeviceAdded()
void usbDeviceAdded(UsbDevice usbDevice) {
...................................
ArrayList prevScanRecs = mCardsParser.getScanRecords();
mCardsParser.scan();
/*
mCardsParser.scan()的时候会读取声卡生成记录系统有多少逻辑设备的文件:/proc/asound/cards
cat /proc/asound/cards 信息如下:
0 [msm8939sndcards]: msm8939-snd-car - msm8939-snd-card-skuk
msm8939-snd-card-skuk
1 [C170 ]: USB-Audio - Webcam C170
Webcam C170 at usb-msm_hsusb_host-1.4.1, high speed
public void scan() {
if (DEBUG) { Slog.i(TAG, "AlsaCardsParser.scan()"); } mCardRecords = new ArrayList();
File cardsFile = new File(kCardsFilePath); //kCardsFilePath=/proc/asound/cards
try {
FileReader reader = new FileReader(cardsFile);
BufferedReader bufferedReader = new BufferedReader(reader);
String line = "";
while ((line = bufferedReader.readLine()) != null) {
AlsaCardRecord cardRecord = new AlsaCardRecord();
cardRecord.parse(line, 0);
line = bufferedReader.readLine();
if (line == null) {
break;
}
cardRecord.parse(line, 1);
mCardRecords.add(cardRecord);
}
reader.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
*/
..................................
if (mCardsParser.isCardUsb(addedCard)) {
UsbAudioDevice audioDevice = selectAudioCard(addedCard);
if (audioDevice != null) {
mAudioDevices.put(usbDevice, audioDevice);
}
..................................
}
UsbAudioDevice selectAudioCard(int card) {
..................................
notifyDeviceState(audioDevice, true);
...................................
}
private void notifyDeviceState(UsbAudioDevice audioDevice, boolean enabled) {
...........................
// Capture Device
if (audioDevice.mHasCapture) {
int device = (audioDevice == mAccessoryAudioDevice ?
AudioSystem.DEVICE_IN_USB_ACCESSORY :
AudioSystem.DEVICE_IN_USB_DEVICE);
mAudioService.setWiredDeviceConnectionState(
device, state, address, audioDevice.mDeviceName, TAG);
}
...........................
}
frameworks/base/services/core/java/com/android/server/audio/AudioService.java
public void setWiredDeviceConnectionState(int type, int state, String address, String name,
String caller) {
synchronized (mConnectedDevices) {
int delay = checkSendBecomingNoisyIntent(type, state);
queueMsgUnderWakeLock(mAudioHandler,
MSG_SET_WIRED_DEVICE_CONNECTION_STATE,
0,
0,
new WiredDeviceConnectionState(type, state, address, name, caller),
delay);
}
}
public void handleMessage(Message msg) {
..............................
case MSG_SET_WIRED_DEVICE_CONNECTION_STATE:
{ WiredDeviceConnectionState connectState =
(WiredDeviceConnectionState)msg.obj;
onSetWiredDeviceConnectionState(connectState.mType, connectState.mState,
connectState.mAddress, connectState.mName, connectState.mCaller);
mAudioEventWakeLock.release();
}
break;
..............................
}
private void onSetWiredDeviceConnectionState(int device, int state, String address,
String deviceName, String caller) {
.............................................................
boolean isUsb = ((device & ~AudioSystem.DEVICE_OUT_ALL_USB) == 0) ||
(((device & AudioSystem.DEVICE_BIT_IN) != 0) &&
((device & ~AudioSystem.DEVICE_IN_ALL_USB) == 0));
if (!handleDeviceConnection(state == 1, device, address, deviceName)) {
// change of connection state failed, bailout
return;
}
............................................................
}
private boolean handleDeviceConnection(boolean connect, int device, String address,
String deviceName) {
........................................
if (connect && !isConnected) {//第一次连接走这里
final int res = AudioSystem.setDeviceConnectionState(device,
AudioSystem.DEVICE_STATE_AVAILABLE, address, deviceName);
if (res != AudioSystem.AUDIO_STATUS_OK) {
Slog.e(TAG, "not connecting device 0x" + Integer.toHexString(device) +
" due to command error " + res );
return false;
}
mConnectedDevices.put(deviceKey, new DeviceListSpec(device, deviceName, address));
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;
}
..........................................
}
frameworks/base/media/java/android/media/AudioSystem.java
public static native int setDeviceConnectionState(int device, int state,
String device_address, String device_name);
通过JNI调到:frameworks/base/core/jni/android_media_AudioSystem.cpp
static jintandroid_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(device), static_cast(state),
c_address, c_name));
env->ReleaseStringUTFChars(device_address, c_address);
env->ReleaseStringUTFChars(device_name, c_name);
return (jint) status;
}
frameworks/av/media/libmedia/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& 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);
}
最终调到:
hardware\qcom\audio\policy_hal\AudioPolicyManager.cpp
status_t AudioPolicyManagerCustom::setDeviceConnectionStateInt(audio_devices_t device,
audio_policy_dev_state_t state,
const char *device_address,
const char *device_name)
{
..........................................................
// handle input devices if (audio_is_input_device(device)) { SortedVectorinputs; ssize_t index = mAvailableInputDevices.indexOf(devDesc); switch (state) { // handle input device connection case AUDIO_POLICY_DEVICE_STATE_AVAILABLE: { if (index >= 0) { ALOGW("setDeviceConnectionState() device already connected: %d", device); return INVALID_OPERATION; } sp module = mHwModules.getModuleForDevice(device);
if (module == NULL) {
ALOGW("setDeviceConnectionState(): could not find HW module for device %08x",
device);
return INVALID_OPERATION;
}
if (checkInputsForDevice(devDesc, state, inputs, devDesc->mAddress) != NO_ERROR) {
return INVALID_OPERATION;
}
index = mAvailableInputDevices.add(devDesc);//添加到可用输入设备列表中待选
if (index >= 0) {
mAvailableInputDevices[index]->attach(module);
} else {
return NO_MEMORY;
}
// Set connect to HALs
AudioParameter param = AudioParameter(devDesc->mAddress);
param.addInt(String8(AUDIO_PARAMETER_DEVICE_CONNECT), device);
mpClientInterface->setParameters(AUDIO_IO_HANDLE_NONE, param.toString());
// Propagate device availability to Engine
mEngine->setDeviceConnectionState(devDesc, state);
} break;
..........................................................
}
没有插入USB麦克风是输入设备列表LOG如下:
APM::Devices: Device id:5 type:0x80000004:Built-In Mic, addr:
APM::AudioPort: Port[nm:, type:1, role:1]
APM::Devices: Device id:6 type:0x80000080:Built-In Back Mic, addr:
APM::AudioPort: Port[nm:, type:1, role:1]
APM::Devices: Device id:9 type:0x80000100:Reroute Submix In, addr:0
APM::AudioPort: Port[nm:, type:1, role:1]
APM::Devices: Device id:7 type:0x80000040:Telephony Rx, addr:
APM::AudioPort: Port[nm:, type:1, role:1]
APM::Devices: Device id:8 type:0x80002000:FM Tuner In, addr:
APM::AudioPort: Port[nm:, type:1, role:1]
当插入USB麦克风是输入设备列表LOG如下:
APM::Devices: Device id:5 type:0x80000004:Built-In Mic, addr:
APM::AudioPort: Port[nm:, type:1, role:1]
APM::Devices: Device id:6 type:0x80000080:Built-In Back Mic, addr:
APM::AudioPort: Port[nm:, type:1, role:1]
APM::Devices: Device id:9 type:0x80000100:Reroute Submix In, addr:0
APM::AudioPort: Port[nm:, type:1, role:1]
APM::Devices: Device id:7 type:0x80000040:Telephony Rx, addr:
APM::AudioPort: Port[nm:, type:1, role:1]
APM::Devices: Device id:8 type:0x80002000:FM Tuner In, addr:
APM::AudioPort: Port[nm:, type:1, role:1]
APM::Devices: Device id:13 type:0x80001000:USB Device In, addr:card=1;device=0;
APM::AudioPort: Port[nm:USB-Audio - Webcam C170, type:1, role:1]
-----------------------------------------------------------------------------------------------------------------------
当APP通过:audioRecord =new AudioRecord(MediaRecorder.AudioSource.MIC, frequency,
channelConfiguration, audioEncoding, recBufSize);
audioRecord.startRecording();
最终会转到
status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr,
audio_io_handle_t *input,
audio_session_t session,
uid_t uid,
uint32_t samplingRate,
audio_format_t format,
audio_channel_mask_t channelMask,
audio_input_flags_t flags,
audio_port_handle_t selectedDeviceId,
input_type_t *inputType)
{
。。。。。。。。。。。。。。。
//根据输入源类型我们在app中选择的是inputSource=MediaRecorder.AudioSource.MIC
device = getDeviceAndMixForInputSource(inputSource, &policyMix);
。。。。。。。
}
audio_devices_t AudioPolicyManager::getDeviceAndMixForInputSource(audio_source_t inputSource,AudioMix **policyMix)
{
audio_devices_t availableDeviceTypes = mAvailableInputDevices.types() & ~AUDIO_DEVICE_BIT_IN;
audio_devices_t selectedDeviceFromMix =
mPolicyMixes.getDeviceAndMixForInputSource(inputSource, availableDeviceTypes, policyMix);
if (selectedDeviceFromMix != AUDIO_DEVICE_NONE) {
return selectedDeviceFromMix;
}
return getDeviceForInputSource(inputSource);
}
audio_devices_t AudioPolicyManager::getDeviceForInputSource(audio_source_t inputSource){ for (size_t routeIndex = 0; routeIndex < mInputRoutes.size(); routeIndex++) { sp route = mInputRoutes.valueAt(routeIndex);
if (inputSource == route->mSource && route->isActive()) {
return route->mDeviceDescriptor->type();
}
}
return mEngine->getDeviceForInputSource(inputSource);
}
audio_devices_t Engine::getDeviceForInputSource(audio_source_t inputSource) const
{
。。。。。。。。。。。
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) {
device = 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) {
device = AUDIO_DEVICE_IN_USB_DEVICE;
} else if (availableDeviceTypes & AUDIO_DEVICE_IN_BUILTIN_MIC) {
device = AUDIO_DEVICE_IN_BUILTIN_MIC;
}
break;
。。。。。。。。
}
从次可以看出系统选择麦克风的优先顺序