[Feature]add MT2731_MP2_MR2_SVN388 baseline version

Change-Id: Ief04314834b31e27effab435d3ca8ba33b499059
diff --git a/src/multimedia/dtmf/LICENSE b/src/multimedia/dtmf/LICENSE
new file mode 100644
index 0000000..e6e7948
--- /dev/null
+++ b/src/multimedia/dtmf/LICENSE
@@ -0,0 +1,31 @@
+Copyright Statement:

+

+This software/firmware and related documentation ("MediaTek Software") are

+protected under relevant copyright laws. The information contained herein is

+confidential and proprietary to MediaTek Inc. and/or its licensors. Without

+the prior written permission of MediaTek inc. and/or its licensors, any

+reproduction, modification, use or disclosure of MediaTek Software, and

+information contained herein, in whole or in part, shall be strictly

+prohibited.

+

+MediaTek Inc. (C) 2015. All rights reserved.

+

+BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES

+THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")

+RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER

+ON AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL

+WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED

+WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR

+NONINFRINGEMENT. NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH

+RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,

+INCORPORATED IN, OR SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES

+TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.

+RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO

+OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN MEDIATEK

+SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE

+RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR

+STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S

+ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE

+RELEASED HEREUNDER WILL BE, AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE

+MEDIATEK SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE

