Support voice-recognition with BT SCO 68/141568/5
authorSangchul Lee <sc11.lee@samsung.com>
Tue, 1 Aug 2017 04:46:47 +0000 (13:46 +0900)
committerSangchul Lee <sc11.lee@samsung.com>
Wed, 2 Aug 2017 06:45:33 +0000 (15:45 +0900)
Open/close hw:0,2 for this case.
Refer to bt_wideband to set param of samplerate(narrowband:8k, wideband:16k).
Remove unused codes.

[Version] 0.1.3
[Profile] Wearable
[Issue Type] New feature

Change-Id: Id7bca9b4e1ed01e8cb529323b3a01c6a16879b59
Signed-off-by: Sangchul Lee <sc11.lee@samsung.com>
packaging/audio-hal-wm1831-tw2.spec
tizen-audio-impl-pcm.c
tizen-audio-impl.h
tizen-audio-internal.h
tizen-audio-pcm.c
tizen-audio-routing.c

index 2fd151c55a7a625317c3429cae91b1593a46d5af..bdc00a7e1ca8c400aa7d1ffefaa0e6a7011ec646 100644 (file)
@@ -1,6 +1,6 @@
 Name:       audio-hal-wm1831-tw2
 Summary:    TIZEN Audio HAL for WM1831(TW2)
-Version:    0.1.2
+Version:    0.1.3
 Release:    0
 Group:      System/Libraries
 License:    Apache-2.0
index 908576ed6c45f55962f2755b84b39510670fc704..9623af0df9a389de4da2d6a4df0cc76713f40b63 100644 (file)
@@ -58,9 +58,6 @@ static const uint32_t g_format_convert_table[] = {
 };
 #endif
 
