Move set audio path api here
authorNicolas Bertrand <nicolas.bertrand@linux.intel.com>
Mon, 24 Sep 2012 16:09:05 +0000 (18:09 +0200)
committerAuke Kok <auke-jan.h.kok@intel.com>
Fri, 8 Feb 2013 20:25:50 +0000 (12:25 -0800)
CMakeLists.txt
include/pr3_audio.h [new file with mode: 0644]
packaging/tel-plugin-imc-pr3.spec
src/desc_imc_pr3.c
src/pr3_audio.c [new file with mode: 0644]

index 78556a2..2068376 100644 (file)
@@ -11,7 +11,7 @@ SET(CMAKE_INSTALL_PREFIX "${PREFIX}")
 
 # Set required packages
 INCLUDE(FindPkgConfig)
-pkg_check_modules(pkgs REQUIRED glib-2.0 tcore dlog)
+pkg_check_modules(pkgs REQUIRED glib-2.0 tcore dlog alsa)
 
 FOREACH(flag ${pkgs_CFLAGS})
        SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
@@ -30,6 +30,7 @@ MESSAGE(${CMAKE_EXE_LINKER_FLAGS})
 SET(SRCS
        src/desc_imc_pr3.c
        src/tty_imc.c
+       src/pr3_audio.c
 )
 
 
diff --git a/include/pr3_audio.h b/include/pr3_audio.h
new file mode 100644 (file)
index 0000000..063049b
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ *
+ *  oFono - Server
+ *
+ *  Copyright (C) 2012  Intel Corporation. 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 as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+
+#include <glib.h>
+#include <tcore.h>
+
+TReturn pr3_audio_set_sound_path(TcoreHal *hal, int device);
+gboolean pr3_audio_init(void);
+gboolean pr3_audio_unload(void);
index a8b7554..36e9830 100644 (file)
@@ -11,6 +11,7 @@ BuildRequires:  cmake
 BuildRequires:  pkgconfig(glib-2.0)
 BuildRequires:  pkgconfig(dlog)
 BuildRequires:  pkgconfig(tcore)
+BuildRequires:  pkgconfig(alsa)
 
 %description
 PR3 plateform telephony plugin
index c7f5673..7cc6bf7 100644 (file)
@@ -35,6 +35,7 @@
 #include <hal.h>
 
 #include "tty_imc.h"
+#include "pr3_audio.h"
 
 #define BUF_LEN_MAX 512
 
@@ -96,6 +97,7 @@ static struct tcore_hal_operations hops =
 {
        .power = hal_power,
        .send = hal_send,
+       .set_sound_path = pr3_audio_set_sound_path,
 };
 
 static gboolean on_recv_tty_message(GIOChannel *channel, GIOCondition condition, gpointer data)
@@ -168,6 +170,10 @@ static gboolean on_init(TcorePlugin *plugin)
 
        dbg("tty_fd = %d, watch_id_tty=%d ", data->tty_fd, data->watch_id_tty);
 
+       if (pr3_audio_init() != TRUE)
+               err("Error in audio initialization")
+
+
        return TRUE;
 }
 
@@ -176,6 +182,9 @@ static void on_unload(TcorePlugin *plugin)
        if (!plugin)
                return;
 
+       if (pr3_audio_unload() != TRUE)
+               err("Error in audio unload")
+
        dbg("I'm unload");
 }
 
