Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit acbf386d authored by Narsinga Rao Chella's avatar Narsinga Rao Chella
Browse files

ASoC: msm: Add support to change bit rate during VoIP call



Add support to change bit rate for AMR NB and AMR WB
vocoders while in VoIP call. This change is needed as part
of supporting VoWLAN feature.

Change-Id: Ic486dd7f48aca2c640b2364d00712741b50df4c8
Signed-off-by: default avatarNarsinga Rao Chella <nrchella@codeaurora.org>
parent a18f488c
Loading
Loading
Loading
Loading
+48 −19
Original line number Diff line number Diff line
/* 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 @@ enum voip_state {
struct voip_frame_hdr {
	uint32_t timestamp;
	union {
		/*
		 * Bits 0-3: Frame type
		 * [optional] Bits 16-19: Frame rate
		 */
		uint32_t frame_type;
		uint32_t packet_rate;
	};
@@ -162,8 +166,6 @@ static int msm_voip_mode_config_get(struct snd_kcontrol *kcontrol,
				    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 @@ static struct snd_kcontrol_new msm_voip_controls[] = {
	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,
@@ -386,6 +388,8 @@ static void voip_process_dl_pkt(uint8_t *voc_pkt, void *private_data)
	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;
@@ -409,7 +413,19 @@ static void voip_process_dl_pkt(uint8_t *voc_pkt, void *private_data)
			 * 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],
@@ -1090,30 +1106,43 @@ static int msm_voip_mode_config_put(struct snd_kcontrol *kcontrol,
	return 0;
}

static int msm_voip_rate_config_get(struct snd_kcontrol *kcontrol,
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);

	ucontrol->value.integer.value[0] = voip_info.rate;
	if (voip_info.rate != rate) {
		voip_info.rate = rate;
		pr_debug("%s: rate=%d\n", __func__, voip_info.rate);

	mutex_unlock(&voip_info.lock);
		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);

	return 0;
				goto done;
			}

static int msm_voip_rate_config_put(struct snd_kcontrol *kcontrol,
				    struct snd_ctl_elem_value *ucontrol)
{
	mutex_lock(&voip_info.lock);

	voip_info.rate = ucontrol->value.integer.value[0];

	pr_debug("%s: rate=%d\n", __func__, voip_info.rate);
			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,
+101 −72
Original line number Diff line number Diff line
@@ -1496,6 +1496,77 @@ done:
	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;
@@ -1600,80 +1671,13 @@ static int voice_config_cvs_vocoder(struct voice_data *v)

		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;
		}

@@ -1700,6 +1704,31 @@ fail:
	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;
+2 −1
Original line number Diff line number Diff line
/* 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
@@ -1596,5 +1596,6 @@ int voc_start_playback(uint32_t set, uint16_t port_id);
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