[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