C++程序  |  731行  |  23.7 KB

/*
 * Copyright (c) 2013, The Linux Foundation. All rights reserved.
 * Not a Contribution.
 *
 * Copyright (C) 2013 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#define LOG_TAG "audio_hw_usb"
#define LOG_NDEBUG 0
#define LOG_NDDEBUG 0

#include <errno.h>
#include <pthread.h>
#include <stdlib.h>
#include <cutils/log.h>
#include <cutils/str_parms.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <sys/stat.h>

#include <system/audio.h>
#include <tinyalsa/asoundlib.h>

#ifdef USB_HEADSET_ENABLED
#define USB_LOW_LATENCY_OUTPUT_PERIOD_SIZE   512
#define USB_LOW_LATENCY_OUTPUT_PERIOD_COUNT  8
#define USB_DEFAULT_OUTPUT_SAMPLING_RATE     48000

#define USB_PROXY_DEFAULT_SAMPLING_RATE      48000
#define USB_PROXY_OPEN_RETRY_COUNT           100
#define USB_PROXY_OPEN_WAIT_TIME             20
#define USB_PROXY_PERIOD_SIZE                3072
#define USB_PROXY_RATE_8000                  8000
#define USB_PROXY_RATE_16000                 16000
#define USB_PROXY_RATE_48000                 48000
#define USB_PERIOD_SIZE                      2048
#define USB_BUFF_SIZE                        2048
#define AFE_PROXY_PERIOD_COUNT               32
#define AFE_PROXY_PLAYBACK_DEVICE            8
#define AFE_PROXY_CAPTURE_DEVICE             7

struct usb_module {
    uint32_t usb_card;
    uint32_t proxy_card;
    uint32_t usb_device_id;
    uint32_t proxy_device_id;

    int32_t channels_playback;
    int32_t sample_rate_playback;
    int32_t channels_record;
    int32_t sample_rate_record;

    bool is_playback_running;
    bool is_record_running;

    pthread_t usb_playback_thr;
    pthread_t usb_record_thr;
    pthread_mutex_t usb_playback_lock;
    pthread_mutex_t usb_record_lock;

    struct pcm *proxy_pcm_playback_handle;
    struct pcm *usb_pcm_playback_handle;
    struct pcm *proxy_pcm_record_handle;
    struct pcm *usb_pcm_record_handle;
    struct audio_device *adev;
};

static struct usb_module *usbmod = NULL;
static pthread_once_t alloc_usbmod_once_ctl = PTHREAD_ONCE_INIT;

struct pcm_config pcm_config_usbmod = {
    .channels = 2,
    .rate = USB_DEFAULT_OUTPUT_SAMPLING_RATE,
    .period_size = USB_LOW_LATENCY_OUTPUT_PERIOD_SIZE,
    .period_count = USB_LOW_LATENCY_OUTPUT_PERIOD_COUNT,
    .format = PCM_FORMAT_S16_LE,
    .start_threshold = USB_LOW_LATENCY_OUTPUT_PERIOD_SIZE / 4,
    .stop_threshold = INT_MAX,
    .avail_min = USB_LOW_LATENCY_OUTPUT_PERIOD_SIZE / 4,
};

static void usb_alloc()
{
    usbmod = calloc(1, sizeof(struct usb_module));
}

// Some USB audio accessories have a really low default volume set. Look for a suitable
// volume control and set the volume to default volume level.
static void initPlaybackVolume() {
    ALOGD("initPlaybackVolume");
    struct mixer *usbMixer = mixer_open(1);

    if (usbMixer) {
         struct mixer_ctl *ctl = NULL;
         unsigned int usbPlaybackVolume;
         unsigned int i;
         unsigned int num_ctls = mixer_get_num_ctls(usbMixer);

         // Look for the first control named ".*Playback Volume" that isn't for a microphone
         for (i = 0; i < num_ctls; i++) {
             ctl = mixer_get_ctl(usbMixer, i);
             if ((ctl) && (strstr((const char *)mixer_ctl_get_name(ctl), "Playback Volume") &&
                 !strstr((const char *)mixer_ctl_get_name(ctl), "Mic"))) {
                   break;
             }
         }
         if (ctl != NULL) {
            ALOGD("Found a volume control for USB: %s", mixer_ctl_get_name(ctl) );
            usbPlaybackVolume = mixer_ctl_get_value(ctl, 0);
            ALOGD("Value got from mixer_ctl_get is:%u", usbPlaybackVolume);
            if (mixer_ctl_set_value(ctl,0,usbPlaybackVolume) < 0) {
               ALOGE("Failed to set volume; default volume might be used");
            }
         } else {
            ALOGE("No playback volume control found; default volume will be used");
         }
         mixer_close(usbMixer);
    } else {
         ALOGE("Failed to open mixer for card 1");
    }
}

static int usb_get_numof_rates(char *rates_str)
{
    int i, size = 0;
    char *next_sr_string, *temp_ptr;
    next_sr_string = strtok_r(rates_str, " ,", &temp_ptr);

    if (next_sr_string == NULL) {
        ALOGE("%s: get_numof_rates: could not find rates string", __func__);
        return 0;
    }

    for (i = 1; next_sr_string != NULL; i++) {
        size ++;
        next_sr_string = strtok_r(NULL, " ,.-", &temp_ptr);
    }
    return size;
}

static int usb_get_capability(char *type, int32_t *channels,
                                    int32_t *sample_rate)
{
    ALOGD("%s: for %s", __func__, type);
    long unsigned file_size;
    FILE *fp;
    char *buffer;
    int32_t err = 1;
    int32_t size = 0;
    int32_t fd=-1, i, channels_playback;
    char *str_start, *channel_start, *rates_str_start, *next_sr_str,
         *next_sr_string, *temp_ptr;
    struct stat st;
    char *read_buf = NULL;
    char *rates_str = NULL;
    char *rates_str_for_val = NULL;
    int  *rates_supported = NULL;
    char path[128];
    int ret = 0;

    memset(&st, 0x0, sizeof(struct stat));
    *sample_rate = 0;
    snprintf(path, sizeof(path), "/proc/asound/card%u/stream0",
             usbmod->usb_card);

    fd = open(path, O_RDONLY);
    if (fd <0) {
        ALOGE("%s: error failed to open config file %s error: %d\n",
              __func__, path, errno);
        ret = -EINVAL;
        goto done;
    }

    if (fstat(fd, &st) < 0) {
        ALOGE("%s: error failed to stat %s error %d\n",
             __func__, path, errno);
        ret = -EINVAL;
        goto done;
    }

    file_size = st.st_size;

    read_buf = (char *)calloc(1, USB_BUFF_SIZE + 1);

    if (!read_buf) {
        ALOGE("Failed to create read_buf");
        ret = -ENOMEM;
        goto done;
    }

    err = read(fd, read_buf, USB_BUFF_SIZE);
    str_start = strstr(read_buf, type);
    if (str_start == NULL) {
        ALOGE("%s: error %s section not found in usb config file",
               __func__, type);
        ret = -EINVAL;
        goto done;
    }

    channel_start = strstr(str_start, "Channels:");
    if (channel_start == NULL) {
        ALOGE("%s: error could not find Channels information", __func__);
        ret = -EINVAL;
        goto done;
    }

    channel_start = strstr(channel_start, " ");
    if (channel_start == NULL) {
        ALOGE("%s: error channel section not found in usb config file",
               __func__);
        ret = -EINVAL;
        goto done;
    }

    channels_playback = atoi(channel_start);
    if (channels_playback == 1) {
        *channels = 1;
    } else {
        *channels = 2;
    }

    ALOGD("%s: channels supported by device: %d", __func__, *channels);
    rates_str_start = strstr(str_start, "Rates:");
    if (rates_str_start == NULL) {
        ALOGE("%s: error cant find rates information", __func__);
        ret = -EINVAL;
        goto done;
    }

    rates_str_start = strstr(rates_str_start, " ");
    if (rates_str_start == NULL) {
        ALOGE("%s: error channel section not found in usb config file",
               __func__);
        ret = -EINVAL;
        goto done;
    }

    char *target = strchr(rates_str_start, '\n');
    if (target == NULL) {
        ALOGE("%s: error end of line not found", __func__);
        ret = -EINVAL;
        goto done;
    }

    size = target - rates_str_start;
    if ((rates_str = (char *)malloc(size + 1)) == NULL) {
        ALOGE("%s: error unable to allocate memory to hold sample rate strings",
              __func__);
        ret = -EINVAL;
        goto done;
    }

    if ((rates_str_for_val = (char *)malloc(size + 1)) == NULL) {
        ALOGE("%s: error unable to allocate memory to hold sample rate string",
               __func__);
        ret = -EINVAL;
        goto done;
    }

    memcpy(rates_str, rates_str_start, size);
    memcpy(rates_str_for_val, rates_str_start, size);
    rates_str[size] = '\0';
    rates_str_for_val[size] = '\0';

    size = usb_get_numof_rates(rates_str);
    if (!size) {
        ALOGE("%s: error could not get rate size, returning", __func__);
        ret = -EINVAL;
        goto done;
    }

    rates_supported = (int *)malloc(sizeof(int) * size);

    if (!rates_supported) {
        ALOGE("couldn't allocate mem for rates_supported");
        ret = -EINVAL;
        goto done;
    }

    next_sr_string = strtok_r(rates_str_for_val, " ,", &temp_ptr);
    if (next_sr_string == NULL) {
        ALOGE("%s: error could not get first rate val", __func__);
        ret = -EINVAL;
        goto done;
    }

    rates_supported[0] = atoi(next_sr_string);
    ALOGD("%s: rates_supported[0] for playback: %d",
           __func__, rates_supported[0]);
    for (i = 1; i<size; i++) {
        next_sr_string = strtok_r(NULL, " ,.-", &temp_ptr);
        if (next_sr_string == NULL) {
            rates_supported[i] = -1; // fill in an invalid sr for the rest
            continue;
        }
        rates_supported[i] = atoi(next_sr_string);
        ALOGD("rates_supported[%d] for playback: %d",i, rates_supported[i]);
    }

    for (i = 0; i<size; i++) {
        if ((rates_supported[i] > *sample_rate) &&
            (rates_supported[i] <= 48000)) {
            /* Sample Rate should be one of the proxy supported rates only
               This is because proxy port is used to read from/write to DSP */
            if ((rates_supported[i] == USB_PROXY_RATE_8000) ||
                (rates_supported[i] == USB_PROXY_RATE_16000) ||
                (rates_supported[i] == USB_PROXY_RATE_48000)) {
                *sample_rate = rates_supported[i];
            }
        }
    }
    ALOGD("%s: sample_rate: %d", __func__, *sample_rate);

