ASoC: msm: Add G711 media type support for Voip call
G711 is currently not supported in the Voip driver.
Add G711 media type to existing Voip driver.
Change-Id: If464afa68400ddc63a0b2700d8357511d4435787
Signed-off-by: Prashanth Reddy <pgreddy@codeaurora.org>
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c
index e3c8944..6b32064 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-voip-v2.c
@@ -47,8 +47,27 @@
#define MODE_AMR_WB 0xD
#define MODE_PCM 0xC
#define MODE_4GV_NW 0xE
+#define MODE_G711 0xA
+#define MODE_G711A 0xF
-#define VOIP_MODE_MAX MODE_4GV_NW
+enum msm_audio_g711a_frame_type {
+ MVS_G711A_SPEECH_GOOD,
+ MVS_G711A_SID,
+ MVS_G711A_NO_DATA,
+ MVS_G711A_ERASURE
+};
+
+enum msm_audio_g711a_mode {
+ MVS_G711A_MODE_MULAW,
+ MVS_G711A_MODE_ALAW
+};
+
+enum msm_audio_g711_mode {
+ MVS_G711_MODE_MULAW,
+ MVS_G711_MODE_ALAW
+};
+
+#define VOIP_MODE_MAX MODE_G711A
#define VOIP_RATE_MAX 23850
enum format {
@@ -153,7 +172,7 @@
uint32_t evrc_max_rate;
};
-static int voip_get_media_type(uint32_t mode,
+static int voip_get_media_type(uint32_t mode, uint32_t rate_type,
unsigned int samp_rate,
unsigned int *media_type);
static int voip_get_rate_type(uint32_t mode,
@@ -358,6 +377,81 @@
list_add_tail(&buf_node->list, &prtd->out_queue);
break;
}
+ case MODE_G711:
+ case MODE_G711A:{
+ /* G711 frames are 10ms each, but the DSP works with
+ * 20ms frames and sends two 10ms frames per buffer.
+ * Extract the two frames and put them in separate
+ * buffers.
+ */
+ /* Remove the first DSP frame info header.
+ * Header format: G711A
+ * Bits 0-1: Frame type
+ * Bits 2-3: Frame rate
+ *
+ * Header format: G711
+ * Bits 2-3: Frame rate
+ */
+ if (prtd->mode == MODE_G711A)
+ buf_node->frame.frm_hdr.frame_type =
+ (*voc_pkt) & 0x03;
+ buf_node->frame.frm_hdr.timestamp = timestamp;
+ voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
+
+ /* There are two frames in the buffer. Length of the
+ * first frame:
+ */
+ buf_node->frame.pktlen = (pkt_len -
+ 2 * DSP_FRAME_HDR_LEN) / 2;
+
+ memcpy(&buf_node->frame.voc_pkt[0],
+ voc_pkt,
+ buf_node->frame.pktlen);
+ voc_pkt = voc_pkt + buf_node->frame.pktlen;
+
+ list_add_tail(&buf_node->list, &prtd->out_queue);
+
+ /* Get another buffer from the free Q and fill in the
+ * second frame.
+ */
+ if (!list_empty(&prtd->free_out_queue)) {
+ buf_node =
+ list_first_entry(&prtd->free_out_queue,
+ struct voip_buf_node,
+ list);
+ list_del(&buf_node->list);
+
+ /* Remove the second DSP frame info header.
+ * Header format:
+ * Bits 0-1: Frame type
+ * Bits 2-3: Frame rate
+ */
+
+ if (prtd->mode == MODE_G711A)
+ buf_node->frame.frm_hdr.frame_type =
+ (*voc_pkt) & 0x03;
+ buf_node->frame.frm_hdr.timestamp = timestamp;
+ voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
+
+ /* There are two frames in the buffer. Length
+ * of the second frame:
+ */
+ buf_node->frame.pktlen = (pkt_len -
+ 2 * DSP_FRAME_HDR_LEN) / 2;
+
+ memcpy(&buf_node->frame.voc_pkt[0],
+ voc_pkt,
+ buf_node->frame.pktlen);
+
+ list_add_tail(&buf_node->list,
+ &prtd->out_queue);
+ } else {
+ /* Drop the second frame */
+ pr_err("%s: UL data dropped, read is slow\n",
+ __func__);
+ }
+ break;
+ }
default: {
buf_node->frame.frm_hdr.timestamp = timestamp;
buf_node->frame.pktlen = pkt_len;
@@ -389,6 +483,8 @@
unsigned long dsp_flags;
uint32_t rate_type;
uint32_t frame_rate;
+ u32 pkt_len;
+ u8 *voc_addr = NULL;
if (prtd->playback_substream == NULL)
return;
@@ -454,6 +550,70 @@
list_add_tail(&buf_node->list, &prtd->free_in_queue);
break;
}
+ case MODE_G711:
+ case MODE_G711A:{
+ /* G711 frames are 10ms each but the DSP expects 20ms
+ * worth of data, so send two 10ms frames per buffer.
+ */
+ /* Add the first DSP frame info header. Header format:
+ * Bits 0-1: Frame type
+ * Bits 2-3: Frame rate
+ */
+ voc_addr = voc_pkt;
+ voc_pkt = voc_pkt + sizeof(uint32_t);
+
+ *voc_pkt = ((prtd->rate_type & 0x0F) << 2) |
+ (buf_node->frame.frm_hdr.frame_type & 0x03);
+ voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
+
+ pkt_len = buf_node->frame.pktlen + DSP_FRAME_HDR_LEN;
+
+ memcpy(voc_pkt,
+ &buf_node->frame.voc_pkt[0],
+ buf_node->frame.pktlen);
+ voc_pkt = voc_pkt + buf_node->frame.pktlen;
+
+ list_add_tail(&buf_node->list, &prtd->free_in_queue);
+
+ if (!list_empty(&prtd->in_queue)) {
+ /* Get the second buffer. */
+ buf_node = list_first_entry(&prtd->in_queue,
+ struct voip_buf_node,
+ list);
+ list_del(&buf_node->list);
+
+ /* Add the second DSP frame info header.
+ * Header format:
+ * Bits 0-1: Frame type
+ * Bits 2-3: Frame rate
+ */
+ *voc_pkt = ((prtd->rate_type & 0x0F) << 2) |
+ (buf_node->frame.frm_hdr.frame_type & 0x03);
+ voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
+
+ pkt_len = pkt_len + buf_node->frame.pktlen +
+ DSP_FRAME_HDR_LEN;
+
+ memcpy(voc_pkt,
+ &buf_node->frame.voc_pkt[0],
+ buf_node->frame.pktlen);
+
+ list_add_tail(&buf_node->list,
+ &prtd->free_in_queue);
+ } else {
+ /* Only 10ms worth of data is available, signal
+ * erasure frame.
+ */
+ *voc_pkt = ((prtd->rate_type & 0x0F) << 2) |
+ (MVS_G711A_ERASURE & 0x03);
+
+ pkt_len = pkt_len + DSP_FRAME_HDR_LEN;
+ pr_debug("%s, Only 10ms read, erase 2nd frame\n",
+ __func__);
+ }
+ *((uint32_t *)voc_addr) = pkt_len;
+ break;
+ }
default: {
*((uint32_t *)voc_pkt) = buf_node->frame.pktlen;
voc_pkt = voc_pkt + sizeof(uint32_t);
@@ -829,10 +989,12 @@
pr_debug("%s(): mode=%d, playback sample rate=%d, capture sample rate=%d\n",
__func__, prtd->mode, prtd->play_samp_rate, prtd->cap_samp_rate);
- if ((runtime->format != FORMAT_S16_LE) && ((prtd->mode == MODE_PCM) ||
- (prtd->mode == MODE_AMR) || (prtd->mode == MODE_AMR_WB) ||
+ if ((runtime->format != FORMAT_S16_LE &&
+ runtime->format != FORMAT_SPECIAL) &&
+ ((prtd->mode == MODE_AMR) || (prtd->mode == MODE_AMR_WB) ||
(prtd->mode == MODE_IS127) || (prtd->mode == MODE_4GV_NB) ||
- (prtd->mode == MODE_4GV_WB) || (prtd->mode == MODE_4GV_NW))) {
+ (prtd->mode == MODE_4GV_WB) || (prtd->mode == MODE_4GV_NW) ||
+ (prtd->mode == MODE_G711) || (prtd->mode == MODE_G711A))) {
pr_err("%s(): mode:%d and format:%u are not matched\n",
__func__, prtd->mode, (uint32_t)runtime->format);
@@ -840,21 +1002,19 @@
goto done;
}
- ret = voip_get_media_type(prtd->mode,
- prtd->play_samp_rate,
- &media_type);
- if (ret < 0) {
- pr_err("%s(): fail at getting media_type, ret=%d\n",
- __func__, ret);
+ if (runtime->format != FORMAT_S16_LE && (prtd->mode == MODE_PCM)) {
+ pr_err("%s(): mode:%d and format:%u are not matched\n",
+ __func__, prtd->mode, runtime->format);
- ret = -EINVAL;
+ ret = -EINVAL;
goto done;
}
- pr_debug("%s(): media_type=%d\n", __func__, media_type);
if ((prtd->mode == MODE_PCM) ||
(prtd->mode == MODE_AMR) ||
- (prtd->mode == MODE_AMR_WB)) {
+ (prtd->mode == MODE_AMR_WB) ||
+ (prtd->mode == MODE_G711) ||
+ (prtd->mode == MODE_G711A)) {
ret = voip_get_rate_type(prtd->mode,
prtd->rate,
&rate_type);
@@ -909,6 +1069,19 @@
pr_debug("%s(): min rate=%d, max rate=%d\n",
__func__, evrc_min_rate_type, evrc_max_rate_type);
}
+ ret = voip_get_media_type(prtd->mode,
+ prtd->rate_type,
+ prtd->play_samp_rate,
+ &media_type);
+ if (ret < 0) {
+ pr_err("%s(): fail at getting media_type, ret=%d\n",
+ __func__, ret);
+
+ ret = -EINVAL;
+ goto done;
+ }
+ pr_debug("%s(): media_type=%d\n", __func__, media_type);
+
if ((prtd->play_samp_rate == 8000) &&
(prtd->cap_samp_rate == 8000))
voc_config_vocoder(media_type, rate_type,
@@ -1285,6 +1458,10 @@
}
break;
}
+ case MODE_G711:
+ case MODE_G711A:
+ *rate_type = rate;
+ break;
default:
pr_err("wrong mode type.\n");
ret = -EINVAL;
@@ -1294,9 +1471,9 @@
return ret;
}
-static int voip_get_media_type(uint32_t mode,
- unsigned int samp_rate,
- unsigned int *media_type)
+static int voip_get_media_type(uint32_t mode, uint32_t rate_type,
+ unsigned int samp_rate,
+ unsigned int *media_type)
{
int ret = 0;
@@ -1327,6 +1504,13 @@
case MODE_4GV_NW: /* EVRC-NW */
*media_type = VSS_MEDIA_ID_4GV_NW_MODEM;
break;
+ case MODE_G711:
+ case MODE_G711A:
+ if (rate_type == MVS_G711A_MODE_MULAW)
+ *media_type = VSS_MEDIA_ID_G711_MULAW;
+ else
+ *media_type = VSS_MEDIA_ID_G711_ALAW;
+ break;
default:
pr_debug(" input mode is not supported\n");
ret = -EINVAL;