chiark / gitweb /
Merge some more mini-Disobedience work
authorRichard Kettlewell <rjk@greenend.org.uk>
Sat, 28 Nov 2009 18:52:39 +0000 (18:52 +0000)
committerRichard Kettlewell <rjk@greenend.org.uk>
Sat, 28 Nov 2009 18:52:39 +0000 (18:52 +0000)
CHANGES.html
lib/trackname.c
server/disorder-server.h
server/normalize.c
server/play.c
server/queue-ops.c

index b9ed4e32114ca266f81c3e6e572e05750f776223..81e2a86db14649619a680a50c3184a9017be2234 100644 (file)
@@ -58,7 +58,7 @@ span.command {
 <p>This file documents recent user-visible changes to <a
  href="http://www.greenend.org.uk/rjk/disorder/">DisOrder</a>.</p>
 
-<h2>Changes up to version 4.4</h2>
+<h2>Changes up to version 5.0</h2>
 
   <div class=section>
   
@@ -75,7 +75,8 @@ span.command {
       <p>Gapless play should be more reliable, and playback latency over RTP
       should be a bit lower.  Note though that all the sound output code has
       been reorganized and in some cases completely rewritten, so it's possible
-      that bugs may have been (re-)introduced.</p>
+      that bugs may have been (re-)introduced.  Decoding of scratches is also
+      initiated ahead of time, giving more reliable playback.</p>
       
       <p>The <tt>command</tt> backend now (optionally) sends silence instead
       of suspending writes when a pause occurs or no track is playing.</p>
@@ -156,7 +157,12 @@ span.command {
           <th>ID</th>
           <th>Description</th>
         </tr>
-        
+
+        <tr>
+          <td><a href="http://code.google.com/p/disorder/issues/detail?id=22">#22</a></td>
+          <td>Background decoders interact badly with server reload</td>
+        </tr>
+
         <tr>
           <td><a href="http://code.google.com/p/disorder/issues/detail?id=27">#27</a></td>
           <td>Mac DisOrder uses wrong sound device</td>
@@ -217,6 +223,12 @@ span.command {
           <td>Disobedience's 'When' column gets out of date</td>
         </tr>
 
+        <tr>
+          <td>(none)</td>
+         <td>&ldquo;found track in no collection&rdquo; messages for scratches
+         are now suppressed</td>
+        </tr>
+
       </table>
     </div>
   </div>
index 4e2e06e22e32487ceea76ac08e70750d710399da..aa11e2e819286fc38ec8ea84b354e44e47180918 100644 (file)
@@ -51,6 +51,10 @@ const char *find_track_root(const char *track) {
   const struct collection *c = find_track_collection(track);
   if(c)
     return c->root;
+  /* Suppress this message for scratches */
+  for(int n = 0; n < config->scratch.n; ++n)
+    if(!strcmp(track, config->scratch.s[n]))
+      return 0;
   disorder_error(0, "found track in no collection '%s'", track);
   return 0;
 }
index f980b6f3ea9a1ab1aabbe171dc4d466c996ee58e..e8f4dabd17c6aea1a3df02eb623766a0bbe82d7e 100644 (file)
@@ -140,6 +140,7 @@ struct queue_entry *queue_add(const char *track, const char *submitter,
 #define WHERE_END 1                    /* Add to end of queue */
 #define WHERE_BEFORE_RANDOM 2          /* End, or before random track */
 #define WHERE_AFTER 3                   /* After the target */
+#define WHERE_NOWHERE 4                 /* Don't add to queue at all */
 /* add an entry to the queue.  Return a pointer to the new entry. */
 
 void queue_remove(struct queue_entry *q, const char *who);
index 89359273561602345b549d24f004bf26453edc80..0f97a2ff024a9d3360526af306828b3ad7767630 100644 (file)
@@ -278,7 +278,6 @@ int main(int argc, char attribute((unused)) **argv) {
                                                  converted, 0);
         //syslog(LOG_INFO, "used=%zu consumed=%zu", used, consumed);
         D(("consumed=%zu", consumed));
-        assert(consumed != 0);
         memmove(buffer, buffer + consumed, used - consumed);
         used -= consumed;
       }
index f93fd5a8707d96de6af9558fbd08ed7e088b5a0f..aa5b8c7270eaa4e52c4114efc5e48a89ab7d22e7 100644 (file)
@@ -39,6 +39,7 @@ static int start_child(struct queue_entry *q,
 static int prepare_child(struct queue_entry *q, 
                          const struct pbgc_params *params,
                          void attribute((unused)) *bgdata);
+static void ensure_next_scratch(ev_source *ev);
 
 /** @brief File descriptor of our end of the socket to the speaker */
 static int speaker_fd = -1;
@@ -195,7 +196,9 @@ static void finished(ev_source *ev) {
  * some time before the speaker reports it as finished) or when a non-raw
  * (i.e. non-speaker) player terminates.  In the latter case it's imaginable
  * that the OS has buffered the last few samples.
- * 
+ *
+ * NB.  The finished track might NOT be in the queue (yet) - it might be a
+ * pre-chosen scratch.
  */
 static int player_finished(ev_source *ev,
                           pid_t pid,
@@ -609,6 +612,8 @@ void play(ev_source *ev) {
      * potentially be a just-added random track. */
     if(qhead.next != &qhead)
       prepare(ev, qhead.next);
+    /* Make sure there is a prepared scratch */
+    ensure_next_scratch(ev);
     break;
   }
 }
@@ -656,12 +661,27 @@ void disable_random(const char *who) {
 
 /* Scratching --------------------------------------------------------------- */
 
+/** @brief Track to play next time something is scratched */
+static struct queue_entry *next_scratch;
+
+/** @brief Ensure there isa prepared scratch */
+static void ensure_next_scratch(ev_source *ev) {
+  if(next_scratch)                      /* There's one already */
+    return;
+  if(!config->scratch.n)                /* There are no scratches */
+    return;
+  int r = rand() * (double)config->scratch.n / (RAND_MAX + 1.0);
+  next_scratch = queue_add(config->scratch.s[r], NULL,
+                           WHERE_NOWHERE, NULL, origin_scratch);
+  if(ev)
+    prepare(ev, next_scratch);
+}
+
 /** @brief Scratch a track
  * @param who User responsible (or NULL)
  * @param id Track ID (or NULL for current)
  */
 void scratch(const char *who, const char *id) {
-  struct queue_entry *q;
   struct speaker_message sm;
 
   D(("scratch playing=%p state=%d id=%s playing->id=%s",
@@ -692,12 +712,14 @@ void scratch(const char *who, const char *id) {
       speaker_send(speaker_fd, &sm);
       D(("sending SM_CANCEL for %s", playing->id));
     }
-    /* put a scratch track onto the front of the queue (but don't
-     * bother if playing is disabled) */
-    if(playing_is_enabled() && config->scratch.n) {
-      int r = rand() * (double)config->scratch.n / (RAND_MAX + 1.0);
-      q = queue_add(config->scratch.s[r], who, WHERE_START, NULL, 
-                    origin_scratch);
+    /* Try to make sure there is a scratch */
+    ensure_next_scratch(NULL);
+    /* Insert it at the head of the queue */
+    if(next_scratch){
+      next_scratch->submitter = who;
+      queue_insert_entry(&qhead, next_scratch);
+      eventlog_raw("queue", queue_marshall(next_scratch), (const char *)0);
+      next_scratch = NULL;
     }
     notify_scratch(playing->track, playing->submitter, who,
                   xtime(0) - playing->played);
index e513d164b61410e30a7efe3ed332ec6b645b0bda..7dcaa845bef920505f6b29979b1659bbac5f3367 100644 (file)
@@ -104,6 +104,8 @@ struct queue_entry *queue_add(const char *track, const char *submitter,
     }
     queue_insert_entry(afterme, q);
     break;
+  case WHERE_NOWHERE:
+    return q;
   }
   /* submitter will be a null pointer for a scratch */
   if(submitter)