Emotion: remove unused var on generic
[profile/ivi/emotion.git] / src / modules / generic / emotion_generic.c
index 0243f95..b67a78b 100644 (file)
@@ -1,14 +1,18 @@
 #ifdef HAVE_CONFIG_H
 # include "config.h"
 #endif
+
 #include <sys/mman.h>
 #include <sys/stat.h>
 #include <sys/time.h>
 #include <sys/types.h>
 #include <fcntl.h>
 #include <unistd.h>
+#include <errno.h>
+
 #include <Eina.h>
 #include <Evas.h>
+#include <Ecore.h>
 
 #include "Emotion.h"
 #include "emotion_private.h"
@@ -30,7 +34,7 @@ struct _default_players {
 };
 
 static struct _default_players players[] = {
-#ifdef EMOTION_BUILD_VLC
+#ifdef EMOTION_BUILD_GENERIC_VLC
        { "vlc", "em_generic_vlc" },
 #endif
        { NULL, NULL }
@@ -103,19 +107,19 @@ _player_send_cmd(Emotion_Generic_Video *ev, int cmd)
        ERR("invalid command to player.");
        return;
      }
-   ecore_exe_send(ev->player.exe, &cmd, sizeof(cmd));
+   if (write(ev->fd_write, &cmd, sizeof(cmd)) < 0) perror("write");
 }
 
 static void
 _player_send_int(Emotion_Generic_Video *ev, int number)
 {
-   ecore_exe_send(ev->player.exe, &number, sizeof(number));
+   if (write(ev->fd_write, &number, sizeof(number)) < 0) perror("write");
 }
 
 static void
 _player_send_float(Emotion_Generic_Video *ev, float number)
 {
-   ecore_exe_send(ev->player.exe, &number, sizeof(number));
+   if (write(ev->fd_write, &number, sizeof(number)) < 0) perror("write");
 }
 
 static void
@@ -127,8 +131,8 @@ _player_send_str(Emotion_Generic_Video *ev, const char *str, Eina_Bool stringsha
      len = eina_stringshare_strlen(str) + 1;
    else
      len = strlen(str) + 1;
-   ecore_exe_send(ev->player.exe, &len, sizeof(len));
-   ecore_exe_send(ev->player.exe, str, len);
+   if (write(ev->fd_write, &len, sizeof(len)) < 0) perror("write");
+   if (write(ev->fd_write, str, len) < 0) perror("write");
 }
 
 static Eina_Bool
@@ -140,6 +144,12 @@ _create_shm_data(Emotion_Generic_Video *ev, const char *shmname)
    Emotion_Generic_Video_Shared *vs;
 
    shmfd = shm_open(shmname, O_CREAT | O_RDWR | O_TRUNC, 0777);
+   if (shmfd == -1)
+     {
+       ERR("player: could not open shm: %s", shmname);
+       ERR("player: %s", strerror(errno));
+       return 0;
+     }
    size = 3 * (ev->w * ev->h * DEFAULTPITCH) + sizeof(*vs);
 
    npages = (int)(size / getpagesize()) + 1;
@@ -149,12 +159,13 @@ _create_shm_data(Emotion_Generic_Video *ev, const char *shmname)
      {
        ERR("error when allocating shared memory (size = %zd): "
            "%s", size, strerror(errno));
+       shm_unlink(shmname);
        return EINA_FALSE;
      }
    vs = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, shmfd, 0);
    if (vs == MAP_FAILED)
      {
-       ERR("error when mapping shared memory.\n");
+       ERR("error when mapping shared memory");
        return EINA_FALSE;
      }
 
@@ -166,7 +177,12 @@ _create_shm_data(Emotion_Generic_Video *ev, const char *shmname)
    vs->frame.player = 1;
    vs->frame.last = 2;
    vs->frame.next = 2;
-   sem_init(&vs->lock, 1, 1);
+   vs->frame_drop = 0;
+   if (!eina_semaphore_new(&vs->lock, 1))
+     {
+       ERR("can not create semaphore");
+       return EINA_FALSE;
+     }
    ev->frame.frames[0] = (unsigned char *)vs + sizeof(*vs);
    ev->frame.frames[1] = (unsigned char *)vs + sizeof(*vs) + vs->height * vs->width * vs->pitch;
    ev->frame.frames[2] = (unsigned char *)vs + sizeof(*vs) + 2 * vs->height * vs->width * vs->pitch;
@@ -181,39 +197,42 @@ _create_shm_data(Emotion_Generic_Video *ev, const char *shmname)
 static void
 _player_new_frame(Emotion_Generic_Video *ev)
 {
-   if (!ev->drop++)
-     _emotion_frame_new(ev->obj);
-}
-
-static void
-_player_file_set_done(Emotion_Generic_Video *ev)
-{
-   if (!_create_shm_data(ev, ev->shmname))
-     {
-       ERR("could not create shared memory.");
-       return;
-     }
-   _player_send_cmd(ev, EM_CMD_FILE_SET_DONE);
+   if (!ev->file_ready)
+     return;
+   _emotion_frame_new(ev->obj);
 }
 
 static void
 _file_open(Emotion_Generic_Video *ev)
 {
    INF("Opening file: %s", ev->filename);
-   ev->w = DEFAULTWIDTH;
-   ev->h = DEFAULTHEIGHT;
-   ev->ratio = (double)DEFAULTWIDTH / DEFAULTHEIGHT;
-   ev->speed = 1.0;
-   ev->len = 0;
    ev->drop = 0;
 
-   if (!ev->ready)
+   if (!ev->ready || !ev->filename)
      return;
    _player_send_cmd(ev, EM_CMD_FILE_SET);
    _player_send_str(ev, ev->filename, EINA_TRUE);
 }
 
 static void