done:
    if (fd >= 0) close(fd);
    if (rates_str_for_val) free(rates_str_for_val);
    if (rates_str) free(rates_str);
    if (rates_supported) free(rates_supported);
    if (read_buf) free(read_buf);
    return ret;
}

static int32_t usb_playback_entry(void *adev)
{
    unsigned char usbbuf[USB_PROXY_PERIOD_SIZE] = {0};
    int32_t ret, bytes, proxy_open_retry_count;

    ALOGD("%s: entry", __func__);
    /* update audio device pointer */
    usbmod->adev = (struct audio_device*)adev;
    proxy_open_retry_count = USB_PROXY_OPEN_RETRY_COUNT;

    /* get capabilities */
    pthread_mutex_lock(&usbmod->usb_playback_lock);
    ret = usb_get_capability((char *)"Playback:",
            &usbmod->channels_playback, &usbmod->sample_rate_playback);
    if (ret) {
        ALOGE("%s: could not get playback capabilities from usb device",
               __func__);
        pthread_mutex_unlock(&usbmod->usb_playback_lock);
        return -EINVAL;
    }
    /* update config for usb
       1 pcm frame(sample)= 4 bytes since two channels*/
    pcm_config_usbmod.period_size = USB_PERIOD_SIZE/4;
    pcm_config_usbmod.channels = usbmod->channels_playback;
    pcm_config_usbmod.rate = usbmod->sample_rate_playback;
    ALOGV("%s: usb device %u:period %u:channels %u:sample", __func__,
          pcm_config_usbmod.period_size, pcm_config_usbmod.channels,
          pcm_config_usbmod.rate);

    usbmod->usb_pcm_playback_handle = pcm_open(usbmod->usb_card, \
                                    usbmod->usb_device_id, PCM_OUT |
                                    PCM_MMAP | PCM_NOIRQ , &pcm_config_usbmod);

    if ((usbmod->usb_pcm_playback_handle \
        && !pcm_is_ready(usbmod->usb_pcm_playback_handle))
        || (!usbmod->is_playback_running)) {
        ALOGE("%s: failed: %s", __func__,
               pcm_get_error(usbmod->usb_pcm_playback_handle));
        pcm_close(usbmod->usb_pcm_playback_handle);
        usbmod->usb_pcm_playback_handle = NULL;
        pthread_mutex_unlock(&usbmod->usb_playback_lock);
        return -ENOMEM;
    }
    ALOGD("%s: USB configured for playback", __func__);

    /* update config for proxy*/
    pcm_config_usbmod.period_size = USB_PROXY_PERIOD_SIZE/3;
    pcm_config_usbmod.rate = usbmod->sample_rate_playback;
    pcm_config_usbmod.channels = usbmod->channels_playback;
    pcm_config_usbmod.period_count = AFE_PROXY_PERIOD_COUNT;
    usbmod->proxy_device_id = AFE_PROXY_PLAYBACK_DEVICE;
    ALOGD("%s: proxy device %u:period %u:channels %u:sample", __func__,
          pcm_config_usbmod.period_size, pcm_config_usbmod.channels,
          pcm_config_usbmod.rate);

    while(proxy_open_retry_count){
        usbmod->proxy_pcm_playback_handle = pcm_open(usbmod->proxy_card,
                                            usbmod->proxy_device_id, PCM_IN |
                                     PCM_MMAP | PCM_NOIRQ, &pcm_config_usbmod);
        if(usbmod->proxy_pcm_playback_handle
            && !pcm_is_ready(usbmod->proxy_pcm_playback_handle)){
                     pcm_close(usbmod->proxy_pcm_playback_handle);
                     proxy_open_retry_count--;
                     usleep(USB_PROXY_OPEN_WAIT_TIME * 1000);
                     ALOGE("%s: pcm_open for proxy failed retrying = %d",
                            __func__, proxy_open_retry_count);
                }
                else{
                  break;
                }
    }

    if ((usbmod->proxy_pcm_playback_handle
        && !pcm_is_ready(usbmod->proxy_pcm_playback_handle))
        || (!usbmod->is_playback_running)) {
        ALOGE("%s: failed: %s", __func__,
               pcm_get_error(usbmod->proxy_pcm_playback_handle));
        pcm_close(usbmod->proxy_pcm_playback_handle);
        usbmod->proxy_pcm_playback_handle = NULL;
        pthread_mutex_unlock(&usbmod->usb_playback_lock);
        return -ENOMEM;
    }
    ALOGD("%s: PROXY configured for playback", __func__);
    pthread_mutex_unlock(&usbmod->usb_playback_lock);

    ALOGD("Init USB volume");
    initPlaybackVolume();
    /* main loop to read from proxy and write to usb */
    while (usbmod->is_playback_running) {
        /* read data from proxy */
        ret = pcm_mmap_read(usbmod->proxy_pcm_playback_handle,
                                 (void *)usbbuf, USB_PROXY_PERIOD_SIZE);
        /* Write to usb */
        ret = pcm_mmap_write(usbmod->usb_pcm_playback_handle,
                                (void *)usbbuf, USB_PROXY_PERIOD_SIZE);
        if(!usbmod->is_playback_running)
            break;

        memset(usbbuf, 0, USB_PROXY_PERIOD_SIZE);
    } /* main loop end */

    ALOGD("%s: exiting USB playback thread",__func__);
    return 0;
}

