Emotion: remove unused var on generic
[profile/ivi/emotion.git] / src / modules / generic / emotion_generic.c
index c0dfe89..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"
@@ -103,19 +107,19 @@ _player_send_cmd(Emotion_Generic_Video *ev, int cmd)
        ERR("invalid command to player.");
        return;
      }
-   write(ev->fd_write, &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)
 {
-   write(ev->fd_write, &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)
 {
-   write(ev->fd_write, &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;
-   write(ev->fd_write, &len, sizeof(len));
-   write(ev->fd_write, 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
@@ -161,7 +165,7 @@ _create_shm_data(Emotion_Generic_Video *ev, const char *shmname)
    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;
      }
 
@@ -173,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;
@@ -188,22 +197,18 @@ _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);
+   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);
@@ -241,94 +246,60 @@ _player_ready(Emotion_Generic_Video *ev)
    _file_open(ev);
 }
 
-static int
-_em_read_safe(int fd, void *buf, ssize_t size)
+static Eina_Bool
+_player_cmd_param_read(Emotion_Generic_Video *ev, void *param, size_t size)
 {
-   ssize_t todo;
-   char *p;
+   ssize_t done, todo, i;
 
-   todo = size;
-   p = buf;
-
-   while (todo > 0)
+   /* 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)
      {
-        ssize_t r;
-
-        r = read(fd, p, todo);
-        if (r > 0)
-          {
-             todo -= r;
-             p += r;
-          }
-        else if (r == 0)
-          return 0;
-        else
-          {
-             if (errno == EINTR || errno == EAGAIN)
-               continue;
-             else
-               {
-                  ERR("could not read from fd %d: %s", fd, strerror(errno));
-                  return 0;
-               }
-          }
+       ev->cmd.tmp = malloc(size);
+       ev->cmd.i = 0;
+       ev->cmd.total = size;
      }
 
-   return 1;
-}
+   todo = ev->cmd.total - ev->cmd.i;
+   i = ev->cmd.i;
+   done = read(ev->fd_read, &ev->cmd.tmp[i], todo);
 
-static Eina_Bool
-_player_int_read(Emotion_Generic_Video *ev, int *i)
-{
-   int n;
-   n = _em_read_safe(ev->fd_read, i, sizeof(*i));
-   if (n <= 0)
+   if (done < 0 &&  errno != EINTR && errno != EAGAIN)
      {
-       ERR("could not read int from fd_read %d\n", ev->fd_read);
+       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 EINA_TRUE;
-}
-
-static Eina_Bool
-_player_float_read(Emotion_Generic_Video *ev, float *f)
-{
-   int n;
-   n = _em_read_safe(ev->fd_read, f, sizeof(*f));
-   if (n <= 0)
+   if (done == todo)
      {
-       ERR("could not read float from fd_read %d\n", ev->fd_read);
-       return EINA_FALSE;
+       memcpy(param, ev->cmd.tmp, size);
+       free(ev->cmd.tmp);
+       ev->cmd.tmp = NULL;
+       return EINA_TRUE;
      }
 
-   return EINA_TRUE;
-}
-
-static Eina_Bool
-_player_str_read(Emotion_Generic_Video *ev, char *str, int *len)
-{
-   int n;
-
-   if (!_player_int_read(ev, len))
-     return EINA_FALSE;
+   if (done > 0)
+     ev->cmd.i += done;
 
-   n = _em_read_safe(ev->fd_read, str, *len);
-   if (n <= 0)
-     {
-       ERR("could not read string from fd_read %d\n", ev->fd_read);
-       return EINA_FALSE;
-     }
-
-   return EINA_TRUE;
+   return EINA_FALSE;
 }
 
 static void
 _player_frame_resize(Emotion_Generic_Video *ev)
 {
    int w, h;
-   _player_int_read(ev, &w);
-   _player_int_read(ev, &h);
+
+   w = ev->cmd.param.size.width;
+   h = ev->cmd.param.size.height;
 
    INF("received frame resize: %dx%d", w, h);
    ev->w = w;
@@ -344,8 +315,7 @@ _player_frame_resize(Emotion_Generic_Video *ev)
 static void
 _player_length_changed(Emotion_Generic_Video *ev)
 {
-   float length;
-   _player_float_read(ev, &length);
+   float length = ev->cmd.param.f_num;
 
    INF("received length changed: %0.3f", length);
 
@@ -356,14 +326,13 @@ _player_length_changed(Emotion_Generic_Video *ev)
 static void
 _player_position_changed(Emotion_Generic_Video *ev)
 {
-   float position;
-   _player_float_read(ev, &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;
 
@@ -372,13 +341,13 @@ _player_position_changed(Emotion_Generic_Video *ev)
    snprintf(buf, sizeof(buf), "%0.1f%%", progress * 100);
 
    _emotion_progress_set(ev->obj, buf, progress);
+ */
 }
 
 static void
 _player_seekable_changed(Emotion_Generic_Video *ev)
 {
-   int seekable;
-   _player_int_read(ev, &seekable);
+   int seekable = ev->cmd.param.i_num;
 
    INF("received seekable changed: %d", seekable);
 
@@ -388,74 +357,128 @@ _player_seekable_changed(Emotion_Generic_Video *ev)
 }
 
 static void