+_player_file_set_done(Emotion_Generic_Video *ev)
+{
+   if (ev->file_changed)
+     {
+       _file_open(ev);
+       ev->file_changed = EINA_FALSE;
+       return;
+     }
+
+   if (!_create_shm_data(ev, ev->shmname))
+     {
+       ERR("could not create shared memory.");
+       return;
+     }
+   _player_send_cmd(ev, EM_CMD_FILE_SET_DONE);
+}
+
+static void
 _player_ready(Emotion_Generic_Video *ev)
 {
    INF("received: player ready.");
@@ -227,31 +246,60 @@ _player_ready(Emotion_Generic_Video *ev)
    _file_open(ev);
 }
 
-#define RCV_CMD_PARAM(src, param) \
-   memcpy(&(param), (src), sizeof((param))); \
-   (src) = (char *)(src) + sizeof((param));
+static Eina_Bool
+_player_cmd_param_read(Emotion_Generic_Video *ev, void *param, size_t size)
+{
+   ssize_t done, todo, i;
+
+   /* When a parameter must be read, we cannot make sure it will be entirely
+    * available. Thus we store the bytes that could be read in a temp buffer,
+    * and when more data is read we try to complete the buffer and finally use
+    * the read value.
+    */
+   if (!ev->cmd.tmp)
+     {
+       ev->cmd.tmp = malloc(size);
+       ev->cmd.i = 0;
+       ev->cmd.total = size;
+     }
 
-#define RCV_CMD_STR(src, buf, len) \
-   RCV_CMD_PARAM((src), (len)); \
-   memcpy((buf), (src), (len)); \
-   (src) = (char *)(src) + len;
+   todo = ev->cmd.total - ev->cmd.i;
+   i = ev->cmd.i;
+   done = read(ev->fd_read, &ev->cmd.tmp[i], todo);
 
-static int
-_player_int_read(Emotion_Generic_Video *ev __UNUSED__, void **data)
-{
-   int number;
-   memcpy(&number, *data, sizeof(number));
-   *data = (char *)(*data) + sizeof(number);
+   if (done < 0 &&  errno != EINTR && errno != EAGAIN)
+     {
+       if (ev->cmd.tmp)
+         {
+            free(ev->cmd.tmp);
+            ev->cmd.tmp = NULL;
+         }
+       ERR("problem when reading parameter from pipe.");
+       ev->cmd.type = -1;
+       return EINA_FALSE;
+     }
 
-   return number;
+   if (done == todo)
+     {
+       memcpy(param, ev->cmd.tmp, size);
+       free(ev->cmd.tmp);
+       ev->cmd.tmp = NULL;
+       return EINA_TRUE;
+     }
+
+   if (done > 0)
+     ev->cmd.i += done;
+
+   return EINA_FALSE;
 }
 
 static void
-_player_frame_resize(Emotion_Generic_Video *ev, void *line)
+_player_frame_resize(Emotion_Generic_Video *ev)
 {
    int w, h;
-   RCV_CMD_PARAM(line, w);
-   RCV_CMD_PARAM(line, h);
+
+   w = ev->cmd.param.size.width;
+   h = ev->cmd.param.size.height;
 
    INF("received frame resize: %dx%d", w, h);
    ev->w = w;
@@ -265,10 +313,9 @@ _player_frame_resize(Emotion_Generic_Video *ev, void *line)
 }
 
 static void
-_player_length_changed(Emotion_Generic_Video *ev, void *line)
+_player_length_changed(Emotion_Generic_Video *ev)
 {
-   float length;
-   RCV_CMD_PARAM(line, length);
+   float length = ev->cmd.param.f_num;
 
    INF("received length changed: %0.3f", length);
 
@@ -277,16 +324,15 @@ _player_length_changed(Emotion_Generic_Video *ev, void *line)
 }
 
 static void
-_player_position_changed(Emotion_Generic_Video *ev, void *line)
+_player_position_changed(Emotion_Generic_Video *ev)
 {
-   float position;
-   RCV_CMD_PARAM(line, position);
+   float position = ev->cmd.param.f_num;
 
    INF("received position changed: %0.3f", position);
 
    ev->pos = position;
    _emotion_video_pos_update(ev->obj, ev->pos, ev->len);
-
+/* hmmm. no _emotion_progress_set() is for "buffering" progress.
    if (ev->len == 0)
      return;
 
@@ -295,13 +341,13 @@ _player_position_changed(Emotion_Generic_Video *ev, void *line)
    snprintf(buf, sizeof(buf), "%0.1f%%", progress * 100);
 
    _emotion_progress_set(ev->obj, buf, progress);
+ */
 }
 
 static void
-_player_seekable_changed(Emotion_Generic_Video *ev, void *line)
+_player_seekable_changed(Emotion_Generic_Video *ev)
 {
-   int seekable;
-   RCV_CMD_PARAM(line, seekable);
+   int seekable = ev->cmd.param.i_num;
 
    INF("received seekable changed: %d", seekable);
 
@@ -311,74 +357,128 @@ _player_seekable_changed(Emotion_Generic_Video *ev, void *line)
 }
 
 static void
-_player_volume(Emotion_Generic_Video *ev, void *line)
+_audio_channels_free(Emotion_Generic_Video *ev)
 {
-   float vol, oldvol;
-   RCV_CMD_PARAM(line, vol);
-
-   INF("received volume: %0.3f", vol);
-
-   oldvol = ev->volume;
-   ev->volume = vol;
-   if (vol != oldvol && !ev->opening)
-     _emotion_audio_level_change(ev->obj);
+   int i;
+   for (i = 0; i < ev->audio_channels_count; i++)
+     eina_stringshare_del(ev->audio_channels[i].name);
+   free(ev->audio_channels);
+   ev->audio_channels_count = 0;
 }
 
 static void
-_player_audio_mute(Emotion_Generic_Video *ev, void *line)
+_video_channels_free(Emotion_Generic_Video *ev)
 {
-   int mute;
-   RCV_CMD_PARAM(line, mute);
-
-   INF("received audio mute: %d", mute);
-
-   ev->audio_mute = !!mute;
+   int i;
+   for (i = 0; i < ev->video_channels_count; i++)
+     eina_stringshare_del(ev->video_channels[i].name);
+   free(ev->video_channels);
+   ev->video_channels_count = 0;
 }
 
 static void
-_audio_channels_free(Emotion_Generic_Video *ev)
+_spu_channels_free(Emotion_Generic_Video *ev)
 {
    int i;
-   for (i = 0; i < ev->audio_channels_count; i++)
-     eina_stringshare_del(ev->audio_channels[i].name);
-   free(ev->audio_channels);
-   ev->audio_channels_count = 0;
+   for (i = 0; i < ev->spu_channels_count; i++)
+     eina_stringshare_del(ev->spu_channels[i].name);
+   free(ev->spu_channels);
+   ev->spu_channels_count = 0;
 }
 
 static void
-_player_audio_tracks_info(Emotion_Generic_Video *ev, void *line)
+_player_tracks_info(Emotion_Generic_Video *ev, Emotion_Generic_Channel **channels, int *count, int *current)
 {
-   int track_current, tracks_count;
+   Emotion_Generic_Channel *pchannels;
    int i;
 
-   if (ev->audio_channels_count)
-     _audio_channels_free(ev);
+   *count = ev->cmd.param.track.total;
+   *current = ev->cmd.param.track.current;
+   pchannels = ev->cmd.param.track.channels;
 
-   RCV_CMD_PARAM(line, track_current);
-   RCV_CMD_PARAM(line, tracks_count);
-   INF("video with %d audio tracks (current = %d):", tracks_count, track_current);
-   ev->audio_channels = calloc(
-      tracks_count, sizeof(Emotion_Generic_Audio_Channel));
-   ev->audio_channels_count = tracks_count;
-   ev->audio_channel_current = track_current;
-   for (i = 0; i < tracks_count; i++)
+   INF("number of tracks: %d (current = %d):", *count, *current);
+   for (i = 0; i < *count; i++)
      {
-       int tid, len;
-       char buf[PATH_MAX];
-       RCV_CMD_PARAM(line, tid);
-       RCV_CMD_STR(line, buf, len);
-       ev->audio_channels[i].id = tid;
-       ev->audio_channels[i].name = eina_stringshare_add_length(buf, len);
-       INF("\t%d: %s", tid, buf);
+       INF("\tchannel %d: %s", pchannels[i].id, pchannels[i].name);
      }
+
+   *channels = pchannels;
+}
+
+static void
+_player_audio_tracks_info(Emotion_Generic_Video *ev)
+{
+   INF("Receiving audio channels:");
+   if (ev->audio_channels_count)
+     _audio_channels_free(ev);
+
+   _player_tracks_info(ev, &ev->audio_channels, &ev->audio_channels_count,
+                      &ev->audio_channel_current);
+}
+
+static void
+_player_video_tracks_info(Emotion_Generic_Video *ev)
+{
+   INF("Receiving video channels:");
+   if (ev->video_channels_count)
+     _video_channels_free(ev);
+
+   _player_tracks_info(ev, &ev->video_channels, &ev->video_channels_count,
+                      &ev->video_channel_current);
+}
+
+static void
+_player_spu_tracks_info(Emotion_Generic_Video *ev)
+{
+   INF("Receiving spu channels:");
+   if (ev->spu_channels_count)
+     _spu_channels_free(ev);
+
+   _player_tracks_info(ev, &ev->spu_channels, &ev->spu_channels_count,
+                      &ev->spu_channel_current);
+}
+
+static void
+_player_meta_info_free(Emotion_Generic_Video *ev)
+{
+   eina_stringshare_replace(&ev->meta.title, NULL);
+   eina_stringshare_replace(&ev->meta.artist, NULL);
+   eina_stringshare_replace(&ev->meta.album, NULL);
+   eina_stringshare_replace(&ev->meta.year, NULL);
+   eina_stringshare_replace(&ev->meta.genre, NULL);
+   eina_stringshare_replace(&ev->meta.comment, NULL);
+   eina_stringshare_replace(&ev->meta.disc_id, NULL);
+   eina_stringshare_replace(&ev->meta.count, NULL);
+}
+
+static void
+_player_meta_info_read(Emotion_Generic_Video *ev)
+{
+   INF("Receiving meta info:");
+   _player_meta_info_free(ev);
+   ev->meta.title = ev->cmd.param.meta.title;
+   ev->meta.artist = ev->cmd.param.meta.artist;
+   ev->meta.album = ev->cmd.param.meta.album;
+   ev->meta.year = ev->cmd.param.meta.year;
+   ev->meta.genre = ev->cmd.param.meta.genre;
+   ev->meta.comment = ev->cmd.param.meta.comment;
+   ev->meta.disc_id = ev->cmd.param.meta.disc_id;
+   ev->meta.count = ev->cmd.param.meta.count;
+   INF("title: '%s'", ev->meta.title);
+   INF("artist: '%s'", ev->meta.artist);
+   INF("album: '%s'", ev->meta.album);
+   INF("year: '%s'", ev->meta.year);
+   INF("genre: '%s'", ev->meta.genre);
+   INF("comment: '%s'", ev->meta.comment);
+   INF("disc_id: '%s'", ev->meta.disc_id);
+   INF("count: '%s'", ev->meta.count);
 }
 
 static void
 _player_file_closed(Emotion_Generic_Video *ev)
 {
    INF("Closed previous file.");
-   sem_destroy(&ev->shared->lock);
-
+   eina_semaphore_free(&ev->shared->lock);
    ev->closing = EINA_FALSE;
 
    if (ev->opening)
@@ -388,8 +488,27 @@ _player_file_closed(Emotion_Generic_Video *ev)
 static void
 _player_open_done(Emotion_Generic_Video *ev)
 {
-   ev->opening = EINA_FALSE;
+   int success;
+
+   success = ev->cmd.param.i_num;
    shm_unlink(ev->shmname);
+
+   if (ev->file_changed)
+     {
+       _file_open(ev);
+       ev->file_changed = EINA_FALSE;
+       return;
+     }
+
+   ev->opening = EINA_FALSE;
+   if (!success)
+     {
+       ERR("Could not open file.");
+       return;
+     }
+
+   ev->file_ready = EINA_TRUE;
+
    _emotion_open_done(ev->obj);
 
    if (ev->play)
@@ -398,16 +517,31 @@ _player_open_done(Emotion_Generic_Video *ev)
        _player_send_float(ev, ev->pos);
      }
 
+   _player_send_cmd(ev, EM_CMD_VOLUME_SET);
+   _player_send_float(ev, ev->volume);
+
+   _player_send_cmd(ev, EM_CMD_SPEED_SET);
+   _player_send_float(ev, ev->speed);
+
+   int mute = ev->audio_mute;
+   _player_send_cmd(ev, EM_CMD_AUDIO_MUTE_SET);
+   _player_send_int(ev, mute);
+
+   mute = ev->video_mute;
+   _player_send_cmd(ev, EM_CMD_VIDEO_MUTE_SET);
+   _player_send_int(ev, mute);
+
+   mute = ev->spu_mute;
+   _player_send_cmd(ev, EM_CMD_SPU_MUTE_SET);
+   _player_send_int(ev, mute);
+
    INF("Open done");
 }
 
 static void
-_player_read_cmd(Emotion_Generic_Video *ev, void *line, int size __UNUSED__)
+_player_cmd_process(Emotion_Generic_Video *ev)
 {
-   int type;
-   RCV_CMD_PARAM(line, type);
-
-   switch (type) {
+   switch (ev->cmd.type) {
       case EM_RESULT_INIT:
         _player_ready(ev);
         break;
@@ -427,26 +561,265 @@ _player_read_cmd(Emotion_Generic_Video *ev, void *line, int size __UNUSED__)
         _emotion_playback_finished(ev->obj);
         break;
       case EM_RESULT_FRAME_SIZE:
-        _player_frame_resize(ev, line);
+        _player_frame_resize(ev);
         break;
       case EM_RESULT_LENGTH_CHANGED:
-        _player_length_changed(ev, line);
+        _player_length_changed(ev);
         break;
       case EM_RESULT_POSITION_CHANGED:
-        _player_position_changed(ev, line);
+        _player_position_changed(ev);
         break;
       case EM_RESULT_SEEKABLE_CHANGED:
-        _player_seekable_changed(ev, line);
+        _player_seekable_changed(ev);
         break;
       case EM_RESULT_AUDIO_TRACK_INFO:
-        _player_audio_tracks_info(ev, line);
+        _player_audio_tracks_info(ev);
+        break;
+      case EM_RESULT_VIDEO_TRACK_INFO:
+        _player_video_tracks_info(ev);
+        break;
+      case EM_RESULT_SPU_TRACK_INFO:
+        _player_spu_tracks_info(ev);
+        break;
+      case EM_RESULT_META_INFO:
+        _player_meta_info_read(ev);
         break;
       default:
-        WRN("received wrong command: %d", type);
-   };
+        WRN("received wrong command: %d", ev->cmd.type);
+   }
+
+   ev->cmd.type = -1;
+}
+
+static void
+_player_cmd_single_int_process(Emotion_Generic_Video *ev)
+{
+   if (!_player_cmd_param_read(ev, &ev->cmd.param.i_num, sizeof(ev->cmd.param.i_num)))
+     return;
+
+   _player_cmd_process(ev);
+}
+
+static void
+_player_cmd_single_float_process(Emotion_Generic_Video *ev)
+{
+   if (!_player_cmd_param_read(ev, &ev->cmd.param.f_num, sizeof(ev->cmd.param.f_num)))
+     return;
+
+   _player_cmd_process(ev);
 }
 
-#undef RCV_CMD_PARAM
+static void
+_player_cmd_double_int_process(Emotion_Generic_Video *ev)
+{
+   int param;
+
+   if (ev->cmd.num_params == 0)
+     {
+       ev->cmd.num_params = 2;
+       ev->cmd.cur_param = 0;
+       ev->cmd.param.size.width = 0;
+       ev->cmd.param.size.height = 0;
+     }
+
+   if (!_player_cmd_param_read(ev, &param, sizeof(param)))
+     return;
+
+   if (ev->cmd.cur_param == 0)
+     ev->cmd.param.size.width = param;
+   else
+     ev->cmd.param.size.height = param;
+
+   ev->cmd.cur_param++;
+   if (ev->cmd.cur_param == ev->cmd.num_params)
+     _player_cmd_process(ev);
+}
+
+static void
+_player_cmd_track_info(Emotion_Generic_Video *ev)
+{
+   int param;
+   int i;
+
+   if (ev->cmd.num_params == 0)
+     {
+       ev->cmd.cur_param = 0;
+       ev->cmd.num_params = 2;
+       ev->cmd.param.track.channels = NULL;
+       ev->cmd.s_len = -1;
+     }
+
+   while (ev->cmd.cur_param < 2)
+     {
+       if (!_player_cmd_param_read(ev, &param, sizeof(param)))
+         return;
+
+       if (ev->cmd.cur_param == 0)
+         ev->cmd.param.track.current = param;
+       else
+         {
+            ev->cmd.param.track.total = param;
+            ev->cmd.num_params += param * 2;
+            ev->cmd.param.track.channels =
+               calloc(param, sizeof(*ev->cmd.param.track.channels));
+         }
+       ev->cmd.cur_param++;
+     }
+
+   if (ev->cmd.cur_param == ev->cmd.num_params)
+     {
+       _player_cmd_process(ev);
+       return;
+     }
+
+   i = (ev->cmd.cur_param - 2) / 2;
+   if ((ev->cmd.cur_param % 2) == 0) // reading track id
+     {
+       if (!_player_cmd_param_read(ev, &param, sizeof(param)))
+         return;
+       ev->cmd.param.track.channels[i].id = param;
+       ev->cmd.cur_param++;
+     }
+   else // reading track name
+     {
+       char buf[PATH_MAX];
+
+       if (ev->cmd.s_len == -1)
+         {
+            if (!_player_cmd_param_read(ev, &param, sizeof(param)))
+              return;
+            ev->cmd.s_len = param;
+         }
+
+       if (!_player_cmd_param_read(ev, buf, ev->cmd.s_len))
+         return;
+       ev->cmd.param.track.channels[i].name = 
+          eina_stringshare_add_length(buf, ev->cmd.s_len);
+       ev->cmd.cur_param++;
+       ev->cmd.s_len = -1;
+     }
+
+   if (ev->cmd.cur_param == ev->cmd.num_params)
+     _player_cmd_process(ev);
+}
+
+static void
+_player_cmd_meta_info(Emotion_Generic_Video *ev)
+{
+   int param;
+   const char *info;
+   char buf[PATH_MAX];
+
+   if (ev->cmd.num_params == 0)
+     {
+       ev->cmd.cur_param = 0;
+       ev->cmd.num_params = 8;
+       ev->cmd.param.meta.title = NULL;
+       ev->cmd.param.meta.artist = NULL;
+       ev->cmd.param.meta.album = NULL;
+       ev->cmd.param.meta.year = NULL;
+       ev->cmd.param.meta.genre = NULL;
+       ev->cmd.param.meta.comment = NULL;
+       ev->cmd.param.meta.disc_id = NULL;
+       ev->cmd.param.meta.count = NULL;
+       ev->cmd.s_len = -1;
+     }
+
+   if (ev->cmd.s_len == -1)
+     {
+       if (!_player_cmd_param_read(ev, &param, sizeof(param)))
+         return;
+       ev->cmd.s_len = param;
+     }
+
+   if (!_player_cmd_param_read(ev, buf, ev->cmd.s_len))
+     return;
+
+   info = eina_stringshare_add_length(buf, ev->cmd.s_len);
+   ev->cmd.s_len = -1;
+
+   if (ev->cmd.cur_param == 0)
+     ev->cmd.param.meta.title = info;
+   else if (ev->cmd.cur_param == 1)
+     ev->cmd.param.meta.artist = info;
+   else if (ev->cmd.cur_param == 2)
+     ev->cmd.param.meta.album = info;
+   else if (ev->cmd.cur_param == 3)
+     ev->cmd.param.meta.year = info;
+   else if (ev->cmd.cur_param == 4)
+     ev->cmd.param.meta.genre = info;
+   else if (ev->cmd.cur_param == 5)
+     ev->cmd.param.meta.comment = info;
+   else if (ev->cmd.cur_param == 6)
+     ev->cmd.param.meta.disc_id = info;
+   else if (ev->cmd.cur_param == 7)
+     ev->cmd.param.meta.count = info;
+
+   ev->cmd.cur_param++;
+
+   if (ev->cmd.cur_param == 8)
+     _player_cmd_process(ev);
+}
+
+static void
+_player_cmd_read(Emotion_Generic_Video *ev)
+{
+   if (ev->cmd.type < 0)
+     {
+       if (!_player_cmd_param_read(ev, &ev->cmd.type, sizeof(ev->cmd.type)))
+         return;
+       ev->cmd.num_params = 0;
+     }
+
+   switch (ev->cmd.type) {
+      case EM_RESULT_INIT:
+      case EM_RESULT_FILE_SET:
+      case EM_RESULT_PLAYBACK_STOPPED:
+      case EM_RESULT_FILE_CLOSE:
+      case EM_RESULT_FRAME_NEW:
+        _player_cmd_process(ev);
+        break;
+      case EM_RESULT_FILE_SET_DONE:
+      case EM_RESULT_SEEKABLE_CHANGED:
+        _player_cmd_single_int_process(ev);
+        break;
+      case EM_RESULT_LENGTH_CHANGED:
+      case EM_RESULT_POSITION_CHANGED:
+        _player_cmd_single_float_process(ev);
+        break;
+      case EM_RESULT_FRAME_SIZE:
+        _player_cmd_double_int_process(ev);
+        break;
+      case EM_RESULT_AUDIO_TRACK_INFO:
+      case EM_RESULT_VIDEO_TRACK_INFO:
+      case EM_RESULT_SPU_TRACK_INFO:
+        _player_cmd_track_info(ev);
+        break;
+      case EM_RESULT_META_INFO:
+        _player_cmd_meta_info(ev);
+        break;
+
+      default:
+        WRN("received wrong command: %d", ev->cmd.type);
+        ev->cmd.type = -1;
+   }
+}
+
+static Eina_Bool
+_player_cmd_handler_cb(void *data, Ecore_Fd_Handler *fd_handler)
+{
+   Emotion_Generic_Video *ev = data;
+
+   if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_ERROR))
+     {
+       ERR("an error occurred on fd_read %d.", ev->fd_read);
+       return ECORE_CALLBACK_CANCEL;
+     }
+
+   _player_cmd_read(ev);
+
+   return ECORE_CALLBACK_RENEW;
+}
 
 static Eina_Bool
 _player_data_cb(void *data, int type __UNUSED__, void *event)