static void* usb_playback_launcher(void *adev)
{
    int32_t ret;

    usbmod->is_playback_running = true;
    ret = usb_playback_entry(adev);

    if (ret) {
        ALOGE("%s: failed with err:%d", __func__, ret);
        usbmod->is_playback_running = false;
    }
    return NULL;
}

static int32_t usb_record_entry(void *adev)
{
    unsigned char usbbuf[USB_PROXY_PERIOD_SIZE] = {0};
    int32_t ret, bytes, proxy_open_retry_count;
    ALOGD("%s: entry", __func__);

    /* update audio device pointer */
    usbmod->adev = (struct audio_device*)adev;
    proxy_open_retry_count = USB_PROXY_OPEN_RETRY_COUNT;

    /* get capabilities */
    pthread_mutex_lock(&usbmod->usb_record_lock);
    ret = usb_get_capability((char *)"Capture:",
            &usbmod->channels_record, &usbmod->sample_rate_record);
    if (ret) {
        ALOGE("%s: could not get capture capabilities from usb device",
               __func__);
        pthread_mutex_unlock(&usbmod->usb_record_lock);
        return -EINVAL;
    }
    /* update config for usb
       1 pcm frame(sample)= 4 bytes since two channels*/
    pcm_config_usbmod.period_size = USB_PERIOD_SIZE/4;
    pcm_config_usbmod.channels = usbmod->channels_record;
    pcm_config_usbmod.rate = usbmod->sample_rate_record;
    ALOGV("%s: usb device %u:period %u:channels %u:sample", __func__,
          pcm_config_usbmod.period_size, pcm_config_usbmod.channels,
          pcm_config_usbmod.rate);

    usbmod->usb_pcm_record_handle = pcm_open(usbmod->usb_card, \
                                    usbmod->usb_device_id, PCM_IN |
                                    PCM_MMAP | PCM_NOIRQ , &pcm_config_usbmod);

    if ((usbmod->usb_pcm_record_handle \
        && !pcm_is_ready(usbmod->usb_pcm_record_handle))
        || (!usbmod->is_record_running)) {
        ALOGE("%s: failed: %s", __func__,
               pcm_get_error(usbmod->usb_pcm_record_handle));
        pcm_close(usbmod->usb_pcm_record_handle);
        usbmod->usb_pcm_record_handle = NULL;
        pthread_mutex_unlock(&usbmod->usb_record_lock);
        return -ENOMEM;
    }
    ALOGD("%s: USB configured for capture", __func__);

    /* update config for proxy*/
    pcm_config_usbmod.period_size = USB_PROXY_PERIOD_SIZE/4;
    pcm_config_usbmod.rate = usbmod->sample_rate_record;
    pcm_config_usbmod.channels = usbmod->channels_record;
    pcm_config_usbmod.period_count = AFE_PROXY_PERIOD_COUNT * 2;
    usbmod->proxy_device_id = AFE_PROXY_CAPTURE_DEVICE;
    ALOGV("%s: proxy device %u:period %u:channels %u:sample", __func__,
          pcm_config_usbmod.period_size, pcm_config_usbmod.channels,
          pcm_config_usbmod.rate);

    while(proxy_open_retry_count){
        usbmod->proxy_pcm_record_handle = pcm_open(usbmod->proxy_card,
                                            usbmod->proxy_device_id, PCM_OUT |
                                     PCM_MMAP | PCM_NOIRQ, &pcm_config_usbmod);
        if(usbmod->proxy_pcm_record_handle
            && !pcm_is_ready(usbmod->proxy_pcm_record_handle)){
                     pcm_close(usbmod->proxy_pcm_record_handle);
                     proxy_open_retry_count--;
                     usleep(USB_PROXY_OPEN_WAIT_TIME * 1000);
                     ALOGE("%s: pcm_open for proxy(recording) failed retrying = %d",
                            __func__, proxy_open_retry_count);
                }
                else{
                  break;
                }
    }
    if ((usbmod->proxy_pcm_record_handle
        && !pcm_is_ready(usbmod->proxy_pcm_record_handle))
        || (!usbmod->is_record_running)) {
        ALOGE("%s: failed: %s", __func__,
               pcm_get_error(usbmod->proxy_pcm_record_handle));
        pcm_close(usbmod->proxy_pcm_record_handle);
        usbmod->proxy_pcm_record_handle = NULL;
        pthread_mutex_unlock(&usbmod->usb_record_lock);
        return -ENOMEM;
    }
    ALOGD("%s: PROXY configured for capture", __func__);
    pthread_mutex_unlock(&usbmod->usb_record_lock);

    /* main loop to read from usb and write to proxy */
    while (usbmod->is_record_running) {
        /* read data from usb */
        ret = pcm_mmap_read(usbmod->usb_pcm_record_handle,
                                 (void *)usbbuf, USB_PROXY_PERIOD_SIZE);
        /* Write to proxy */
        ret = pcm_mmap_write(usbmod->proxy_pcm_record_handle,
                                (void *)usbbuf, USB_PROXY_PERIOD_SIZE);
        if(!usbmod->is_record_running)
            break;

        memset(usbbuf, 0, USB_PROXY_PERIOD_SIZE);
    } /* main loop end */

    ALOGD("%s: exiting USB capture thread",__func__);
    return 0;
}