-_player_volume(Emotion_Generic_Video *ev)
+_audio_channels_free(Emotion_Generic_Video *ev)
 {
-   float vol, oldvol;
-   _player_float_read(ev, &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)
+_video_channels_free(Emotion_Generic_Video *ev)
 {
-   int mute;
-   _player_int_read(ev, &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)
+_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;
 
-   _player_int_read(ev, &track_current);
-   _player_int_read(ev, &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];
-       _player_int_read(ev, &tid);
-       _player_str_read(ev, 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)
@@ -467,7 +490,7 @@ _player_open_done(Emotion_Generic_Video *ev)
 {
    int success;
 
-   _player_int_read(ev, &success);
+   success = ev->cmd.param.i_num;
    shm_unlink(ev->shmname);
 
    if (ev->file_changed)
@@ -484,6 +507,8 @@ _player_open_done(Emotion_Generic_Video *ev)
        return;
      }
 
+   ev->file_ready = EINA_TRUE;
+
    _emotion_open_done(ev->obj);
 
    if (ev->play)
@@ -492,21 +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)
+_player_cmd_process(Emotion_Generic_Video *ev)
 {
-   int type;
-
-   if (!_player_int_read(ev, &type))
-     {
-       ERR("could not read command\n");
-       return;
-     }
-
-   switch (type) {
+   switch (ev->cmd.type) {
       case EM_RESULT_INIT:
         _player_ready(ev);
         break;
@@ -540,9 +575,234 @@ _player_read_cmd(Emotion_Generic_Video *ev)
       case EM_RESULT_AUDIO_TRACK_INFO:
         _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", 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);
+}
+
+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", type);
-   };
+        WRN("received wrong command: %d", ev->cmd.type);
+        ev->cmd.type = -1;
+   }
 }
 
 static Eina_Bool
@@ -556,7 +816,7 @@ _player_cmd_handler_cb(void *data, Ecore_Fd_Handler *fd_handler)
        return ECORE_CALLBACK_CANCEL;
      }
 
-   _player_read_cmd(ev);
+   _player_cmd_read(ev);
 
    return ECORE_CALLBACK_RENEW;
 }
@@ -574,12 +834,6 @@ _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++)
      INF("received input from player: \"%s\"", ev->lines[i].line);
 
@@ -613,6 +867,7 @@ _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);
@@ -652,8 +907,8 @@ _player_exec(Emotion_Generic_Video *ev)
       ECORE_EXE_PIPE_READ_LINE_BUFFERED | ECORE_EXE_NOT_LEADER,
       ev);
 
-   INF("created pipe emotion -> player: %d -> %d\n", pipe_out[1], pipe_out[0]);
-   INF("created pipe player -> emotion: %d -> %d\n", pipe_in[1], pipe_in[0]);
+   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]);
@@ -676,7 +931,7 @@ _player_exec(Emotion_Generic_Video *ev)
 }
 
 static Eina_Bool
-_fork_and_exec(Evas_Object *obj, Emotion_Generic_Video *ev)
+_fork_and_exec(Evas_Object *obj __UNUSED__, Emotion_Generic_Video *ev)
 {
    char shmname[256];
    struct timeval tv;
@@ -724,6 +979,7 @@ em_init(Evas_Object *obj, void **emotion_video, Emotion_Module_Options *opt)
    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);
@@ -756,8 +1012,6 @@ em_shutdown(void *data)
    if (ev->fd_handler)
      ecore_main_fd_handler_del(ev->fd_handler);
 
-   _audio_channels_free(ev);
-
    eina_stringshare_del(ev->cmdline);
    eina_stringshare_del(ev->shmname);
 
@@ -778,6 +1032,10 @@ em_file_open(const char *file, Evas_Object *obj __UNUSED__, void *data)
    eina_stringshare_replace(&ev->filename, file);
 
    ev->pos = 0;
+   ev->w = 0;
+   ev->h = 0;
+   ev->ratio = 1;
+   ev->len = 0;
 
    if (ev->ready && ev->opening)
      {
@@ -799,11 +1057,17 @@ 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)
-     return;
+   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;
@@ -863,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);
@@ -874,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
@@ -883,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);
@@ -895,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)
 {
@@ -980,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)
@@ -994,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;
@@ -1017,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
@@ -1063,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
@@ -1087,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
@@ -1118,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
@@ -1138,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
@@ -1203,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
@@ -1224,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 =
@@ -1241,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 */
@@ -1288,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 */
 };