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

Commit 4d2fb57e authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

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

parents 821de315 acbf386d
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
@@ -1497,6 +1497,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;
@@ -1601,80 +1672,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;
		}

@@ -1701,6 +1705,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