static void* usb_capture_launcher(void *adev)
{
    int32_t ret;

    usbmod->is_record_running = true;
    ret = usb_record_entry(adev);

    if (ret) {
        ALOGE("%s: failed with err:%d", __func__, ret);
        usbmod->is_record_running = false;
    }
    return NULL;
}

void audio_extn_usb_init(void *adev)
{
    pthread_once(&alloc_usbmod_once_ctl, usb_alloc);

    usbmod->is_playback_running = false;
    usbmod->is_record_running = false;

    usbmod->usb_pcm_playback_handle = NULL;
    usbmod->proxy_pcm_playback_handle = NULL;

    usbmod->usb_pcm_record_handle = NULL;
    usbmod->proxy_pcm_record_handle = NULL;

    usbmod->usb_card = 1;
    usbmod->usb_device_id = 0;
    usbmod->proxy_card = 0;
    usbmod->proxy_device_id = AFE_PROXY_PLAYBACK_DEVICE;
    usbmod->adev = (struct audio_device*)adev;

     pthread_mutex_init(&usbmod->usb_playback_lock,
                        (const pthread_mutexattr_t *) NULL);
     pthread_mutex_init(&usbmod->usb_record_lock,
                        (const pthread_mutexattr_t *) NULL);
}

void audio_extn_usb_deinit()
{
    if (NULL != usbmod){
        free(usbmod);
        usbmod = NULL;
    }
}