@@ -461,14 +834,8 @@ _player_data_cb(void *data, int type __UNUSED__, void *event)
        return ECORE_CALLBACK_DONE;
      }
 
-   if (ev->size < 4)
-     {
-       ERR("invalid command: missing bytes.");
-       return ECORE_CALLBACK_DONE;
-     }
-
    for (i = 0; ev->lines[i].line; i++)
-     _player_read_cmd(evideo, ev->lines[i].line, ev->lines[i].size);
+     INF("received input from player: \"%s\"", ev->lines[i].line);
 
    return ECORE_CALLBACK_DONE;
 }
@@ -500,12 +867,70 @@ _player_del_cb(void *data, int type __UNUSED__, void *event __UNUSED__)
 
    ev->player.exe = NULL;
    ev->ready = EINA_FALSE;
+   ev->file_ready = EINA_FALSE;
+   ecore_main_fd_handler_del(ev->fd_handler);
+   close(ev->fd_read);
+   close(ev->fd_write);
+   ev->fd_read = -1;
+   ev->fd_write = -1;
    _emotion_decode_stop(ev->obj);
 
    return ECORE_CALLBACK_DONE;
 }
 
 static Eina_Bool
+_player_exec(Emotion_Generic_Video *ev)
+{
+   int pipe_out[2];
+   int pipe_in[2];
+   char buf[PATH_MAX];
+
+   if (pipe(pipe_out) == -1)
+     {
+       ERR("could not create pipe for communication emotion -> player: %s", strerror(errno));
+       return EINA_FALSE;
+     }
+
+   if (pipe(pipe_in) == -1)
+     {
+       ERR("could not create pipe for communication player -> emotion: %s", strerror(errno));
+       close(pipe_out[0]);
+       close(pipe_out[1]);
+       return EINA_FALSE;
+     }
+
+   snprintf(buf, sizeof(buf), "%s %d %d\n", ev->cmdline, pipe_out[0], pipe_in[1]);
+
+   ev->player.exe = ecore_exe_pipe_run(
+      buf,
+      ECORE_EXE_PIPE_READ | ECORE_EXE_PIPE_WRITE |
+      ECORE_EXE_PIPE_READ_LINE_BUFFERED | ECORE_EXE_NOT_LEADER,
+      ev);
+
+   INF("created pipe emotion -> player: %d -> %d", pipe_out[1], pipe_out[0]);
+   INF("created pipe player -> emotion: %d -> %d", pipe_in[1], pipe_in[0]);
+
+   close(pipe_in[1]);
+   close(pipe_out[0]);
+
+   if (!ev->player.exe)
+     {
+       close(pipe_in[0]);
+       close(pipe_out[1]);
+       return EINA_FALSE;
+     }
+
+   ev->fd_read = pipe_in[0];
+   ev->fd_write = pipe_out[1];
+
+   ev->fd_handler = ecore_main_fd_handler_add(
+      ev->fd_read, ECORE_FD_READ | ECORE_FD_ERROR, _player_cmd_handler_cb, ev,
+      NULL, NULL);
+
+   return EINA_TRUE;
+}
+
+static Eina_Bool
 _fork_and_exec(Evas_Object *obj __UNUSED__, Emotion_Generic_Video *ev)
 {
    char shmname[256];
@@ -524,13 +949,8 @@ _fork_and_exec(Evas_Object *obj __UNUSED__, Emotion_Generic_Video *ev)
    ev->player_data = ecore_event_handler_add(
       ECORE_EXE_EVENT_DATA, _player_data_cb, ev);
 
-   ev->player.exe = ecore_exe_pipe_run(
-      ev->cmdline,
-      ECORE_EXE_PIPE_READ | ECORE_EXE_PIPE_WRITE |
-      ECORE_EXE_PIPE_READ_LINE_BUFFERED | ECORE_EXE_NOT_LEADER,
-      ev);
 
-   if (!ev->player.exe)
+   if (!_player_exec(ev))
      {
         ERR("could not start player.");
         return EINA_FALSE;
@@ -554,9 +974,12 @@ em_init(Evas_Object *obj, void **emotion_video, Emotion_Module_Options *opt)
    ev = (Emotion_Generic_Video *)calloc(1, sizeof(*ev));
    if (!ev) return 0;
 
+   ev->fd_read = -1;
+   ev->fd_write = -1;
    ev->speed = 1.0;
    ev->volume = 0.5;
    ev->audio_mute = EINA_FALSE;
+   ev->cmd.type = -1;
 
    ev->obj = obj;
    ev->cmdline = eina_stringshare_add(player);
@@ -582,7 +1005,12 @@ em_shutdown(void *data)
    if (ev->shared)
      munmap(ev->shared, ev->shared->size);
 
-   _audio_channels_free(ev);
+   if (ev->fd_read >= 0)
+     close(ev->fd_read);
+   if (ev->fd_write >= 0)
+     close(ev->fd_write);
+   if (ev->fd_handler)
+     ecore_main_fd_handler_del(ev->fd_handler);
 
    eina_stringshare_del(ev->cmdline);
    eina_stringshare_del(ev->shmname);
@@ -601,10 +1029,22 @@ em_file_open(const char *file, Evas_Object *obj __UNUSED__, void *data)
    INF("file set: %s", file);
    if (!ev) return 0;
 
+   eina_stringshare_replace(&ev->filename, file);
+
    ev->pos = 0;
-   ev->opening = EINA_TRUE;
+   ev->w = 0;
+   ev->h = 0;
+   ev->ratio = 1;
+   ev->len = 0;
 
-   eina_stringshare_replace(&ev->filename, file);
+   if (ev->ready && ev->opening)
+     {
+       INF("file changed while opening.");
+       ev->file_changed = EINA_TRUE;
+       return 1;
+     }
+
+   ev->opening = EINA_TRUE;
 
    if (!ev->closing)
      _file_open(ev);
@@ -617,10 +1057,19 @@ em_file_close(void *data)
 {
    Emotion_Generic_Video *ev = data;
 
-   if (!ev) return;
+   if (!ev || !ev->filename) return;
+
    INF("file close: %s", ev->filename);
 
-   if (!ev->filename)
+   eina_stringshare_replace(&ev->filename, NULL);
+
+   ev->file_ready = EINA_FALSE;
+   _audio_channels_free(ev);
+   _video_channels_free(ev);
+   _spu_channels_free(ev);
+   _player_meta_info_free(ev);
+
+   if (ev->opening)
      return;
 
    _player_send_cmd(ev, EM_CMD_FILE_CLOSE);
@@ -664,13 +1113,7 @@ em_play(void *data, double pos)
        return;
      }
 
-   ev->player.exe = ecore_exe_pipe_run(
-      ev->cmdline,
-      ECORE_EXE_PIPE_READ | ECORE_EXE_PIPE_WRITE |
-      ECORE_EXE_PIPE_READ_LINE_BUFFERED | ECORE_EXE_NOT_LEADER,
-      ev);
-
-   if (!ev->player.exe)
+   if (!_player_exec(ev))
      ERR("could not start player.");
 }
 
@@ -684,7 +1127,7 @@ em_stop(void *data)
 
    ev->play = EINA_FALSE;
 
-   if (!ev->ready)
+   if (!ev->file_ready)
      return;
 
    _player_send_cmd(ev, EM_CMD_STOP);
@@ -695,8 +1138,8 @@ static void
 em_size_get(void *data, int *w, int *h)
 {
    Emotion_Generic_Video *ev = data;
-   if(w) *w = ev->w;
-   if(h) *h = ev->h;
+   if (w) *w = ev->w;
+   if (h) *h = ev->h;
 }
 
 static void
@@ -704,6 +1147,10 @@ em_pos_set(void *data, double pos)
 {
    Emotion_Generic_Video *ev = data;
    float position = pos;
+
+   if (!ev->file_ready)
+     return;
+
    _player_send_cmd(ev, EM_CMD_POSITION_SET);
    _player_send_float(ev, position);
    _emotion_seek_done(ev->obj);
@@ -716,6 +1163,12 @@ em_len_get(void *data)
    return ev->len;
 }
 
+static double
+em_buffer_size_get(void *data __UNUSED__)
+{
+   return 1.0;
+}
+
 static int
 em_fps_num_get(void *data)
 {
@@ -801,11 +1254,12 @@ em_bgra_data_get(void *data, unsigned char **bgra_data)
 {
    Emotion_Generic_Video *ev = data;
 
-   if (!ev || ev->opening || ev->closing)
+   if (!ev || !ev->file_ready)
      return 0;
 
    // lock frame here
-   sem_wait(&ev->shared->lock);
+   if (!eina_semaphore_lock(&ev->shared->lock))
+     return 0;
 
    // send current frame to emotion
    if (ev->shared->frame.emotion != ev->shared->frame.last)
@@ -815,8 +1269,12 @@ em_bgra_data_get(void *data, unsigned char **bgra_data)
      }
    *bgra_data = ev->frame.frames[ev->shared->frame.emotion];
 
+   if (ev->shared->frame_drop > 1)
+     WRN("dropped frames: %d", ev->shared->frame_drop - 1);
+   ev->shared->frame_drop = 0;
+
    // unlock frame here
-   sem_post(&ev->shared->lock);
+   eina_semaphore_release(&ev->shared->lock, 1);
    ev->drop = 0;
 
    return 1;
@@ -838,32 +1296,61 @@ em_event_mouse_move_feed(void *ef __UNUSED__, int x __UNUSED__, int y __UNUSED__
 }
 
 static int
-em_video_channel_count(void *ef __UNUSED__)
+em_video_channel_count(void *data)
 {
-   int ret  = 0;
-   return ret;
+   Emotion_Generic_Video *ev = data;
+   return ev->video_channels_count;
 }
 
 static void
-em_video_channel_set(void *ef __UNUSED__, int channel __UNUSED__)
+em_video_channel_set(void *data, int channel)
 {
+   Emotion_Generic_Video *ev = data;
+
+   if (channel < 0 || channel >= ev->video_channels_count)
+     {
+       WRN("video channel out of range.");
+       return;
+     }
+
+   _player_send_cmd(ev, EM_CMD_VIDEO_TRACK_SET);
+   _player_send_int(ev, ev->video_channels[channel].id);
+   ev->video_channel_current = channel;
 }
 
 static int
-em_video_channel_get(void *ef __UNUSED__)
+em_video_channel_get(void *data)
 {
-   return 1;
+   Emotion_Generic_Video *ev = data;
+   return ev->video_channel_current;
 }
 
 static const char *
-em_video_channel_name_get(void *ef __UNUSED__, int channel __UNUSED__)
+em_video_channel_name_get(void *data, int channel)
 {
-   return NULL;
+   Emotion_Generic_Video *ev = data;
+
+   if (channel < 0 || channel >= ev->video_channels_count)
+     {
+       WRN("video channel out of range.");
+       return NULL;
+     }
+
+   return ev->video_channels[channel].name;
 }
 
 static void
-em_video_channel_mute_set(void *ef __UNUSED__, int mute __UNUSED__)
+em_video_channel_mute_set(void *data, int mute)
 {
+   Emotion_Generic_Video *ev = data;
+
+   ev->video_mute = !!mute;
+
+   if (!ev || !ev->file_ready)
+     return;
+
+   _player_send_cmd(ev, EM_CMD_VIDEO_MUTE_SET);
+   _player_send_int(ev, mute);
 }
 
 static int
@@ -884,17 +1371,16 @@ static void
 em_audio_channel_set(void *data, int channel)
 {
    Emotion_Generic_Video *ev = data;
-   int i;
 
-   for (i = 0; i < ev->audio_channels_count; i++)
+   if (channel < 0 || channel >= ev->audio_channels_count)
      {
-       if (ev->audio_channels[i].id == channel)
-         {
-            _player_send_cmd(ev, EM_CMD_AUDIO_TRACK_SET);
-            _player_send_int(ev, channel);
-            break;
-         }
+       WRN("audio channel out of range.");
+       return;
      }
+
+   _player_send_cmd(ev, EM_CMD_AUDIO_TRACK_SET);
+   _player_send_int(ev, ev->audio_channels[channel].id);
+   ev->audio_channel_current = channel;
 }
 
 static int
@@ -908,24 +1394,28 @@ static const char *
 em_audio_channel_name_get(void *data, int channel)
 {
    Emotion_Generic_Video *ev = data;
-   int i;
 
-   for (i = 0; i < ev->audio_channels_count; i++)
+   if (channel < 0 || channel >= ev->audio_channels_count)
      {
-       if (ev->audio_channels[i].id == channel)
-         return ev->audio_channels[i].name;
+       WRN("audio channel out of range.");
+       return NULL;
      }
 
-   return NULL;
+   return ev->audio_channels[channel].name;
 }
 
 static void
 em_audio_channel_mute_set(void *data, int mute)
 {
    Emotion_Generic_Video *ev = data;
+
+   ev->audio_mute = !!mute;
+
+   if (!ev || !ev->file_ready)
+     return;
+
    _player_send_cmd(ev, EM_CMD_AUDIO_MUTE_SET);
    _player_send_int(ev, mute);
-   ev->audio_mute = !!mute;
 }
 
 static int
@@ -939,16 +1429,17 @@ static void
 em_audio_channel_volume_set(void *data, double vol)
 {
    Emotion_Generic_Video *ev = data;
-   float fvol;
 
    if (vol > 1.0) vol = 1.0;
    if (vol < 0.0) vol = 0.0;
 
-   fvol = vol;
-   _player_send_cmd(ev, EM_CMD_VOLUME_SET);
-   _player_send_float(ev, fvol);
-
    ev->volume = vol;
+
+   if (!ev || !ev->file_ready)
+     return;
+
+   _player_send_cmd(ev, EM_CMD_VOLUME_SET);
+   _player_send_float(ev, ev->volume);
 }
 
 static double
@@ -959,39 +1450,68 @@ em_audio_channel_volume_get(void *data)
 }
 
 static int
-em_spu_channel_count(void *ef __UNUSED__)
+em_spu_channel_count(void *data)
 {
-   return 0;
+   Emotion_Generic_Video *ev = data;
+   return ev->spu_channels_count;
 }
 
 static void
-em_spu_channel_set(void *ef __UNUSED__, int channel __UNUSED__)
+em_spu_channel_set(void *data, int channel)
 {
+   Emotion_Generic_Video *ev = data;
+
+   if (channel < 0 || channel >= ev->spu_channels_count)
+     {
+       WRN("spu channel out of range.");
+       return;
+     }
+
+   _player_send_cmd(ev, EM_CMD_SPU_TRACK_SET);
+   _player_send_int(ev, ev->spu_channels[channel].id);
+   ev->spu_channel_current = channel;
 }
 
 static int
-em_spu_channel_get(void *ef __UNUSED__)
+em_spu_channel_get(void *data)
 {
-   int num = 0;
-   return num;
+   Emotion_Generic_Video *ev = data;
+   return ev->spu_channel_current;
 }
 
 static const char *
-em_spu_channel_name_get(void *ef __UNUSED__, int channel __UNUSED__)
+em_spu_channel_name_get(void *data, int channel)
 {
-   return NULL;
+   Emotion_Generic_Video *ev = data;
+
+   if (channel < 0 || channel >= ev->spu_channels_count)
+     {
+       WRN("spu channel out of range.");
+       return NULL;
+     }
+
+   return ev->spu_channels[channel].name;
 }
 
 static void
-em_spu_channel_mute_set(void *ef __UNUSED__, int mute __UNUSED__)
+em_spu_channel_mute_set(void *data, int mute)
 {
-   return;
+   Emotion_Generic_Video *ev = data;
+
+   ev->spu_mute = !!mute;
+
+   if (!ev || !ev->file_ready)
+     return;
+
+   _player_send_cmd(ev, EM_CMD_SPU_MUTE_SET);
+   _player_send_int(ev, mute);
 }
 
 static int
-em_spu_channel_mute_get(void *ef __UNUSED__)
+em_spu_channel_mute_get(void *data)
 {
-   return 0;
+   Emotion_Generic_Video *ev = data;
+   return ev->spu_mute;
 }
 
 static int
@@ -1024,11 +1544,13 @@ em_speed_set(void *data, double speed)
 {
    Emotion_Generic_Video *ev = data;
    float rate = speed;
+   ev->speed = rate;
+
+   if (!ev || !ev->file_ready)
+     return;
 
    _player_send_cmd(ev, EM_CMD_SPEED_SET);
    _player_send_float(ev, rate);
-
-   ev->speed = rate;
 }
 
 static double
@@ -1045,10 +1567,30 @@ em_eject(void *ef __UNUSED__)
 }
 
 static const char *