+CHARGE PAID BY RECEIVER TO MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
\ No newline at end of file
diff --git a/src/multimedia/dtmf/Makefile b/src/multimedia/dtmf/Makefile
new file mode 100644
index 0000000..01085e3
--- /dev/null
+++ b/src/multimedia/dtmf/Makefile
@@ -0,0 +1,21 @@
+TARGET  := libdtmf.so
+SOURCES := dtmf.c
+OBJECTS := $(SOURCES:.c=.o)
+
+GET_LOCAL_DIR = $(patsubst %/,%,$(dir $(lastword $(MAKEFILE_LIST))))
+
+.PHONY: all clean install
+
+all: $(TARGET)
+
+$(TARGET): $(OBJECTS)
+	${CC} ${CFLAGS} -shared -fPIC -o ${TARGET} ${SOURCES}
+
+clean:
+	$(RM) $(OBJECTS) $(TARGET)
+
+install: $(TARGET)
+	install -d ${DESTDIR}${LIBDIR}
+	install -d ${DESTDIR}${INCDIR}
+	install -m 755 ${TARGET} $(DESTDIR)${LIBDIR}/${TARGET}
+	install -m 444 *.h $(DESTDIR)${INCDIR}/
diff --git a/src/multimedia/dtmf/dtmf.c b/src/multimedia/dtmf/dtmf.c
new file mode 100755
index 0000000..a1af20b
--- /dev/null
+++ b/src/multimedia/dtmf/dtmf.c
@@ -0,0 +1,360 @@
+#include "dtmf.h"
+
+#define USE_SYSLOG 1
+#if USE_SYSLOG
+#include <log/log.h>
+#endif
+
+#define RET_OK    0
+#define RET_FAIL -1
+
+#define CRITICAL 0
+#define DEFAULT  1
+#define INFO     2
+#define DEBUGLEVEL DEFAULT
+#define DTMF_TAG "[LIBDTMF]"
+
+static guint dtmf_get_time_ms(guint base)
+{	
+	guint current = g_get_monotonic_time() / G_TIME_SPAN_MILLISECOND;
+	if (current >= base) {		
+		return (current - base);	
+	} else {
+		return (G_MAXUINT32 - (base - current));	
+	}
+}
+#if USE_SYSLOG
+#undef LOG_TAG
+#define LOG_TAG "[LIBDTMF]"
+#define PRINT_ERR(fmt, args...)			RLOGE(fmt, ##args)
+#define PRINT_DEFAULT(fmt, args...)		RLOGI(fmt, ##args)
+#define PRINT_INFO(fmt, args...)		RLOGD(fmt, ##args)
+#else
+#define app_printf(level, fmt, args...) \
+	do { if ((level) <= DEBUGLEVEL) \
+	{ fprintf (stderr, fmt, ##args); } } while (0)
+
+#define PRINT_ERR(fmt, args...) \
+	app_printf(CRITICAL, DTMF_TAG"[ERR][L%d][T%d]"fmt, __LINE__, dtmf_get_time_ms(0),##args);
+
+#define PRINT_DEFAULT(fmt, args...) \
+	app_printf(DEFAULT, DTMF_TAG"[DEF][L%d][T%d]"fmt, __LINE__, dtmf_get_time_ms(0), ##args);
+
+#define PRINT_INFO(fmt, args...) \
+	app_printf(INFO, DTMF_TAG"[INFO][L%d][T%d]"fmt, __LINE__, dtmf_get_time_ms(0), ##args);
+#endif
+
+#define FILE_NAME_MAX_LENGTH 64
+#define DTMFSRC_MUTE_LENGTH  100   //unit: ms, from the practice result, the begining 100ms data is 0.
+
+typedef struct {
+	DTMF_HANDLE handle;
+	gint number;		//the event number: 0-15
+	gint volume;		//db value: 0-36
+	gint time_ms;		//the duration of tone, unit: ms
+	
+	pthread_t thread;
+	GMainLoop *loop;
+	GstElement *pipeline;
+	guint bus_watch_id;
+	GstState gst_cur_state;
+
+	gint output;	//0: output to pulsesink; 1: output the buffer pointer
+	char *path; 	//while output==1, file path to store the tone data
+	//FILE *fd;		// file handle to the output file
+} DTMF_PARAM_T;
+
+static int dtmf_stop_full(DTMF_PARAM_T *param)
+{
+	GMainLoop *loop = param->loop;
+	GstElement *pipeline = param->pipeline;
+	guint bus_watch_id = param->bus_watch_id;
+	GstStructure *structure_stop = NULL;
+	GstEvent *event_stop = NULL;
+
+	PRINT_DEFAULT("%s start, param: 0x%x, handle: 0x%x, number: %d, time_ms: %d, volume: %d \n", 
+		__FUNCTION__, param, param->handle, param->number, param->time_ms, param->volume);
+
+	if (param != param->handle) {
+		PRINT_DEFAULT("invalid handle: %p \n", param->handle);
+		return RET_OK;
+	}
+
+	structure_stop = gst_structure_new ("dtmf-event",
+				 "type", G_TYPE_INT, 1,
+				 "number", G_TYPE_INT, 1,
+				 "volume", G_TYPE_INT, 25,
+				 "start", G_TYPE_BOOLEAN, FALSE, NULL);
+	event_stop = gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM, structure_stop);
+	gst_element_send_event (pipeline, event_stop);
+
+	PRINT_DEFAULT("gst_element_set_state NULL start \n");
+	gst_element_set_state (pipeline, GST_STATE_NULL);
+	PRINT_DEFAULT("gst_element_set_state NULL end \n");
+
+	gst_object_unref (GST_OBJECT (pipeline));
+	g_source_remove (bus_watch_id);
+	g_main_loop_unref (loop);
+
+	param->handle = NULL;	
+	free(param);
+	param = NULL;
+	PRINT_DEFAULT("%s end \n", __FUNCTION__);
+	
+	return RET_OK;
+}
+
+static gboolean dtmf_bus_call (GstBus *bus, GstMessage *msg, gpointer data)
+{
+	DTMF_PARAM_T *param = (DTMF_PARAM_T *)data;
+	GstState oldstate, newstate, pending;
+	gchar  *debug;
+	GError *error;
+
+	switch (GST_MESSAGE_TYPE (msg)) {
+	case GST_MESSAGE_EOS:
+		PRINT_DEFAULT ("Receive GST_MESSAGE_EOS \n");
+		g_main_loop_quit (param->loop);
+		break;
+	case GST_MESSAGE_STATE_CHANGED:
+		gst_message_parse_state_changed (msg, &oldstate, &newstate, &pending);
+		param->gst_cur_state = newstate;
+		PRINT_INFO ("GST_MESSAGE_STATE_CHANGED, oldstate[%d], newstate[%d], pending[%d] \n",
+			oldstate, newstate, pending);
+		break;
+	case GST_MESSAGE_ERROR:
+		gst_message_parse_error (msg, &error, &debug);
+		g_free (debug);
+		PRINT_ERR ("Error: %s\n", error->message);
+		g_error_free (error);
+		g_main_loop_quit (param->loop);
+		break;
+    default:
+		break;
+  }
+
+  return TRUE;
+}
+
+#if 0
+void dtmf_wait_ms(gint ms) 
+{
+	gint err;
+	struct timeval wait_tv;
+	wait_tv.tv_sec = ms / 1000;
+	wait_tv.tv_usec = (ms % 1000) * 1000;
+	do {
+		err = select(0, NULL, NULL, NULL, &wait_tv);
+	} while(err<0 && errno == EINTR);
+}
+
+static GstFlowReturn dtmf_tone_data_output(GstElement *sink, void *data)
+{
+	DTMF_PARAM_T *param = (DTMF_PARAM_T *)data;
+	GstSample *sample;
+	GstBuffer *buffer;	
+	GstMapInfo map;
+
+  	sample = gst_app_sink_pull_sample (GST_APP_SINK (sink));
+	if (!sample) 
+	{
+		PRINT_ERR("could not get sample. \n");
+		return GST_FLOW_ERROR;
+	}
+	buffer = gst_sample_get_buffer (sample);
+	gst_buffer_map (buffer, &map, GST_MAP_READ);
+	PRINT_INFO ("tone data:  size=%d, data=%p \n", map.size, map.data);
+	fwrite(map.data, 1, map.size, param->fd);
+
+	gst_buffer_unmap (buffer, &map);
+	gst_sample_unref (sample);
+
+	return GST_FLOW_OK;
+}
+#endif
+
+static gint dtmf_check_param(DTMF_PARAM_T *param)
+{
+	if ((param->number < 0) || (param->number > 15)) {
+		PRINT_ERR("invalid number: %d, valid value is [0,15] \n ", param->number);
+		return RET_FAIL;
+	}
+	if ((param->time_ms != 0) && (param->time_ms < DTMF_MIN_LENGTH)) {
+		PRINT_ERR("invalid time_ms: %d \n ", param->time_ms);
+		return RET_FAIL;
+	}
+	if ((param->volume < 0) || (param->volume > 36)) {
+		PRINT_ERR("invalid volume: %d, valid value is [0,36] \n ", param->volume);
+		return RET_FAIL;
+	}
+	if ((param->output < 0) || (param->output > 1)) {
+		PRINT_ERR("invalid output: %d, valid value is [0,1] \n ", param->output);
+		return RET_FAIL;
+	}
+	if ((param->output == 1) && (param->path == NULL)) {
+		PRINT_ERR("path is NULL while output is filesink \n ");
+		return RET_FAIL;
+	}
+	return RET_OK;
+}
+
+void* dtmf_thread_func(void *arg)
+{
+	DTMF_PARAM_T *param = (DTMF_PARAM_T *)arg;
+	PRINT_DEFAULT("%s start \n", __FUNCTION__);
+
+	g_main_loop_run (param->loop);
+	PRINT_DEFAULT("g_main_loop_run end \n");
+
+	dtmf_stop_full(param);
+	
+	PRINT_DEFAULT("%s end \n", __FUNCTION__);
+	return ((void *)0);
+}
+
+DTMF_HANDLE dtmf_start(gint num, gint time_ms, gint volume, DTMF_EXTRA *extra)
+{
+	GMainLoop *loop;
+	GstElement *pipeline, *source, *sink;
+	GstBus *bus;
+	guint bus_watch_id;
+	pthread_t thread;
+	GstStructure *structure_start = NULL;
+	GstEvent *event_start = NULL;
+
+	DTMF_HANDLE handle = NULL;
+	DTMF_PARAM_T *param = malloc(sizeof(DTMF_PARAM_T));
+	if (param == NULL) {
+		PRINT_ERR("malloc DTMF_PARAM_T fail \n");
+	}
+	memset(param, 0, sizeof(DTMF_PARAM_T));
+	handle = (DTMF_HANDLE)param;
+
+	//param->handle = handle;
+	param->number = num;
+	param->time_ms = time_ms;
+	param->volume = volume;
+
+	PRINT_DEFAULT("%s start, handle: 0x%x, number: %d, time_ms: %d, volume: %d \n ", 
+		__FUNCTION__, handle, param->number, param->time_ms, param->volume);
+
+	if (extra != NULL) {
+		param->output = extra->output;
+		param->path = extra->path;
+		PRINT_DEFAULT("output: %d, path: %s \n", extra->output, extra->path);
+	}
+
+	if (dtmf_check_param(param) < 0) {
+		PRINT_ERR("input parameter is invalid! \n");
+		return NULL;
+	}
+
+	gst_init (NULL, NULL);
+	
+	loop = g_main_loop_new (NULL, FALSE);
+	
+	pipeline = gst_pipeline_new ("dtmf-pipeline");
+	source   = gst_element_factory_make ("dtmfsrc", 	 "dtmf-file-source");
+	switch (param->output) {
+		case 0:
+			sink = gst_element_factory_make ("pulsesink",	 "dtmf-audio-output");
+			break;
+		case 1:
+			sink = gst_element_factory_make ("filesink",	 "dtmf-audio-output");
+			g_object_set(sink, "location", extra->path, NULL);
+			break;
+		default:
+			PRINT_ERR("input parameter 'output' is invalid! \n");
+			break;
+	}
+
+    //sink = gst_element_factory_make ("appsink", 	 "audio-output-buffer");
+	//g_object_set(sink, "emit-signals", TRUE, "sync", TRUE, NULL);
+	//g_signal_connect(sink, "new-sample", G_CALLBACK(tone_data_output), (gpointer)param);
+
+	if (!pipeline || !source || !sink) {
+		PRINT_ERR ("One element creat fail, pipeline: %p, source: %p, sink: %p \n",
+			pipeline, source, sink);
+		free(param);
+		return NULL;
+	}
+
+	guint interval = 50;
+	gint buffers_num = -1;
+	if (time_ms > 0) {
+		// dtmfsrc plugin will send EOS when the number of buffers reach 'buffers_num' .
+		g_object_get(source, "interval", &interval, NULL);
+		buffers_num = (time_ms + DTMFSRC_MUTE_LENGTH) / interval;
+		PRINT_DEFAULT("dtmfsrc interval: %d ms, set num-buffers: %d \n", 
+			interval, buffers_num);
+		g_object_set(source, "num-buffers", buffers_num, NULL);
+	}
+
+	bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
+	bus_watch_id = gst_bus_add_watch (bus, dtmf_bus_call, (gpointer)param);
+	gst_object_unref (bus);
+
+	param->pipeline = pipeline;
+	param->loop = loop;
+	param->bus_watch_id = bus_watch_id;
+
+	pthread_create (&thread, NULL, (void *)dtmf_thread_func, param);
+	param->thread = thread;
+
+	gst_bin_add_many (GST_BIN (pipeline), source, sink, NULL);
+	gst_element_link_many (source, sink, NULL);
+
+	gst_element_set_state (param->pipeline, GST_STATE_PLAYING);
+	
+	PRINT_INFO("wait GST_STATE_PLAYING start \n");
+	do {
+		if (param->gst_cur_state == GST_STATE_PLAYING)
+			break;
+		else
+			usleep(5000);
+	} while (1);
+	PRINT_INFO("wait GST_STATE_PLAYING end \n");
+
+	structure_start = gst_structure_new ("dtmf-event",
+				 "type", G_TYPE_INT, 1,
+				 "number", G_TYPE_INT, param->number,
+				 "volume", G_TYPE_INT, param->volume,
+				 "start", G_TYPE_BOOLEAN, TRUE, NULL);
+
+	//gst_structure_set (structure, "number", G_TYPE_INT, num,
+    //          "volume", G_TYPE_INT, volume, NULL);
+	
+	event_start = gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM, structure_start);
+	gst_element_send_event (param->pipeline, event_start);
+
+	PRINT_DEFAULT("%s end, handle: 0x%x, number: %d, time_ms: %d, volume: %d \n", 
+		__FUNCTION__, handle, param->number, param->time_ms, param->volume);
+
+	param->handle = handle;
+
+	return handle;
+}
+
+int dtmf_stop(DTMF_HANDLE handle)
+{
+	if (handle == NULL) {
+		PRINT_ERR ("%s, handle is NULL\n", __FUNCTION__);
+		return RET_FAIL;
+	}
+	DTMF_PARAM_T *param = (DTMF_PARAM_T *)handle;
+
+	PRINT_DEFAULT("%s start, DTMF_HANDLE: 0x%x, handle: 0x%x \n", 
+		__FUNCTION__, handle, param->handle);
+
+	if (handle != param->handle) {
+		PRINT_DEFAULT("invalid handle: %p \n", handle);
+		return RET_OK;
+	}
+
+	g_main_loop_quit (param->loop);
+	pthread_join(param->thread, NULL);
+
+	PRINT_DEFAULT("%s end, handle: 0x%x \n", __FUNCTION__, handle);
+
+	return RET_OK;
+}
diff --git a/src/multimedia/dtmf/dtmf.h b/src/multimedia/dtmf/dtmf.h
new file mode 100755
index 0000000..6958556
--- /dev/null
+++ b/src/multimedia/dtmf/dtmf.h
@@ -0,0 +1,52 @@
+#ifndef _DTMF_H_

+#define _DTMF_H_

+

+#include <stdio.h>

+#include <stdlib.h>

+#include <string.h>

+#include <assert.h>

+#include <unistd.h>

+#include <errno.h>

+#include <getopt.h>

+#include <pthread.h>

+

+//#include <glib.h>

+#include <gst/gst.h>

+

+#define DTMF_MIN_LENGTH 150    //unit: millisecond

+

+typedef void *DTMF_HANDLE;

+

+typedef struct {

+	gint output;	//0-pulsesink; 1-filesink

+	char *path;		//only used while output is filesink

+} DTMF_EXTRA;

+

+/**

+ * dtmf_start:

+ * @num: the event number, [0, 15]

+ * @time_ms: the length of time of the dtmf tone, must be "==0" or ">=150" (unit: millisecond)

+ * @volume: the power level of the dtmf tone, [0, 36] indicate 0~-36 dBm0

+ * @extra_info: set the extra info for dtmf library, refer to DTMF_EXTRA

+ *

+ * Start to generate DTMF tone packet and output to pulse audio.

+ * If time_ms==0; dtmf tone will not stop until dtmf_stop() API being called

+ * If time_ms>0; dtmf tone will stop automatically when the time is up.

+ *

+ * Returns: the dtmf handle

+ *

+ */

+DTMF_HANDLE dtmf_start(gint num, gint time_ms, gint volume, DTMF_EXTRA *extra);

+

+/**

+ * dtmf_stop:

+ * @handle: the dtmf handle which is got from dtmf_start() API

+ *

+ * Stop generating DTMF tone packet.

+ *

+ * Returns: N/A

+ *

+ */

+int dtmf_stop(DTMF_HANDLE handle);

+

+#endif