diff --git a/src/pr3_audio.c b/src/pr3_audio.c
new file mode 100644 (file)
index 0000000..9cb23cb
--- /dev/null
@@ -0,0 +1,356 @@
+#include <stdio.h>
+#include <stdint.h>
+#include <sys/ioctl.h>
+#include <alsa/asoundlib.h>
+
+#include "pr3_audio.h"
+
+
+#define MODE_NORMAL            0
+#define MODE_RINGTONE          1
+#define MODE_IN_CALL           2
+#define MODE_IN_COMMUNICATION  3
+
+#define DISCONNECT     0x00
+#define DEVICE_OUT_EARPIECE            0x1
+#define DEVICE_OUT_SPEAKER             0x2
+#define DEVICE_OUT_WIRED_HEADSET       0x4
+#define DEVICE_OUT_WIRED_HEADPHONE     0x8
+
+#define A1026_IOCTL_MAGIC 'u'
+
+#define A1026_BOOTUP_INIT      _IO(A1026_IOCTL_MAGIC, 0x01)
+#define A1026_SUSPEND          _IO(A1026_IOCTL_MAGIC, 0x02)
+#define A1026_ENABLE_CLOCK     _IO(A1026_IOCTL_MAGIC, 0x03)
+
+#define ES305B_DEVICE  "/dev/audience_es305"
+
+#define FIRMWARE_NAME_MAX_LENGTH        64
+
+static const unsigned char es305b_no_acoustic[] = { 0x80, 0x31, 0x00, 0x06 };
+
+static int a1026_enabled;
+
+static snd_pcm_t *handle_playback = NULL;
+static snd_pcm_t *handle_capture = NULL;
+
+static const char *playback_name(int mode, uint32_t device)
+{
+       switch (device) {
+       case DEVICE_OUT_EARPIECE:
+               return "VoicePlayback_Earpiece_incall";
+       case DEVICE_OUT_SPEAKER:
+               return "VoicePlayback_Speaker_incall";
+       case DEVICE_OUT_WIRED_HEADSET:
+               return "VoicePlayback_Headset_incall";
+       case DEVICE_OUT_WIRED_HEADPHONE:
+               return "VoicePlayback_Headphone_incall";
+       }
+
+       return NULL;
+}
+static const char *capture_name(int mode, uint32_t device)
+{
+       /* No distinction as ALSA mixer control are set during playback
+        * path opening */
+       return "VoiceCapture_incall";
+}
+
+static void pcm_init(void)
+{
+       int card = snd_card_get_index("medfieldaudio");
+
+       dbg("Card index: %d\n", card);
+}
+
+static void pcm_enable(int mode, uint32_t device)
+{
+       const char *pcm_playback;
+       const char *pcm_capture;
+       int err;
+
+       pcm_playback = playback_name(mode, device);
+       pcm_capture = capture_name(mode, device);
+
+       dbg("Playback: %s\n", pcm_playback);
+       dbg("Capture:  %s\n", pcm_capture);
+
+       if (!pcm_playback || !pcm_capture)
+               return;
+
+       if (handle_capture) {
+               snd_pcm_close(handle_capture);
+               handle_capture = NULL;
+       }
+
+       if (handle_playback) {
+               snd_pcm_close(handle_playback);
+               handle_playback = NULL;
+       }
+
+       err = snd_pcm_open(&handle_playback, pcm_playback,
+                                       SND_PCM_STREAM_PLAYBACK, 0);
+       if (err < 0) {
+               err("Failed to open %s\n", pcm_playback);
+               return;
+       }
+
+       err = snd_pcm_open(&handle_capture, pcm_capture,
+                                       SND_PCM_STREAM_CAPTURE, 0);
+       if (err < 0) {
+               err("Failed to open %s\n", pcm_capture);
+               goto close_playback;
+       }
+
+       err = snd_pcm_set_params(handle_playback,
+                                       SND_PCM_FORMAT_S16_LE,
+                                       SND_PCM_ACCESS_RW_INTERLEAVED,
+                                       2, 48000, 0, 500000);   /* 0.5sec */
+       if (err < 0) {
+               err("Failed to set params for %s\n",
+                                                       pcm_playback);
+               goto close_capture;
+       }
+
+       err = snd_pcm_set_params(handle_capture,
+                                       SND_PCM_FORMAT_S16_LE,
+                                       SND_PCM_ACCESS_RW_INTERLEAVED,
+                                       1, 48000, 1, 500000);   /* 0.5sec */
+       if (err < 0) {
+               err("Failed to set params for %s\n",
+                                                       pcm_capture);
+               goto close_capture;
+       }
+
+       return;
+
+close_capture:
+       snd_pcm_close(handle_capture);
+
+close_playback:
+       snd_pcm_close(handle_playback);
+}
+
+static void pcm_disable(void)
+{
+       if (handle_capture) {
+               snd_pcm_close(handle_capture);
+               handle_capture = NULL;
+       }
+
+       if (handle_playback) {
+               snd_pcm_close(handle_playback);
+               handle_playback = NULL;
+       }
+}
+
+static void a1026_init(void)
+{
+       const unsigned char cmd1[] = { 0x80, 0x20, 0x00, 0x00 };
+       const unsigned char cmd2[] = { 0x80, 0x21, 0x00, 0x00 };
+       const char firmware_name[FIRMWARE_NAME_MAX_LENGTH] = {
+                                               "vpimg_es305b-NH.bin"};
+       unsigned char buf[4];
+       char label[100];
+       ssize_t written, len;
+       unsigned int i;
+       int fd, err;
+
+       dbg("A1026 init\n");
+
+       fd = open(ES305B_DEVICE, O_RDWR, 0);
+       if (fd < 0) {
+               err("Failed to open audience device\n");
+               return;
+       }
+
+       err = ioctl(fd, A1026_ENABLE_CLOCK);
+       if (err < 0) {
+               err("Failed to enable audience clock\n");
+               goto done;
+       }
+
+       err = ioctl(fd, A1026_BOOTUP_INIT, firmware_name);
+       if (err < 0) {
+               err("Failed to boot up audience\n");
+               goto done;
+       }
+
+       dbg("A1026 init done\n");
+
+       written = write(fd, cmd1, sizeof(cmd1));
+       if (written < 0)
+               err("First command failed\n");
+
+       usleep(20000);
+
+       for (i = 0; i < sizeof(label) - 1; i++) {
+               len = read(fd, buf, sizeof(buf));
+               if (len < 0) {
+                       err("Read command failed\n");
+                       goto suspend;
+               }
+
+               label[i] = buf[3];
+
+               written = write(fd, cmd2, sizeof(cmd2));
+               if (written < 0) {
+                       err("Second command failed\n");
+                       goto suspend;
+               }
+
+               usleep(5000);
+       }
+
+       err("Firmware: %s\n", label);
+
+       a1026_enabled = 0;
+
+suspend:
+       err = ioctl(fd, A1026_SUSPEND);
+       if (err < 0)
+               err("Failed to suspend audience\n");
+
+done:
+       close(fd);
+}
+
+static void a1026_wakeup(void)
+{
+       ssize_t written;
+       int fd, err;
+
+       dbg("A1026 wakeup\n");
+
+       if (a1026_enabled)
+               return;
+
+       fd = open(ES305B_DEVICE, O_RDWR, 0);
+       if (fd < 0) {
+               err("Failed to open audience device\n");
+               return;
+       }
+
+       err = ioctl(fd, A1026_ENABLE_CLOCK);
+       if (err < 0) {
+               err("Failed to enable audience clock\n");
+               goto done;
+       }
+
+       written = write(fd, es305b_no_acoustic, sizeof(es305b_no_acoustic));
+       if (written < 0)
+               err("Acoustic command failed\n");
+
+       a1026_enabled = 1;
+
+done:
+       close(fd);
+}
+
+static void a1026_suspend(void)
+{
+       int fd, err;
+
+       dbg("A1026 suspend\n");
+
+       if (!a1026_enabled)
+               return;
+
+       fd = open(ES305B_DEVICE, O_RDWR, 0);
+       if (fd < 0) {
+               err("Failed to open audience device\n");
+               return;
+       }
+
+       err = ioctl(fd, A1026_SUSPEND);
+       if (err < 0)
+               err("Failed to suspend audience\n");
+
+       a1026_enabled = 0;
+
+       close(fd);
+}
+
+static void medfield_init(void)
+{
+       a1026_init();
+
+       pcm_init();
+
+       a1026_wakeup();
+
+       usleep(50000);
+
+       /* Enable and disable voice device since otherwise it seems the
+        * first call stays silent */
+       pcm_enable(MODE_IN_CALL, DEVICE_OUT_EARPIECE);
+
+       usleep(100000);
+
+       pcm_disable();
+
+       a1026_suspend();
+}
+
+static void medfield_cleanup(void)
+{
+       pcm_disable();
+
+       a1026_suspend();
+}
+
+static void medfield_enable(int mode, uint32_t device)
+{
+       a1026_wakeup();
+
+       pcm_enable(mode, device);
+}
+
+static void medfield_disable(void)
+{
+       pcm_disable();
+
+       a1026_suspend();
+}
+
+static inline int audio_device_converter(int device)
+{
+       switch (device) {
+       case 0:
+               return DISCONNECT;
+       case CALL_SOUND_PATH_HANDSET:
+               return DEVICE_OUT_EARPIECE;
+       case CALL_SOUND_PATH_SPEAKER:
+               return DEVICE_OUT_SPEAKER;
+       default:
+               return DEVICE_OUT_EARPIECE;
+       }
+}
+
+TReturn pr3_audio_set_sound_path(TcoreHal *hal, int device)
+{
+       int devId = audio_device_converter(device);
+
+       dbg("device Id %d", devId);
+
+       if (devId == DISCONNECT)
+               medfield_disable();
+       else
+               medfield_enable(MODE_IN_CALL, devId);
+
+       return TCORE_RETURN_SUCCESS;
+}
+
+gboolean pr3_audio_init(void)
+{
+       medfield_init();
+
+       return TRUE;
+}
+
+gboolean pr3_audio_unload(void)
+{
+       medfield_cleanup();
+
+       return TRUE;
+}