예제 #1
0
static void
poll_func (GstBus * bus, GstMessage * message, GstBusPollData * poll_data)
{
  GstMessageType type;

  if (!g_main_loop_is_running (poll_data->loop)) {
    GST_DEBUG ("mainloop %p not running", poll_data->loop);
    return;
  }

  type = GST_MESSAGE_TYPE (message);

  if (type & poll_data->events) {
    g_return_if_fail (poll_data->message == NULL);
    /* keep ref to message */
    poll_data->message = gst_message_ref (message);
    GST_DEBUG ("mainloop %p quit", poll_data->loop);
    g_main_loop_quit (poll_data->loop);
  } else {
    GST_DEBUG ("type %08x does not match %08x", type, poll_data->events);
  }
}
static gboolean
play_bus_msg (GstBus * bus, GstMessage * msg, gpointer user_data)
{
  GstPlay *play = user_data;

  switch (GST_MESSAGE_TYPE (msg)) {
    case GST_MESSAGE_ASYNC_DONE:

      /* dump graph on preroll */
      GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (play->playbin),
          GST_DEBUG_GRAPH_SHOW_ALL, "gst-play.async-done");

      g_print ("Prerolled.\r");
      if (play->missing != NULL && play_install_missing_plugins (play)) {
        g_print ("New plugins installed, trying again...\n");
        --play->cur_idx;
        play_next (play);
      }
      break;
    case GST_MESSAGE_BUFFERING:{
      gint percent;

      if (!play->buffering)
        g_print ("\n");

      gst_message_parse_buffering (msg, &percent);
      g_print ("%s %d%%  \r", _("Buffering..."), percent);

      if (percent == 100) {
        /* a 100% message means buffering is done */
        if (play->buffering) {
          play->buffering = FALSE;
          /* no state management needed for live pipelines */
          if (!play->is_live)
            gst_element_set_state (play->playbin, play->desired_state);
        }
      } else {
        /* buffering... */
        if (!play->buffering) {
          if (!play->is_live)
            gst_element_set_state (play->playbin, GST_STATE_PAUSED);
          play->buffering = TRUE;
        }
      }
      break;
    }
    case GST_MESSAGE_CLOCK_LOST:{
      g_print (_("Clock lost, selecting a new one\n"));
      gst_element_set_state (play->playbin, GST_STATE_PAUSED);
      gst_element_set_state (play->playbin, GST_STATE_PLAYING);
      break;
    }
    case GST_MESSAGE_LATENCY:
      g_print ("Redistribute latency...\n");
      gst_bin_recalculate_latency (GST_BIN (play->playbin));
      break;
    case GST_MESSAGE_REQUEST_STATE:{
      GstState state;
      gchar *name;

      name = gst_object_get_path_string (GST_MESSAGE_SRC (msg));

      gst_message_parse_request_state (msg, &state);

      g_print ("Setting state to %s as requested by %s...\n",
          gst_element_state_get_name (state), name);

      gst_element_set_state (play->playbin, state);
      g_free (name);
      break;
    }
    case GST_MESSAGE_EOS:
      /* print final position at end */
      play_timeout (play);
      g_print ("\n");
      /* and switch to next item in list */
      if (!play_next (play)) {
        g_print ("%s\n", _("Reached end of play list."));
        g_main_loop_quit (play->loop);
      }
      break;
    case GST_MESSAGE_WARNING:{
      GError *err;
      gchar *dbg = NULL;

      /* dump graph on warning */
      GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (play->playbin),
          GST_DEBUG_GRAPH_SHOW_ALL, "gst-play.warning");

      gst_message_parse_warning (msg, &err, &dbg);
      g_printerr ("WARNING %s\n", err->message);
      if (dbg != NULL)
        g_printerr ("WARNING debug information: %s\n", dbg);
      g_clear_error (&err);
      g_free (dbg);
      break;
    }
    case GST_MESSAGE_ERROR:{
      GError *err;
      gchar *dbg;

      /* dump graph on error */
      GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (play->playbin),
          GST_DEBUG_GRAPH_SHOW_ALL, "gst-play.error");

      gst_message_parse_error (msg, &err, &dbg);
      g_printerr ("ERROR %s for %s\n", err->message, play->uris[play->cur_idx]);
      if (dbg != NULL)
        g_printerr ("ERROR debug information: %s\n", dbg);
      g_clear_error (&err);
      g_free (dbg);

      /* flush any other error messages from the bus and clean up */
      gst_element_set_state (play->playbin, GST_STATE_NULL);

      if (play->missing != NULL && play_install_missing_plugins (play)) {
        g_print ("New plugins installed, trying again...\n");
        --play->cur_idx;
        play_next (play);
        break;
      }
      /* try next item in list then */
      if (!play_next (play)) {
        g_print ("%s\n", _("Reached end of play list."));
        g_main_loop_quit (play->loop);
      }
      break;
    }
    case GST_MESSAGE_ELEMENT:
    {
      GstNavigationMessageType mtype = gst_navigation_message_get_type (msg);
      if (mtype == GST_NAVIGATION_MESSAGE_EVENT) {
        GstEvent *ev = NULL;

        if (gst_navigation_message_parse_event (msg, &ev)) {
          GstNavigationEventType e_type = gst_navigation_event_get_type (ev);
          switch (e_type) {
            case GST_NAVIGATION_EVENT_KEY_PRESS:
            {
              const gchar *key;

              if (gst_navigation_event_parse_key_event (ev, &key)) {
                GST_INFO ("Key press: %s", key);

                if (strcmp (key, "Left") == 0)
                  key = GST_PLAY_KB_ARROW_LEFT;
                else if (strcmp (key, "Right") == 0)
                  key = GST_PLAY_KB_ARROW_RIGHT;
                else if (strcmp (key, "Up") == 0)
                  key = GST_PLAY_KB_ARROW_UP;
                else if (strcmp (key, "Down") == 0)
                  key = GST_PLAY_KB_ARROW_DOWN;
                else if (strcmp (key, "space") == 0)
                  key = " ";
                else if (strlen (key) > 1)
                  break;

                keyboard_cb (key, user_data);
              }
              break;
            }
            case GST_NAVIGATION_EVENT_MOUSE_BUTTON_PRESS:
            {
              gint button;
              if (gst_navigation_event_parse_mouse_button_event (ev, &button,
                      NULL, NULL)) {
                if (button == 4) {
                  /* wheel up */
                  relative_seek (play, +0.08);
                } else if (button == 5) {
                  /* wheel down */
                  relative_seek (play, -0.01);
                }
              }
              break;
            }
            default:
              break;
          }
        }
        if (ev)
          gst_event_unref (ev);
      }
      break;
    }
    default:
      if (gst_is_missing_plugin_message (msg)) {
        gchar *desc;

        desc = gst_missing_plugin_message_get_description (msg);
        g_print ("Missing plugin: %s\n", desc);
        g_free (desc);
        play->missing = g_list_append (play->missing, gst_message_ref (msg));
      }
      break;
  }

  return TRUE;
}
예제 #3
0
static gboolean
play_bus_msg (GstBus * bus, GstMessage * msg, gpointer user_data)
{
  GstPlay *play = user_data;

  switch (GST_MESSAGE_TYPE (msg)) {
    case GST_MESSAGE_ASYNC_DONE:

      /* dump graph on preroll */
      GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (play->playbin),
          GST_DEBUG_GRAPH_SHOW_ALL, "gst-play.async-done");

      g_print ("Prerolled.\r");
      if (play->missing != NULL && play_install_missing_plugins (play)) {
        g_print ("New plugins installed, trying again...\n");
        --play->cur_idx;
        play_next (play);
      }
      break;
    case GST_MESSAGE_BUFFERING:{
      gint percent;

      if (!play->buffering)
        g_print ("\n");

      gst_message_parse_buffering (msg, &percent);
      g_print ("%s %d%%  \r", _("Buffering..."), percent);

      if (percent == 100) {
        /* a 100% message means buffering is done */
        if (play->buffering) {
          play->buffering = FALSE;
          /* no state management needed for live pipelines */
          if (!play->is_live)
            gst_element_set_state (play->playbin, play->desired_state);
        }
      } else {
        /* buffering... */
        if (!play->buffering) {
          if (!play->is_live)
            gst_element_set_state (play->playbin, GST_STATE_PAUSED);
          play->buffering = TRUE;
        }
      }
      break;
    }
    case GST_MESSAGE_CLOCK_LOST:{
      g_print (_("Clock lost, selecting a new one\n"));
      gst_element_set_state (play->playbin, GST_STATE_PAUSED);
      gst_element_set_state (play->playbin, GST_STATE_PLAYING);
      break;
    }
    case GST_MESSAGE_LATENCY:
      g_print ("Redistribute latency...\n");
      gst_bin_recalculate_latency (GST_BIN (play->playbin));
      break;
    case GST_MESSAGE_REQUEST_STATE:{
      GstState state;
      gchar *name;

      name = gst_object_get_path_string (GST_MESSAGE_SRC (msg));

      gst_message_parse_request_state (msg, &state);

      g_print ("Setting state to %s as requested by %s...\n",
          gst_element_state_get_name (state), name);

      gst_element_set_state (play->playbin, state);
      g_free (name);
      break;
    }
    case GST_MESSAGE_EOS:
      /* print final position at end */
      play_timeout (play);
      g_print ("\n");
      /* and switch to next item in list */
      if (!play_next (play)) {
        g_print ("Reached end of play list.\n");
        g_main_loop_quit (play->loop);
      }
      break;
    case GST_MESSAGE_WARNING:{
      GError *err;
      gchar *dbg = NULL;

      /* dump graph on warning */
      GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (play->playbin),
          GST_DEBUG_GRAPH_SHOW_ALL, "gst-play.warning");

      gst_message_parse_warning (msg, &err, &dbg);
      g_printerr ("WARNING %s\n", err->message);
      if (dbg != NULL)
        g_printerr ("WARNING debug information: %s\n", dbg);
      g_error_free (err);
      g_free (dbg);
      break;
    }
    case GST_MESSAGE_ERROR:{
      GError *err;
      gchar *dbg;

      /* dump graph on error */
      GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (play->playbin),
          GST_DEBUG_GRAPH_SHOW_ALL, "gst-play.error");

      gst_message_parse_error (msg, &err, &dbg);
      g_printerr ("ERROR %s for %s\n", err->message, play->uris[play->cur_idx]);
      if (dbg != NULL)
        g_printerr ("ERROR debug information: %s\n", dbg);
      g_error_free (err);
      g_free (dbg);

      /* flush any other error messages from the bus and clean up */
      gst_element_set_state (play->playbin, GST_STATE_NULL);

      if (play->missing != NULL && play_install_missing_plugins (play)) {
        g_print ("New plugins installed, trying again...\n");
        --play->cur_idx;
        play_next (play);
        break;
      }
      /* try next item in list then */
      if (!play_next (play)) {
        g_print ("Reached end of play list.\n");
        g_main_loop_quit (play->loop);
      }
      break;
    }
    default:
      if (gst_is_missing_plugin_message (msg)) {
        gchar *desc;

        desc = gst_missing_plugin_message_get_description (msg);
        g_print ("Missing plugin: %s\n", desc);
        g_free (desc);
        play->missing = g_list_append (play->missing, gst_message_ref (msg));
      }
      break;
  }

  return TRUE;
}
예제 #4
0
QGstreamerMessage::QGstreamerMessage(QGstreamerMessage const& m):
    m_message(m.m_message)
{
    gst_message_ref(m_message);
}
예제 #5
0
QGstreamerMessage::QGstreamerMessage(GstMessage* message):
    m_message(message)
{
    gst_message_ref(m_message);
}
예제 #6
0
Message::Message(GstMessage* message):
    m_message(message)
{
    gst_message_ref(m_message);
}
예제 #7
0
Message::Message(Message const& m):
    m_message(m.m_message)
{
    gst_message_ref(m_message);
}
예제 #8
0
static GstElement *
gst_auto_video_src_find_best (GstAutoVideoSrc * src)
{
  GList *list, *item;
  GstElement *choice = NULL;
  GstMessage *message = NULL;
  GSList *errors = NULL;
  GstBus *bus = gst_bus_new ();
  GstPad *el_pad = NULL;
  GstCaps *el_caps = NULL, *intersect = NULL;
  gboolean no_match = TRUE;

  list = gst_registry_feature_filter (gst_registry_get_default (),
      (GstPluginFeatureFilter) gst_auto_video_src_factory_filter, FALSE, src);
  list = g_list_sort (list, (GCompareFunc) gst_auto_video_src_compare_ranks);

  GST_LOG_OBJECT (src, "Trying to find usable video devices ...");

  for (item = list; item != NULL; item = item->next) {
    GstElementFactory *f = GST_ELEMENT_FACTORY (item->data);
    GstElement *el;

    if ((el = gst_auto_video_src_create_element_with_pretty_name (src, f))) {
      GstStateChangeReturn ret;

      GST_DEBUG_OBJECT (src, "Testing %s", GST_PLUGIN_FEATURE (f)->name);

      /* If AutoVideoSrc has been provided with filter caps,
       * accept only sources that match with the filter caps */
      if (src->filter_caps) {
        el_pad = gst_element_get_static_pad (GST_ELEMENT (el), "src");
        el_caps = gst_pad_get_caps (el_pad);
        gst_object_unref (el_pad);
        GST_DEBUG_OBJECT (src,
            "Checking caps: %" GST_PTR_FORMAT " vs. %" GST_PTR_FORMAT,
            src->filter_caps, el_caps);
        intersect = gst_caps_intersect (src->filter_caps, el_caps);
        no_match = gst_caps_is_empty (intersect);
        gst_caps_unref (el_caps);
        gst_caps_unref (intersect);

        if (no_match) {
          GST_DEBUG_OBJECT (src, "Incompatible caps");
          gst_object_unref (el);
          continue;
        } else {
          GST_DEBUG_OBJECT (src, "Found compatible caps");
        }
      }

      gst_element_set_bus (el, bus);
      ret = gst_element_set_state (el, GST_STATE_READY);
      if (ret == GST_STATE_CHANGE_SUCCESS) {
        GST_DEBUG_OBJECT (src, "This worked!");
        choice = el;
        break;
      }

      /* collect all error messages */
      while ((message = gst_bus_pop_filtered (bus, GST_MESSAGE_ERROR))) {
        GST_DEBUG_OBJECT (src, "error message %" GST_PTR_FORMAT, message);
        errors = g_slist_append (errors, message);
      }

      gst_element_set_state (el, GST_STATE_NULL);
      gst_object_unref (el);
    }
  }

  GST_DEBUG_OBJECT (src, "done trying");
  if (!choice) {
    if (errors) {
      /* FIXME: we forward the first error for now; but later on it might make
       * sense to actually analyse them */
      gst_message_ref (GST_MESSAGE (errors->data));
      GST_DEBUG_OBJECT (src, "reposting message %p", errors->data);
      gst_element_post_message (GST_ELEMENT (src), GST_MESSAGE (errors->data));
    } else {
      /* send warning message to application and use a fakesrc */
      GST_ELEMENT_WARNING (src, RESOURCE, NOT_FOUND, (NULL),
          ("Failed to find a usable video source"));
      choice = gst_element_factory_make ("fakesrc", "fake-video-src");
      if (g_object_class_find_property (G_OBJECT_GET_CLASS (choice), "sync"))
        g_object_set (choice, "sync", TRUE, NULL);
      gst_element_set_state (choice, GST_STATE_READY);
    }
  }
  gst_object_unref (bus);
  gst_plugin_feature_list_free (list);
  g_slist_foreach (errors, (GFunc) gst_mini_object_unref, NULL);
  g_slist_free (errors);

  return choice;
}
예제 #9
0
파일: message.cpp 프로젝트: phen89/rtqt
Message::Message(const Message &other)
{
    m_message = other.m_message;
    gst_message_ref(m_message);
    m_source = other.m_source;
}
예제 #10
0
static gpointer _gst_message_ref0 (gpointer self) {
	return self ? gst_message_ref (self) : NULL;
}
static void
gst_net_client_internal_clock_observe_times (GstNetClientInternalClock * self,
    GstClockTime local_1, GstClockTime remote_1, GstClockTime remote_2,
    GstClockTime local_2)
{
  GstClockTime current_timeout = 0;
  GstClockTime local_avg, remote_avg;
  gdouble r_squared;
  GstClock *clock;
  GstClockTime rtt, rtt_limit, min_update_interval;
  /* Use for discont tracking */
  GstClockTime time_before = 0;
  GstClockTime min_guess = 0;
  GstClockTimeDiff time_discont = 0;
  gboolean synched, now_synched;
  GstClockTime internal_time, external_time, rate_num, rate_den;
  GstClockTime orig_internal_time, orig_external_time, orig_rate_num,
      orig_rate_den;
  GstClockTime max_discont;
  GstClockTime last_rtts[MEDIAN_PRE_FILTERING_WINDOW];
  GstClockTime median;
  gint i;

  GST_OBJECT_LOCK (self);
  rtt_limit = self->roundtrip_limit;

  GST_LOG_OBJECT (self,
      "local1 %" G_GUINT64_FORMAT " remote1 %" G_GUINT64_FORMAT " remote2 %"
      G_GUINT64_FORMAT " local2 %" G_GUINT64_FORMAT, local_1, remote_1,
      remote_2, local_2);

  /* If the server told us a poll interval and it's bigger than the
   * one configured via the property, use the server's */
  if (self->last_remote_poll_interval != GST_CLOCK_TIME_NONE &&
      self->last_remote_poll_interval > self->minimum_update_interval)
    min_update_interval = self->last_remote_poll_interval;
  else
    min_update_interval = self->minimum_update_interval;
  GST_OBJECT_UNLOCK (self);

  if (local_2 < local_1) {
    GST_LOG_OBJECT (self, "Dropping observation: receive time %" GST_TIME_FORMAT
        " < send time %" GST_TIME_FORMAT, GST_TIME_ARGS (local_1),
        GST_TIME_ARGS (local_2));
    goto bogus_observation;
  }

  if (remote_2 < remote_1) {
    GST_LOG_OBJECT (self,
        "Dropping observation: remote receive time %" GST_TIME_FORMAT
        " < send time %" GST_TIME_FORMAT, GST_TIME_ARGS (remote_1),
        GST_TIME_ARGS (remote_2));
    goto bogus_observation;
  }

  /* The round trip time is (assuming symmetric path delays)
   * delta = (local_2 - local_1) - (remote_2 - remote_1)
   */

  rtt = GST_CLOCK_DIFF (local_1, local_2) - GST_CLOCK_DIFF (remote_1, remote_2);

  if ((rtt_limit > 0) && (rtt > rtt_limit)) {
    GST_LOG_OBJECT (self,
        "Dropping observation: RTT %" GST_TIME_FORMAT " > limit %"
        GST_TIME_FORMAT, GST_TIME_ARGS (rtt), GST_TIME_ARGS (rtt_limit));
    goto bogus_observation;
  }

  for (i = 1; i < MEDIAN_PRE_FILTERING_WINDOW; i++)
    self->last_rtts[i - 1] = self->last_rtts[i];
  self->last_rtts[i - 1] = rtt;

  if (self->last_rtts_missing) {
    self->last_rtts_missing--;
  } else {
    memcpy (&last_rtts, &self->last_rtts, sizeof (last_rtts));
    g_qsort_with_data (&last_rtts,
        MEDIAN_PRE_FILTERING_WINDOW, sizeof (GstClockTime),
        (GCompareDataFunc) compare_clock_time, NULL);

    median = last_rtts[MEDIAN_PRE_FILTERING_WINDOW / 2];

    /* FIXME: We might want to use something else here, like only allowing
     * things in the interquartile range, or also filtering away delays that
     * are too small compared to the median. This here worked well enough
     * in tests so far.
     */
    if (rtt > 2 * median) {
      GST_LOG_OBJECT (self,
          "Dropping observation, long RTT %" GST_TIME_FORMAT " > 2 * median %"
          GST_TIME_FORMAT, GST_TIME_ARGS (rtt), GST_TIME_ARGS (median));
      goto bogus_observation;
    }
  }

  /* Track an average round trip time, for a bit of smoothing */
  /* Always update before discarding a sample, so genuine changes in
   * the network get picked up, eventually */
  if (self->rtt_avg == GST_CLOCK_TIME_NONE)
    self->rtt_avg = rtt;
  else if (rtt < self->rtt_avg) /* Shorter RTTs carry more weight than longer */
    self->rtt_avg = (3 * self->rtt_avg + rtt) / 4;
  else
    self->rtt_avg = (15 * self->rtt_avg + rtt) / 16;

  if (rtt > 2 * self->rtt_avg) {
    GST_LOG_OBJECT (self,
        "Dropping observation, long RTT %" GST_TIME_FORMAT " > 2 * avg %"
        GST_TIME_FORMAT, GST_TIME_ARGS (rtt), GST_TIME_ARGS (self->rtt_avg));
    goto bogus_observation;
  }

  /* The difference between the local and remote clock (again assuming
   * symmetric path delays):
   *
   * local_1 + delta / 2 - remote_1 = theta
   * or
   * local_2 - delta / 2 - remote_2 = theta
   *
   * which gives after some simple algebraic transformations:
   *
   *         (remote_1 - local_1) + (remote_2 - local_2)
   * theta = -------------------------------------------
   *                              2
   *
   *
   * Thus remote time at local_avg is equal to:
   *
   * local_avg + theta =
   *
   * local_1 + local_2   (remote_1 - local_1) + (remote_2 - local_2)
   * ----------------- + -------------------------------------------
   *         2                                2
   *
   * =
   *
   * remote_1 + remote_2
   * ------------------- = remote_avg
   *          2
   *
   * We use this for our clock estimation, i.e. local_avg at remote clock
   * being the same as remote_avg.
   */

  local_avg = (local_2 + local_1) / 2;
  remote_avg = (remote_2 + remote_1) / 2;

  GST_LOG_OBJECT (self,
      "remoteavg %" G_GUINT64_FORMAT " localavg %" G_GUINT64_FORMAT,
      remote_avg, local_avg);

  clock = GST_CLOCK_CAST (self);

  /* Store what the clock produced as 'now' before this update */
  gst_clock_get_calibration (GST_CLOCK_CAST (self), &orig_internal_time,
      &orig_external_time, &orig_rate_num, &orig_rate_den);
  internal_time = orig_internal_time;
  external_time = orig_external_time;
  rate_num = orig_rate_num;
  rate_den = orig_rate_den;

  min_guess =
      gst_clock_adjust_with_calibration (GST_CLOCK_CAST (self), local_1,
      internal_time, external_time, rate_num, rate_den);
  time_before =
      gst_clock_adjust_with_calibration (GST_CLOCK_CAST (self), local_2,
      internal_time, external_time, rate_num, rate_den);

  /* Maximum discontinuity, when we're synched with the master. Could make this a property,
   * but this value seems to work fine */
  max_discont = self->rtt_avg / 4;

  /* If the remote observation was within a max_discont window around our min/max estimates, we're synched */
  synched =
      (GST_CLOCK_DIFF (remote_avg, min_guess) < (GstClockTimeDiff) (max_discont)
      && GST_CLOCK_DIFF (time_before,
          remote_avg) < (GstClockTimeDiff) (max_discont));

  if (gst_clock_add_observation_unapplied (GST_CLOCK_CAST (self),
          local_avg, remote_avg, &r_squared, &internal_time, &external_time,
          &rate_num, &rate_den)) {

    /* Now compare the difference (discont) in the clock
     * after this observation */
    time_discont = GST_CLOCK_DIFF (time_before,
        gst_clock_adjust_with_calibration (GST_CLOCK_CAST (self), local_2,
            internal_time, external_time, rate_num, rate_den));

    /* If we were in sync with the remote clock, clamp the allowed
     * discontinuity to within quarter of one RTT. In sync means our send/receive estimates
     * of remote time correctly windowed the actual remote time observation */
    if (synched && ABS (time_discont) > max_discont) {
      GstClockTimeDiff offset;
      GST_DEBUG_OBJECT (clock,
          "Too large a discont, clamping to 1/4 average RTT = %"
          GST_TIME_FORMAT, GST_TIME_ARGS (max_discont));
      if (time_discont > 0) {   /* Too large a forward step - add a -ve offset */
        offset = max_discont - time_discont;
        if (-offset > external_time)
          external_time = 0;
        else
          external_time += offset;
      } else {                  /* Too large a backward step - add a +ve offset */
        offset = -(max_discont + time_discont);
        external_time += offset;
      }

      time_discont += offset;
    }

    /* Check if the new clock params would have made our observation within range */
    now_synched =
        (GST_CLOCK_DIFF (remote_avg,
            gst_clock_adjust_with_calibration (GST_CLOCK_CAST (self),
                local_1, internal_time, external_time, rate_num,
                rate_den)) < (GstClockTimeDiff) (max_discont))
        &&
        (GST_CLOCK_DIFF (gst_clock_adjust_with_calibration
            (GST_CLOCK_CAST (self), local_2, internal_time, external_time,
                rate_num, rate_den),
            remote_avg) < (GstClockTimeDiff) (max_discont));

    /* Only update the clock if we had synch or just gained it */
    if (synched || now_synched || self->skipped_updates > MAX_SKIPPED_UPDATES) {
      gst_clock_set_calibration (GST_CLOCK_CAST (self), internal_time,
          external_time, rate_num, rate_den);
      /* ghetto formula - shorter timeout for bad correlations */
      current_timeout = (1e-3 / (1 - MIN (r_squared, 0.99999))) * GST_SECOND;
      current_timeout =
          MIN (current_timeout, gst_clock_get_timeout (GST_CLOCK_CAST (self)));
      self->skipped_updates = 0;

      /* FIXME: When do we consider the clock absolutely not synced anymore? */
      gst_clock_set_synced (GST_CLOCK (self), TRUE);
    } else {
      /* Restore original calibration vars for the report, we're not changing the clock */
      internal_time = orig_internal_time;
      external_time = orig_external_time;
      rate_num = orig_rate_num;
      rate_den = orig_rate_den;
      time_discont = 0;
      self->skipped_updates++;
    }
  }

  /* Limit the polling to at most one per minimum_update_interval */
  if (rtt < min_update_interval)
    current_timeout = MAX (min_update_interval - rtt, current_timeout);

  GST_OBJECT_LOCK (self);
  if (self->busses) {
    GstStructure *s;
    GstMessage *msg;
    GList *l;

    /* Output a stats message, whether we updated the clock or not */
    s = gst_structure_new ("gst-netclock-statistics",
        "synchronised", G_TYPE_BOOLEAN, synched,
        "rtt", G_TYPE_UINT64, rtt,
        "rtt-average", G_TYPE_UINT64, self->rtt_avg,
        "local", G_TYPE_UINT64, local_avg,
        "remote", G_TYPE_UINT64, remote_avg,
        "discontinuity", G_TYPE_INT64, time_discont,
        "remote-min-estimate", G_TYPE_UINT64, min_guess,
        "remote-max-estimate", G_TYPE_UINT64, time_before,
        "remote-min-error", G_TYPE_INT64, GST_CLOCK_DIFF (remote_avg,
            min_guess), "remote-max-error", G_TYPE_INT64,
        GST_CLOCK_DIFF (remote_avg, time_before), "request-send", G_TYPE_UINT64,
        local_1, "request-receive", G_TYPE_UINT64, local_2, "r-squared",
        G_TYPE_DOUBLE, r_squared, "timeout", G_TYPE_UINT64, current_timeout,
        "internal-time", G_TYPE_UINT64, internal_time, "external-time",
        G_TYPE_UINT64, external_time, "rate-num", G_TYPE_UINT64, rate_num,
        "rate-den", G_TYPE_UINT64, rate_den, "rate", G_TYPE_DOUBLE,
        (gdouble) (rate_num) / rate_den, "local-clock-offset", G_TYPE_INT64,
        GST_CLOCK_DIFF (internal_time, external_time), NULL);
    msg = gst_message_new_element (GST_OBJECT (self), s);

    for (l = self->busses; l; l = l->next)
      gst_bus_post (l->data, gst_message_ref (msg));
    gst_message_unref (msg);
  }
  GST_OBJECT_UNLOCK (self);

  GST_INFO ("next timeout: %" GST_TIME_FORMAT, GST_TIME_ARGS (current_timeout));
  self->timeout_expiration = gst_util_get_timestamp () + current_timeout;

  return;

bogus_observation:
  /* Schedule a new packet again soon */
  self->timeout_expiration = gst_util_get_timestamp () + (GST_SECOND / 4);
  return;
}
예제 #12
0
static GstElement *
gst_auto_audio_sink_find_best (GstAutoAudioSink * sink)
{
  GList *list, *item;
  GstElement *choice = NULL;
  GstMessage *message = NULL;
  GSList *errors = NULL;
  GstBus *bus = gst_bus_new ();
  GstPad *el_pad = NULL;
  GstCaps *el_caps = NULL;
  gboolean no_match = TRUE;

  list = gst_registry_feature_filter (gst_registry_get (),
      (GstPluginFeatureFilter) gst_auto_audio_sink_factory_filter, FALSE, sink);
  list = g_list_sort (list, (GCompareFunc) gst_auto_audio_sink_compare_ranks);

  /* We don't treat sound server sinks special. Our policy is that sound
   * server sinks that have a rank must not auto-spawn a daemon under any
   * circumstances, so there's nothing for us to worry about here */
  GST_LOG_OBJECT (sink, "Trying to find usable audio devices ...");

  for (item = list; item != NULL; item = item->next) {
    GstElementFactory *f = GST_ELEMENT_FACTORY (item->data);
    GstElement *el;

    if ((el = gst_auto_audio_sink_create_element_with_pretty_name (sink, f))) {
      GstStateChangeReturn ret;

      GST_DEBUG_OBJECT (sink, "Testing %s", GST_OBJECT_NAME (f));

      /* If autoaudiosink has been provided with filter caps,
       * accept only sinks that match with the filter caps */
      if (sink->filter_caps) {
        el_pad = gst_element_get_static_pad (GST_ELEMENT (el), "sink");
        el_caps = gst_pad_query_caps (el_pad, NULL);
        gst_object_unref (el_pad);
        GST_DEBUG_OBJECT (sink,
            "Checking caps: %" GST_PTR_FORMAT " vs. %" GST_PTR_FORMAT,
            sink->filter_caps, el_caps);
        no_match = !gst_caps_can_intersect (sink->filter_caps, el_caps);
        gst_caps_unref (el_caps);

        if (no_match) {
          GST_DEBUG_OBJECT (sink, "Incompatible caps");
          gst_object_unref (el);
          continue;
        } else {
          GST_DEBUG_OBJECT (sink, "Found compatible caps");
        }
      }

      gst_element_set_bus (el, bus);
      ret = gst_element_set_state (el, GST_STATE_READY);
      if (ret == GST_STATE_CHANGE_SUCCESS) {
        GST_DEBUG_OBJECT (sink, "This worked!");
        choice = el;
        break;
      }

      /* collect all error messages */
      while ((message = gst_bus_pop_filtered (bus, GST_MESSAGE_ERROR))) {
        GST_DEBUG_OBJECT (sink, "error message %" GST_PTR_FORMAT, message);
        errors = g_slist_append (errors, message);
      }

      gst_element_set_state (el, GST_STATE_NULL);
      gst_object_unref (el);
    }
  }

  GST_DEBUG_OBJECT (sink, "done trying");
  if (!choice) {
    if (errors) {
      /* FIXME: we forward the first error for now; but later on it might make
       * sense to actually analyse them */
      gst_message_ref (GST_MESSAGE (errors->data));
      GST_DEBUG_OBJECT (sink, "reposting message %p", errors->data);
      gst_element_post_message (GST_ELEMENT (sink), GST_MESSAGE (errors->data));
    } else {
      /* send warning message to application and use a fakesink */
      GST_ELEMENT_WARNING (sink, RESOURCE, NOT_FOUND, (NULL),
          ("Failed to find a usable audio sink"));
      choice = gst_element_factory_make ("fakesink", "fake-audio-sink");
      if (g_object_class_find_property (G_OBJECT_GET_CLASS (choice), "sync"))
        g_object_set (choice, "sync", TRUE, NULL);
      gst_element_set_state (choice, GST_STATE_READY);
    }
  }
  gst_object_unref (bus);
  gst_plugin_feature_list_free (list);
  g_slist_foreach (errors, (GFunc) gst_mini_object_unref, NULL);
  g_slist_free (errors);

  return choice;
}