]> git.ipfire.org Git - thirdparty/shairport-sync.git/commitdiff
Clean up code for the silent lead-in on a non-syncing back end e.g. a pipe. Clean...
authorMike Brady <mikebradydublin@icloud.com>
Fri, 5 Jun 2020 16:22:53 +0000 (17:22 +0100)
committerMike Brady <mikebradydublin@icloud.com>
Fri, 5 Jun 2020 16:22:53 +0000 (17:22 +0100)
audio_pipe.c
common.c
dbus-service.c
mpris-service.c
mqtt.c
player.c
rtsp.c

index a2b33349c1f9c794ad57e085113c687309a6a92e..7953dc234f82baecfceb32b588203c988560d7f6 100644 (file)
@@ -51,8 +51,19 @@ static void start(__attribute__((unused)) int sample_rate,
   // "ENXIO  O_NONBLOCK | O_WRONLY is set, the named file is a FIFO, and no process has the FIFO
   // open for reading."
 
- fd = try_to_open_pipe_for_writing(pipename);
- }
+       fd = try_to_open_pipe_for_writing(pipename);
+       // we check that it's not a "real" error. From the "man 2 open" page:
+       // "ENXIO  O_NONBLOCK | O_WRONLY is set, the named file is a FIFO, and no process has the FIFO
+       // open for reading." Which is okay.
+       if ((fd == -1) && (errno != ENXIO)) {
+               char errorstring[1024];
+               strerror_r(errno, (char *)errorstring, sizeof(errorstring));
+               debug(1, "audio_pipe start -- error %d (\"%s\") opening pipe: \"%s\".", errno,
+                                       (char *)errorstring, pipename);
+               warn("can not open audio pipe -- error %d (\"%s\") opening pipe: \"%s\".", errno,
+                                       (char *)errorstring, pipename);
+       }
+}
 
 static int play(void *buf, int samples) {
   // if the file is not open, try to open it.
@@ -74,6 +85,7 @@ static int play(void *buf, int samples) {
 
 static void stop(void) {
   // Don't close the pipe just because a play session has stopped.
+
 }
 
 static int init(int argc, char **argv) {
index 9bf0dd14b052e767588c76aec3f1d104ba0e78b9..480410c1e2420abb92763b1263c3ce010bb70736 100644 (file)
--- a/common.c
+++ b/common.c
@@ -283,10 +283,10 @@ char *generate_preliminary_string(char *buffer, size_t buffer_length, double tss
     insertion_point = insertion_point + strlen(insertion_point);
     space_remaining = space_remaining - strlen(insertion_point);
   }
-
   if (prefix) {
     snprintf(insertion_point, space_remaining, "%s", prefix);
     insertion_point = insertion_point + strlen(insertion_point);
+    space_remaining = space_remaining - strlen(insertion_point);
   }
   return insertion_point;
 }
@@ -308,7 +308,8 @@ void _die(const char *filename, const int linenumber, const char *format, ...) {
                                     1.0 * time_since_last_debug_message / 1000000000, filename,
                                     linenumber, " *fatal error: ");
   } else {
-    s = b;
+       strncpy(b, "fatal error: ", sizeof(b));
+    s = b+strlen(b);
   }
   va_list args;
   va_start(args, format);
@@ -336,7 +337,8 @@ void _warn(const char *filename, const int linenumber, const char *format, ...)
                                     1.0 * time_since_last_debug_message / 1000000000, filename,
                                     linenumber, " *warning: ");
   } else {
-    s = b;
+       strncpy(b, "warning: ", sizeof(b));
+    s = b+strlen(b);
   }
   va_list args;
   va_start(args, format);