-em_meta_get(void *ef __UNUSED__, int meta __UNUSED__)
+em_meta_get(void *data, int meta)
 {
-   char * meta_data = NULL;
-   return meta_data;
+   Emotion_Generic_Video *ev = data;
+
+   switch (meta) {
+      case EMOTION_META_INFO_TRACK_TITLE:
+        return ev->meta.title;
+      case EMOTION_META_INFO_TRACK_ARTIST:
+        return ev->meta.artist;
+      case EMOTION_META_INFO_TRACK_ALBUM:
+        return ev->meta.album;
+      case EMOTION_META_INFO_TRACK_YEAR:
+        return ev->meta.year;
+      case EMOTION_META_INFO_TRACK_GENRE:
+        return ev->meta.genre;
+      case EMOTION_META_INFO_TRACK_COMMENT:
+        return ev->meta.comment;
+      case EMOTION_META_INFO_TRACK_DISC_ID:
+        return ev->meta.disc_id;
+      case EMOTION_META_INFO_TRACK_COUNT:
+        return ev->meta.count;
+   }
+
+   return NULL;
 }
 
 static Emotion_Video_Module em_module =
@@ -1062,6 +1604,7 @@ static Emotion_Video_Module em_module =
    em_size_get, /* size_get */
    em_pos_set, /* pos_set */
    em_len_get, /* len_get */
+   em_buffer_size_get, /* buffer_size_get */
    em_fps_num_get, /* fps_num_get */
    em_fps_den_get, /* fps_den_get */
    em_fps_get, /* fps_get */
@@ -1109,6 +1652,8 @@ static Emotion_Video_Module em_module =
    em_speed_get, /* speed_get */
    em_eject, /* eject */
    em_meta_get, /* meta_get */
+   NULL, /* priority_set */
+   NULL, /* priority_get */
    NULL /* handle */
 };
 
@@ -1148,7 +1693,7 @@ static void module_close(Emotion_Video_Module *module __UNUSED__, void *video)
 }
 
 
-static Eina_Bool
+Eina_Bool
 generic_module_init(void)
 {
    if (!pfx)