new implementation for read the MPlayer's fifo out, a thread will look the stdout/stderr and gives a response when that is necessary
authorMathieu Schroeter <mathieu.schroeter@mycable.ch>
Sat Aug 04 17:00:27 2007 +0200 (2 years ago)
changeset 77936d51b7d234
parent 76d9c93772c639
child 78a47596f52cce
new implementation for read the MPlayer's fifo out, a thread will look the stdout/stderr and gives a response when that is necessary
src/wrapper_mplayer.c
       1 --- a/src/wrapper_mplayer.c	Wed Aug 01 22:46:23 2007 +0200
       2 +++ b/src/wrapper_mplayer.c	Sat Aug 04 17:00:27 2007 +0200
       3 @@ -30,6 +30,8 @@
       4  #include <sys/types.h>
       5  #include <sys/stat.h>     /* stat */
       6  #include <signal.h>       /* sigaction */
       7 +#include <pthread.h>      /* pthread_... */
       8 +#include <semaphore.h>    /* sem_post sem_wait sem_init */
       9  
      10  #include "player.h"
      11  #include "player_internals.h"
      12 @@ -54,6 +56,12 @@
      13    MPLAYER_IS_DEAD
      14  } mplayer_status_t;
      15  
      16 +/* property and value for a search in the fifo_out */
      17 +typedef struct mp_search_s {
      18 +  char *property;
      19 +  char *value;
      20 +} mp_search_t;
      21 +
      22  /* player specific structure */
      23  typedef struct mplayer_s {
      24    mplayer_status_t status;
      25 @@ -62,6 +70,11 @@
      26    int pipe_out[2];    /* pipe for receive results */
      27    FILE *fifo_in;      /* fifo on the pipe_in  (write only) */
      28    FILE *fifo_out;     /* fifo on the pipe_out (read only) */
      29 +  /* specific to thread */
      30 +  pthread_t th_fifo;      /* thread for the fifo_out parser */
      31 +  pthread_mutex_t mutex;
      32 +  sem_t sem;
      33 +  mp_search_t *search;    /* use when a property is searched */
      34  } mplayer_t;
      35  
      36  /* slave commands */
      37 @@ -166,21 +179,109 @@
      38  }
      39  
      40  /**
      41 + * Thread for parse the fifo_out of MPlayer. This thread must be used only
      42 + * with slave_result() when a property is needed. The rest of the time,
      43 + * this thread will just respond to some events.
      44 + */
      45 +static void *
      46 +thread_fifo (void *arg)
      47 +{
      48 +  char buffer[SLAVE_CMD_BUFFER];
      49 +  char *its, *ite;
      50 +  player_t *player;
      51 +  mplayer_t *mplayer;
      52 +
      53 +  player = (player_t *) arg;
      54 +
      55 +  if (player) {
      56 +    mplayer = (mplayer_t *) player->priv;
      57 +
      58 +    if (mplayer && mplayer->fifo_out) {
      59 +      /* MPlayer's stdout parser */
      60 +      while (fgets (buffer, SLAVE_CMD_BUFFER, mplayer->fifo_out))
      61 +      {
      62 +        /* lock the mutex for protect mplayer->search */
      63 +        pthread_mutex_lock (&mplayer->mutex);
      64 +        /* search the result for a property */
      65 +        if (mplayer->search && mplayer->search->property &&
      66 +            (its = strstr(buffer, mplayer->search->property)))
      67 +        {
      68 +          /* value start */
      69 +          its += strlen (mplayer->search->property);
      70 +          ite = its;
      71 +          while (*ite != '\0' && *ite != '\n')
      72 +            ite++;
      73 +
      74 +          /* value end */
      75 +          *ite = '\0';
      76 +
      77 +          if ((mplayer->search->value = malloc (strlen (its) + 1))) {
      78 +            memcpy (mplayer->search->value, its, strlen (its));
      79 +            *(mplayer->search->value + strlen (its)) = '\0';
      80 +          }
      81 +        }
      82 +        /* If this error (from stderr) exists, then we can go out
      83 +        * because there is no result for the real command.
      84 +        */
      85 +        else if (strstr (buffer, "Command loadfile")) {
      86 +          if (mplayer->search) {
      87 +            free (mplayer->search->property);
      88 +            mplayer->search->property = NULL;
      89 +            /* search ended */
      90 +            sem_post (&mplayer->sem);
      91 +          }
      92 +        }
      93 +        pthread_mutex_unlock (&mplayer->mutex);
      94 +
      95 +        if (strstr (buffer, "Exiting")) {
      96 +          mplayer->status = MPLAYER_IS_DEAD;
      97 +          break;
      98 +        }
      99 +      }
     100 +    }
     101 +  }
     102 +
     103 +  pthread_exit (0);
     104 +}
     105 +
     106 +/**
     107 + * Send a command to slave for get a property. That will return nothing
     108 + * because the response is grabbed with slave_result().
     109 + */
     110 +static void
     111 +slave_get_property (player_t *player, slave_property_t property)
     112 +{
     113 +  mplayer_t *mplayer = NULL;
     114 +  char *prop;
     115 +
     116 +  if (!player)
     117 +    return;
     118 +
     119 +  mplayer = (mplayer_t *) player->priv;
     120 +
     121 +  if (!mplayer || !mplayer->fifo_in)
     122 +    return;
     123 +
     124 +  /* get the right property in the global list */
     125 +  prop = get_prop (property);
     126 +  if (prop)
     127 +    send_to_slave (mplayer, "get_property %s", prop);
     128 +  else
     129 +    /* should never going here */
     130 +    return;
     131 +}
     132 +
     133 +/**
     134   * Get results of commands sent to MPlayer. The MPlayer's stdout and sterr
     135 - * are connected to fifo_out. Because MPlayer doesn't confirm all commands
     136 - * (for example, a get_property with no stream return nothing), that is
     137 - * necessary for send an other command with an output in all cases.
     138 - * Here, this command create an error captured in the stderr for confirm
     139 - * the end of the fifo_out.
     140 + * are connected to fifo_out. This function uses the thread_fifo for get
     141 + * the result. That uses semaphore and mutex.
     142   */
     143  static char *
     144  slave_result (slave_property_t property, player_t *player)
     145  {
     146    char str[SLAVE_CMD_BUFFER];
     147 -  char *buffer;
     148    char *prop;
     149    char *ret = NULL;
     150 -  char *its, *ite;
     151    mplayer_t *mplayer = NULL;
     152  
     153    if (!player)
     154 @@ -199,50 +300,43 @@
     155      /* should never going here */
     156      return NULL;
     157  
     158 -  /* NOTE: /!\ That is ugly but it works pretty well :o)
     159 -   * Because MPlayer doesn't confirm commands, that is necessary for
     160 -   * have a text in the fifo_out for know if there is no new message.
     161 -   * Else, the fgets (read) will block on the pipe. NONBLOCK is not a
     162 -   * solution, better for have an information that will to confirm if
     163 -   * MPlayer has no result and then to stop the read.
     164 -   *
     165 -   * An error is created by the command 'loadfile' without arguments. This
     166 -   * error is got with fgets() and the while is break if there is no
     167 -   * result for the real command in var 'str'.
     168 -   */
     169 -  send_to_slave (mplayer, "loadfile");
     170 +  /* lock the mutex for protect mplayer->search */
     171 +  pthread_mutex_lock (&mplayer->mutex);
     172 +  mplayer->search = malloc (sizeof (mp_search_t));
     173  
     174 -  if ((buffer = malloc (SLAVE_CMD_BUFFER))) {
     175 -    /* MPlayer's stdout parser */
     176 -    while (fgets (buffer, SLAVE_CMD_BUFFER, mplayer->fifo_out))
     177 -    {
     178 -      /* search the result */
     179 -      if ((its = strstr(buffer, str))) {
     180 -        /* value start */
     181 -        its += strlen (str);
     182 -        ite = its;
     183 -        while (*ite != '\0' && *ite != '\n')
     184 -          ite++;
     185 +  if (mplayer->search) {
     186 +    mplayer->search->property = strdup (str);
     187 +    mplayer->search->value = NULL;
     188 +    pthread_mutex_unlock (&mplayer->mutex);
     189  
     190 -        /* value end */
     191 -        *ite = '\0';
     192 +    /* send the slave command for get a response from MPlayer */
     193 +    slave_get_property (player, property);
     194  
     195 -        if ((ret = malloc (strlen (its) + 1))) {
     196 -          memcpy (ret, its, strlen (its));
     197 -          *(ret + strlen (its)) = '\0';
     198 -        }
     199 -      }
     200 -      /* If this error (from stderr) exists, then we can go out
     201 -       * because there is no result for the real command.
     202 -       */
     203 -      else if (strstr (buffer, "Command loadfile"))
     204 -        break;
     205 +    /* NOTE: /!\ That is ugly but it works pretty well :o)
     206 +    * Because MPlayer doesn't confirm commands, that is necessary for
     207 +    * have a text in the fifo_out for know if there is no new message
     208 +    * because MPlayer will not response all the time to get_property.
     209 +    *
     210 +    * An error is created by the command 'loadfile' without argument. This
     211 +    * error is got with fgets() and the search is ended if there is no
     212 +    * result for the real command.
     213 +    */
     214 +    send_to_slave (mplayer, "loadfile");
     215  
     216 -      *buffer = '\0';
     217 -    }
     218 +    /* wait that the thread will found the value */
     219 +    sem_wait (&mplayer->sem);
     220  
     221 -    free (buffer);
     222 +    /* we take the result */
     223 +    ret = mplayer->search->value;
     224 +
     225 +    /* the search is ended */
     226 +    pthread_mutex_lock (&mplayer->mutex);
     227 +    free (mplayer->search);
     228 +    mplayer->search = NULL;
     229 +    pthread_mutex_unlock (&mplayer->mutex);
     230    }
     231 +  else
     232 +    pthread_mutex_unlock (&mplayer->mutex);
     233  
     234    return ret;
     235  }
     236 @@ -313,45 +407,22 @@
     237    }
     238  }
     239  
     240 -/**
     241 - * Send a command to slave for get a property. That will return nothing
     242 - * because the response is grabbed with slave_result().
     243 - */
     244 -static void
     245 -slave_get_property (player_t *player, slave_property_t property)
     246 -{
     247 -  mplayer_t *mplayer = NULL;
     248 -  char *prop;
     249 -
     250 -  if (!player)
     251 -    return;
     252 -
     253 -  mplayer = (mplayer_t *) player->priv;
     254 -
     255 -  if (!mplayer || !mplayer->fifo_in)
     256 -    return;
     257 -
     258 -  /* get the right property in the global list */
     259 -  prop = get_prop (property);
     260 -  if (prop)
     261 -    send_to_slave (mplayer, "get_property %s", prop);
     262 -  else
     263 -    /* should never going here */
     264 -    return;
     265 -}
     266 -
     267  static inline int
     268  slave_get_property_int (player_t *player, slave_property_t property)
     269  {
     270 -  slave_get_property (player, property);
     271 -  return slave_result_int (player, property);
     272 +  int res;
     273 +
     274 +  res = slave_result_int (player, property);
     275 +  return res;
     276  }
     277  
     278  static inline char *
     279  slave_get_property_str (player_t *player, slave_property_t property)
     280  {
     281 -  slave_get_property (player, property);
     282 -  return slave_result_str (player, property);
     283 +  char *res;
     284 +
     285 +  res = slave_result_str (player, property);
     286 +  return res;
     287  }
     288  
     289  static void
     290 @@ -673,7 +744,14 @@
     291  
     292          mplayer->status = MPLAYER_IS_IDLE;
     293  
     294 -        return PLAYER_INIT_OK;
     295 +        /* init semaphore and mutex */
     296 +        sem_init (&mplayer->sem, 0, 0);
     297 +        pthread_mutex_init (&mplayer->mutex, NULL);
     298 +
     299 +        /* create the thread */
     300 +        if (pthread_create (&mplayer->th_fifo, NULL,
     301 +                            thread_fifo, (void *) player) >= 0)
     302 +          return PLAYER_INIT_OK;
     303        }
     304      }
     305    }
     306 @@ -685,6 +763,7 @@
     307  mplayer_uninit (player_t *player)
     308  {
     309    mplayer_t *mplayer = NULL;
     310 +  void *ret;
     311  
     312    plog (MODULE_NAME, "uninit");
     313  
     314 @@ -699,6 +778,9 @@
     315    if (mplayer && mplayer->fifo_in) {
     316      /* suicide of MPlayer */
     317      slave_cmd (player, SLAVE_QUIT);
     318 +
     319 +    /* wait the death of the thread fifo_out */
     320 +    (void) pthread_join (mplayer->th_fifo, &ret);
     321  
     322      /* wait the death of MPlayer */
     323      waitpid (mplayer->pid, NULL, 0);
     324 @@ -1123,6 +1205,7 @@
     325    mplayer->status = MPLAYER_IS_DEAD;
     326    mplayer->fifo_in = NULL;
     327    mplayer->fifo_out = NULL;
     328 +  mplayer->search = NULL;
     329  
     330    return mplayer;
     331  }