@@ -1135,27 +1137,25 @@ int try_to_open_pipe_for_writing(const char* pathname) {
        // if it succeeds, it sets it to blocking.
        // if not, it returns -1.
 
-  char errorstring[1024];
        int fdis = open(pathname, O_WRONLY | O_NONBLOCK); // open it in non blocking mode first
+
   // we check that it's not a "real" error. From the "man 2 open" page:
   // "ENXIO  O_NONBLOCK | O_WRONLY is set, the named file is a FIFO, and no process has the FIFO
   // open for reading." Which is okay.
+  // This is checked by the caller.
 
-  if ((fdis == -1) && (errno != ENXIO)) {
-    strerror_r(errno, (char *)errorstring, sizeof(errorstring));
-    debug(1, "try_to_open_pipe -- error %d (\"%s\") opening pipe: \"%s\".", errno,
-          (char *)errorstring, pathname);
-  } else
   if (fdis >= 0) {
        // now we switch to blocking mode
        int flags = fcntl(fdis, F_GETFL);
        if ((flags == -1)) {
+               char errorstring[1024];
                        strerror_r(errno, (char *)errorstring, sizeof(errorstring));
                        debug(1, "try_to_open_pipe -- error %d (\"%s\") getting flags of pipe: \"%s\".", errno,
                                                (char *)errorstring, pathname);
        } else {
                flags = fcntl(fdis, F_SETFL,flags & ~O_NONBLOCK);
                if (flags == -1) {
+                       char errorstring[1024];
                                strerror_r(errno, (char *)errorstring, sizeof(errorstring));
                                debug(1, "try_to_open_pipe -- error %d (\"%s\") unsetting NONBLOCK of pipe: \"%s\".", errno,
                                                        (char *)errorstring, pathname);
index 3c4e6daf477b206c04dade682b595c64c9aca6b2..bbd5dcd45f0c54288da45a5f236eba632beabf7e 100644 (file)
@@ -1050,14 +1050,14 @@ static void on_dbus_name_acquired(GDBusConnection *connection, const gchar *name
 static void on_dbus_name_lost_again(__attribute__((unused)) GDBusConnection *connection,
                                     __attribute__((unused)) const gchar *name,
                                     __attribute__((unused)) gpointer user_data) {
-  warn("Could not acquire a Shairport Sync native D-Bus interface \"%s\" on the %s bus.", name,
+  warn("could not acquire a Shairport Sync native D-Bus interface \"%s\" on the %s bus.", name,
        (config.dbus_service_bus_type == DBT_session) ? "session" : "system");
 }
 
 static void on_dbus_name_lost(__attribute__((unused)) GDBusConnection *connection,
                               __attribute__((unused)) const gchar *name,
                               __attribute__((unused)) gpointer user_data) {
-  // debug(1, "Could not acquire a Shairport Sync native D-Bus interface \"%s\" on the %s bus --
+  // debug(1, "could not acquire a Shairport Sync native D-Bus interface \"%s\" on the %s bus --
   // will try adding the process "
   //         "number to the end of it.",
   //      name, (config.dbus_service_bus_type == DBT_session) ? "session" : "system");
index 8258baf6426c47fbb3861e2451e8b1ec63eebc57..9851f0b724b90dca67818b03d81596bbcea6b3bb 100644 (file)
@@ -345,7 +345,7 @@ static void on_mpris_name_acquired(GDBusConnection *connection, const gchar *nam
 static void on_mpris_name_lost_again(__attribute__((unused)) GDBusConnection *connection,
                                      const gchar *name,
                                      __attribute__((unused)) gpointer user_data) {
-  warn("Could not acquire an MPRIS interface named \"%s\" on the %s bus.", name,
+  warn("could not acquire an MPRIS interface named \"%s\" on the %s bus.", name,
        (config.mpris_service_bus_type == DBT_session) ? "session" : "system");
 }
 
diff --git a/mqtt.c b/mqtt.c
index e2b86c5d788924dcea3b05cab6e7e2a71d4a291d..ad5a4c407e2024228425cfb5726352ac2e8ae256 100644 (file)
--- a/mqtt.c
+++ b/mqtt.c
@@ -50,7 +50,7 @@ void on_message(__attribute__((unused)) struct mosquitto *mosq,
   memcpy(payload, msg->payload, msg->payloadlen);
   payload[msg->payloadlen] = 0;
 
-  debug(1, "[MQTT]: received Message on topic %s: %s\n", msg->topic, payload);
+  debug(2, "[MQTT]: received Message on topic %s: %s\n", msg->topic, payload);
 
   // All recognized commands
   char *commands[] = {"command",    "beginff",       "beginrew",   "mutetoggle", "nextitem",
@@ -63,7 +63,7 @@ void on_message(__attribute__((unused)) struct mosquitto *mosq,
   while (commands[it] != NULL) {
     if ((size_t)msg->payloadlen >= strlen(commands[it]) &&
         strncmp(msg->payload, commands[it], strlen(commands[it])) == 0) {
-      debug(1, "[MQTT]: DACP Command: %s\n", commands[it]);
+      debug(2, "[MQTT]: DACP Command: %s\n", commands[it]);
       send_simple_dacp_command(commands[it]);
       break;
     }
@@ -74,13 +74,13 @@ void on_message(__attribute__((unused)) struct mosquitto *mosq,
 void on_disconnect(__attribute__((unused)) struct mosquitto *mosq,
                    __attribute__((unused)) void *userdata, __attribute__((unused)) int rc) {
   connected = 0;
-  debug(1, "[MQTT]: disconnected");
+  debug(2, "[MQTT]: disconnected");
 }
 
 void on_connect(struct mosquitto *mosq, __attribute__((unused)) void *userdata,
                 __attribute__((unused)) int rc) {
   connected = 1;
-  debug(1, "[MQTT]: connected");
+  debug(2, "[MQTT]: connected");
 
   // subscribe if requested
   if (config.mqtt_enable_remote) {
@@ -95,7 +95,7 @@ void mqtt_publish(char *topic, char *data, uint32_t length) {
   char fulltopic[strlen(config.mqtt_topic) + strlen(topic) + 3];
   snprintf(fulltopic, strlen(config.mqtt_topic) + strlen(topic) + 2, "%s/%s", config.mqtt_topic,
            topic);
-  debug(1, "[MQTT]: publishing under %s", fulltopic);
+  debug(2, "[MQTT]: publishing under %s", fulltopic);
 
   int rc;
   if ((rc = mosquitto_publish(global_mosq, NULL, fulltopic, length, data, 0, 0)) !=
index c7020fc7fad57758cb0b31f2190b2e7935811c9c..6f4978b5b37aad67cc1043457353c1f169c05db7 100644 (file)
--- a/player.c
+++ b/player.c
@@ -1040,8 +1040,7 @@ static abuf_t *buffer_get_frame(rtsp_conn_info *conn) {
 #endif
               // Here, calculate when we should start playing. We need to know when to allow the
               // packets to be sent to the player.
-              // We will send packets of silence from now until that time and then we will send the
-              // first packet, which will be followed by the subsequent packets.
+
 
               // every second or so, we get a reference on when a particular packet should be
               // played.
@@ -1087,175 +1086,170 @@ static abuf_t *buffer_get_frame(rtsp_conn_info *conn) {
             }
           }
 
-          if (conn->first_packet_time_to_play != 0) {
-            // recalculate conn->first_packet_time_to_play -- the latency might change
-
-            uint64_t should_be_time;
-            uint32_t effective_latency = conn->latency;
-
-            switch (get_and_check_effective_latency(conn, &effective_latency,
-                                                    config.audio_backend_latency_offset)) {
-            case -1:
-              if (conn->unachievable_audio_backend_latency_offset_notified == 0) {
-                warn("Negative latency! A latency of %d frames requested by the player, when "
-                     "combined with an audio_backend_latency_offset of %f seconds, would make the "
-                     "overall latency negative. The audio_backend_latency_offset setting is "
-                     "ignored.",
-                     conn->latency, config.audio_backend_latency_offset);
-                config.audio_backend_latency_offset = 0; // set it to zero
-                conn->unachievable_audio_backend_latency_offset_notified = 1;
-              };
-              break;
-            case 1:
-              if (conn->unachievable_audio_backend_latency_offset_notified == 0) {
-                warn("An audio_backend_latency_offset of %f seconds may exceed the frame buffering "
-                     "capacity -- the setting is ignored.",
-                     config.audio_backend_latency_offset);
-                config.audio_backend_latency_offset = 0; // set it to zero;
-                conn->unachievable_audio_backend_latency_offset_notified = 1;
-              };
-              break;
-            default:
-              break;
-            }
 
-            frame_to_local_time(conn->first_packet_timestamp +
-                                    effective_latency, // this will go modulo 2^32
-                                &should_be_time, conn);
 
-            conn->first_packet_time_to_play = should_be_time;
-
-            if (local_time_now > conn->first_packet_time_to_play) {
-              uint64_t lateness = local_time_now - conn->first_packet_time_to_play;
-              debug(2, "Gone past starting time by %" PRIu64 " nanoseconds.", lateness);
-              // have_sent_prefiller_silence = 1;
-              conn->ab_buffering = 0;
-            } else {
-              // do some calculations
-              int64_t lead_time = conn->first_packet_time_to_play - local_time_now;
-              if ((config.audio_backend_silent_lead_in_time_auto == 1) ||
-                  (lead_time <=
-                   (int64_t)(config.audio_backend_silent_lead_in_time * (int64_t)1000000000))) {
-                debug(3, "Lead time: %" PRId64 ".", lead_time);
-                if (config.output->delay) { // if the output device has a delay function
-                  debug(3, "Checking");
-                  int resp = 0;
-                  dac_delay = 0;
-                  if (have_sent_prefiller_silence != 0)
-                    resp = config.output->delay(&dac_delay);
-                  if (resp == 0) {
-                    int64_t gross_frame_gap =
-                        ((conn->first_packet_time_to_play - local_time_now) * config.output_rate) /
-                        1000000000;
-                    int64_t exact_frame_gap = gross_frame_gap - dac_delay;
-                    int64_t frames_needed_to_maintain_desired_buffer =
-                        (int64_t)(config.audio_backend_buffer_desired_length * config.output_rate) -
-                        dac_delay;
-                    // below, remember that exact_frame_gap and
-                    // frames_needed_to_maintain_desired_buffer could both be negative
-                    int64_t fs = frames_needed_to_maintain_desired_buffer;
-
-                    // if there isn't enough time to have the desired buffer size
-                    if (exact_frame_gap <= frames_needed_to_maintain_desired_buffer) {
-                      fs = conn->max_frames_per_packet * 2;
-                    }
-
-                    // if we are very close to the end of buffering, i.e. within to frame-lengths,
-                    // add the remaining silence needed and end buffering
-                    if (exact_frame_gap <= conn->max_frames_per_packet * 2) {
-                      fs = exact_frame_gap;
-                      if (fs > first_frame_early_bias)
-                       fs = fs - first_frame_early_bias; // deliberately make the first packet a tiny bit early so that the player may compensate for it at the last minute
-                      conn->ab_buffering = 0;
-                    }
-                    void *silence;
-                    if (fs > 0) {
-                      silence = malloc(conn->output_bytes_per_frame * fs);
-                      if (silence == NULL)
-                        debug(1, "Failed to allocate %d byte silence buffer.", fs);
-                      else {
-                        // generate frames of silence with dither if necessary
-                        conn->previous_random_number =
-                            generate_zero_frames(silence, fs, config.output_format,
-                                                 conn->enable_dither, conn->previous_random_number);
-                        config.output->play(silence, fs);
-                        debug(3, "Sent %" PRId64 " frames of silence", fs);
-                        free(silence);
-                        have_sent_prefiller_silence = 1;
-                      }
-                    }
-                  } else {
-
-                    if (resp == sps_extra_code_output_stalled) {
-                      if (conn->unfixable_error_reported == 0) {
-                        conn->unfixable_error_reported = 1;
-                        if (config.cmd_unfixable) {
-                          command_execute(config.cmd_unfixable, "output_device_stalled", 1);
-                        } else {
-                          warn("an unrecoverable error, \"output_device_stalled\", has been "
-                               "detected.",
-                               conn->connection_number);
-                        }
-                      }
-                    } else {
-                      debug(2, "Unexpected response to getting dac delay: %d.", resp);
-                    }
-                  }
-                } else {
-                  // no delay function on back end -- just send the prefiller silence
-                  // debug(2,"Back end has no delay function.");
-                  // send the appropriate prefiller here...
-
-                  void *silence;
-                  if (lead_time != 0) {
-                    int64_t frame_gap = (lead_time * config.output_rate) / 1000000000;
-                    // debug(1,"%d frames needed.",frame_gap);
-                    while (frame_gap > 0) {
-                      ssize_t fs = config.output_rate / 10;
-                      if (fs > frame_gap)
-                        fs = frame_gap;
-
-                      silence = malloc(conn->output_bytes_per_frame * fs);
-                      if (silence == NULL)
-                        debug(1, "Failed to allocate %d frame silence buffer.", fs);
-                      else {
-                        // debug(1, "No delay function -- outputting %d frames of silence.", fs);
-                        conn->previous_random_number =
-                            generate_zero_frames(silence, fs, config.output_format,
-                                                 conn->enable_dither, conn->previous_random_number);
-                        config.output->play(silence, fs);
-                        free(silence);
-                      }
-                      frame_gap -= fs;
-                    }
-                  }
-                  have_sent_prefiller_silence = 1;
-                  conn->ab_buffering = 0;
-                }
-              }
-            }
-          }
-          if (conn->ab_buffering == 0) {
-/*
-  // note the time of the playing of the first frame
-  uint64_t reference_timestamp_time; // don't need this...
-  get_reference_timestamp_stuff(&conn->play_segment_reference_frame,
-                                &reference_timestamp_time,
-                                &conn->play_segment_reference_frame_remote_time, conn);
-  conn->play_segment_reference_frame *= conn->output_sample_ratio;
-*/
+          if (conn->first_packet_time_to_play != 0) {
+                                               // Now that we know the timing of the first packet...
+                                               if (config.output->delay) {
+                                                       // and that the output device is capable of synchronization...
+
+                                                       // We may send packets of
+                                                       // silence from now until the time the first audio packet should be sent
+                                                       // and then we will send the first packet, which will be followed by
+                                                       // the subsequent packets.
+                                                       // here, we figure out whether and what silence to send.
+
+                                                               uint64_t should_be_time;
+                                                               uint32_t effective_latency = conn->latency;
+
+                                                               switch (get_and_check_effective_latency(conn, &effective_latency,
+                                                                                                                                                                                                                               config.audio_backend_latency_offset)) {
+                                                               case -1:
+                                                                       if (conn->unachievable_audio_backend_latency_offset_notified == 0) {
+                                                                               warn("Negative latency! A latency of %d frames requested by the player, when "
+                                                                                                "combined with an audio_backend_latency_offset of %f seconds, would make the "
+                                                                                                "overall latency negative. The audio_backend_latency_offset setting is "
+                                                                                                "ignored.",
+                                                                                                conn->latency, config.audio_backend_latency_offset);
+                                                                               config.audio_backend_latency_offset = 0; // set it to zero
+                                                                               conn->unachievable_audio_backend_latency_offset_notified = 1;
+                                                                       };
+                                                                       break;
+                                                               case 1:
+                                                                       if (conn->unachievable_audio_backend_latency_offset_notified == 0) {
+                                                                               warn("An audio_backend_latency_offset of %f seconds may exceed the frame buffering "
+                                                                                                "capacity -- the setting is ignored.",
+                                                                                                config.audio_backend_latency_offset);
+                                                                               config.audio_backend_latency_offset = 0; // set it to zero;
+                                                                               conn->unachievable_audio_backend_latency_offset_notified = 1;
+                                                                       };
+                                                                       break;
+                                                               default:
+                                                                       break;
+                                                               }
+
+                                                               // readjust first packet time to play
+                                                               frame_to_local_time(conn->first_packet_timestamp +
+                                                                                                                                                               effective_latency, // this will go modulo 2^32
+                                                                                                                                               &should_be_time, conn);
+
+                                                               conn->first_packet_time_to_play = should_be_time;
+
+                                                               if (local_time_now > conn->first_packet_time_to_play) {
+                                                                       uint64_t lateness = local_time_now - conn->first_packet_time_to_play;
+                                                                       debug(2, "Gone past starting time by %" PRIu64 " nanoseconds.", lateness);
+                                                                       conn->ab_buffering = 0;
+                                                               } else {
+                                                                       // do some calculations
+                                                                       int64_t lead_time = conn->first_packet_time_to_play - local_time_now;
+                                                                       if ((config.audio_backend_silent_lead_in_time_auto == 1) ||
+                                                                                       (lead_time <=
+                                                                                        (int64_t)(config.audio_backend_silent_lead_in_time * (int64_t)1000000000))) {
+                                                                               debug(1, "Lead time: %" PRId64 " nanoseconds.", lead_time);
+                                                                               int resp = 0;
+                                                                               dac_delay = 0;
+                                                                               if (have_sent_prefiller_silence != 0)
+                                                                                       resp = config.output->delay(&dac_delay); // we know the output device must have a delay function
+                                                                               if (resp == 0) {
+                                                                                       int64_t gross_frame_gap =
+                                                                                                       ((conn->first_packet_time_to_play - local_time_now) * config.output_rate) /
+                                                                                                       1000000000;
+                                                                                       int64_t exact_frame_gap = gross_frame_gap - dac_delay;
+                                                                                       int64_t frames_needed_to_maintain_desired_buffer =
+                                                                                                       (int64_t)(config.audio_backend_buffer_desired_length * config.output_rate) -
+                                                                                                       dac_delay;
+                                                                                       // below, remember that exact_frame_gap and
+                                                                                       // frames_needed_to_maintain_desired_buffer could both be negative
+                                                                                       int64_t fs = frames_needed_to_maintain_desired_buffer;
+
+                                                                                       // if there isn't enough time to have the desired buffer size
+                                                                                       if (exact_frame_gap <= frames_needed_to_maintain_desired_buffer) {
+                                                                                               fs = conn->max_frames_per_packet * 2;
+                                                                                       }
+
+                                                                                       // if we are very close to the end of buffering, i.e. within two frame-lengths,
+                                                                                       // add the remaining silence needed and end buffering
+                                                                                       if (exact_frame_gap <= conn->max_frames_per_packet * 2) {
+                                                                                               fs = exact_frame_gap;
+                                                                                               if (fs > first_frame_early_bias)
+                                                                                                       fs = fs - first_frame_early_bias; // deliberately make the first packet a tiny bit early so that the player may compensate for it at the last minute
+                                                                                               conn->ab_buffering = 0;
+                                                                                       }
+                                                                                       void *silence;
+                                                                                       if (fs > 0) {
+                                                                                               silence = malloc(conn->output_bytes_per_frame * fs);
+                                                                                               if (silence == NULL)
+                                                                                                       debug(1, "Failed to allocate %d byte silence buffer.", fs);
+                                                                                               else {
+                                                                                                       // generate frames of silence with dither if necessary
+                                                                                                       conn->previous_random_number =
+                                                                                                                       generate_zero_frames(silence, fs, config.output_format,
+                                                                                                                                                                                                        conn->enable_dither, conn->previous_random_number);
+                                                                                                       config.output->play(silence, fs);
+                                                                                                       debug(1, "Sent %" PRId64 " frames of silence", fs);
+                                                                                                       free(silence);
+                                                                                                       have_sent_prefiller_silence = 1;
+                                                                                               }
+                                                                                       }
+                                                                               } else {
+
+                                                                                       if (resp == sps_extra_code_output_stalled) {
+                                                                                               if (conn->unfixable_error_reported == 0) {
+                                                                                                       conn->unfixable_error_reported = 1;
+                                                                                                       if (config.cmd_unfixable) {
+                                                                                                               command_execute(config.cmd_unfixable, "output_device_stalled", 1);
+                                                                                                       } else {
+                                                                                                               warn("an unrecoverable error, \"output_device_stalled\", has been "
+                                                                                                                                "detected.",
+                                                                                                                                conn->connection_number);
+                                                                                                       }
+                                                                                               }
+                                                                                       } else {
+                                                                                               debug(2, "Unexpected response to getting dac delay: %d.", resp);
+                                                                                       }
+                                                                               }
+                                                                       }
+                                                               }
+                                                       } else {
+                                                               // if the output device doesn't have a delay, we simply send the lead-in
+                                                               int64_t lead_time = conn->first_packet_time_to_play - local_time_now; // negative if we are late
+                                                               void *silence;
+                                                               int64_t frame_gap = (lead_time * config.output_rate) / 1000000000;
+                                                               // debug(1,"%d frames needed.",frame_gap);
+                                                               while (frame_gap > 0) {
+                                                                       ssize_t fs = config.output_rate / 10;
+                                                                       if (fs > frame_gap)
+                                                                               fs = frame_gap;
+
+                                                                       silence = malloc(conn->output_bytes_per_frame * fs);
+                                                                       if (silence == NULL)
+                                                                               debug(1, "Failed to allocate %d frame silence buffer.", fs);
+                                                                       else {
+                                                                               // debug(1, "No delay function -- outputting %d frames of silence.", fs);
+                                                                               conn->previous_random_number =
+                                                                                               generate_zero_frames(silence, fs, config.output_format,
+                                                                                                                                                                                conn->enable_dither, conn->previous_random_number);
+                                                                               config.output->play(silence, fs);
+                                                                               free(silence);
+                                                                       }
+                                                                       frame_gap -= fs;
+                                                               }
+                                                               conn->ab_buffering = 0;
+                                                       }
+                                               }
 #ifdef CONFIG_METADATA
-            debug(2, "prsm");
-            send_ssnc_metadata('prsm', NULL, 0,
-                               0); // "resume", but don't wait if the queue is locked
+                                               if (conn->ab_buffering == 0) {
+                                                       debug(2, "prsm");
+                                                       send_ssnc_metadata('prsm', NULL, 0,
+                                                                                                                                0); // "resume", but don't wait if the queue is locked
+                                               }
 #endif
           }
         }
       }
-    }
 
     // Here, we work out whether to release a packet or wait
-    // We release a buffer when the time is right.
+    // We release a packet when the time is right.
 
     // To work out when the time is right, we need to take account of (1) the actual time the packet
     // should be released,
@@ -2107,10 +2101,18 @@ void *player_thread_func(void *arg) {
           // frames from then onwards
 
           inbuflength *= conn->output_sample_ratio;
+          /*
           uint32_t reference_timestamp;
           uint64_t reference_timestamp_time, remote_reference_timestamp_time;
           get_reference_timestamp_stuff(&reference_timestamp, &reference_timestamp_time,
                                         &remote_reference_timestamp_time, conn); // types okay
+          */
+
+          // nt is the rtp timestamp of the first frame of the current packet of
+          // frames from the source.
+          // multiply it by the output frame ratio to get, effectively, the rtp timestamp
+          // of the first frame of the corresponding packet of output frames.
+
           uint64_t nt;
           nt = inframe->given_timestamp; // uint32_t to int64_t
           nt = nt * conn->output_sample_ratio;
@@ -2529,8 +2531,36 @@ void *player_thread_func(void *arg) {
               */
             }
           } else {
-            // if there is no delay procedure, or it's not working or not allowed, there can be no
-            // synchronising
+
+            // if there is no delay procedure, then we should be sending the packet
+            // to the output at the time determined by
+            // the packet's time to play + requested latency + requested offset.
+/*
+                                               // This is just for checking during development
+
+            uint32_t should_be_frame_32;
+            local_time_to_frame(local_time_now, &should_be_frame_32, conn);
+            // int64_t should_be_frame = ((int64_t)should_be_frame_32) * conn->output_sample_ratio;
+
+            int32_t ilatency = (int32_t)((config.audio_backend_latency_offset - config.audio_backend_buffer_desired_length) * conn->input_rate) + conn->latency;
+            if (ilatency < 0)
+               debug(1,"incorrect latency %d.", ilatency);
+
+            int32_t idelay = (int32_t)(should_be_frame_32 - inframe->given_timestamp);
+
+            idelay = idelay - ilatency;
+
+            debug(2,"delay is %d input frames.", idelay);
+*/
+
+            // if this is the first frame, see if it's close to when it's supposed to be
+            // release, which will be its time plus latency and any offset_time
+            if (at_least_one_frame_seen_this_session == 0) {
+               at_least_one_frame_seen_this_session = 1;
+
+
+            }
+
             play_samples =
                 stuff_buffer_basic_32((int32_t *)conn->tbuf, inbuflength, config.output_format,
                                       conn->outbuf, 0, conn->enable_dither, conn);
diff --git a/rtsp.c b/rtsp.c
index 55789a124a70423562da7b33c4c798f241b81f60..9057b9834aed355f2db65cbb83a5f18243678869 100644 (file)
--- a/rtsp.c
+++ b/rtsp.c
@@ -1306,19 +1306,6 @@ void metadata_create_multicast_socket(void) {
       }
     }
   }
-
-  size_t pl = strlen(config.metadata_pipename) + 1;
-
-  char *path = malloc(pl + 1);
-  snprintf(path, pl + 1, "%s", config.metadata_pipename);
-
-  mode_t oldumask = umask(000);
-
-  if (mkfifo(path, 0666) && errno != EEXIST)
-    die("Could not create metadata FIFO %s", path);
-
-  free(path);
-  umask(oldumask);
 }
 
 void metadata_delete_multicast_socket(void) {
@@ -1331,7 +1318,6 @@ void metadata_delete_multicast_socket(void) {
 }
 
 
-
 void metadata_open(void) {
   if (config.metadata_enabled == 0)
     return;
@@ -1563,6 +1549,33 @@ void metadata_hub_thread_cleanup_function(__attribute__((unused)) void *arg) {
 }
 
 void *metadata_hub_thread_function(__attribute__((unused)) void *ignore) {
+
+  // create the fifo, if necessary
+  size_t pl = strlen(config.metadata_pipename) + 1;
+  char *path = malloc(pl + 1);
+  snprintf(path, pl + 1, "%s", config.metadata_pipename);
+
+  mode_t oldumask = umask(000);
+  if (mkfifo(path, 0644) && errno != EEXIST)
+    die("Could not create metadata pipe \"%s\".", path);
+  umask(oldumask);
+  debug(1, "metadata pipe name is \"%s\".", path);
+
+  // try to open it
+  fd = try_to_open_pipe_for_writing(path);
+  // we check that it's not a "real" error. From the "man 2 open" page:
+  // "ENXIO  O_NONBLOCK | O_WRONLY is set, the named file is a FIFO, and no process has the FIFO
+  // open for reading." Which is okay.
+       if ((fd == -1) && (errno != ENXIO)) {
+               char errorstring[1024];
+               strerror_r(errno, (char *)errorstring, sizeof(errorstring));
+               debug(1, "metadata_hub_thread_function -- error %d (\"%s\") opening pipe: \"%s\".", errno,
+                                       (char *)errorstring, path);
+               warn("can not open metadata pipe -- error %d (\"%s\") opening pipe: \"%s\".", errno,
+                                       (char *)errorstring, path);
+       }
+  free(path);
+
   // create a pc_queue for passing information to a threaded metadata handler
   pc_queue_init(&metadata_hub_queue, (char *)&metadata_hub_queue_items, sizeof(metadata_package),
                 metadata_hub_queue_size, "hub");