speaker beforepoll() now gets to modify the timeout. This allows
authorRichard Kettlewell <rjk@greenend.org.uk>
Wed, 10 Oct 2007 19:26:43 +0000 (20:26 +0100)
committerRichard Kettlewell <rjk@greenend.org.uk>
Wed, 10 Oct 2007 19:26:43 +0000 (20:26 +0100)
speaker-network to transmit at a constant rate instead of bursting
once a second.

server/speaker-alsa.c
server/speaker-command.c
server/speaker-coreaudio.c
server/speaker-network.c
server/speaker-oss.c
server/speaker.c
server/speaker.h

index 731c4ff..8ed01a8 100644 (file)
@@ -219,7 +219,7 @@ static size_t alsa_play(size_t frames) {
 static int alsa_slots, alsa_nslots = -1;
 
 /** @brief Fill in poll fd array for ALSA */
-static void alsa_beforepoll(void) {
+static void alsa_beforepoll(int attribute((unused)) *timeoutp) {
   /* We send sample data to ALSA as fast as it can accept it, relying on
    * the fact that it has a relatively small buffer to minimize pause
    * latency. */
index 088d0cd..17efb99 100644 (file)
@@ -96,7 +96,7 @@ static size_t command_play(size_t frames) {
 }
 
 /** @brief Update poll array for writing to subprocess */
-static void command_beforepoll(void) {
+static void command_beforepoll(int attribute((unused)) *timeoutp) {
   /* We send sample data to the subprocess as fast as it can accept it.
    * This isn't ideal as pause latency can be very high as a result. */
   if(cmdfd >= 0)
index 75a69dd..4f46891 100644 (file)
@@ -202,7 +202,7 @@ static size_t coreaudio_play(size_t frames) {
 }
 
 /** @brief Fill in poll fd array for Core Audio */
-static void coreaudio_beforepoll(void) {
+static void coreaudio_beforepoll(int attribute((unused)) *timeoutp) {
   pfd_slot = addfd(pfd[1], POLLOUT);
 }
 
index 89412f5..c8edbfe 100644 (file)
@@ -306,14 +306,16 @@ static size_t network_play(size_t frames) {
 static int bfd_slot;
 
 /** @brief Set up poll array for network play */
-static void network_beforepoll(void) {
+static void network_beforepoll(int *timeoutp) {
   struct timeval now;
   uint64_t target_us;
   uint64_t target_rtp_time;
+  const int64_t samples_per_second = config->sample_format.rate
+                                   * config->sample_format.channels;
   const int64_t samples_ahead = ((uint64_t)RTP_AHEAD_MS
-                                 * config->sample_format.rate
-                                 * config->sample_format.channels
+                                 * samples_per_second
                                  / 1000);
+  int64_t lead, ahead_ms;
   
   /* If we're starting then initialize the base time */
   if(!rtp_time)
@@ -326,8 +328,17 @@ static void network_beforepoll(void) {
   target_rtp_time = (target_us * config->sample_format.rate
                                * config->sample_format.channels)
                      / 1000000;
-  if((int64_t)(rtp_time - target_rtp_time) < samples_ahead)
+  lead = rtp_time - target_rtp_time;
+  if(lead < samples_ahead)
+    /* We've not reached the desired lead, write as fast as we can */
     bfd_slot = addfd(bfd, POLLOUT);
+  else {
+    /* We've reached the desired lead, we can afford to wait a bit even if the
+     * IP stack thinks it can accept more. */
+    ahead_ms = 1000 * (lead - samples_ahead) / samples_per_second;
+    if(ahead_ms < *timeoutp)
+      *timeoutp = ahead_ms;
+  }
 }
 
 /** @brief Process poll() results for network play */
index 9f409d5..9682cde 100644 (file)
@@ -142,7 +142,7 @@ static size_t oss_play(size_t frames) {
 static int oss_slot;
 
 /** @brief Fill in poll fd array for OSS */
-static void oss_beforepoll(void) {
+static void oss_beforepoll(int attribute((unused)) *timeoutp) {
   oss_slot = addfd(ossfd, POLLOUT|POLLERR);
 }
 
index 41a12e5..19f88b2 100644 (file)
@@ -432,7 +432,7 @@ static void mainloop(void) {
        * instead, but the post-poll code will cope even if it's
        * device_closed. */
       if(device_state == device_open)
-        backend->beforepoll();
+        backend->beforepoll(&timeout);
     }
     /* If any other tracks don't have a full buffer, try to read sample data
      * from them.  We do this last of all, so that if we run out of slots,
index ae4eac3..4e897e4 100644 (file)
@@ -167,12 +167,18 @@ struct speaker_backend {
   void (*deactivate)(void);
 
   /** @brief Called before poll()
+   * @param timeoutp Pointer to timeout
    *
-   * Called before the call to poll().  Should call addfd() to update
-   * the FD array and stash the slot number somewhere safe.  This will
-   * only be called if @ref device_state = @ref device_open.
+   * Called before the call to poll().
+   *
+   * If desirable, should call addfd() to update the FD array and stash the
+   * slot number somewhere safe.  This will only be called if @ref device_state
+   * is @ref device_open.
+   *
+   * @p timeoutp points to the poll timeout value in milliseconds.  It may be
+   * reduced, but never increased.
    */
-  void (*beforepoll)(void);
+  void (*beforepoll)(int *timeoutp);
 
   /** @brief Called after poll()
    * @return 1 if output device ready for play, 0 otherwise