问题:
当不插usb声卡时,打开录像机,点录像键,几秒钟后系统提示错误,退出,再次点击录像键或照相机,均打不开
用录像机录像时,要打开音频输入设备
在AudioFlinger层
frameworks/base/services/audioflinger/AudioFlinger.cpp
int AudioFlinger::openInput(uint32_t *pDevices,
uint32_t *pSamplingRate,
uint32_t *pFormat,
uint32_t *pChannels,
uint32_t acoustics)
{
status_t status;
RecordThread *thread = NULL;
uint32_t samplingRate = pSamplingRate ? *pSamplingRate : 0;
uint32_t format = pFormat ? *pFormat : 0;
uint32_t channels = pChannels ? *pChannels : 0;
uint32_t reqSamplingRate = samplingRate;
uint32_t reqFormat = format;
uint32_t reqChannels = channels;
audio_stream_in_t *inStream;
audio_hw_device_t *inHwDev;
if (pDevices == NULL || *pDevices == 0) {
return 0;
}
Mutex::Autolock _l(mLock);
inHwDev = findSuitableHwDev_l(*pDevices);
if (inHwDev == NULL)
return 0;
status = inHwDev->open_input_stream(inHwDev, *pDevices, (int *)&format,
&channels, &samplingRate,
(audio_in_acoustics_t)acoustics,
&inStream); //问题出在这,当没有USB声卡时,这个函数没有返回。
LOGV("openInput() openInputStream returned input %p, SamplingRate %d, Format %d, Channels %x, acoustics %x, status %d",
inStream,
samplingRate,
format,
channels,
acoustics,
status);
// If the input could not be opened with the requested parameters and we can handle the conversion internally,
// try to open again with the proposed parameters. The AudioFlinger can resample the input and do mono to stereo
// or stereo to mono conversions on 16 bit PCM inputs.
if (inStream == NULL && status == BAD_VALUE &&
reqFormat == format && format == AUDIO_FORMAT_PCM_16_BIT &&
(samplingRate <= 2 * reqSamplingRate) &&
(getInputChannelCount(channels) < 3) && (getInputChannelCount(reqChannels) < 3)) {
LOGV("openInput() reopening with proposed sampling rate and channels");
status = inHwDev->open_input_stream(inHwDev, *pDevices, (int *)&format,
&channels, &samplingRate,
(audio_in_acoustics_t)acoustics,
&inStream);
}
if (inStream != NULL) {
AudioStreamIn *input = new AudioStreamIn(inHwDev, inStream);
int id = nextUniqueId();
// Start record thread
// RecorThread require both input and output device indication to forward to audio
// pre processing modules
uint32_t device = (*pDevices) | primaryOutputDevice_l();
thread = new RecordThread(this,
input,
reqSamplingRate,
reqChannels,
id,
device);
mRecordThreads.add(id, thread);
LOGV("openInput() created record thread: ID %d thread %p", id, thread);
if (pSamplingRate) *pSamplingRate = reqSamplingRate;
if (pFormat) *pFormat = format;
if (pChannels) *pChannels = reqChannels;
input->stream->common.standby(&input->stream->common);
// notify client processes of the new input creation
thread->audioConfigChanged_l(AudioSystem::INPUT_OPENED);
return id;
}
return 0;
}
在AudioHardware层
hardware/qcom/media/audio/msm8660/audio_hw_hal.cpp
static int qcom_adev_open(const hw_module_t* module, const char* name,
hw_device_t** device)
{
struct qcom_audio_device *qadev;
int ret;
if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0)
return -EINVAL;
qadev = (struct qcom_audio_device *)calloc(1, sizeof(*qadev));
if (!qadev)
return -ENOMEM;
qadev->device.common.tag = HARDWARE_DEVICE_TAG;
qadev->device.common.version = 0;
qadev->device.common.module = const_cast<hw_module_t*>(module);
qadev->device.common.close = qcom_adev_close;
qadev->device.get_supported_devices = adev_get_supported_devices;
qadev->device.init_check = adev_init_check;
qadev->device.set_voice_volume = adev_set_voice_volume;
qadev->device.set_master_volume = adev_set_master_volume;
qadev->device.set_fm_volume = adev_set_fm_volume;
qadev->device.set_mode = adev_set_mode;
qadev->device.set_mic_mute = adev_set_mic_mute;
qadev->device.get_mic_mute = adev_get_mic_mute;
qadev->device.set_parameters = adev_set_parameters;
qadev->device.get_parameters = adev_get_parameters;
qadev->device.get_input_buffer_size = adev_get_input_buffer_size;
qadev->device.open_output_stream = adev_open_output_stream;
qadev->device.open_output_session = adev_open_output_session;
qadev->device.close_output_stream = adev_close_output_stream;
qadev->device.open_input_stream = adev_open_input_stream; //指向adev_open_input_stream()
qadev->device.close_input_stream = adev_close_input_stream;
qadev->device.dump = adev_dump;
qadev->hwif = createAudioHardware();
if (!qadev->hwif) {
ret = -EIO;
goto err_create_audio_hw;
}
*device = &qadev->device.common;
return 0;
err_create_audio_hw:
free(qadev);
return ret;
}
/** This method creates and opens the audio hardware input stream */
static int adev_open_input_stream(struct audio_hw_device *dev,
uint32_t devices, int *format,
uint32_t *channels, uint32_t *sample_rate,
audio_in_acoustics_t acoustics,
struct audio_stream_in **stream_in)
{
struct legacy_audio_device *ladev = to_ladev(dev);
status_t status;
struct legacy_stream_in *in;
int ret;
in = (struct legacy_stream_in *)calloc(1, sizeof(*in));
if (!in)
return -ENOMEM;
in->legacy_in = ladev->hwif->openInputStream(devices, format, channels,
sample_rate, &status,
(AudioSystem::audio_in_acoustics)acoustics); //这里没有返回
if (!in->legacy_in) {
ret = status;
goto err_open;
}
in->stream.common.get_sample_rate = in_get_sample_rate;
in->stream.common.set_sample_rate = in_set_sample_rate;
in->stream.common.get_buffer_size = in_get_buffer_size;
in->stream.common.get_channels = in_get_channels;
in->stream.common.get_format = in_get_format;
in->stream.common.set_format = in_set_format;
in->stream.common.standby = in_standby;
in->stream.common.dump = in_dump;
in->stream.common.set_parameters = in_set_parameters;
in->stream.common.get_parameters = in_get_parameters;
in->stream.common.add_audio_effect = in_add_audio_effect;
in->stream.common.remove_audio_effect = in_remove_audio_effect;
in->stream.set_gain = in_set_gain;
in->stream.read = in_read;
in->stream.get_input_frames_lost = in_get_input_frames_lost;
*stream_in = &in->stream;
return 0;
err_open:
free(in);
*stream_in = NULL;
return ret;
}
hardware/qcom/media/audio/msm8660/AudioHardware.cpp
887 AudioStreamIn* AudioHardware::openInputStream(
888 uint32_t devices, int *format, uint32_t *channels, uint32_t *sampleRate, status_t *status,
889 AudioSystem::audio_in_acoustics acoustic_flags)
890 {
891 // check for valid input source
892 if (!AudioSystem::isInputDevice((AudioSystem::audio_devices)devices)) {
893 return 0;
894 }
895
896 #if 1 //WNC:WJ Wang 20110719: Add USB-Mic path: BEGIN
897 if (devices == AudioSystem::DEVICE_IN_USB_MIC)
898 {
899 Mutex::Autolock lock(mLock);
900
901 AudioStreamInUSBMic *in_usb = new AudioStreamInUSBMic();
902 status_t lStatus = in_usb->set(this, devices, format, channels, sampleRate, acoustic_flags);
903
904 if (status) {
906 *status = lStatus;
907 }
908 if (lStatus != NO_ERROR) //If open USB-Mic failed, continue to open the analog Mic
909 {
910 LOGE("before delete in_usb\n");
911 delete in_usb; //这句之后的log没有打出来。delete in_usb对象时,进入AudioStreamInUSBMic的析构函数
912 LOGE("delete in_usb\n");
913 }
914 else
915 {
916 mUsbInputs.add(in_usb);
917 return in_usb;
918 }
919 }
920 #endif //WNC:WJ Wang 20110719: Add USB-Mic path: END
922 mLock.lock();
923 if(devices == AudioSystem::DEVICE_IN_COMMUNICATION) {
924 LOGE("Create Audio stream Voip \n");
925 AudioStreamInVoip* inVoip = new AudioStreamInVoip();
926 status_t lStatus = NO_ERROR;
927 lStatus = inVoip->set(this, devices, format, channels, sampleRate, acoustic_flags);
928 if (status) {
929 *status = lStatus;
930 }
931 if (lStatus != NO_ERROR) {
932 LOGE(" Error creating voip input \n");
933 mLock.unlock();
934 delete inVoip;
935 return 0;
936 }
937 mVoipInputs.add(inVoip);
938 mLock.unlock();
939 return inVoip;
940 } else {
941 AudioStreamInMSM72xx* in72xx = new AudioStreamInMSM72xx();
942 status_t lStatus = in72xx->set(this, devices, format, channels, sampleRate, acoustic_flags);
943 if (status) {
944 *status = lStatus;
945 }
946 if (lStatus != NO_ERROR) {
947 LOGE("Error creating Audio stream AudioStreamInMSM72xx \n");
948 mLock.unlock();
949 delete in72xx;
950 return 0;
951 }
952 mInputs.add(in72xx);
953 mLock.unlock();
954 return in72xx;
955 }
956 }
AudioHardware::AudioStreamInUSBMic::~AudioStreamInUSBMic()
{
standby();
}
status_t AudioHardware::AudioStreamInUSBMic::standby()
{
AudioHardware *hw = mHardware;
if (!mHardware) return -1;
hw->mLock.lock();
if (mState > AUDIO_INPUT_CLOSED)
{
if (mHandle != 0)
{
snd_pcm_close(mHandle);
mHandle = 0;
if (mHardware != 0)
{
if(mHardware->mNumPcmRec > 0 && mFormat == AUDIO_HW_IN_FORMAT)
mHardware->mNumPcmRec--;
}
}
mState = AUDIO_INPUT_CLOSED;
}
hw->mLock.unlock();
return NO_ERROR;
}
找到问题了:
在执行delete in_usb之前,执行了Mutex::Autolock lock(mLock); mLock被锁住了,所以在析构函数所调用的standby函数里,调用hw->mLock.lock();时,就获取不到锁,导致死锁!
AutoLock类是定义在Mutex内部的一个类,AutoLock的定义代码如下所示:
[-->Thread.h Mutex::Autolock声明和实现]
class Autolock {
public:
//构造的时候调用lock。
inline Autolock(Mutex& mutex) : mLock(mutex) { mLock.lock(); }
inline Autolock(Mutex* mutex) : mLock(*mutex) { mLock.lock(); }
//析构的时候调用unlock。
inline ~Autolock() { mLock.unlock(); }
private:
Mutex& mLock;
};
AutoLock的用法很简单: 先定义一个Mutex,如 Mutex xlock。 在使用xlock的地方,定义一个AutoLock,如 AutoLock autoLock(xlock)。由于C++对象的构造和析构函数都是自动被调用的,所以在AutoLock的生命周期内,xlock的lock和unlock也就自动被调用了,这样就省去了重复书写unlock的麻烦,而且lock和unlock的调用肯定是一一对应的,这样就绝对不会出错。
在作用域里加锁,脱离作用域就会自动解锁。作用域是指同级{}范围。
Mutex::Autolock lock(mLock)的mLock在class AudioHardware中定义,所以和hw->mLock.lock();中的mLock是同一个锁。
相关代码:
set函数由openInputStream()调用,没有usb声卡时返回BAD_VALUE,否则返回NO_ERROR。
status_t AudioHardware::AudioStreamInUSBMic::set(
AudioHardware* hw, uint32_t devices, int *pFormat, uint32_t *pChannels, uint32_t *pRate,
AudioSystem::audio_in_acoustics acoustic_flags)
{
char cap_pcm[16];
LOGD("AudioHardware::AudioStreamInUSBMic::set(%d)...mState=%d", *pFormat, *pChannels);
if (pFormat == 0 || pRate == 0 || pChannels == 0) {
return BAD_VALUE;
}
uint32_t rate = hw->getInputSampleRate(*pRate);
if (rate != *pRate) {
*pRate = rate;
return BAD_VALUE;
}
//Eaddy temp
if (rate != 16000)
rate = 16000;
if ((*pChannels & (AudioSystem::CHANNEL_IN_MONO | AudioSystem::CHANNEL_IN_STEREO)) == 0) {
*pChannels = AUDIO_HW_IN_CHANNELS;
return BAD_VALUE;
}
if (mHandle != 0) {
LOGE("Audio record already set");
return NO_ERROR;
}
mHardware = hw;
if(mHardware->mNumPcmRec > 0) {
/* Only one PCM recording is allowed at a time */
LOGE("Multiple PCM recordings is not allowed");
return -1;
}
status_t status = NO_ERROR;
int dir = 0;
snd_pcm_t *handle = 0;
snd_pcm_hw_params_t *params = 0;
status = getCaptureDevice(cap_pcm);
if (status < 0) {
LOGE("No USB-Audio:");
return BAD_VALUE;
}
/* Open PCM device for recording (capture). Old setting == "hw:2,0,0" */
status = snd_pcm_open(&handle, cap_pcm, SND_PCM_STREAM_CAPTURE, 0);
if (status < 0) {
LOGE("unable to open pcm device");
return status;
}
mHandle = handle;
mHardware->mNumPcmRec++;
mDevices = devices;
mFormat = AUDIO_HW_IN_FORMAT;
mChannels = *pChannels;
mChannelCount = AudioSystem::popCount(mChannels);
mSampleRate = rate;
mAcoustics = acoustic_flags;
mBufferSize = mHardware->getInputBufferSize(mSampleRate, AUDIO_HW_IN_FORMAT, mChannelCount);
mBufferSize <<= 1; // We double the size of input buffer for ping pong use of record buffer.
LOGD("AudioStreamInUSBMic::set(%d)...(%d, %d, %d)", __LINE__, mChannelCount, mSampleRate, mBufferSize);
/* Allocate a hardware parameters object. */
snd_pcm_hw_params_alloca(¶ms);
if (params == 0)
{
LOGE("unable to allocate parameter memory");
goto Error;
}
/* Fill it in with default values. */
snd_pcm_hw_params_any(handle, params);
/* Set the desired hardware parameters. */
/* Interleaved mode */
snd_pcm_hw_params_set_access(handle, params,
SND_PCM_ACCESS_RW_INTERLEAVED);
/* Signed 16-bit little-endian format */
snd_pcm_hw_params_set_format(handle, params,
SND_PCM_FORMAT_S16_LE);
/* Two channels (stereo) */
snd_pcm_hw_params_set_channels(handle, params, mChannelCount);
snd_pcm_uframes_t lvFrames;
/* Set period size to frames. */
lvFrames = 32;
snd_pcm_hw_params_set_period_size_near(handle, params, &lvFrames, &dir);
/* Write the parameters to the driver */
status = snd_pcm_hw_params(handle, params);
if (status < 0) {
LOGE("unable to set hw params");
goto Error;
}
mState = AUDIO_INPUT_OPENED;
return NO_ERROR;
Error:
if (mHandle != 0) {
snd_pcm_close(mHandle);
mHandle = 0;
}
return -1;
}
getCaptureDevice,找到USB-Audio时,返回0,找不到时返回-1
int AudioHardware::AudioStreamInUSBMic::getCaptureDevice(char * cap_pcm_str)
{
int rc,idx,dev;
snd_ctl_t *handle;
snd_pcm_hw_params_t *params;
snd_ctl_card_info_t *info;
snd_pcm_info_t *pcminfo;
char str[16];
char usb_card_str[16];
int cap_pcm_dev;
int cap_pcm_sub_dev;
snd_ctl_card_info_alloca(&info);
snd_pcm_info_alloca(&pcminfo);
idx = -1;
while (1)
{
if ((rc = snd_card_next(&idx)) < 0) {
LOGE("Card next error ");
break;
}
if (idx < 0)
break;
/* Check sound card */
sprintf(str, "hw:CARD=%i", idx);
if ((rc = snd_ctl_open(&handle, str, 0)) < 0) {
LOGE("Open error: card = %s\n", str);
continue;
}
if ((rc = snd_ctl_card_info(handle, info)) < 0) {
LOGE("HW info error:");
continue;
}
/* Find "USB-Audio" */
sprintf(usb_card_str, "%s", snd_ctl_card_info_get_driver(info));
LOGI("Soundcard Driver = %s", usb_card_str);
if ((rc = strncmp(usb_card_str, "USB-Audio", 9)) == 0)
{
LOGI("[--------------Got USB-Audio--------------]");
dev = -1;
while (1) {
snd_pcm_sync_id_t sync;
if ((rc = snd_ctl_pcm_next_device(handle, &dev)) < 0) {
LOGE(" PCM next device error ");
break;
}
if (dev < 0)
break;
snd_pcm_info_set_device(pcminfo, dev);
snd_pcm_info_set_subdevice(pcminfo, 0);
snd_pcm_info_set_stream(pcminfo, SND_PCM_STREAM_CAPTURE);
if ((rc = snd_ctl_pcm_info(handle, pcminfo)) < 0) {
LOGE(" PCM info error");
continue;
}
/* Find the PCM capture device */
cap_pcm_dev = snd_pcm_info_get_device(pcminfo);
cap_pcm_sub_dev = snd_pcm_info_get_subdevice(pcminfo);
sprintf(cap_pcm_str, "hw:%i,%i,%i", idx, cap_pcm_dev, cap_pcm_sub_dev);
LOGD("Open capture pcm device [%s]\n", cap_pcm_str);
return 0;
}
}else{
continue;
}
}
return idx;
}
class AudioHardware定义:
hardware/qcom/media/audio/msm8660/AudioHardware.h
class AudioHardware : public AudioHardwareBase
{
class AudioStreamOutMSM72xx;
class AudioStreamInMSM72xx;
public:
AudioHardware();
virtual ~AudioHardware();
virtual status_t initCheck();
virtual status_t setVoiceVolume(float volume);
virtual status_t setMasterVolume(float volume);
virtual status_t setMode(int mode);
// mic mute
virtual status_t setMicMute(bool state);
virtual status_t getMicMute(bool* state);
virtual status_t setParameters(const String8& keyValuePairs);
virtual String8 getParameters(const String8& keys);
// create I/O streams
virtual AudioStreamOut* openOutputStream(
uint32_t devices,
int *format=0,
uint32_t *channels=0,
uint32_t *sampleRate=0,
status_t *status=0);
virtual AudioStreamIn* openInputStream(
uint32_t devices,
int *format,
uint32_t *channels,
uint32_t *sampleRate,
status_t *status,
AudioSystem::audio_in_acoustics acoustics);
virtual void closeOutputStream(AudioStreamOut* out);
virtual void closeInputStream(AudioStreamIn* in);
virtual size_t getInputBufferSize(uint32_t sampleRate, int format, int channelCount);
void clearCurDevice() { mCurSndDevice = -1; }
protected:
virtual status_t dump(int fd, const Vector<String16>& args);
private:
status_t doAudioRouteOrMute(uint32_t device);
status_t setMicMute_nosync(bool state);
status_t checkMicMute();
status_t dumpInternals(int fd, const Vector<String16>& args);
uint32_t getInputSampleRate(uint32_t sampleRate);
bool checkOutputStandby();
status_t doRouting(AudioStreamInMSM72xx *input);
AudioStreamInMSM72xx* getActiveInput_l();
class AudioStreamOutMSM72xx : public AudioStreamOut {
public:
AudioStreamOutMSM72xx();
virtual ~AudioStreamOutMSM72xx();
status_t set(AudioHardware* mHardware,
uint32_t devices,
int *pFormat,
uint32_t *pChannels,
uint32_t *pRate);
virtual uint32_t sampleRate() const { return 44100; }
// must be 32-bit aligned - driver only seems to like 4800
virtual size_t bufferSize() const { return 4800; }
virtual uint32_t channels() const { return AudioSystem::CHANNEL_OUT_STEREO; }
virtual int format() const { return AudioSystem::PCM_16_BIT; }
virtual uint32_t latency() const { return (1000*AUDIO_HW_NUM_OUT_BUF*(bufferSize()/frameSize()))/sampleRate()+AUDIO_HW_OUT_LATENCY_MS; }
virtual status_t setVolume(float left, float right) { return INVALID_OPERATION; }
virtual ssize_t write(const void* buffer, size_t bytes);
virtual status_t standby();
virtual status_t dump(int fd, const Vector<String16>& args);
bool checkStandby();
virtual status_t setParameters(const String8& keyValuePairs);
virtual String8 getParameters(const String8& keys);
uint32_t devices() { return mDevices; }
virtual status_t getRenderPosition(uint32_t *dspFrames);
private:
AudioHardware* mHardware;
int mFd;
int mStartCount;
int mRetryCount;
bool mStandby;
uint32_t mDevices;
};
class AudioStreamInMSM72xx : public AudioStreamIn {
public:
enum input_state {
AUDIO_INPUT_CLOSED,
AUDIO_INPUT_OPENED,
AUDIO_INPUT_STARTED
};
AudioStreamInMSM72xx();
virtual ~AudioStreamInMSM72xx();
status_t set(AudioHardware* mHardware,
uint32_t devices,
int *pFormat,
uint32_t *pChannels,
uint32_t *pRate,
AudioSystem::audio_in_acoustics acoustics);
virtual size_t bufferSize() const { return mBufferSize; }
virtual uint32_t channels() const { return mChannels; }
virtual int format() const { return mFormat; }
virtual uint32_t sampleRate() const { return mSampleRate; }
virtual status_t setGain(float gain) { return INVALID_OPERATION; }
virtual ssize_t read(void* buffer, ssize_t bytes);
virtual status_t dump(int fd, const Vector<String16>& args);
virtual status_t standby();
virtual status_t setParameters(const String8& keyValuePairs);
virtual String8 getParameters(const String8& keys);
virtual unsigned int getInputFramesLost() const { return 0; }
uint32_t devices() { return mDevices; }
int state() const { return mState; }
virtual status_t addAudioEffect(effect_interface_s**) { return 0;}
virtual status_t removeAudioEffect(effect_interface_s**) { return 0;}
private:
AudioHardware* mHardware;
int mFd;
int mState;
int mRetryCount;
int mFormat;
uint32_t mChannels;
uint32_t mSampleRate;
size_t mBufferSize;
AudioSystem::audio_in_acoustics mAcoustics;
uint32_t mDevices;
bool mFirstread;
};
static const uint32_t inputSamplingRates[];
bool mInit;
bool mMicMute;
bool mBluetoothNrec;
uint32_t mBluetoothId;
AudioStreamOutMSM72xx* mOutput;
SortedVector <AudioStreamInMSM72xx*> mInputs;
msm_snd_endpoint *mSndEndpoints;
int mNumSndEndpoints;
int mCurSndDevice;
int m7xsnddriverfd;
bool mDualMicEnabled;
int mTtyMode;
friend class AudioStreamInMSM72xx;
Mutex mLock;
};