不插usb声卡时,录像机无法关闭


问题:

当不插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;
};

 


 


















评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值