Implements TIVI-1126 - Support ringtone for incoming call 93/17393/1
authorJimmy Huang <jimmy.huang@intel.com>
Thu, 6 Mar 2014 23:10:41 +0000 (15:10 -0800)
committerJimmy Huang <jimmy.huang@intel.com>
Thu, 6 Mar 2014 23:10:41 +0000 (15:10 -0800)
- Add support for ringtone playback through pulseaudio
- Added sample ringtone using gettext-generated human voice

Change-Id: I9fc9e19e73bd2764fcad762efa2e55d606c379db
Signed-off-by: Jimmy Huang <jimmy.huang@intel.com>
Makefile.am
configure.ac
data/ringtones/default.wav [new file with mode: 0644]
dialer/callscreen.c
packaging/lemolo.spec
utils/pulseaudio.c
utils/pulseaudio.h

index cd5a83b..7f29e81 100644 (file)
@@ -170,6 +170,9 @@ if HAVE_TIZEN
 EDJE_FLAGS += -DHAVE_TIZEN=1
 endif
 
+ringtonesdir = $(pkgdatadir)/ringtones
+ringtones_DATA = data/ringtones/default.wav
+
 filesdir = $(pkgdatadir)/themes
 files_DATA = \
 data/themes/default.edj \
index 86a7179..3f85ae8 100644 (file)
@@ -36,6 +36,7 @@ PKG_CHECK_MODULES([PULSEAUDIO],
        [
                libpulse
                libpulse-mainloop-glib
+               libpulse-simple
         ])
 
 EFL_WITH_BIN([edje], [edje-cc], [edje_cc])
diff --git a/data/ringtones/default.wav b/data/ringtones/default.wav
new file mode 100644 (file)
index 0000000..2839ae8
Binary files /dev/null and b/data/ringtones/default.wav differ
index 42ab020..a4d8a38 100644 (file)
@@ -11,6 +11,7 @@
 #include "ofono.h"
 #include "util.h"
 #include "simple-popup.h"
+#include "pulseaudio.h"
 #include "i18n.h"
 
 typedef struct _Callscreen
@@ -1004,8 +1005,10 @@ static void _call_added(void *data, OFono_Call *c)
                _call_waiting_set(ctx, c);
        else {
                _call_auto_place(ctx, c);
-               if (state == OFONO_CALL_STATE_INCOMING)
+               if (state == OFONO_CALL_STATE_INCOMING) {
+                       pa_play_ringtone();
                        _call_incoming_set(ctx, c);
+               }
        }
 
        gui_call_enter();
@@ -1018,6 +1021,7 @@ static void _call_removed(void *data, OFono_Call *c)
                ctx, ctx->calls.first, ctx->calls.second, ctx->calls.current,
                ctx->calls.waiting, c);
 
+       pa_stop_ringtone();
        ctx->calls.list = eina_list_remove(ctx->calls.list, c);
        _call_disconnected_show(ctx, c, "local");
 }
@@ -1235,9 +1239,13 @@ static void _call_changed(void *data, OFono_Call *c)
        Callscreen *ctx = data;
        OFono_Call_State state = ofono_call_state_get(c);
 
-       DBG("BEGIN: ctx=%p, %p, %p, current=%p, waiting=%p, changed=%p (%d)",
+       DBG("BEGIN: ctx=%p, %p, %p, current=%p, waiting=%p, changed=%p (%s)",
                ctx, ctx->calls.first, ctx->calls.second, ctx->calls.current,
-               ctx->calls.waiting, c, state);
+               ctx->calls.waiting, c, _call_state_str(state));
+
+       if (state == OFONO_CALL_STATE_ACTIVE || state == OFONO_CALL_STATE_DISCONNECTED) {
+               pa_stop_ringtone();
+       }
 
        if (ctx->calls.waiting == c)
                _call_changed_waiting_update(ctx, c);
@@ -1267,9 +1275,9 @@ static void _call_changed(void *data, OFono_Call *c)
 
        _call_changed_swap_merge_update(ctx);
 
-       DBG("END: ctx=%p, %p, %p, current=%p, waiting=%p, changed=%p (%d)",
+       DBG("END: ctx=%p, %p, %p, current=%p, waiting=%p, changed=%p (%s)",
                ctx, ctx->calls.first, ctx->calls.second, ctx->calls.current,
-               ctx->calls.waiting, c, state);
+               ctx->calls.waiting, c, _call_state_str(state));
 }
 
 static void _call_disconnected(void *data, OFono_Call *c, const char *reason)
index 3e71da1..df3c1d3 100644 (file)
@@ -55,6 +55,7 @@ rm -rf %{buildroot}
 %{_bindir}/dialer_open
 %{_bindir}/message_daemon
 %{_datadir}/lemolo/examples/contacts.csv
+%{_datadir}/lemolo/ringtones/default.wav
 %{_datadir}/lemolo/scripts/ofono-efl-contacts-db-create.py
 %{_datadir}/lemolo/themes/default.edj
 %{_datadir}/lemolo/themes/night.edj
index 294d1e5..f63d09b 100644 (file)
 #include <pulse/context.h>
 #include <pulse/pulseaudio.h>
 #include <pulse/glib-mainloop.h>
+#include <pulse/simple.h>
 
+#include "fcntl.h"
 #include "pulseaudio.h"
 #include "log.h"
 
+#define BUFFERSIZE 1024
+
 static pa_glib_mainloop *mainloop = NULL;
 static pa_context *pa_ctx = NULL;
