[xiph-commits] r12216 - trunk/vorbis-tools/ogg123

conrad at svn.xiph.org conrad at svn.xiph.org
Sat Dec 16 15:45:22 PST 2006


Author: conrad
Date: 2006-12-16 15:45:16 -0800 (Sat, 16 Dec 2006)
New Revision: 12216

Modified:
   trunk/vorbis-tools/ogg123/Makefile.am
   trunk/vorbis-tools/ogg123/cmdline_options.c
   trunk/vorbis-tools/ogg123/format.h
   trunk/vorbis-tools/ogg123/ogg123.c
   trunk/vorbis-tools/ogg123/ogg123.h
Log:
Apply patch adding remote control interface to ogg123, towards ticket:1109.
Patch by Richard van Paasen, from http://www.t3i.nl/myblog/?page_id=9
This patch required a bit of munging to apply to svn trunk. Note that while in
remote control mode, it busy waits on stdin. This should be fixed up (to use
select() etc.) before release. Nevertheless, it seems to work ok, and normal
operation of ogg123 is unaffected.


Modified: trunk/vorbis-tools/ogg123/Makefile.am
===================================================================
--- trunk/vorbis-tools/ogg123/Makefile.am	2006-12-16 12:57:35 UTC (rev 12215)
+++ trunk/vorbis-tools/ogg123/Makefile.am	2006-12-16 23:45:16 UTC (rev 12216)
@@ -32,11 +32,11 @@
                 cfgfile_options.c cmdline_options.c \
                 file_transport.c format.c http_transport.c \
                 ogg123.c oggvorbis_format.c playlist.c \
-                status.c transport.c  vorbis_comments.c \
+                status.c remote.c transport.c vorbis_comments.c \
                 audio.h buffer.h callbacks.h compat.h \
                 cfgfile_options.h cmdline_options.h \
                 format.h ogg123.h playlist.h status.h \
-                transport.h vorbis_comments.h \
+                transport.h remote.h vorbis_comments.h \
                 $(flac_sources) $(speex_sources)
 
 man_MANS = ogg123.1

Modified: trunk/vorbis-tools/ogg123/cmdline_options.c
===================================================================
--- trunk/vorbis-tools/ogg123/cmdline_options.c	2006-12-16 12:57:35 UTC (rev 12215)
+++ trunk/vorbis-tools/ogg123/cmdline_options.c	2006-12-16 23:45:16 UTC (rev 12216)
@@ -30,6 +30,9 @@
 
 #define MIN_INPUT_BUFFER_SIZE 8
 
+extern double strtotime(char *s);
+extern void set_seek_opt(ogg123_options_t *ogg123_opts, char *buf);
+
 struct option long_options[] = {
   /* GNU standard options */
     {"help", no_argument, 0, 'h'},
@@ -45,6 +48,7 @@
     {"device-option", required_argument, 0, 'o'},
     {"prebuffer", required_argument, 0, 'p'},
     {"quiet", no_argument, 0, 'q'},
+    {"remote", no_argument, 0, 'R'},
     {"verbose", no_argument, 0, 'v'},
     {"nth", required_argument, 0, 'x'},
     {"ntimes", required_argument, 0, 'y'},
@@ -56,18 +60,6 @@
     {0, 0, 0, 0}
 };
 
-double strtotime(char *s)
-{
-	double time;
-
-	time = strtod(s, &s);
-
-	while (*s == ':')
-		time = 60 * time + strtod(s + 1, &s);
-
-	return time;
-}
-
 int parse_cmdline_options (int argc, char **argv,
 			   ogg123_options_t *ogg123_opts,
 			   file_option_t    *file_opts)
@@ -80,7 +72,7 @@
   audio_device_t *current;
   int ret;
 