void audio_extn_usb_set_proxy_sound_card(uint32_t sndcard_idx)
{
    /* Proxy port and USB headset are related to two different sound cards */
    if (sndcard_idx == usbmod->usb_card) {
        usbmod->usb_card = usbmod->proxy_card;
    }

    usbmod->proxy_card = sndcard_idx;
}

void audio_extn_usb_start_playback(void *adev)
{
    int32_t ret;

    if (NULL == usbmod){
        ALOGE("%s: USB device object is NULL", __func__);
        return;
    }

    if (usbmod->is_playback_running){
        ALOGE("%s: USB playback thread already running", __func__);
        return;
    }

    ALOGD("%s: creating USB playback thread", __func__);
    ret = pthread_create(&usbmod->usb_playback_thr, NULL,
                         usb_playback_launcher, (void*)adev);
    if (ret)
        ALOGE("%s: failed to create USB playback thread with err:%d",
              __func__, ret);
}

void audio_extn_usb_stop_playback()
{
    int32_t ret;
    ALOGD("%s: entry", __func__);

    usbmod->is_playback_running = false;
    if (NULL != usbmod->proxy_pcm_playback_handle)
        pcm_stop(usbmod->proxy_pcm_playback_handle);

    if (NULL != usbmod->usb_pcm_playback_handle)
        pcm_stop(usbmod->usb_pcm_playback_handle);

    if(usbmod->usb_playback_thr) {
        ret = pthread_join(usbmod->usb_playback_thr,NULL);
        ALOGE("%s: return for pthread_join = %d", __func__, ret);
        usbmod->usb_playback_thr = (pthread_t)NULL;
    }

    pthread_mutex_lock(&usbmod->usb_playback_lock);
    if (NULL != usbmod->usb_pcm_playback_handle){
        pcm_close(usbmod->usb_pcm_playback_handle);
        usbmod->usb_pcm_playback_handle = NULL;
    }

    if (NULL != usbmod->proxy_pcm_playback_handle){
        pcm_close(usbmod->proxy_pcm_playback_handle);
        usbmod->proxy_pcm_playback_handle = NULL;
    }
    pthread_mutex_unlock(&usbmod->usb_playback_lock);

    ALOGD("%s: exiting",__func__);
}

