summaryrefslogtreecommitdiffstats
path: root/hal/audio_extn
diff options
context:
space:
mode:
authorKuirong Wang <kuirongw@codeaurora.org>2016-03-07 11:21:52 -0800
committerGerrit - the friendly Code Review server <code-review@localhost>2016-06-23 10:28:19 -0700
commita9f7cee0718c0bee1d7bbe27ef6603e104822fe1 (patch)
treee1129ae75f3be74a9815c4514a8869c082e618de /hal/audio_extn
parentbff5f0bee0fd2cca7a54be4d113e0925f9ed92de (diff)
downloadhardware_qcom_audio-a9f7cee0718c0bee1d7bbe27ef6603e104822fe1.tar.gz
hardware_qcom_audio-a9f7cee0718c0bee1d7bbe27ef6603e104822fe1.tar.bz2
hardware_qcom_audio-a9f7cee0718c0bee1d7bbe27ef6603e104822fe1.zip
hal: Add USB audio via ADSP support
Add changes to support USB audio via ADSP tunnel solution. CRs-Fixed: 1019158 Change-Id: I95a9796d7cad71e09dedd2bcd451183cbd25ca71
Diffstat (limited to 'hal/audio_extn')
-rw-r--r--hal/audio_extn/audio_extn.c6
-rw-r--r--hal/audio_extn/audio_extn.h25
-rw-r--r--hal/audio_extn/usb.c1224
3 files changed, 670 insertions, 585 deletions
diff --git a/hal/audio_extn/audio_extn.c b/hal/audio_extn/audio_extn.c
index 8b8632ea..49e649c6 100644
--- a/hal/audio_extn/audio_extn.c
+++ b/hal/audio_extn/audio_extn.c
@@ -677,11 +677,7 @@ int audio_extn_get_afe_proxy_parameters(const struct audio_device *adev,
ret = str_parms_get_str(query, AUDIO_PARAMETER_CAN_OPEN_PROXY, value,
sizeof(value));
if (ret >= 0) {
- if (audio_extn_usb_is_proxy_inuse() ||
- !adev->allow_afe_proxy_usage)
- val = 0;
- else
- val = 1;
+ val = (adev->allow_afe_proxy_usage ? 1: 0);
str_parms_add_int(reply, AUDIO_PARAMETER_CAN_OPEN_PROXY, val);
}
ALOGV("%s: called ... can_use_proxy %d", __func__, val);
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
index 3ce83b19..0ef17838 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -151,24 +151,19 @@ int32_t audio_extn_get_afe_proxy_channel_count();
#endif
#ifndef USB_HEADSET_ENABLED
-#define audio_extn_usb_init(adev) (0)
-#define audio_extn_usb_deinit() (0)
-#define audio_extn_usb_start_playback(adev) (0)
-#define audio_extn_usb_stop_playback() (0)
-#define audio_extn_usb_start_capture(adev) (0)
-#define audio_extn_usb_stop_capture() (0)
-#define audio_extn_usb_set_proxy_sound_card(sndcard_idx) (0)
-#define audio_extn_usb_is_proxy_inuse() (0)
+#define audio_extn_usb_init(adev) (0)
+#define audio_extn_usb_deinit() (0)
+#define audio_extn_usb_add_device(device, card) (0)
+#define audio_extn_usb_remove_device(device, card) (0)
+#define audio_extn_usb_is_config_supported(bit_width, sample_rate, ch) (0)
#else
-void initPlaybackVolume();
void audio_extn_usb_init(void *adev);
void audio_extn_usb_deinit();
-void audio_extn_usb_start_playback(void *adev);
-void audio_extn_usb_stop_playback();
-void audio_extn_usb_start_capture(void *adev);
-void audio_extn_usb_stop_capture();
-void audio_extn_usb_set_proxy_sound_card(uint32_t sndcard_idx);
-bool audio_extn_usb_is_proxy_inuse();
+void audio_extn_usb_add_device(audio_devices_t device, int card);
+void audio_extn_usb_remove_device(audio_devices_t device, int card);
+bool audio_extn_usb_is_config_supported(unsigned int *bit_width,
+ unsigned int *sample_rate,
+ unsigned int ch);
#endif
#ifndef SSR_ENABLED
diff --git a/hal/audio_extn/usb.c b/hal/audio_extn/usb.c
index 13e3138b..141ef377 100644
--- a/hal/audio_extn/usb.c
+++ b/hal/audio_extn/usb.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013, 2016, The Linux Foundation. All rights reserved.
* Not a Contribution.
*
* Copyright (C) 2013 The Android Open Source Project
@@ -32,148 +32,181 @@
#include <system/audio.h>
#include <tinyalsa/asoundlib.h>
+#include <audio_hw.h>
+#include <cutils/properties.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
+#define USB_BUFF_SIZE 2048
+#define CHANNEL_NUMBER_STR "Channels: "
+#define PLAYBACK_PROFILE_STR "Playback:"
+#define CAPTURE_PROFILE_STR "Capture:"
+#define ABS_SUB(A, B) (((A) > (B)) ? ((A) - (B)):((B) - (A)))
+#define SAMPLE_RATE_8000 8000
+#define SAMPLE_RATE_11025 11025
+
+// Supported sample rates for USB
+static uint32_t supported_sample_rates[] =
+ {44100, 48000, 64000, 88200, 96000, 176400, 192000};
+
+#define MAX_SAMPLE_RATE_SIZE sizeof(supported_sample_rates)/sizeof(supported_sample_rates[0])
+
+enum usb_usecase_type{
+ USB_PLAYBACK = 0,
+ USB_CAPTURE,
+};
+
+struct usb_device_config {
+ struct listnode list;
+ unsigned int bit_width;
+ unsigned int channels;
+ unsigned int rate_size;
+ unsigned int rates[MAX_SAMPLE_RATE_SIZE];
+};
+
+struct usb_card_config {
+ struct listnode list;
+ audio_devices_t usb_device_type;
+ int usb_card;
+ struct listnode usb_device_conf_list;
+};
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 listnode usb_card_conf_list;
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 bool usb_audio_debug_enable = false;
-static void usb_alloc()
+static int usb_set_channel_mixer_ctl(int channel,
+ char *ch_mixer_ctl_name)
{
- 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");
+ struct mixer_ctl *ctl;
+
+ ctl = mixer_get_ctl_by_name(usbmod->adev->mixer, ch_mixer_ctl_name);
+ if (!ctl) {
+ ALOGE("%s: Could not get ctl for mixer cmd - %s",
+ __func__, ch_mixer_ctl_name);
+ return -EINVAL;
+ }
+ switch (channel) {
+ case 1:
+ mixer_ctl_set_enum_by_string(ctl, "One");
+ break;
+ case 2:
+ mixer_ctl_set_enum_by_string(ctl, "Two");
+ break;
+ default:
+ ALOGV("%s: channel(%d) not supported, set as default 2 channels",
+ __func__, channel);
+ mixer_ctl_set_enum_by_string(ctl, "Two");
+ break;
}
+ return 0;
}
-static int usb_get_numof_rates(char *rates_str)
+static int usb_set_dev_id_mixer_ctl(unsigned int usb_usecase_type, int card,
+ char *dev_mixer_ctl_name)
{
- int i, size = 0;
- char *next_sr_string, *temp_ptr;
- next_sr_string = strtok_r(rates_str, " ,", &temp_ptr);
+ struct mixer_ctl *ctl;
+ unsigned int dev_token;
+ unsigned int pcm_device_number = 0;
+
+ /*
+ * usb_dev_token_id is 32 bit number and is defined as below:
+ * usb_sound_card_idx(31:16) | usb PCM device ID(15:8) | usb_usecase_type(7:0)
+ */
+ dev_token = (card << 16 ) |
+ (pcm_device_number << 8) | (usb_usecase_type & 0xFF);
- if (next_sr_string == NULL) {
- ALOGE("%s: get_numof_rates: could not find rates string", __func__);
- return 0;
+ ctl = mixer_get_ctl_by_name(usbmod->adev->mixer, dev_mixer_ctl_name);
+ if (!ctl) {
+ ALOGE("%s: Could not get ctl for mixer cmd - %s",
+ __func__, dev_mixer_ctl_name);
+ return -EINVAL;
}
+ mixer_ctl_set_value(ctl, 0, dev_token);
- for (i = 1; next_sr_string != NULL; i++) {
- size ++;
+ return 0;
+}
+
+static int usb_get_sample_rates(char *rates_str,
+ struct usb_device_config *config)
+{
+ uint32_t i;
+ char *next_sr_string, *temp_ptr;
+ uint32_t sr, min_sr, max_sr, sr_size = 0;
+
+ /* Sample rate string can be in any of the folloing two bit_widthes:
+ * Rates: 8000 - 48000 (continuous)
+ * Rates: 8000, 44100, 48000
+ * Support both the bit_widths
+ */
+ ALOGV("%s: rates_str %s", __func__, rates_str);
+ if (strstr(rates_str, "continuous") != NULL) {
+ next_sr_string = strtok_r(rates_str, " ,", &temp_ptr);
+ if (next_sr_string == NULL) {
+ ALOGE("%s: could not find min rates string", __func__);
+ return -EINVAL;
+ }
+ min_sr = atoi(next_sr_string);
next_sr_string = strtok_r(NULL, " ,.-", &temp_ptr);
+ if (next_sr_string == NULL) {
+ ALOGE("%s: could not find max rates string", __func__);
+ return -EINVAL;
+ }
+ max_sr = atoi(next_sr_string);
+
+ for (i = 0; i < MAX_SAMPLE_RATE_SIZE; i++)
+ if (supported_sample_rates[i] >= min_sr &&
+ supported_sample_rates[i] <= max_sr)
+ config->rates[sr_size++] = supported_sample_rates[i];
+ } else {
+ 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 -EINVAL;
+ }
+ do {
+ sr = (uint32_t)atoi(next_sr_string);
+ for (i = 0; i < MAX_SAMPLE_RATE_SIZE; i++) {
+ if (supported_sample_rates[i] == sr) {
+ ALOGI_IF(usb_audio_debug_enable,
+ "%s: sr %d, supported_sample_rates[%d] %d -> matches!!",
+ __func__, sr, i, supported_sample_rates[i]);
+ config->rates[sr_size++] = supported_sample_rates[i];
+ }
+ }
+ next_sr_string = strtok_r(NULL, " ,.-", &temp_ptr);
+ } while (next_sr_string != NULL);
}
- return size;
+ config->rate_size = sr_size;
+ return 0;
}
-static int usb_get_capability(char *type, int32_t *channels,
- int32_t *sample_rate)
+static int usb_get_capability(int type,
+ struct usb_card_config *usb_card_info,
+ int card)
{
- 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;
+ int32_t fd=-1;
+ int32_t altset_index = 1;
+ int32_t channels_no;
+ char *str_start, *channel_start, *bit_width_start, *rates_str_start,
+ *target;
char *read_buf = NULL;
char *rates_str = NULL;
- char *rates_str_for_val = NULL;
- int *rates_supported = NULL;
- char path[128];
+ char path[128], altset[9];
int ret = 0;
+ char *bit_width_str = NULL;
+ struct usb_device_config * usb_device_info;
+
+ ALOGV("%s: for %s", __func__, (type == USB_PLAYBACK) ?
+ PLAYBACK_PROFILE_STR : CAPTURE_PROFILE_STR);
- memset(&st, 0x0, sizeof(struct stat));
- *sample_rate = 0;
snprintf(path, sizeof(path), "/proc/asound/card%u/stream0",
- usbmod->usb_card);
+ card);
fd = open(path, O_RDONLY);
if (fd <0) {
@@ -183,15 +216,6 @@ static int usb_get_capability(char *type, int32_t *channels,
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) {
@@ -201,530 +225,600 @@ static int usb_get_capability(char *type, int32_t *channels,
}
err = read(fd, read_buf, USB_BUFF_SIZE);
- str_start = strstr(read_buf, type);
+ str_start = strstr(read_buf, ((type == USB_PLAYBACK) ?
+ PLAYBACK_PROFILE_STR : CAPTURE_PROFILE_STR));
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__);
+ __func__, ((type == USB_PLAYBACK) ?
+ PLAYBACK_PROFILE_STR : CAPTURE_PROFILE_STR));
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
+ ALOGV("%s: usb_config = %s\n", __func__, str_start);
+
+ while (str_start != NULL) {
+ sprintf(altset, "Altset %d", altset_index);
+ ALOGV("%s: altset_index %d\n", __func__, altset_index);
+ str_start = strstr(str_start, altset);
+ if (str_start == NULL) {
+ if (altset_index == 1) {
+ ALOGE("%s: error %s section not found in usb config file",
+ __func__, (type == USB_PLAYBACK) ?
+ PLAYBACK_PROFILE_STR : CAPTURE_PROFILE_STR);
+ ret = -EINVAL;
+ }
+ break;
+ }
+ usb_device_info = calloc(1, sizeof(struct usb_device_config));
+ if (usb_device_info == NULL) {
+ ALOGE("%s: error unable to allocate memory",
+ __func__);
+ ret = -ENOMEM;
+ break;
+ }
+ altset_index++;
+ /* Bit bit_width parsing */
+ bit_width_start = strstr(str_start, "Format: ");
+ if (bit_width_start == NULL) {
+ ALOGI("%s: Could not find bit_width string", __func__);
+ free(usb_device_info);
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];
- }
+ target = strchr(bit_width_start, '\n');
+ if (target == NULL) {
+ ALOGI("%s:end of line not found", __func__);
+ free(usb_device_info);
+ continue;
+ }
+ size = target - bit_width_start;
+ if ((bit_width_str = (char *)malloc(size + 1)) == NULL) {
+ ALOGE("%s: unable to allocate memory to hold bit width strings",
+ __func__);
+ ret = -EINVAL;
+ free(usb_device_info);
+ break;
+ }
+ memcpy(bit_width_str, bit_width_start, size);
+ bit_width_str[size] = '\0';
+ if (strstr(bit_width_str, "S16_LE"))
+ usb_device_info->bit_width = 16;
+ else if (strstr(bit_width_str, "S24_LE"))
+ usb_device_info->bit_width = 24;
+ else if (strstr(bit_width_str, "S24_3LE"))
+ usb_device_info->bit_width = 24;
+ else if (strstr(bit_width_str, "S32_LE"))
+ usb_device_info->bit_width = 32;
+
+ if (bit_width_str)
+ free(bit_width_str);
+
+ /* channels parsing */
+ channel_start = strstr(str_start, CHANNEL_NUMBER_STR);
+ if (channel_start == NULL) {
+ ALOGI("%s: could not find Channels string", __func__);
+ free(usb_device_info);
+ continue;
}
+ channels_no = atoi(channel_start + strlen(CHANNEL_NUMBER_STR));
+ usb_device_info->channels = channels_no;
+
+ /* Sample rates parsing */
+ rates_str_start = strstr(str_start, "Rates: ");
+ if (rates_str_start == NULL) {
+ ALOGI("%s: cant find rates string", __func__);
+ free(usb_device_info);
+ continue;
+ }
+ target = strchr(rates_str_start, '\n');
+ if (target == NULL) {
+ ALOGI("%s: end of line not found", __func__);
+ free(usb_device_info);
+ continue;
+ }
+ size = target - rates_str_start;
+ if ((rates_str = (char *)malloc(size + 1)) == NULL) {
+ ALOGE("%s: unable to allocate memory to hold sample rate strings",
+ __func__);
+ ret = -EINVAL;
+ free(usb_device_info);
+ break;
+ }
+ memcpy(rates_str, rates_str_start, size);
+ rates_str[size] = '\0';
+ ret = usb_get_sample_rates(rates_str, usb_device_info);
+ if (rates_str)
+ free(rates_str);
+ if (ret < 0) {
+ ALOGI("%s: error unable to get sample rate values",
+ __func__);
+ free(usb_device_info);
+ continue;
+ }
+ /* Add to list if every field is valid */
+ list_add_tail(&usb_card_info->usb_device_conf_list,
+ &usb_device_info->list);
}
- 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)
+static int usb_get_device_pb_config(struct usb_card_config *usb_card_info,
+ int card)
{
- 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;
+ int ret;
+ struct listnode *node_d;
+ struct usb_device_config *dev_info;
/* 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",
+ if ((ret = usb_get_capability(USB_PLAYBACK, usb_card_info, card))) {
+ ALOGE("%s: could not get Playback capabilities from usb device",
__func__);
- pthread_mutex_unlock(&usbmod->usb_playback_lock);
- return -EINVAL;
+ goto exit;
}
- /* 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)
+ /* Currently only use the first profile using to configure channel for simplification */
+ list_for_each(node_d, &usb_card_info->usb_device_conf_list) {
+ dev_info = node_to_item(node_d, struct usb_device_config, list);
+ if (dev_info != NULL) {
+ usb_set_channel_mixer_ctl(dev_info->channels, "USB_AUDIO_RX Channels");
break;
+ }
+ }
+ usb_set_dev_id_mixer_ctl(USB_PLAYBACK, card, "USB_AUDIO_RX dev_token");
- 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);
+exit:
- if (ret) {
- ALOGE("%s: failed with err:%d", __func__, ret);
- usbmod->is_playback_running = false;
- }
- return NULL;
+ return ret;
}
-static int32_t usb_record_entry(void *adev)
+static int usb_get_device_cap_config(struct usb_card_config *usb_card_info,
+ int card)
{
- 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;
+ int ret;
+ struct listnode *node_d;
+ struct usb_device_config *dev_info;
/* 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",
+ if ((ret = usb_get_capability(USB_CAPTURE, usb_card_info, card))) {
+ ALOGE("%s: could not get Playback 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;
- }
+ goto exit;
}
- 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)
+ /* Currently only use the first profile using to configure channel for simplification */
+ list_for_each(node_d, &usb_card_info->usb_device_conf_list) {
+ dev_info = node_to_item(node_d, struct usb_device_config, list);
+ if (dev_info != NULL) {
+ usb_set_channel_mixer_ctl(dev_info->channels, "USB_AUDIO_TX Channels");
break;
+ }
+ }
+ usb_set_dev_id_mixer_ctl(USB_CAPTURE, card, "USB_AUDIO_TX dev_token");
- memset(usbbuf, 0, USB_PROXY_PERIOD_SIZE);
- } /* main loop end */
-
- ALOGD("%s: exiting USB capture thread",__func__);
- return 0;
+exit:
+ return ret;
}
-static void* usb_capture_launcher(void *adev)
+static bool usb_valid_device(int device)
{
- int32_t ret;
-
- usbmod->is_record_running = true;
- ret = usb_record_entry(adev);
+ bool is_usb_device = false;
+ if ((device & AUDIO_DEVICE_OUT_USB_DEVICE) ||
+ (device & AUDIO_DEVICE_IN_USB_DEVICE))
+ is_usb_device = true;
+ return is_usb_device;
+}
- if (ret) {
- ALOGE("%s: failed with err:%d", __func__, ret);
- usbmod->is_record_running = false;
+static void usb_print_active_device(void){
+ struct listnode *node_i, *node_j;
+ struct usb_device_config *dev_info;
+ struct usb_card_config *card_info;
+ unsigned int i;
+
+ ALOGI("%s", __func__);
+ list_for_each(node_i, &usbmod->usb_card_conf_list) {
+ card_info = node_to_item(node_i, struct usb_card_config, list);
+ ALOGI("%s: card_dev_type (0x%x), card_no(%d)",
+ __func__, card_info->usb_device_type, card_info->usb_card);
+ list_for_each(node_j, &card_info->usb_device_conf_list) {
+ dev_info = node_to_item(node_j, struct usb_device_config, list);
+ ALOGI("%s: bit-width(%d) channel(%d)",
+ __func__, dev_info->bit_width, dev_info->channels);
+ for (i = 0; i < dev_info->rate_size; i++)
+ ALOGI("%s: rate %d", __func__, dev_info->rates[i]);
+ }
}
- return NULL;
}
-void audio_extn_usb_init(void *adev)
+static bool usb_get_best_match_for_bit_width(
+ struct listnode *dev_list,
+ unsigned int stream_bit_width,
+ unsigned int *bit_width)
{
- 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;
+ struct listnode *node_i;
+ struct usb_device_config *dev_info;
+ unsigned int candidate = 0;
+
+ list_for_each(node_i, dev_list) {
+ dev_info = node_to_item(node_i, struct usb_device_config, list);
+ ALOGI_IF(usb_audio_debug_enable,
+ "%s: USB bw(%d), stream bw(%d), candidate(%d)",
+ __func__, dev_info->bit_width,
+ stream_bit_width, candidate);
+ if (dev_info->bit_width == stream_bit_width) {
+ *bit_width = dev_info->bit_width;
+ ALOGV("%s: Found match bit-width (%d)",
+ __func__, dev_info->bit_width);
+ goto exit;
+ } else if (candidate == 0) {
+ candidate = dev_info->bit_width;
+ }
+ /*
+ * If stream bit is 24, USB supports both 16 bit and 32 bit, then
+ * higher bit width 32 is picked up instead of 16-bit
+ */
+ else if (ABS_SUB(stream_bit_width, dev_info->bit_width) <
+ ABS_SUB(stream_bit_width, candidate)) {
+ candidate = dev_info->bit_width;
+ }
+ else if ((ABS_SUB(stream_bit_width, dev_info->bit_width) ==
+ ABS_SUB(stream_bit_width, candidate)) &&
+ (dev_info->bit_width > candidate)) {
+ candidate = dev_info->bit_width;
+ }
+ }
+ ALOGV("%s: No match found, use the best candidate bw(%d)",
+ __func__, candidate);
+ *bit_width = candidate;
+exit:
+ return true;
+}
- 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;
+static bool usb_get_best_match_for_channels(
+ struct listnode *dev_list,
+ unsigned int bit_width,
+ unsigned int stream_ch,
+ unsigned int *ch)
+{
+ struct listnode *node_i;
+ struct usb_device_config *dev_info;
+ unsigned int candidate = 0;
+
+ list_for_each(node_i, dev_list) {
+ dev_info = node_to_item(node_i, struct usb_device_config, list);
+ ALOGI_IF(usb_audio_debug_enable,
+ "%s: USB ch(%d)bw(%d), stream ch(%d)bw(%d), candidate(%d)",
+ __func__, dev_info->channels, dev_info->bit_width,
+ stream_ch, bit_width, candidate);
+ if (dev_info->bit_width != bit_width)
+ continue;
+ if (dev_info->channels== stream_ch) {
+ *ch = dev_info->channels;
+ ALOGV("%s: Found match channels (%d)",
+ __func__, dev_info->channels);
+ goto exit;
+ } else if (candidate == 0)
+ candidate = dev_info->channels;
+ /*
+ * If stream channel is 4, USB supports both 3 and 5, then
+ * higher channel 5 is picked up instead of 3
+ */
+ else if (ABS_SUB(stream_ch, dev_info->channels) <
+ ABS_SUB(stream_ch, candidate)) {
+ candidate = dev_info->channels;
+ } else if ((ABS_SUB(stream_ch, dev_info->channels) ==
+ ABS_SUB(stream_ch, candidate)) &&
+ (dev_info->channels > candidate)) {
+ candidate = dev_info->channels;
+ }
+ }
+ ALOGV("%s: No match found, use the best candidate ch(%d)",
+ __func__, candidate);
+ *ch = candidate;
+exit:
+ return true;
- 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()
+static bool usb_sample_rate_multiple(
+ unsigned int stream_sample_rate,
+ unsigned int base)
{
- if (NULL != usbmod){
- free(usbmod);
- usbmod = NULL;
- }
+ return (((stream_sample_rate / base) * base) == stream_sample_rate);
}
-void audio_extn_usb_set_proxy_sound_card(uint32_t sndcard_idx)
+static bool usb_find_sample_rate_candidate(unsigned int base,
+ unsigned stream_rate,
+ unsigned int usb_rate,
+ unsigned int cur_candidate,
+ unsigned int *update_candidate)
{
- /* Proxy port and USB headset are related to two different sound cards */
- if (sndcard_idx == usbmod->usb_card) {
- usbmod->usb_card = usbmod->proxy_card;
+ /* For sample rate, we should consider fracational sample rate as high priority.
+ * For example, if the stream is 88.2kHz and USB device support both 44.1kH and
+ * 48kHz sample rate, we should pick 44.1kHz instead of 48kHz
+ */
+ if (!usb_sample_rate_multiple(cur_candidate, base) &&
+ usb_sample_rate_multiple(usb_rate, base)) {
+ *update_candidate = usb_rate;
+ } else if (usb_sample_rate_multiple(cur_candidate, base) &&
+ usb_sample_rate_multiple(usb_rate, base)) {
+ if (ABS_SUB(stream_rate, usb_rate) <
+ ABS_SUB(stream_rate, cur_candidate)) {
+ *update_candidate = usb_rate;
+ } else if ((ABS_SUB(stream_rate, usb_rate) ==
+ ABS_SUB(stream_rate, cur_candidate)) &&
+ (usb_rate > cur_candidate)) {
+ *update_candidate = usb_rate;
+ }
+ } else if (!usb_sample_rate_multiple(cur_candidate, base) &&
+ !usb_sample_rate_multiple(usb_rate, base)) {
+ if (ABS_SUB(stream_rate, usb_rate) <
+ ABS_SUB(stream_rate, cur_candidate)) {
+ *update_candidate = usb_rate;
+ } else if ((ABS_SUB(stream_rate, usb_rate) ==
+ ABS_SUB(stream_rate, cur_candidate)) &&
+ (usb_rate > cur_candidate)) {
+ *update_candidate = usb_rate;
+ }
}
-
- usbmod->proxy_card = sndcard_idx;
+ return true;
}
-void audio_extn_usb_start_playback(void *adev)
+static bool usb_get_best_match_for_sample_rate(
+ struct listnode *dev_list,
+ unsigned int bit_width,
+ unsigned int ch,
+ unsigned int stream_sample_rate,
+ unsigned int *sr)
{
- int32_t ret;
+ struct listnode *node_i;
+ struct usb_device_config *dev_info;
+ unsigned int candidate = 48000;
+ unsigned int base = SAMPLE_RATE_8000;
+ bool multiple_8k = usb_sample_rate_multiple(stream_sample_rate, base);
+ unsigned int i;
+
+ ALOGV("%s: stm ch(%d)bw(%d)sr(%d), stream sample multiple of 8kHz(%d)",
+ __func__, ch, bit_width, stream_sample_rate, multiple_8k);
+
+ list_for_each(node_i, dev_list) {
+ dev_info = node_to_item(node_i, struct usb_device_config, list);
+ ALOGI_IF(usb_audio_debug_enable,
+ "%s: USB ch(%d)bw(%d), stm ch(%d)bw(%d)sr(%d), candidate(%d)",
+ __func__, dev_info->channels, dev_info->bit_width,
+ ch, bit_width, stream_sample_rate, candidate);
+ if ((dev_info->bit_width != bit_width) && dev_info->channels != ch)
+ continue;
- if (NULL == usbmod){
- ALOGE("%s: USB device object is NULL", __func__);
- return;
+ candidate = 0;
+ for (i = 0; i < dev_info->rate_size; i++) {
+ ALOGI_IF(usb_audio_debug_enable,
+ "%s: USB ch(%d)bw(%d)sr(%d), stm ch(%d)bw(%d)sr(%d), candidate(%d)",
+ __func__, dev_info->channels,
+ dev_info->bit_width, dev_info->rates[i],
+ ch, bit_width, stream_sample_rate, candidate);
+ if (stream_sample_rate == dev_info->rates[i]) {
+ *sr = dev_info->rates[i];
+ ALOGV("%s: Found match sample rate (%d)",
+ __func__, dev_info->rates[i]);
+ goto exit;
+ } else if (candidate == 0) {
+ candidate = dev_info->rates[i];
+ /*
+ * For sample rate, we should consider fracational sample rate as high priority.
+ * For example, if the stream is 88.2kHz and USB device support both 44.1kH and
+ * 48kHz sample rate, we should pick 44.1kHz instead of 48kHz
+ */
+ } else if (multiple_8k) {
+ usb_find_sample_rate_candidate(SAMPLE_RATE_8000,
+ stream_sample_rate,
+ dev_info->rates[i],
+ candidate,
+ &candidate);
+ } else {
+ usb_find_sample_rate_candidate(SAMPLE_RATE_11025,
+ stream_sample_rate,
+ dev_info->rates[i],
+ candidate,
+ &candidate);
+ }
+ }
}
+ ALOGV("%s: No match found, use the best candidate sr(%d)",
+ __func__, candidate);
+ *sr = candidate;
+exit:
+ return true;
+}
- 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);
+static bool usb_audio_backend_apply_policy(struct listnode *dev_list,
+ unsigned int *bit_width,
+ unsigned int *sample_rate,
+ unsigned int ch)
+{
+ unsigned int channel;
+ bool is_usb_supported = true;
+
+ ALOGV("%s: from stream: bit-width(%d) sample_rate(%d) channels (%d)",
+ __func__, *bit_width, *sample_rate, ch);
+ if (list_empty(dev_list)) {
+ *sample_rate = 48000;
+ *bit_width = 16;
+ channel = 2;
+ ALOGI("%s: list is empty,fall back to default setting", __func__);
+ goto exit;
+ }
+ usb_get_best_match_for_bit_width(dev_list, *bit_width, bit_width);
+ usb_get_best_match_for_channels(dev_list,
+ *bit_width,
+ ch,
+ &channel);
+ usb_get_best_match_for_sample_rate(dev_list,
+ *bit_width,
+ channel,
+ *sample_rate,
+ sample_rate);
+exit:
+ ALOGV("%s: Updated sample rate per profile: bit-width(%d) rate(%d) chs(%d)",
+ __func__, *bit_width, *sample_rate, channel);
+ usb_set_channel_mixer_ctl(channel, "USB_AUDIO_RX Channels");
+ return is_usb_supported;
}
-void audio_extn_usb_stop_playback()
+bool audio_extn_usb_is_config_supported(unsigned int *bit_width,
+ unsigned int *sample_rate,
+ unsigned int ch)
{
- 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;
+ struct listnode *node_i;
+ struct usb_card_config *card_info;
+ bool is_usb_supported = false;
+
+ ALOGV("%s: from stream: bit-width(%d) sample_rate(%d) ch(%d)",
+ __func__, *bit_width, *sample_rate, ch);
+ list_for_each(node_i, &usbmod->usb_card_conf_list) {
+ card_info = node_to_item(node_i, struct usb_card_config, list);
+ ALOGI_IF(usb_audio_debug_enable,
+ "%s: card_dev_type (0x%x), card_no(%d)",
+ __func__, card_info->usb_device_type, card_info->usb_card);
+ /* Currently only apply the first playback sound card configuration */
+ if (card_info->usb_device_type == AUDIO_DEVICE_OUT_USB_DEVICE) {
+ is_usb_supported = usb_audio_backend_apply_policy(
+ &card_info->usb_device_conf_list,
+ bit_width,
+ sample_rate,
+ ch);
+ break;
+ }
}
- pthread_mutex_unlock(&usbmod->usb_playback_lock);
+ ALOGV("%s: updated: bit-width(%d) sample_rate(%d)",
+ __func__, *bit_width, *sample_rate);
- ALOGD("%s: exiting",__func__);
+ return is_usb_supported;
}
-void audio_extn_usb_start_capture(void *adev)
+void audio_extn_usb_add_device(audio_devices_t device, int card)
{
- int32_t ret;
+ struct usb_card_config *usb_card_info;
+ char check_debug_enable[PROPERTY_VALUE_MAX];
- if (NULL == usbmod){
+ property_get("audio.usb.enable.debug", check_debug_enable, NULL);
+ if (atoi(check_debug_enable)) {
+ usb_audio_debug_enable = true;
+ }
+
+ ALOGI_IF(usb_audio_debug_enable,
+ "%s: parameters device(0x%x), card(%d)",
+ __func__, device, card);
+ if (usbmod == NULL) {
ALOGE("%s: USB device object is NULL", __func__);
- return;
+ goto exit;
}
- if (usbmod->is_record_running){
- ALOGE("%s: USB capture thread already running", __func__);
- return;
+ if (!(usb_valid_device(device)) || (card < 0)) {
+ ALOGE("%s:device(0x%x), card(%d)",
+ __func__, device, card);
+ goto exit;
}
- 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);
+ usb_card_info = calloc(1, sizeof(struct usb_card_config));
+ if (usb_card_info == NULL) {
+ ALOGE("%s: error unable to allocate memory",
+ __func__);
+ goto exit;
+ }
+ list_init(&usb_card_info->usb_device_conf_list);
+ if (device & AUDIO_DEVICE_OUT_USB_DEVICE) {
+ if (!usb_get_device_pb_config(usb_card_info, card)){
+ usb_card_info->usb_card = card;
+ usb_card_info->usb_device_type = AUDIO_DEVICE_OUT_USB_DEVICE;
+ list_add_tail(&usbmod->usb_card_conf_list, &usb_card_info->list);
+ goto exit;
+ }
+ } else if (device & AUDIO_DEVICE_IN_USB_DEVICE) {
+ if (!usb_get_device_cap_config(usb_card_info, card)) {
+ usb_card_info->usb_card = card;
+ usb_card_info->usb_device_type = AUDIO_DEVICE_IN_USB_DEVICE;
+ list_add_tail(&usbmod->usb_card_conf_list, &usb_card_info->list);
+ goto exit;
+ }
+ }
+ /* free memory in error case */
+ if (usb_card_info != NULL)
+ free(usb_card_info);
+exit:
+ if (usb_audio_debug_enable)
+ usb_print_active_device();
+ return;
}
-void audio_extn_usb_stop_capture()
+void audio_extn_usb_remove_device(audio_devices_t device, int card)
{
- int32_t ret;
- ALOGD("%s: entry", __func__);
+ struct listnode *node_i, *temp_i;
+ struct listnode *node_j, *temp_j;
+ struct usb_device_config *dev_info;
+ struct usb_card_config *card_info;
+ unsigned int i;
- usbmod->is_record_running = false;
- if (NULL != usbmod->proxy_pcm_record_handle)
- pcm_stop(usbmod->proxy_pcm_record_handle);
+ ALOGV("%s: device(0x%x), card(%d)",
+ __func__, device, card);
- 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;
+ if (usbmod == NULL) {
+ ALOGE("%s: USB device object is NULL", __func__);
+ goto exit;
+ }
+
+ if (!(usb_valid_device(device)) || (card < 0)) {
+ ALOGE("%s: Invalid parameters device(0x%x), card(%d)",
+ __func__, device, card);
+ goto exit;
+ }
+ list_for_each_safe(node_i, temp_i, &usbmod->usb_card_conf_list) {
+ card_info = node_to_item(node_i, struct usb_card_config, list);
+ ALOGV("%s: card_dev_type (0x%x), card_no(%d)",
+ __func__, card_info->usb_device_type, card_info->usb_card);
+ if ((device == card_info->usb_device_type) && (card == card_info->usb_card)){
+ list_for_each_safe(node_j, temp_j, &card_info->usb_device_conf_list) {
+ dev_info = node_to_item(node_j, struct usb_device_config, list);
+ ALOGV("%s: bit-width(%d) channel(%d)",
+ __func__, dev_info->bit_width, dev_info->channels);
+ for (i = 0; i < dev_info->rate_size; i++)
+ ALOGV("%s: rate %d", __func__, dev_info->rates[i]);
+
+ list_remove(node_j);
+ free(node_to_item(node_j, struct usb_device_config, list));
+ }
+ list_remove(node_i);
+ free(node_to_item(node_i, struct usb_card_config, list));
+ }
}
+exit:
+ if (usb_audio_debug_enable)
+ usb_print_active_device();
- 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;
- }
+ return;
+}
- if (NULL != usbmod->proxy_pcm_record_handle){
- pcm_close(usbmod->proxy_pcm_record_handle);
- usbmod->proxy_pcm_record_handle = NULL;
+void audio_extn_usb_init(void *adev)
+{
+ if (usbmod == NULL) {
+ usbmod = calloc(1, sizeof(struct usb_module));
+ if (usbmod == NULL) {
+ ALOGE("%s: error unable to allocate memory", __func__);
+ goto exit;
+ }
}
- pthread_mutex_unlock(&usbmod->usb_record_lock);
-
- ALOGD("%s: exiting",__func__);
+ list_init(&usbmod->usb_card_conf_list);
+ usbmod->adev = (struct audio_device*)adev;
+exit:
+ return;
}
-bool audio_extn_usb_is_proxy_inuse()
+void audio_extn_usb_deinit(void)
{
- if( usbmod->is_record_running || usbmod->is_playback_running)
- return true;
- else
- return false;
+ if (NULL != usbmod){
+ free(usbmod);
+ usbmod = NULL;
+ }
}
#endif /*USB_HEADSET_ENABLED end*/