/*
* 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*/