void audio_extn_usb_start_capture(void *adev)
{
    int32_t ret;

    if (NULL == usbmod){
        ALOGE("%s: USB device object is NULL", __func__);
        return;
    }

    if (usbmod->is_record_running){
        ALOGE("%s: USB capture thread already running", __func__);
        return;
    }

    ALOGD("%s: creating USB capture thread", __func__);
    ret = pthread_create(&usbmod->usb_record_thr, NULL,
                         usb_capture_launcher, (void*)adev);
    if (ret)
        ALOGE("%s: failed to create USB capture thread with err:%d",
              __func__, ret);
}

void audio_extn_usb_stop_capture()
{
    int32_t ret;
    ALOGD("%s: entry", __func__);

    usbmod->is_record_running = false;
    if (NULL != usbmod->proxy_pcm_record_handle)
        pcm_stop(usbmod->proxy_pcm_record_handle);

    if (NULL != usbmod->usb_pcm_record_handle)
        pcm_stop(usbmod->usb_pcm_record_handle);

    if(usbmod->usb_record_thr) {
        ret = pthread_join(usbmod->usb_record_thr,NULL);
        ALOGE("%s: return for pthread_join = %d", __func__, ret);
        usbmod->usb_record_thr = (pthread_t)NULL;
    }

    pthread_mutex_lock(&usbmod->usb_record_lock);
    if (NULL != usbmod->usb_pcm_record_handle){
        pcm_close(usbmod->usb_pcm_record_handle);
        usbmod->usb_pcm_record_handle = NULL;
    }

    if (NULL != usbmod->proxy_pcm_record_handle){
        pcm_close(usbmod->proxy_pcm_record_handle);
        usbmod->proxy_pcm_record_handle = NULL;
    }
    pthread_mutex_unlock(&usbmod->usb_record_lock);

    ALOGD("%s: exiting",__func__);
}

bool audio_extn_usb_is_proxy_inuse()
{
    if( usbmod->is_record_running || usbmod->is_playback_running)
        return true;
    else
        return false;
}
#endif /*USB_HEADSET_ENABLED end*/