chiark / gitweb /
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 731c4ff4c3dddd07db298de5bf8fdc51d7cac20c..8ed01a849cab810aa2a83dcb9a876944f8408f90 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 088d0cd77b5faf57112aafecef8627491a2b19db..17efb99718c666e8e089113e94e3c3705c3ed17e 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 75a69dd7d2d9ba72819f6458ca607e92eb8b3570..4f46891b94f9c5f4ec7664bc4d62da6261335309 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 89412f55486aa637d74d1da1b5e9d8830b403ad1..c8edbfe2d28d2c85f70e3cb7717870b9cceb28e0 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 9f409d5d24793e7fd071c4203fc5bde4f659abdc..9682cdee6d7c3ccb458cac4befa38e120ef1e63d 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 41a12e507dc60d680d76cc55de7ded744f47c315..19f88b27a6d40f37f14abd98299ce407e10e89fc 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 ae4eac3d08a315ca821d1ffa5f34dbc643d4a879..4e897e4bab6f0f906140e318b38139adf5a666d1 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