-#define VOICE_PCM_SAMPLERATE 48000
-#define VOICE_PCM_CHANNELS 2
-
 static uint32_t __convert_format(audio_sample_format_t format)
 {
     return g_format_convert_table[format];
@@ -68,7 +65,7 @@ static uint32_t __convert_format(audio_sample_format_t format)
 
 /* #define DEBUG_TIMING */
 
-static int __voice_pcm_set_params(audio_hal_t *ah, snd_pcm_t *pcm)
+static int __pcm_device_set_params(audio_hal_t *ah, snd_pcm_t *pcm, uint32_t samplerate, uint32_t channels)
 {
     snd_pcm_hw_params_t *params = NULL;
     int err = 0;
@@ -97,12 +94,12 @@ static int __voice_pcm_set_params(audio_hal_t *ah, snd_pcm_t *pcm)
         AUDIO_LOG_ERROR("snd_pcm_hw_params_set_access() : failed! - %s\n", snd_strerror(err));
         goto error;
     }
-    err = snd_pcm_hw_params_set_rate(pcm, params, VOICE_PCM_SAMPLERATE, 0);
+    err = snd_pcm_hw_params_set_rate(pcm, params, samplerate, 0);
     if (err < 0) {
         AUDIO_LOG_ERROR("snd_pcm_hw_params_set_rate() : failed! - %s\n", snd_strerror(err));
         goto error;
     }
-    err = snd_pcm_hw_params_set_channels(pcm, params, VOICE_PCM_CHANNELS);
+    err = snd_pcm_hw_params_set_channels(pcm, params, channels);
     if (err < 0) {
         AUDIO_LOG_ERROR("snd_pcm_hw_params_set_channels() : failed! - %s\n", snd_strerror(err));
         goto error;
@@ -192,7 +189,7 @@ static int __tinyalsa_pcm_recover(struct pcm *pcm, int err)
 }
 #endif
 
-audio_return_t _voice_pcm_open(audio_hal_t *ah)
+static audio_return_t __pcm_device_open(audio_hal_t *ah, audio_pcm_devices_t *pcm_devices, const char *device, uint32_t direction, uint32_t samplerate, uint32_t channels)
 {
     int err, ret = 0;
 
@@ -202,62 +199,96 @@ audio_return_t _voice_pcm_open(audio_hal_t *ah)
     AUDIO_LOG_WARN("need implementation for tinyAlsa");
     return AUDIO_ERR_NOT_IMPLEMENTED;
 #else
-    AUDIO_LOG_INFO("Setup Voice DAIs");
-
-    /* Voice Capture DAI */
-    if ((err = snd_pcm_open((snd_pcm_t **)&ah->device.pcm_in, VOICE_PCM_DEVICE, SND_PCM_STREAM_CAPTURE, 0)) < 0) {
-        AUDIO_LOG_ERROR("snd_pcm_open for %s failed. %s", VOICE_PCM_DEVICE, snd_strerror(err));
-        ret = AUDIO_ERR_IOCTL;
-        goto error;
-    }
-    ret = __voice_pcm_set_params(ah, ah->device.pcm_in);
-    if (ret != 0) {
-        AUDIO_LOG_ERROR("voice capture DAI(%s, %p) setparam failure", VOICE_PCM_DEVICE, ah->device.pcm_in);
-        ret = AUDIO_ERR_INTERNAL;
-        goto error;
+    AUDIO_LOG_INFO("Setup DAI PCM");
+
+    if (direction & AUDIO_DEVICE_DIRECTION_IN) {
+        /* Capture PCM */
+        if ((err = snd_pcm_open((snd_pcm_t **)&pcm_devices->in, device, SND_PCM_STREAM_CAPTURE, 0)) < 0) {
+            AUDIO_LOG_ERROR("snd_pcm_open for %s failed. %s", device, snd_strerror(err));
+            ret = AUDIO_ERR_IOCTL;
+            goto error;
+        }
+        ret = __pcm_device_set_params(ah, pcm_devices->in, samplerate, channels);
+        if (ret != 0) {
+            AUDIO_LOG_ERROR("capture DAI PCM(%s, %p) setparam failure", device, pcm_devices->in);
+            ret = AUDIO_ERR_INTERNAL;
+            goto error;
+        }
+        AUDIO_LOG_INFO("capture DAI PCM(%s, %p) open/setparam success", device, pcm_devices->in);
     }
-    AUDIO_LOG_INFO("voice capture DAI(%s, %p) open/setparam success", VOICE_PCM_DEVICE, ah->device.pcm_in);
 
-    /* Voice Playback DAI */
-    if ((err = snd_pcm_open((snd_pcm_t **)&ah->device.pcm_out, VOICE_PCM_DEVICE, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
-        AUDIO_LOG_ERROR("snd_pcm_open for %s failed. %s", VOICE_PCM_DEVICE, snd_strerror(err));
-        ret = AUDIO_ERR_IOCTL;
-        goto error;
-    }
-    ret = __voice_pcm_set_params(ah, ah->device.pcm_out);
-    if (ret != 0) {
-        AUDIO_LOG_ERROR("voice playback DAI(%s, %p) setparam failure", VOICE_PCM_DEVICE, ah->device.pcm_out);
-        ret = AUDIO_ERR_INTERNAL;
-        goto error;
+    if (direction & AUDIO_DEVICE_DIRECTION_OUT) {
+        /* Playback PCM */
+        if ((err = snd_pcm_open((snd_pcm_t **)&pcm_devices->out, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
+            AUDIO_LOG_ERROR("snd_pcm_open for %s failed. %s", device, snd_strerror(err));
+            ret = AUDIO_ERR_IOCTL;
+            goto error;
+        }
+        ret = __pcm_device_set_params(ah, pcm_devices->out, samplerate, channels);
+        if (ret != 0) {
+            AUDIO_LOG_ERROR("playback DAI PCM(%s, %p) setparam failure", device, pcm_devices->out);
+            ret = AUDIO_ERR_INTERNAL;
+            goto error;
+        }
+        AUDIO_LOG_INFO("playback DAI PCM(%s, %p) open/setparam success", device, pcm_devices->out);
     }
-    AUDIO_LOG_INFO("voice playback DAI(%s, %p) open/setparam success", VOICE_PCM_DEVICE, ah->device.pcm_out);
 #endif
 
     return AUDIO_RET_OK;
 
 error:
-    if (ah->device.pcm_out) {
-        snd_pcm_close(ah->device.pcm_out);
-        ah->device.pcm_out = NULL;
+    if ((direction & AUDIO_DEVICE_DIRECTION_OUT) && pcm_devices->out) {
+        snd_pcm_close(pcm_devices->out);
+        pcm_devices->out = NULL;
     }
-    if (ah->device.pcm_in) {
-        snd_pcm_close(ah->device.pcm_in);
-        ah->device.pcm_in = NULL;
+    if ((direction & AUDIO_DEVICE_DIRECTION_IN) && pcm_devices->in) {
+        snd_pcm_close(pcm_devices->in);
+        pcm_devices->in = NULL;
     }
     return ret;
 }
 
-bool _is_voice_pcm_opened(audio_hal_t *ah)
+audio_return_t _voice_pcm_open(audio_hal_t *ah)
+{
+    AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+
+    return __pcm_device_open(ah, &ah->device.voice_pcm, VOICE_PCM_DEVICE,
+                             AUDIO_DEVICE_DIRECTION_IN | AUDIO_DEVICE_DIRECTION_OUT, 48000, 2);
+}
+
+audio_return_t _bt_pcm_open(audio_hal_t *ah)
+{
+    uint32_t samplerate;
+
+    AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+
+    samplerate = (ah->device.bt_wideband) ? 16000 : 8000;
+
+    return __pcm_device_open(ah, &ah->device.bt_pcm, BT_PCM_DEVICE,
+                             AUDIO_DEVICE_DIRECTION_IN | AUDIO_DEVICE_DIRECTION_OUT, samplerate, 1);
+}
+
+bool _is_voice_pcm_opened_all(audio_hal_t *ah)
+{
+    AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+
+    if (ah->device.voice_pcm.in && ah->device.voice_pcm.out)
+        return true;
+    else
+        return false;
+}
+
+bool _is_bt_pcm_opened_all(audio_hal_t *ah)
 {
     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
 
-    if (ah->device.pcm_in && ah->device.pcm_out)
+    if (ah->device.bt_pcm.in && ah->device.bt_pcm.out)
         return true;
     else
         return false;
 }
 
-audio_return_t _voice_pcm_close(audio_hal_t *ah, uint32_t direction)
+audio_return_t _voice_pcm_close(audio_hal_t *ah)
 {
     audio_return_t audio_ret = AUDIO_RET_OK;
 
@@ -265,18 +296,47 @@ audio_return_t _voice_pcm_close(audio_hal_t *ah, uint32_t direction)
 
     AUDIO_LOG_INFO("close voice pcm handles");
 
-    if (ah->device.pcm_out && (direction == AUDIO_DIRECTION_OUT)) {
-        if ((audio_ret = _pcm_close(ah->device.pcm_out)))
-            AUDIO_LOG_ERROR("failed to _pcm_close() for pcm_out, ret(0x%x)", audio_ret);
+    if (ah->device.voice_pcm.out) {
+        if ((audio_ret = _pcm_close(ah->device.voice_pcm.out)))
+            AUDIO_LOG_ERROR("failed to _pcm_close() for voice pcm out, ret(0x%x)", audio_ret);
         else {
-            ah->device.pcm_out = NULL;
+            ah->device.voice_pcm.out = NULL;
             AUDIO_LOG_INFO("voice pcm_out handle close success");
         }
-    } else if (ah->device.pcm_in && (direction == AUDIO_DIRECTION_IN)) {
-        if ((audio_ret = _pcm_close(ah->device.pcm_in)))
-            AUDIO_LOG_ERROR("failed to _pcm_close() for pcm_in, ret(0x%x)", audio_ret);
+    }
+    if (ah->device.voice_pcm.in) {
+        if ((audio_ret = _pcm_close(ah->device.voice_pcm.in)))
+            AUDIO_LOG_ERROR("failed to _pcm_close() for voice pcm in, ret(0x%x)", audio_ret);
+        else {
+            ah->device.voice_pcm.in = NULL;
+            AUDIO_LOG_INFO("voice pcm_in handle close success");
+        }
+    }
+
+    return audio_ret;
+}
+
+audio_return_t _bt_pcm_close(audio_hal_t *ah)
+{
+    audio_return_t audio_ret = AUDIO_RET_OK;
+
+    AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+
+    AUDIO_LOG_INFO("close bt pcm handles");
+
+    if (ah->device.bt_pcm.out) {
+        if ((audio_ret = _pcm_close(ah->device.bt_pcm.out)))
+            AUDIO_LOG_ERROR("failed to _pcm_close() for bt pcm out, ret(0x%x)", audio_ret);
+        else {
+            ah->device.bt_pcm.out = NULL;
+            AUDIO_LOG_INFO("bt pcm_out handle close success");
+        }
+    }
+    if (ah->device.bt_pcm.in) {
+        if ((audio_ret = _pcm_close(ah->device.bt_pcm.in)))
+            AUDIO_LOG_ERROR("failed to _pcm_close() for bt pcm in, ret(0x%x)", audio_ret);
         else {
-            ah->device.pcm_in = NULL;
+            ah->device.bt_pcm.in = NULL;
             AUDIO_LOG_INFO("voice pcm_in handle close success");
         }
     }
@@ -290,16 +350,28 @@ audio_return_t _reset_pcm_devices(audio_hal_t *ah)
 
     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
 
-    if (ah->device.pcm_out) {
-        if (!(audio_ret = _pcm_close(ah->device.pcm_out))) {
-            ah->device.pcm_out = NULL;
-            AUDIO_LOG_INFO("pcm_out handle close success");
+    if (ah->device.voice_pcm.out) {
+        if (!(audio_ret = _pcm_close(ah->device.voice_pcm.out))) {
+            ah->device.voice_pcm.out = NULL;
+            AUDIO_LOG_INFO("voice pcm out handle close success");
+        }
+    }
+    if (ah->device.voice_pcm.in) {
+        if (!(audio_ret = _pcm_close(ah->device.voice_pcm.in))) {
+            ah->device.voice_pcm.in = NULL;
+            AUDIO_LOG_INFO("voice pcm in handle close success");
+        }
+    }
+    if (ah->device.bt_pcm.out) {
+        if (!(audio_ret = _pcm_close(ah->device.bt_pcm.out))) {
+            ah->device.bt_pcm.out = NULL;
+            AUDIO_LOG_INFO("bt pcm out handle close success");
         }
     }
-    if (ah->device.pcm_in) {
-        if (!(audio_ret = _pcm_close(ah->device.pcm_in))) {
-            ah->device.pcm_in = NULL;
-            AUDIO_LOG_INFO("pcm_in handle close success");
+    if (ah->device.bt_pcm.in) {
+        if (!(audio_ret = _pcm_close(ah->device.bt_pcm.in))) {
+            ah->device.bt_pcm.in = NULL;
+            AUDIO_LOG_INFO("bt pcm in handle close success");
         }
     }
 
index 64daeaff3696aebdd7c737a665419d2c9c563719..ee48fa951595cb95a575b4376e4087a31767068b 100644 (file)
  *
  */
 
+#include <stdbool.h>
+
 /* PCM */
 audio_return_t _voice_pcm_open(audio_hal_t *ah);
-audio_return_t _voice_pcm_close(audio_hal_t *ah, uint32_t direction);
+audio_return_t _voice_pcm_close(audio_hal_t *ah);
+audio_return_t _bt_pcm_open(audio_hal_t *ah);
+audio_return_t _bt_pcm_close(audio_hal_t *ah);
+bool _is_voice_pcm_opened_all(audio_hal_t *ah);
+bool _is_bt_pcm_opened_all(audio_hal_t *ah);
 audio_return_t _reset_pcm_devices(audio_hal_t *ah);
 audio_return_t _pcm_open(void **pcm_handle, uint32_t direction, void *sample_spec, uint32_t period_size, uint32_t periods);
 audio_return_t _pcm_start(void *pcm_handle);
index b2ab3b7707519f05ce0baec1170ebe75e28ccdbf..81ec92aea80bcad79ec1f329a1fff1b7887f8a05 100644 (file)
@@ -118,7 +118,10 @@ typedef struct device_type {
 #define ALSA_DEFAULT_CARD       "universal7270la"
 #define PLAYBACK_PCM_DEVICE     "hw:0,0"
 #define CAPTURE_PCM_DEVICE      "hw:0,0"
+
+/* DAI PCM DEVICE */
 #define VOICE_PCM_DEVICE        "hw:0,1"
+#define BT_PCM_DEVICE           "hw:0,2"
 
 /* hw:0,0 */
 #define PLAYBACK_CARD_ID        0
@@ -148,14 +151,18 @@ typedef enum audio_route_mode {
     VERB_VOIP,
 } audio_route_mode_t;
 
+typedef struct {
+    snd_pcm_t *in;
+    snd_pcm_t *out;
+} audio_pcm_devices_t;
+
 typedef struct audio_hal_device {
     uint32_t active_in;
     uint32_t active_out;
-    snd_pcm_t *pcm_in;
-    snd_pcm_t *pcm_out;
-    pthread_mutex_t pcm_lock;
-    uint32_t pcm_count;
+    audio_pcm_devices_t voice_pcm;
+    audio_pcm_devices_t bt_pcm;
     audio_route_mode_t mode;
+    uint32_t bt_wideband;
 } audio_hal_device_t;
 
 /* Volume */
@@ -193,6 +200,11 @@ typedef struct audio_volume_value_table {
     double gain[AUDIO_GAIN_TYPE_MAX];
 } audio_volume_value_table_t;
 
+enum {
+    AUDIO_DEVICE_DIRECTION_IN  = 0x01,
+    AUDIO_DEVICE_DIRECTION_OUT = 0x02
+};
+
 enum {
     AUDIO_VOLUME_DEVICE_DEFAULT,
     AUDIO_VOLUME_DEVICE_MAX,
index 0a09cba53c11e746002cd0981a04ff64707917c6..89ca48298ec920bfe7872924413d365ae889956e 100644 (file)
@@ -28,10 +28,10 @@ audio_return_t _audio_pcm_init(audio_hal_t *ah)
 {
     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
 
-    ah->device.pcm_in = NULL;
-    ah->device.pcm_out = NULL;
-    pthread_mutex_init(&ah->device.pcm_lock, NULL);
-    ah->device.pcm_count = 0;
+    ah->device.voice_pcm.in = NULL;
+    ah->device.voice_pcm.out = NULL;
+    ah->device.bt_pcm.in = NULL;
+    ah->device.bt_pcm.out = NULL;
 
     return AUDIO_RET_OK;
 }
@@ -40,15 +40,12 @@ audio_return_t _audio_pcm_deinit(audio_hal_t *ah)
 {
     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
 
-    pthread_mutex_destroy(&ah->device.pcm_lock);
-
     return AUDIO_RET_OK;
 }
 
 audio_return_t audio_pcm_open(void *audio_handle, void **pcm_handle, uint32_t direction, void *sample_spec, uint32_t period_size, uint32_t periods)
 {
     audio_return_t audio_ret = AUDIO_RET_OK;
-    audio_hal_t *ah = NULL;
 
     AUDIO_RETURN_VAL_IF_FAIL(audio_handle, AUDIO_ERR_PARAMETER);
     AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
@@ -59,8 +56,6 @@ audio_return_t audio_pcm_open(void *audio_handle, void **pcm_handle, uint32_t di
     if ((audio_ret = _pcm_open(pcm_handle, direction, sample_spec, period_size, periods)))
         return audio_ret;
 
-    ah = (audio_hal_t*)audio_handle;
-    ah->device.pcm_count++;
     AUDIO_LOG_INFO("Opening PCM handle 0x%x", *pcm_handle);
 
     return AUDIO_RET_OK;
@@ -93,7 +88,6 @@ audio_return_t audio_pcm_stop(void *audio_handle, void *pcm_handle)
 audio_return_t audio_pcm_close(void *audio_handle, void *pcm_handle)
 {
     audio_return_t audio_ret = AUDIO_RET_OK;
-    audio_hal_t *ah = NULL;
 
     AUDIO_RETURN_VAL_IF_FAIL(audio_handle, AUDIO_ERR_PARAMETER);
     AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
@@ -102,10 +96,8 @@ audio_return_t audio_pcm_close(void *audio_handle, void *pcm_handle)
         return audio_ret;
 
     pcm_handle = NULL;
-    ah = (audio_hal_t*)audio_handle;
-    ah->device.pcm_count--;
 
-    AUDIO_LOG_INFO("PCM handle close success (count:%d)", ah->device.pcm_count);
+    AUDIO_LOG_INFO("PCM handle close success");
 
     return audio_ret;
 }
index ffa629d569949b68858a4eb741003dc2c8897114..fc1f79477abb64599dc294e93b6c949593c2e254 100644 (file)
@@ -161,17 +161,9 @@ static audio_return_t __update_route_ap_playback_capture(audio_hal_t *ah, audio_
     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
     AUDIO_RETURN_VAL_IF_FAIL(route_info, AUDIO_ERR_PARAMETER);
 
-#if 0
-    if (ah->modem.is_connected) {
-        AUDIO_LOG_WARN("modem is connected, skip verb[%s]", verb);
-        return audio_ret;
-    }
-#endif
-
     if (ah->device.mode != VERB_NORMAL) {
         if (ah->device.mode == VERB_VOICECALL) {
             __reset_voice_devices_info(ah);
-//            COND_SIGNAL(ah->device.device_cond, "device_cond");
         }
        _reset_pcm_devices(ah);
        ah->device.mode = VERB_NORMAL;
@@ -196,15 +188,11 @@ static audio_return_t __update_route_voicecall(audio_hal_t *ah, device_info_t *d
     const char *verb = mode_to_verb_str[VERB_VOICECALL];
 
     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
-    /* if both params are 0, return error for invalid state,
-         * this error would be used to tizen-audio-modem.c */
-    AUDIO_RETURN_VAL_IF_FAIL((devices||num_of_devices), AUDIO_ERR_INVALID_STATE);
     AUDIO_RETURN_VAL_IF_FAIL(devices, AUDIO_ERR_PARAMETER);
 
     AUDIO_LOG_INFO("update_route_voicecall++");
 
-    audio_ret = __set_devices(ah, verb, devices, num_of_devices);
-    if (audio_ret) {
+    if ((audio_ret = __set_devices(ah, verb, devices, num_of_devices))) {
         AUDIO_LOG_ERROR("Failed to set devices: error = 0x%x", audio_ret);
         return audio_ret;
     }
@@ -212,9 +200,16 @@ static audio_return_t __update_route_voicecall(audio_hal_t *ah, device_info_t *d
     if (ah->device.mode != VERB_VOICECALL) {
         ah->device.mode = VERB_VOICECALL;
         /* FIXME. Get network info and configure rate in pcm device */
+        _reset_pcm_devices(ah);
     } else {
-        if (!_is_voice_pcm_opened(ah))
-            _voice_pcm_open(ah);
+        if (_is_voice_pcm_opened_all(ah)) {
+            AUDIO_LOG_INFO("voice pcm device is already opened, skip it");
+            return audio_ret;
+        }
+        if ((audio_ret = _voice_pcm_open(ah))) {
+            AUDIO_LOG_ERROR("Failed to open voice pcm device: error = 0x%x", audio_ret);
+            return audio_ret;
+        }
     }
 
     return audio_ret;
@@ -230,8 +225,7 @@ static audio_return_t __update_route_voip(audio_hal_t *ah, device_info_t *device
 
     AUDIO_LOG_INFO("update_route_voip++");
 
-    audio_ret = __set_devices(ah, verb, devices, num_of_devices);
-    if (audio_ret) {
+    if ((audio_ret = __set_devices(ah, verb, devices, num_of_devices))) {
         AUDIO_LOG_ERROR("Failed to set devices: error = 0x%x", audio_ret);
         return audio_ret;
     }
@@ -242,6 +236,42 @@ static audio_return_t __update_route_voip(audio_hal_t *ah, device_info_t *device
     return audio_ret;
 }
 
+static audio_return_t __update_route_voice_recognition(audio_hal_t *ah, device_info_t *devices, int32_t num_of_devices)
+{
+    audio_return_t audio_ret = AUDIO_RET_OK;
+    const char *verb = mode_to_verb_str[VERB_NORMAL];
+
+    AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
+    AUDIO_RETURN_VAL_IF_FAIL(devices, AUDIO_ERR_PARAMETER);
+
+    AUDIO_LOG_INFO("update_route_voice_recognition++");
+
+    if ((audio_ret = __set_devices(ah, verb, devices, num_of_devices))) {
+        AUDIO_LOG_ERROR("Failed to set devices: error = 0x%x", audio_ret);
+        return audio_ret;
+    }
+
+    if (ah->device.mode != VERB_NORMAL) {
+        ah->device.mode = VERB_NORMAL;
+       _reset_pcm_devices(ah);
+    }
+
+    /* if this request is for BT SCO device */
+    if (ah->device.active_in & AUDIO_DEVICE_IN_BT_SCO) {
+        if (_is_bt_pcm_opened_all(ah)) {
+            AUDIO_LOG_INFO("bt pcm device is already opened, skip it");
+            return audio_ret;
+        }
+
+        if ((audio_ret = _bt_pcm_open(ah))) {
+            AUDIO_LOG_ERROR("Failed to open bt pcm device: error = 0x%x", audio_ret);
+            return audio_ret;
+        }
+    }
+
+    return audio_ret;
+}
+
 static audio_return_t __update_route_reset(audio_hal_t *ah, uint32_t direction)
 {
     audio_return_t audio_ret = AUDIO_RET_OK;
@@ -275,13 +305,21 @@ static audio_return_t __update_route_reset(audio_hal_t *ah, uint32_t direction)
             }
         }
     }
+
     if (ah->device.mode == VERB_VOICECALL) {
-        if ((audio_ret = _voice_pcm_close(ah, direction)))
+        if ((audio_ret = _bt_pcm_close(ah)))
+            AUDIO_LOG_ERROR("failed to _bt_pcm_close(), ret(0x%x)", audio_ret);
+        if ((audio_ret = _voice_pcm_close(ah)))
             AUDIO_LOG_ERROR("failed to _voice_pcm_close(), ret(0x%x)", audio_ret);
         if (!ah->device.active_in && !ah->device.active_out)
             ah->device.mode = VERB_NORMAL;
         __reset_voice_devices_info(ah);
-//        COND_SIGNAL(ah->device.device_cond, "device_cond");
+    } else if (ah->device.mode == VERB_NORMAL) {
+        if (direction == AUDIO_DIRECTION_IN) {
+            /* voice-recognition case */
+            if ((audio_ret = _bt_pcm_close(ah)))
+                AUDIO_LOG_ERROR("failed to _bt_pcm_close(), ret(0x%x)", audio_ret);
+        }
     }
 
     if (active_devices[0] == NULL) {
@@ -346,17 +384,21 @@ audio_return_t audio_update_route(void *audio_handle, audio_route_info_t *info)
         if ((audio_ret = __update_route_voicecall(ah, devices, info->num_of_devices)))
             AUDIO_LOG_WARN("update voicecall route return 0x%x", audio_ret);
 
-//        COND_SIGNAL(ah->device.device_cond, "device_cond");
     } else if (!strncmp("voip", info->role, MAX_NAME_LEN)) {
         if ((audio_ret = __update_route_voip(ah, devices, info->num_of_devices)))
             AUDIO_LOG_WARN("update voip route return 0x%x", audio_ret);
 
+    } else if (!strncmp("voice-recognition", info->role, MAX_NAME_LEN) ||
+               !strncmp("voice-recognition-service", info->role, MAX_NAME_LEN)) {
+        if ((audio_ret = __update_route_voice_recognition(ah, devices, info->num_of_devices)))
+            AUDIO_LOG_WARN("update voice-recognition route return 0x%x", audio_ret);
+
     } else if (!strncmp("reset", info->role, MAX_NAME_LEN)) {
         if ((audio_ret = __update_route_reset(ah, devices->direction)))
             AUDIO_LOG_WARN("update reset return 0x%x", audio_ret);
 
     } else {
-        /* need to prepare for "alarm","notification","emergency","voice-information","voice-recognition","ringtone" */
+        /* need to prepare for "alarm","notification","emergency","voice-information","ringtone" */
         if ((audio_ret = __update_route_ap_playback_capture(ah, info)))
             AUDIO_LOG_WARN("update playback route return 0x%x", audio_ret);
     }
@@ -372,6 +414,14 @@ audio_return_t audio_update_route_option(void *audio_handle, audio_route_option_
     AUDIO_RETURN_VAL_IF_FAIL(option, AUDIO_ERR_PARAMETER);
 
     AUDIO_LOG_INFO("role:%s, name:%s, value:%d", option->role, option->name, option->value);
+    if (!strncmp("voice-recognition", option->role, MAX_NAME_LEN)) {
+        if (!strncmp("bt-wideband", option->name, MAX_NAME_LEN)) {
+            if (option->value > 0)
+                ah->device.bt_wideband = 1;
+            else
+                ah->device.bt_wideband = 0;
+        }
+    }
 
     return audio_ret;
 }