-  while (-1 != (ret = getopt_long(argc, argv, "b:c::d:f:hl:k:K:o:p:qrvVx:y:zZ@:",
+  while (-1 != (ret = getopt_long(argc, argv, "b:c::d:f:hl:k:K:o:p:qrRvVx:y:zZ@:",
 				  long_options, &option_index))) {
 
       switch (ret) {
@@ -154,7 +146,7 @@
 	break;
 
 	case 'k':
-	  ogg123_opts->seekpos = strtotime(optarg);
+ 	  set_seek_opt(ogg123_opts, optarg);
 	  break;
 	  
 	case 'K':
@@ -196,6 +188,11 @@
         ogg123_opts->repeat = 1;
 	break;
 
+      case 'R':
+	ogg123_opts->remote = 1;
+	ogg123_opts->verbosity = 0;
+	break;
+
       case 'v':
 	ogg123_opts->verbosity++;
 	break;
@@ -247,7 +244,7 @@
 
   /* Sanity check bad option combinations */
   if (ogg123_opts->endpos > 0.0 &&
-      ogg123_opts->seekpos > ogg123_opts->endpos) {
+      ogg123_opts->seekoff > ogg123_opts->endpos) {
     status_error(_("=== Option conflict: End time is before start time.\n"));
     exit(1);
   }
@@ -344,6 +341,7 @@
   printf (_("Playlist options\n"));
   printf (_("  -@ file, --list file    Read playlist of files and URLs from \"file\"\n"));
   printf (_("  -r, --repeat            Repeat playlist indefinitely\n"));
+  printf (_("  -R, --remote            Use remote control interface\n"));
   printf (_("  -z, --shuffle           Shuffle list of files before playing\n"));
   printf (_("  -Z, --random            Play files randomly until interrupted\n"));
   printf ("\n");

Modified: trunk/vorbis-tools/ogg123/format.h
===================================================================
--- trunk/vorbis-tools/ogg123/format.h	2006-12-16 12:57:35 UTC (rev 12215)
+++ trunk/vorbis-tools/ogg123/format.h	2006-12-16 23:45:16 UTC (rev 12216)
@@ -53,6 +53,7 @@
 } decoder_t;
 
 /* whence constants */
+#define DECODER_SEEK_NONE  0
 #define DECODER_SEEK_START 1
 #define DECODER_SEEK_CUR   2
 

Modified: trunk/vorbis-tools/ogg123/ogg123.c
===================================================================
--- trunk/vorbis-tools/ogg123/ogg123.c	2006-12-16 12:57:35 UTC (rev 12215)
+++ trunk/vorbis-tools/ogg123/ogg123.c	2006-12-16 23:45:16 UTC (rev 12216)
@@ -46,6 +46,7 @@
 #include "status.h"
 #include "playlist.h"
 #include "compat.h"
+#include "remote.h"
 
 #include "ogg123.h"
 #include "i18n.h"
@@ -151,8 +152,9 @@
   opts->delay = 500;
   opts->nth = 1;
   opts->ntimes = 1;
-  opts->seekpos = 0.0;
+  opts->seekoff = 0.0;
   opts->endpos = -1.0; /* Mark as unset */
+  opts->seekmode = DECODER_SEEK_NONE;
   opts->buffer_size = 128 * 1024;
   opts->prebuffer = 0.0f;
   opts->input_buffer_size = 64 * 1024;
@@ -161,11 +163,86 @@
 
   opts->status_freq = 10.0;
   opts->playlist = NULL;
+  opts->remote = 0;
   opts->repeat = 0;
 
 }
 
+double strtotime(char *s)
+{
+	double time;
 
+	time = strtod(s, &s);
+
+	while (*s == ':')
+		time = 60 * time + strtod(s + 1, &s);
+
+	return time;
+}
+
+void set_seek_opt(ogg123_options_t *ogg123_opts, char *buf) {
+
+  char *b = buf;
+
+  /* skip spaces */
+  while (*b && (*b == ' ')) b++;
+  
+  if (*b == '-') {
+  /* relative seek back */
+    ogg123_opts->seekoff = -1 * strtotime(b+1);
+    ogg123_opts->seekmode = DECODER_SEEK_CUR;
+  } else
+  if (*b == '+') {
+  /* relative seek forward */
+    ogg123_opts->seekoff = strtotime(b+1);
+    ogg123_opts->seekmode = DECODER_SEEK_CUR;
+  } else {
+  /* absolute seek */
+    ogg123_opts->seekoff = strtotime(b);
+    ogg123_opts->seekmode = DECODER_SEEK_START;
+  }
+}
+
+int handle_seek_opt(ogg123_options_t *options, decoder_t *decoder, format_t *format) {
+
+  float pos=decoder->format->statistics(decoder)->current_time;
+
+  /* this functions handles a seek request. It prevents seeking out
+     of band, i.e. before the beginning or after the end. Instead,
+	 it seeks to the start or near-end resp. */
+
+  if (options->seekmode != DECODER_SEEK_NONE) {
+
+    if (options->seekmode == DECODER_SEEK_START) {
+      pos = options->seekoff;
+    } else {
+      pos += options->seekoff;
+    }
+
+    if (pos < 0) {
+      pos = 0;
+    }
+
+    if (pos > decoder->format->statistics(decoder)->total_time) {
+      /* seek to almost the end of the stream */
+      pos = decoder->format->statistics(decoder)->total_time - 0.01;
+    }
+
+    if (!format->seek(decoder, pos, DECODER_SEEK_START)) {
+      status_error(_("Could not skip to %f in audio stream."), options->seekoff);
+#if 0
+      /* Handle this fatally -- kill the audio thread */
+      if (audio_buffer != NULL)
+	buffer_thread_kill(audio_buffer);
+#endif
+    }
+  }
+
+  options->seekmode = DECODER_SEEK_NONE;
+  
+  return 1;
+}
+  
 /* This function selects which statistics to display for our
    particular configuration.  This does not have anything to do with
    verbosity, but rather with which stats make sense to display. */
@@ -216,38 +293,48 @@
 					source->transport->statistics(source),
 					decoder->format->statistics(decoder));
 
-  /* Disable/Enable statistics as needed */
+  if (options.remote) {
+  
+    /* Display statistics via the remote interface */
+    remote_time(pstats_arg->decoder_statistics->current_time, 
+                pstats_arg->decoder_statistics->total_time,
+				pstats_arg->decoder_statistics->instant_bitrate);
+				
+  } else {
+  
+	/* Disable/Enable statistics as needed */
 
-  if (pstats_arg->decoder_statistics->total_time <
-      pstats_arg->decoder_statistics->current_time) {
-    stat_format[2].enabled = 0;  /* Remaining playback time */
-    stat_format[3].enabled = 0;  /* Total playback time */
-  }
+	if (pstats_arg->decoder_statistics->total_time <
+    	pstats_arg->decoder_statistics->current_time) {
+      stat_format[2].enabled = 0;  /* Remaining playback time */
+      stat_format[3].enabled = 0;  /* Total playback time */
+	}
 
-  if (pstats_arg->data_source_statistics->input_buffer_used) {
-    stat_format[6].enabled = 1;  /* Input buffer fill % */
-    stat_format[7].enabled = 1;  /* Input buffer state  */
+	if (pstats_arg->data_source_statistics->input_buffer_used) {
+      stat_format[6].enabled = 1;  /* Input buffer fill % */
+      stat_format[7].enabled = 1;  /* Input buffer state  */
+	}
+
+	if (audio_buffer) {
+      /* Place a status update into the buffer */
+      buffer_append_action_at_end(audio_buffer,
+				  &print_statistics_action,
+				  pstats_arg);
+
+      /* And if we are not playing right now, do an immediate
+    	 update just the output buffer */
+      buffer_stats = buffer_statistics(audio_buffer);
+      if (buffer_stats->paused || buffer_stats->prebuffering) {
+    	pstats_arg = new_print_statistics_arg(stat_format,
+					      NULL,
+					      NULL);
+    	print_statistics_action(audio_buffer, pstats_arg);
+      }
+      free(buffer_stats);
+
+	} else
+      print_statistics_action(NULL, pstats_arg);
   }
-
-  if (audio_buffer) {
-    /* Place a status update into the buffer */
-    buffer_append_action_at_end(audio_buffer,
-				&print_statistics_action,
-				pstats_arg);
-    
-    /* And if we are not playing right now, do an immediate
-       update just the output buffer */
-    buffer_stats = buffer_statistics(audio_buffer);
-    if (buffer_stats->paused || buffer_stats->prebuffering) {
-      pstats_arg = new_print_statistics_arg(stat_format,
-					    NULL,
-					    NULL);
-      print_statistics_action(audio_buffer, pstats_arg);
-    }
-    free(buffer_stats);
-    
-  } else
-    print_statistics_action(NULL, pstats_arg);
 }
 
 
@@ -385,29 +472,37 @@
   signal (SIGCONT, signal_handler);
   signal (SIGTERM, signal_handler);
 
-  do {
-    /* Shuffle playlist */
-    if (options.shuffle) {
-      int i;
+  if (options.remote) {
+  
+    /* run the mainloop for the remote interface */
+    remote_mainloop();
+
+  } else {
+
+    do {
+      /* Shuffle playlist */
+      if (options.shuffle) {
+        int i;
     
-      srandom(time(NULL));
+        srandom(time(NULL));
     
-      for (i = 0; i < items; i++) {
-        int j = i + random() % (items - i);
-        char *temp = playlist_array[i];
-        playlist_array[i] = playlist_array[j];
-        playlist_array[j] = temp;
+        for (i = 0; i < items; i++) {
+          int j = i + random() % (items - i);
+          char *temp = playlist_array[i];
+          playlist_array[i] = playlist_array[j];
+          playlist_array[j] = temp;
+        }
       }
-    }
 
-    /* Play the files/streams */
-    i = 0;
-    while (i < items && !sig_request.exit) {
-      play(playlist_array[i]);
-      i++;
-    }
-  } while (options.repeat);
+      /* Play the files/streams */
+      i = 0;
+      while (i < items && !sig_request.exit) {
+        play(playlist_array[i]);
+        i++;
+      }
+    } while (options.repeat);
 
+  }
   playlist_array_destroy(playlist_array, items);
 
   exit (exit_status);
@@ -502,9 +597,15 @@
 				    _("Playing: %s"), source_string);
 
   /* Skip over audio */
-  if (options.seekpos > 0.0) {
-    if (!format->seek(decoder, options.seekpos, DECODER_SEEK_START)) {
-      status_error(_("Could not skip %f seconds of audio."), options.seekpos);
+  if (options.seekoff > 0.0) {
+    /* Note: it may be simpler to handle this condition by just calling:
+     *   handle_seek_opt(&options, decoder, format);
+     * which was introduced with the remote control interface. However, that
+     * function does not call buffer_thread_kill() on error, which is
+     * necessary in this situation.
+     */
+    if (!format->seek(decoder, options.seekoff, DECODER_SEEK_START)) {
+      status_error(_("Could not skip %f seconds of audio."), options.seekoff);
       if (audio_buffer != NULL)
 	buffer_thread_kill(audio_buffer);
       return;
@@ -524,7 +625,20 @@
 	break;
       }
 
-      if (sig_request.pause) {
+	if (options.remote) {
+	
+		/* run the playloop for the remote interface */
+		if (remote_playloop()) {
+			/* end song requested */
+			eof = eos = 1;
+			break;
+		}
+
+		/* Skip over audio */
+		handle_seek_opt(&options, decoder, format);
+	}
+
+	if (sig_request.pause) {
 	if (audio_buffer)
 	  buffer_thread_pause (audio_buffer);
 

Modified: trunk/vorbis-tools/ogg123/ogg123.h
===================================================================
--- trunk/vorbis-tools/ogg123/ogg123.h	2006-12-16 12:57:35 UTC (rev 12215)
+++ trunk/vorbis-tools/ogg123/ogg123.h	2006-12-16 23:45:16 UTC (rev 12216)
@@ -30,8 +30,9 @@
   ogg_int64_t delay;          /* delay (in millisecs) for skip to next song */
   int nth;                    /* Play every nth chunk */
   int ntimes;                 /* Play every chunk n times */
-  double seekpos;             /* Position in file to seek to */
+  double seekoff;             /* Offset to seek to */
   double endpos;              /* Position in file to play to (greater than seekpos) */
+  int seekmode;               /* DECODER_SEEK_[NONE | START | CUR */
 
   long buffer_size;           /* Size of audio buffer */
   float prebuffer;            /* Percent of buffer to fill before playing */
@@ -44,6 +45,8 @@
 
   double status_freq;         /* Number of status updates per second */
 
+  int remote;                 /* Remotely controlled */
+
   playlist_t *playlist;       /* List of files to play */
 
 } ogg123_options_t;



More information about the commits mailing list