Merge "ASoC: msm: Add support to change bit rate during VoIP call"
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c
index 97c7b5d..e3c8944 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -86,6 +86,10 @@
struct voip_frame_hdr {
uint32_t timestamp;
union {
+ /*
+ * Bits 0-15: Frame type
+ * Bits 16-31: Frame rate
+ */
uint32_t frame_type;
uint32_t packet_rate;
};
@@ -162,8 +166,6 @@
struct snd_ctl_elem_value *ucontrol);
static int msm_voip_rate_config_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
-static int msm_voip_rate_config_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol);
static int msm_voip_evrc_min_max_rate_config_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
static int msm_voip_evrc_min_max_rate_config_get(struct snd_kcontrol *kcontrol,
@@ -277,7 +279,7 @@
SOC_SINGLE_EXT("Voip Mode Config", SND_SOC_NOPM, 0, VOIP_MODE_MAX, 0,
msm_voip_mode_config_get, msm_voip_mode_config_put),
SOC_SINGLE_EXT("Voip Rate Config", SND_SOC_NOPM, 0, VOIP_RATE_MAX, 0,
- msm_voip_rate_config_get, msm_voip_rate_config_put),
+ NULL, msm_voip_rate_config_put),
SOC_SINGLE_MULTI_EXT("Voip Evrc Min Max Rate Config", SND_SOC_NOPM,
0, VOC_1_RATE, 0, 2, msm_voip_evrc_min_max_rate_config_get,
msm_voip_evrc_min_max_rate_config_put),
@@ -385,6 +387,8 @@
struct voip_buf_node *buf_node = NULL;
struct voip_drv_info *prtd = private_data;
unsigned long dsp_flags;
+ uint32_t rate_type;
+ uint32_t frame_rate;
if (prtd->playback_substream == NULL)
return;
@@ -408,7 +412,19 @@
* Bits 4-7: Frame type
*/
*voc_pkt = ((buf_node->frame.frm_hdr.frame_type &
- 0x0F) << 4) | (prtd->rate_type & 0x0F);
+ 0x0F) << 4);
+ frame_rate = (buf_node->frame.frm_hdr.frame_type &
+ 0xFFFF0000) >> 16;
+ if (frame_rate) {
+ if (voip_get_rate_type(prtd->mode, frame_rate,
+ &rate_type)) {
+ pr_err("%s(): fail at getting rate_type \n",
+ __func__);
+ } else
+ prtd->rate_type = rate_type;
+ }
+ *voc_pkt |= prtd->rate_type & 0x0F;
+
voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
memcpy(voc_pkt,
&buf_node->frame.voc_pkt[0],
@@ -1087,30 +1103,43 @@
return 0;
}
-static int msm_voip_rate_config_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- mutex_lock(&voip_info.lock);
-
- ucontrol->value.integer.value[0] = voip_info.rate;
-
- mutex_unlock(&voip_info.lock);
-
- return 0;
-}
-
static int msm_voip_rate_config_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
+ int ret = 0;
+ int rate = ucontrol->value.integer.value[0];
+
mutex_lock(&voip_info.lock);
- voip_info.rate = ucontrol->value.integer.value[0];
+ if (voip_info.rate != rate) {
+ voip_info.rate = rate;
+ pr_debug("%s: rate=%d\n", __func__, voip_info.rate);
- pr_debug("%s: rate=%d\n", __func__, voip_info.rate);
+ if (voip_info.state == VOIP_STARTED &&
+ (voip_info.mode == MODE_AMR ||
+ voip_info.mode == MODE_AMR_WB)) {
+ ret = voip_config_vocoder(
+ voip_info.capture_substream);
+ if (ret) {
+ pr_err("%s:Failed to configure vocoder, ret=%d\n",
+ __func__, ret);
+ goto done;
+ }
+
+ ret = voc_update_amr_vocoder_rate(
+ voc_get_session_id(VOIP_SESSION_NAME));
+ if (ret) {
+ pr_err("%s:Failed to update AMR rate, ret=%d\n",
+ __func__, ret);
+ }
+ }
+ }
+
+done:
mutex_unlock(&voip_info.lock);
- return 0;
+ return ret;
}
static int msm_voip_evrc_min_max_rate_config_get(struct snd_kcontrol *kcontrol,
diff --git a/sound/soc/msm/qdsp6v2/q6voice.c b/sound/soc/msm/qdsp6v2/q6voice.c
index 5580dc7..06ee692 100644
--- a/sound/soc/msm/qdsp6v2/q6voice.c
+++ b/sound/soc/msm/qdsp6v2/q6voice.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -1494,6 +1494,77 @@
return ret;
}
+static int voice_config_cvs_vocoder_amr_rate(struct voice_data *v)
+{
+ int ret = 0;
+ void *apr_cvs;
+ u16 cvs_handle;
+ struct cvs_set_amr_enc_rate_cmd cvs_set_amr_rate;
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL\n", __func__);
+
+ ret = -EINVAL;
+ goto done;
+ }
+ apr_cvs = common.apr_q6_cvs;
+
+ if (!apr_cvs) {
+ pr_err("%s: apr_cvs is NULL.\n", __func__);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ cvs_handle = voice_get_cvs_handle(v);
+
+ pr_debug("%s: Setting AMR rate. Media Type: %d\n", __func__,
+ common.mvs_info.media_type);
+
+ cvs_set_amr_rate.hdr.hdr_field =
+ APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+ APR_HDR_LEN(APR_HDR_SIZE),
+ APR_PKT_VER);
+ cvs_set_amr_rate.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+ sizeof(cvs_set_amr_rate) - APR_HDR_SIZE);
+ cvs_set_amr_rate.hdr.src_port =
+ voice_get_idx_for_session(v->session_id);
+ cvs_set_amr_rate.hdr.dest_port = cvs_handle;
+ cvs_set_amr_rate.hdr.token = 0;
+
+ if (common.mvs_info.media_type == VSS_MEDIA_ID_AMR_NB_MODEM)
+ cvs_set_amr_rate.hdr.opcode =
+ VSS_ISTREAM_CMD_VOC_AMR_SET_ENC_RATE;
+ else if (common.mvs_info.media_type == VSS_MEDIA_ID_AMR_WB_MODEM)
+ cvs_set_amr_rate.hdr.opcode =
+ VSS_ISTREAM_CMD_VOC_AMRWB_SET_ENC_RATE;
+
+ cvs_set_amr_rate.amr_rate.mode = common.mvs_info.rate;
+
+ v->cvs_state = CMD_STATUS_FAIL;
+
+ ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_set_amr_rate);
+ if (ret < 0) {
+ pr_err("%s: Error %d sending SET_AMR_RATE\n",
+ __func__, ret);
+
+ goto done;
+ }
+ ret = wait_event_timeout(v->cvs_wait,
+ (v->cvs_state == CMD_STATUS_SUCCESS),
+ msecs_to_jiffies(TIMEOUT_MS));
+ if (!ret) {
+ pr_err("%s: wait_event timeout\n", __func__);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ return 0;
+done:
+ return ret;
+}
+
static int voice_config_cvs_vocoder(struct voice_data *v)
{
int ret = 0;
@@ -1598,80 +1669,13 @@
break;
}
- case VSS_MEDIA_ID_AMR_NB_MODEM: {
- struct cvs_set_amr_enc_rate_cmd cvs_set_amr_rate;
-
- pr_debug("Setting AMR rate\n");
-
- cvs_set_amr_rate.hdr.hdr_field =
- APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
- APR_HDR_LEN(APR_HDR_SIZE),
- APR_PKT_VER);
- cvs_set_amr_rate.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
- sizeof(cvs_set_amr_rate) - APR_HDR_SIZE);
- cvs_set_amr_rate.hdr.src_port =
- voice_get_idx_for_session(v->session_id);
- cvs_set_amr_rate.hdr.dest_port = cvs_handle;
- cvs_set_amr_rate.hdr.token = 0;
- cvs_set_amr_rate.hdr.opcode =
- VSS_ISTREAM_CMD_VOC_AMR_SET_ENC_RATE;
- cvs_set_amr_rate.amr_rate.mode = common.mvs_info.rate;
-
- v->cvs_state = CMD_STATUS_FAIL;
-
- ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_set_amr_rate);
- if (ret < 0) {
- pr_err("%s: Error %d sending SET_AMR_RATE\n",
- __func__, ret);
- goto fail;
- }
- ret = wait_event_timeout(v->cvs_wait,
- (v->cvs_state == CMD_STATUS_SUCCESS),
- msecs_to_jiffies(TIMEOUT_MS));
- if (!ret) {
- pr_err("%s: wait_event timeout\n", __func__);
- goto fail;
- }
-
- ret = voice_set_dtx(v);
- if (ret < 0)
- goto fail;
-
- break;
- }
+ case VSS_MEDIA_ID_AMR_NB_MODEM:
case VSS_MEDIA_ID_AMR_WB_MODEM: {
- struct cvs_set_amrwb_enc_rate_cmd cvs_set_amrwb_rate;
-
- pr_debug("Setting AMR WB rate\n");
-
- cvs_set_amrwb_rate.hdr.hdr_field =
- APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
- APR_HDR_LEN(APR_HDR_SIZE),
- APR_PKT_VER);
- cvs_set_amrwb_rate.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
- sizeof(cvs_set_amrwb_rate) -
- APR_HDR_SIZE);
- cvs_set_amrwb_rate.hdr.src_port =
- voice_get_idx_for_session(v->session_id);
- cvs_set_amrwb_rate.hdr.dest_port = cvs_handle;
- cvs_set_amrwb_rate.hdr.token = 0;
- cvs_set_amrwb_rate.hdr.opcode =
- VSS_ISTREAM_CMD_VOC_AMRWB_SET_ENC_RATE;
- cvs_set_amrwb_rate.amrwb_rate.mode = common.mvs_info.rate;
-
- v->cvs_state = CMD_STATUS_FAIL;
-
- ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_set_amrwb_rate);
- if (ret < 0) {
- pr_err("%s: Error %d sending SET_AMRWB_RATE\n",
+ ret = voice_config_cvs_vocoder_amr_rate(v);
+ if (ret) {
+ pr_err("%s: Failed to update vocoder rate. %d\n",
__func__, ret);
- goto fail;
- }
- ret = wait_event_timeout(v->cvs_wait,
- (v->cvs_state == CMD_STATUS_SUCCESS),
- msecs_to_jiffies(TIMEOUT_MS));
- if (!ret) {
- pr_err("%s: wait_event timeout\n", __func__);
+
goto fail;
}
@@ -1698,6 +1702,31 @@
return -EINVAL;
}
+int voc_update_amr_vocoder_rate(uint32_t session_id)
+{
+ int ret = 0;
+ struct voice_data *v;
+
+ pr_debug("%s: session_id:%d", __func__, session_id);
+
+ v = voice_get_session(session_id);
+
+ if (v == NULL) {
+ pr_err("%s: v is NULL, session_id:%d\n", __func__,
+ session_id);
+
+ ret = -EINVAL;
+ goto done;
+ }
+
+ mutex_lock(&v->lock);
+ ret = voice_config_cvs_vocoder_amr_rate(v);
+ mutex_unlock(&v->lock);
+
+done:
+ return ret;
+}
+
static int voice_send_start_voice_cmd(struct voice_data *v)
{
struct apr_hdr mvm_start_voice_cmd;
diff --git a/sound/soc/msm/qdsp6v2/q6voice.h b/sound/soc/msm/qdsp6v2/q6voice.h
index 5c0cf21..9efc9fc 100644
--- a/sound/soc/msm/qdsp6v2/q6voice.h
+++ b/sound/soc/msm/qdsp6v2/q6voice.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -1465,5 +1465,6 @@
int voc_start_record(uint32_t port_id, uint32_t set, uint32_t session_id);
int voice_get_idx_for_session(u32 session_id);
int voc_set_ext_ec_ref(uint16_t port_id, bool state);
+int voc_update_amr_vocoder_rate(uint32_t session_id);
#endif