diff options
Diffstat (limited to 'msm8909/hal/audio_extn/usb.c')
-rw-r--r-- | msm8909/hal/audio_extn/usb.c | 730 |
1 files changed, 730 insertions, 0 deletions
diff --git a/msm8909/hal/audio_extn/usb.c b/msm8909/hal/audio_extn/usb.c new file mode 100644 index 00000000..13e3138b --- /dev/null +++ b/msm8909/hal/audio_extn/usb.c @@ -0,0 +1,730 @@ +/* + * 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*/ |