+static pa_simple *connection = NULL;
+static Ecore_Thread *ringtone_thread = NULL;
+static pa_proplist *proplist = NULL;
+static Eina_Bool stopped = EINA_TRUE;
+
+/* The Sample format to use */
+static const pa_sample_spec ss = {
+       .format = PA_SAMPLE_S16LE,
+       .rate = 44100,
+       .channels = 2
+};
+
+static void _play(void *data __UNUSED__, Ecore_Thread *thread)
+{
+       int error, fd;
+       char file_path[PATH_MAX];
+
+       DBG("Ringtone playing");
+       stopped = EINA_FALSE;
+
+       snprintf(file_path, sizeof(file_path), "%s/ringtones/default.wav", elm_app_data_dir_get());
+
+       if ((fd = open(file_path, O_RDONLY)) < 0) {
+               DBG("open() failed: %s", strerror(errno));
+               return;
+       }
+
+       if (dup2(fd, STDIN_FILENO) < 0 ) {
+               DBG("dup2() failed: %s", strerror(errno));
+               return;
+       }
+
+       close(fd);
+
+       /* loops until stopped thread is canceled */
+       for (;;) {
+               uint8_t buf[BUFFERSIZE];
+               ssize_t r;
+
+               /* check if playing is stopped */
+               if (ecore_thread_check(thread)) {
+                       DBG("Ringtone stopping");
+                       if (pa_simple_flush(connection, &error) < 0) {
+                               ERR("pa_simple_flush() failed: %s\n", pa_strerror(error));
+                               return;
+                       }
+
+                       break;
+               }
+
+               /* Read the ringtone file */
+               if ((r = read(STDIN_FILENO, buf, sizeof(buf))) <= 0) {
+                       if (r == 0) {
+                               /* EOF, repeat */
+                               DBG("Ringtone repeating");
+                               lseek(STDIN_FILENO, 0, SEEK_SET);
+                               continue;
+                       }
+
+                       ERR("reading from ringtone wav file failed");
+                       return;
+               }
+
+               /* play iit */
+               if (pa_simple_write(connection, buf, (size_t) r, &error) < 0) {
+                       ERR("pa_simple_write() failed: %s", pa_strerror(error));
+                       return;
+               }
+       }
+
+       if (pa_simple_drain(connection, &error) < 0) {
+               ERR("pa_simple_drain() failed: %s\n", pa_strerror(error));
+       }
+}
+
+static void _end(void *data __UNUSED__, Ecore_Thread *thread __UNUSED__)
+{
+       DBG("Ringtone ended");
+       if (ringtone_thread)
+               ringtone_thread = NULL;
+}
+
+
+static void _cancel(void *data __UNUSED__, Ecore_Thread *thread __UNUSED__)
+{
+       DBG("Ringtone stopped");
+       if (ringtone_thread)
+               ringtone_thread = NULL;
+}
 
 Eina_Bool pa_init(void)
 {
+       int error;
+
        if (!mainloop)
                mainloop = pa_glib_mainloop_new(NULL);
 
@@ -26,16 +121,73 @@ Eina_Bool pa_init(void)
                                PA_CONTEXT_NOFAIL, NULL) < 0)
        {
                ERR("Failed to connect to pulseaudio daemon");
-                pa_glib_mainloop_free(mainloop);
-                mainloop = NULL;
-               return EINA_FALSE;
+               goto error;
        }
 
+       // Creates a connection for ringtone
+#ifdef HAVE_TIZEN
+       proplist = pa_proplist_new();
+       if (pa_proplist_sets(proplist, PA_PROP_MEDIA_ROLE, "phone") < 0) {
+               DBG("pa_proplist_sets() failed: %s", pa_strerror(error));
+               goto error;
+       }
+
+       if (!(connection = pa_simple_new_proplist(NULL, NULL, PA_STREAM_PLAYBACK, NULL,
+               "lemolo", &ss, NULL, NULL, proplist, &error))) {
+               DBG("pa_simple_new() failed: %s", pa_strerror(error));
+               goto error;
+       }
+#else
+        if (!(connection = pa_simple_new(NULL, NULL, PA_STREAM_PLAYBACK, NULL,
+                "lemolo", &ss, NULL, NULL, &error))) {
+                DBG("pa_simple_new() failed: %s", pa_strerror(error));
+                goto error;
+        }
+#endif
+
        return EINA_TRUE;
+
+error:
+       if (connection)
+               pa_simple_free(connection);
+
+       if (pa_ctx) {
+               pa_context_disconnect(pa_ctx);
+               pa_context_unref(pa_ctx);
+       }
+
+       if (mainloop) {
+               pa_glib_mainloop_free(mainloop);
+               mainloop = NULL;
+       }
+
+       if (proplist)
+               pa_proplist_free(proplist);
+
+       return EINA_FALSE;
+}
+
+Eina_Bool pa_play_ringtone(void)
+{
+       if (!ringtone_thread)
+               ringtone_thread = ecore_thread_run(_play, _end, _cancel, NULL);
+
+       return EINA_TRUE;
+}
+
+void pa_stop_ringtone(void)
+{
+       if (ringtone_thread)
+               ecore_thread_cancel(ringtone_thread);
 }
 
 void pa_shutdown(void)
 {
+       pa_stop_ringtone();
+
+       if (connection)
+               pa_simple_free(connection);
+
        if (pa_ctx) {
                pa_context_disconnect(pa_ctx);
                pa_context_unref(pa_ctx);
@@ -45,4 +197,7 @@ void pa_shutdown(void)
                pa_glib_mainloop_free(mainloop);
                mainloop = NULL;
        }
+
+       if (proplist)
+               pa_proplist_free(proplist);
 }
index 5dca36b..925f11f 100644 (file)
@@ -3,6 +3,10 @@
 
 Eina_Bool pa_init(void);
 
+Eina_Bool pa_play_ringtone(void);
+
+void pa_stop_ringtone(void);
+
 void pa_shutdown(void);
 
 #endif