/* convert the PacketLost event form a jitterbuffer to a segment update.
 * subclasses can override this.  */
static gboolean
gst_base_rtp_depayload_packet_lost (GstBaseRTPDepayload * filter,
    GstEvent * event)
{
  GstBaseRTPDepayloadPrivate *priv;
  GstClockTime timestamp, duration, position;
  GstEvent *sevent;
  const GstStructure *s;

  priv = filter->priv;

  s = gst_event_get_structure (event);

  /* first start by parsing the timestamp and duration */
  timestamp = -1;
  duration = -1;

  gst_structure_get_clock_time (s, "timestamp", &timestamp);
  gst_structure_get_clock_time (s, "duration", &duration);

  position = timestamp;
  if (duration != -1)
    position += duration;

  /* update the current segment with the elapsed time */
  sevent = create_segment_event (filter, TRUE, position);

  return gst_pad_push_event (filter->srcpad, sevent);
}
Exemplo n.º 2
0
/* convert the PacketLost event from a jitterbuffer to a GAP event.
 * subclasses can override this.  */
static gboolean
gst_rtp_base_depayload_packet_lost (GstRTPBaseDepayload * filter,
    GstEvent * event)
{
  GstClockTime timestamp, duration;
  GstEvent *sevent;
  const GstStructure *s;

  s = gst_event_get_structure (event);

  /* first start by parsing the timestamp and duration */
  timestamp = -1;
  duration = -1;

  if (!gst_structure_get_clock_time (s, "timestamp", &timestamp) ||
      !gst_structure_get_clock_time (s, "duration", &duration)) {
    GST_ERROR_OBJECT (filter,
        "Packet loss event without timestamp or duration");
    return FALSE;
  }

  sevent = gst_pad_get_sticky_event (filter->srcpad, GST_EVENT_SEGMENT, 0);
  if (G_UNLIKELY (!sevent)) {
    /* Typically happens if lost event arrives before first buffer */
    GST_DEBUG_OBJECT (filter, "Ignore packet loss because segment event missing");
    return FALSE;
  }
  gst_event_unref (sevent);

  /* send GAP event */
  sevent = gst_event_new_gap (timestamp, duration);

  return gst_pad_push_event (filter->srcpad, sevent);
}
Exemplo n.º 3
0
static gboolean bus_call (GstBus *bus, GstMessage *msg, gpointer data)
{
   GMainLoop *loop = (GMainLoop *) data;

   switch (GST_MESSAGE_TYPE (msg))
   {

       case GST_MESSAGE_APPLICATION:
       {
       const GstStructure * msg_struct = gst_message_get_structure(msg);
       guint64 duration = 0;
       guint64 timestamp = 0;
       int stream_thread_id = 0;

       g_debug("APPLICATION CUSTOM MESSAGE !!!");
       g_debug("MESSAGE THREAD ID[%p]", g_thread_self());

       gst_structure_get_clock_time (msg_struct, "duration" , &duration);
       gst_structure_get_clock_time (msg_struct, "timestamp" , &timestamp);
       gst_structure_get_int (msg_struct, "stream_thread_id" , &stream_thread_id);
       
       g_debug("STREAM THREAD ID[0x%x]", stream_thread_id);
       g_debug("DURATION[%llu], TIMESTAMP[%llu]", duration, timestamp);
       g_debug("Testing string message, [%s]\n", gst_structure_get_string(msg_struct, "msg"));
       
       break;
       }

       case GST_MESSAGE_EOS:
       {
       g_print ("End of stream\n");
       g_main_loop_quit (loop);
       break;
       }

       case GST_MESSAGE_ERROR:
       {
       gchar  *debug;
       GError *error;

       gst_message_parse_error (msg, &error, &debug);
       g_free (debug);

       g_printerr ("Error: %s\n", error->message);
       g_error_free (error);

       g_main_loop_quit (loop);

       break;
       }

       default:
       g_print("Msg type [%d], Msg name [%s]\n", GST_MESSAGE_TYPE (msg), GST_MESSAGE_TYPE_NAME(msg));
       break;
   }       return TRUE;
}
/**
 * gst_video_event_parse_downstream_force_key_unit:
 * @event: A #GstEvent to parse
 * @timestamp: (out): A pointer to the timestamp in the event
 * @stream_time: (out): A pointer to the stream-time in the event
 * @running_time: (out): A pointer to the running-time in the event
 * @all_headers: (out): A pointer to the all_headers flag in the event
 * @count: (out): A pointer to the count field of the event
 *
 * Get timestamp, stream-time, running-time, all-headers and count in the force
 * key unit event. See gst_video_event_new_downstream_force_key_unit() for a
 * full description of the downstream force key unit event.
 *
 * @running_time will be adjusted for any pad offsets of pads it was passing through.
 *
 * Returns: %TRUE if the event is a valid downstream force key unit event.
 */
gboolean
gst_video_event_parse_downstream_force_key_unit (GstEvent * event,
    GstClockTime * timestamp, GstClockTime * stream_time,
    GstClockTime * running_time, gboolean * all_headers, guint * count)
{
  const GstStructure *s;
  GstClockTime ev_timestamp, ev_stream_time, ev_running_time;
  gboolean ev_all_headers;
  guint ev_count;

  g_return_val_if_fail (event != NULL, FALSE);

  if (GST_EVENT_TYPE (event) != GST_EVENT_CUSTOM_DOWNSTREAM)
    return FALSE;               /* Not a force key unit event */

  s = gst_event_get_structure (event);
  if (s == NULL
      || !gst_structure_has_name (s, GST_VIDEO_EVENT_FORCE_KEY_UNIT_NAME))
    return FALSE;

  if (!gst_structure_get_clock_time (s, "timestamp", &ev_timestamp))
    ev_timestamp = GST_CLOCK_TIME_NONE;
  if (!gst_structure_get_clock_time (s, "stream-time", &ev_stream_time))
    ev_stream_time = GST_CLOCK_TIME_NONE;
  if (!gst_structure_get_clock_time (s, "running-time", &ev_running_time))
    ev_running_time = GST_CLOCK_TIME_NONE;
  if (!gst_structure_get_boolean (s, "all-headers", &ev_all_headers))
    ev_all_headers = FALSE;
  if (!gst_structure_get_uint (s, "count", &ev_count))
    ev_count = 0;

  if (timestamp)
    *timestamp = ev_timestamp;

  if (stream_time)
    *stream_time = ev_stream_time;

  if (running_time) {
    gint64 offset = gst_event_get_running_time_offset (event);

    *running_time = ev_running_time;
    /* Catch underflows */
    if (*running_time > -offset)
      *running_time += offset;
    else
      *running_time = 0;
  }

  if (all_headers)
    *all_headers = ev_all_headers;

  if (count)
    *count = ev_count;

  return TRUE;
}
Exemplo n.º 5
0
static gboolean
gst_rtp_dtmf_src_handle_dtmf_event (GstRTPDTMFSrc * dtmfsrc,
    const GstStructure * event_structure)
{
  gint event_type;
  gboolean start;
  gint method;
  GstClockTime last_stop;
  gint event_number;
  gint event_volume;
  gboolean correct_order;

  if (!gst_structure_get_int (event_structure, "type", &event_type) ||
      !gst_structure_get_boolean (event_structure, "start", &start) ||
      event_type != GST_RTP_DTMF_TYPE_EVENT)
    goto failure;

  if (gst_structure_get_int (event_structure, "method", &method)) {
    if (method != 1) {
      goto failure;
    }
  }

  if (start)
    if (!gst_structure_get_int (event_structure, "number", &event_number) ||
        !gst_structure_get_int (event_structure, "volume", &event_volume))
      goto failure;

  GST_OBJECT_LOCK (dtmfsrc);
  if (gst_structure_get_clock_time (event_structure, "last-stop", &last_stop))
    dtmfsrc->last_stop = last_stop;
  else
    dtmfsrc->last_stop = GST_CLOCK_TIME_NONE;
  correct_order = (start != dtmfsrc->last_event_was_start);
  dtmfsrc->last_event_was_start = start;
  GST_OBJECT_UNLOCK (dtmfsrc);

  if (!correct_order)
    goto failure;

  if (start) {
    if (!gst_structure_get_int (event_structure, "number", &event_number) ||
        !gst_structure_get_int (event_structure, "volume", &event_volume))
      goto failure;

    GST_DEBUG_OBJECT (dtmfsrc, "Received start event %d with volume %d",
        event_number, event_volume);
    gst_rtp_dtmf_src_add_start_event (dtmfsrc, event_number, event_volume);
  }

  else {
    GST_DEBUG_OBJECT (dtmfsrc, "Received stop event");
    gst_rtp_dtmf_src_add_stop_event (dtmfsrc);
  }

  return TRUE;
failure:
  return FALSE;
}
Exemplo n.º 6
0
/* receive spectral data from element message */
static gboolean
message_handler (GstBus * bus, GstMessage * message, gpointer data)
{
  if (message->type == GST_MESSAGE_ELEMENT) {
    const GstStructure *s = gst_message_get_structure (message);
    const gchar *name = gst_structure_get_name (s);

    if (strcmp (name, "spectrum") == 0) {
      GstElement *spectrum = GST_ELEMENT (GST_MESSAGE_SRC (message));
      GstClockTime timestamp, duration;
      GstClockTime waittime = GST_CLOCK_TIME_NONE;

      if (gst_structure_get_clock_time (s, "running-time", &timestamp) &&
          gst_structure_get_clock_time (s, "duration", &duration)) {
        /* wait for middle of buffer */
        waittime = timestamp + duration / 2;
      } else if (gst_structure_get_clock_time (s, "endtime", &timestamp)) {
        waittime = timestamp;
      }
      if (GST_CLOCK_TIME_IS_VALID (waittime)) {
        GstClockID clock_id;
        GstClockTime basetime = gst_element_get_base_time (spectrum);
        gfloat *spect = g_new (gfloat, spect_bands);
        const GValue *list;
        const GValue *value;
        guint i;

        list = gst_structure_get_value (s, "magnitude");
        for (i = 0; i < spect_bands; ++i) {
          value = gst_value_list_get_value (list, i);
          spect[i] = height_scale * g_value_get_float (value);
        }

        clock_id =
            gst_clock_new_single_shot_id (sync_clock, waittime + basetime);
        gst_clock_id_wait_async (clock_id, delayed_spectrum_update,
            (gpointer) spect);
        gst_clock_id_unref (clock_id);
      }
    }
  }
  return TRUE;
}
Exemplo n.º 7
0
gboolean
message_handler (GstBus * bus, GstMessage * message, gpointer data)
{

  if (message->type == GST_MESSAGE_ELEMENT) {
    const GstStructure *s = gst_message_get_structure (message);
    const gchar *name = gst_structure_get_name (s);

    if (strcmp (name, "level") == 0) {
      gint channels;
      GstClockTime endtime;
      gdouble rms_dB, peak_dB, decay_dB;
      gdouble rms;
      const GValue *list;
      const GValue *value;

      gint i;

      if (!gst_structure_get_clock_time (s, "endtime", &endtime))
        g_warning ("Could not parse endtime");
      /* we can get the number of channels as the length of any of the value
       * lists */
      list = gst_structure_get_value (s, "rms");
      channels = gst_value_list_get_size (list);

      g_print ("endtime: %" GST_TIME_FORMAT ", channels: %d\n",
          GST_TIME_ARGS (endtime), channels);
      for (i = 0; i < channels; ++i) {
        g_print ("channel %d\n", i);
        list = gst_structure_get_value (s, "rms");
        value = gst_value_list_get_value (list, i);
        rms_dB = g_value_get_double (value);
        list = gst_structure_get_value (s, "peak");
        value = gst_value_list_get_value (list, i);
        peak_dB = g_value_get_double (value);
        list = gst_structure_get_value (s, "decay");
        value = gst_value_list_get_value (list, i);
        decay_dB = g_value_get_double (value);
        g_print ("    RMS: %f dB, peak: %f dB, decay: %f dB\n",
            rms_dB, peak_dB, decay_dB);

        /* converting from dB to normal gives us a value between 0.0 and 1.0 */
        rms = pow (10, rms_dB / 20);
        g_print ("    normalized rms value: %f\n", rms);
      }
    }
  }
  /* we handled the message we want, and ignored the ones we didn't want.
   * so the core can unref the message for us */
  return TRUE;
}
static GstBusSyncReply
on_message (GstBus * bus, GstMessage * message, gpointer user_data)
{
  const GstStructure *s = gst_message_get_structure (message);
  const gchar *name = gst_structure_get_name (s);
  GValueArray *rms_arr;
  const GValue *array_val;
  const GValue *value;
  gdouble rms;
  gint channels2;
  guint i;
  GstClockTime *rtime;

  if (message->type != GST_MESSAGE_ELEMENT
      || strcmp (name, "videoframe-audiolevel") != 0)
    goto done;

  num_msgs++;
  rtime = g_new (GstClockTime, 1);
  if (!gst_structure_get_clock_time (s, "running-time", rtime)) {
    g_warning ("Could not parse running time");
    g_free (rtime);
  } else {
    g_queue_push_tail (&msg_timestamp_q, rtime);
  }

  /* the values are packed into GValueArrays with the value per channel */
  array_val = gst_structure_get_value (s, "rms");
  rms_arr = (GValueArray *) g_value_get_boxed (array_val);
  channels2 = rms_arr->n_values;
  fail_unless_equals_int (channels2, channels);

  for (i = 0; i < channels; ++i) {
    value = g_value_array_get_nth (rms_arr, i);
    rms = g_value_get_double (value);
    if (per_channel) {
      fail_unless_equals_float (rms, expected_rms_per_channel[i]);
    } else if (early_video && *rtime <= 50 * GST_MSECOND) {
      fail_unless_equals_float (rms, 0);
    } else {
      fail_unless_equals_float (rms, expected_rms);
    }
  }

done:
  return GST_BUS_PASS;
}
Exemplo n.º 9
0
/* receive spectral data from element message */
static gboolean
message_handler (GstBus * bus, GstMessage * message, gpointer data)
{
  if (message->type == GST_MESSAGE_ELEMENT) {
    const GstStructure *s = gst_message_get_structure (message);
    const gchar *name = gst_structure_get_name (s);
    GstClockTime endtime;

    if (strcmp (name, "spectrum") == 0) {
      const GValue *magnitudes;
      const GValue *phases;
      const GValue *mag, *phase;
      gdouble freq;
      guint i;

      if (!gst_structure_get_clock_time (s, "endtime", &endtime))
        endtime = GST_CLOCK_TIME_NONE;

     // g_print ("New spectrum message, endtime %" GST_TIME_FORMAT "\n",
     //     GST_TIME_ARGS (endtime));

      magnitudes = gst_structure_get_value (s, "magnitude");
      phases = gst_structure_get_value (s, "phase");

      for (i = 0; i < spect_bands; ++i) {
        freq = (gdouble) ((AUDIOFREQ / 2) * i + AUDIOFREQ / 4) / spect_bands;
        mag = gst_value_list_get_value (magnitudes, i);
        phase = gst_value_list_get_value (phases, i);

        if (mag != NULL && phase != NULL) {
          g_print ("%g %f\n", freq, g_value_get_float (mag));
	  	
        }
      }
	//system(" perl rtgnuplotter.pl");
    }
  }
  return TRUE;
}
Exemplo n.º 10
0
/* receive spectral data from element message */
gboolean AudioGrabber::message_handler (GstBus * bus, GstMessage * message, gpointer data)
{
  if (message->type == GST_MESSAGE_ELEMENT) {
    const GstStructure *s = gst_message_get_structure (message);
    const gchar *name = gst_structure_get_name (s);
    GstClockTime endtime;

    if (strcmp (name, "spectrum") == 0) {
      const GValue *magnitudes;
      const GValue *phases;
      const GValue *mag, *phase;
      gdouble freq;
      int i;

      if (!gst_structure_get_clock_time (s, "endtime", &endtime))
        endtime = GST_CLOCK_TIME_NONE;

   //g_print ("New spectrum message, endtime %" GST_TIME_FORMAT "\n",
     //     GST_TIME_ARGS (endtime));

      magnitudes = gst_structure_get_value (s, "magnitude");
      phases = gst_structure_get_value (s, "phase");

      for (i = 0; i < 20; ++i) { // TODO 20 = _num_bands
        freq = (gdouble) ((8000 / 2) * i + 8000 / 4) / 20; // TODO 8000=_freq 8000=_freq 20=_num_bands
        mag = gst_value_list_get_value (magnitudes, i);
        phase = gst_value_list_get_value (phases, i);

        if (mag != NULL && phase != NULL && g_value_get_float (mag) >-50 && freq>16) {
          g_print ("band %d (freq %g): magnitude %f dB phase %f\n", i, freq,
              g_value_get_float (mag), g_value_get_float (phase));
          g_print ("\n");
        }
      }
    }
  }
  return TRUE;
}
Exemplo n.º 11
0
static void
gst_hls_sink2_handle_message (GstBin * bin, GstMessage * message)
{
  GstHlsSink2 *sink = GST_HLS_SINK2_CAST (bin);

  switch (message->type) {
    case GST_MESSAGE_ELEMENT:
    {
      const GstStructure *s = gst_message_get_structure (message);
      if (message->src == GST_OBJECT_CAST (sink->splitmuxsink)) {
        if (gst_structure_has_name (s, "splitmuxsink-fragment-opened")) {
          g_free (sink->current_location);
          sink->current_location =
              g_strdup (gst_structure_get_string (s, "location"));
          gst_structure_get_clock_time (s, "running-time",
              &sink->current_running_time_start);
        } else if (gst_structure_has_name (s, "splitmuxsink-fragment-closed")) {
          GstClockTime running_time;
          gchar *entry_location;

          g_assert (strcmp (sink->current_location, gst_structure_get_string (s,
                      "location")) == 0);

          gst_structure_get_clock_time (s, "running-time", &running_time);

          GST_INFO_OBJECT (sink, "COUNT %d", sink->index);
          if (sink->playlist_root == NULL) {
            entry_location = g_path_get_basename (sink->current_location);
          } else {
            gchar *name = g_path_get_basename (sink->current_location);
            entry_location = g_build_filename (sink->playlist_root, name, NULL);
            g_free (name);
          }

          gst_m3u8_playlist_add_entry (sink->playlist, entry_location,
              NULL, running_time - sink->current_running_time_start,
              sink->index++, FALSE);
          g_free (entry_location);

          gst_hls_sink2_write_playlist (sink);

          g_queue_push_tail (&sink->old_locations,
              g_strdup (sink->current_location));

          while (g_queue_get_length (&sink->old_locations) >
              g_queue_get_length (sink->playlist->entries)) {
            gchar *old_location = g_queue_pop_head (&sink->old_locations);
            g_remove (old_location);
            g_free (old_location);
          }
        }
      }
      break;
    }
    case GST_MESSAGE_EOS:{
      sink->playlist->end_list = TRUE;
      gst_hls_sink2_write_playlist (sink);
      break;
    }
    default:
      break;
  }

  GST_BIN_CLASS (parent_class)->handle_message (bin, message);
}
Exemplo n.º 12
0
static gboolean
gst_dtmf_src_handle_dtmf_event (GstDTMFSrc * dtmfsrc, GstEvent * event)
{
  const GstStructure *event_structure;
  GstStateChangeReturn sret;
  GstState state;
  gint event_type;
  gboolean start;
  gint method;
  GstClockTime last_stop;
  gint event_number;
  gint event_volume;
  gboolean correct_order;

  sret = gst_element_get_state (GST_ELEMENT (dtmfsrc), &state, NULL, 0);
  if (sret != GST_STATE_CHANGE_SUCCESS || state != GST_STATE_PLAYING) {
    GST_DEBUG_OBJECT (dtmfsrc, "dtmf-event, but not in PLAYING state");
    goto failure;
  }

  event_structure = gst_event_get_structure (event);

  if (!gst_structure_get_int (event_structure, "type", &event_type) ||
      !gst_structure_get_boolean (event_structure, "start", &start) ||
      (start == TRUE && event_type != GST_TONE_DTMF_TYPE_EVENT))
    goto failure;

  if (gst_structure_get_int (event_structure, "method", &method)) {
    if (method != 2) {
      goto failure;
    }
  }

  if (start)
    if (!gst_structure_get_int (event_structure, "number", &event_number) ||
        !gst_structure_get_int (event_structure, "volume", &event_volume))
      goto failure;


  GST_OBJECT_LOCK (dtmfsrc);
  if (gst_structure_get_clock_time (event_structure, "last-stop", &last_stop))
    dtmfsrc->last_stop = last_stop;
  else
    dtmfsrc->last_stop = GST_CLOCK_TIME_NONE;
  correct_order = (start != dtmfsrc->last_event_was_start);
  dtmfsrc->last_event_was_start = start;
  GST_OBJECT_UNLOCK (dtmfsrc);

  if (!correct_order)
    goto failure;

  if (start) {
    GST_DEBUG_OBJECT (dtmfsrc, "Received start event %d with volume %d",
        event_number, event_volume);
    gst_dtmf_src_add_start_event (dtmfsrc, event_number, event_volume);
  }

  else {
    GST_DEBUG_OBJECT (dtmfsrc, "Received stop event");
    gst_dtmf_src_add_stop_event (dtmfsrc);
  }

  return TRUE;
failure:
  return FALSE;
}
Exemplo n.º 13
0
void TrackAnalyser::messageReceived(GstMessage *message)
{
        switch (GST_MESSAGE_TYPE (message)) {
        case GST_MESSAGE_ERROR: {
                GError *err;
                gchar *debug;
                gst_message_parse_error (message, &err, &debug);
                QString str;
                str = "Error #"+QString::number(err->code)+" in module "+QString::number(err->domain)+"\n"+QString::fromUtf8(err->message);
                if(err->code == 6 && err->domain == 851) {
                        str += "\nMay be you should to install gstreamer0.10-plugins-ugly or gstreamer0.10-plugins-bad";
                }
                qDebug()<< "Gstreamer error:"<< str;
                g_error_free (err);
                g_free (debug);
                need_finish();
                break;
        }
        case GST_MESSAGE_EOS:{
                qDebug() << __PRETTY_FUNCTION__ <<":"<<parentWidget()->objectName()<<" End of track reached";
                need_finish();
                break;
        }
        case GST_MESSAGE_ELEMENT:{
                GstClockTime timestamp;

                const GstStructure *s = gst_message_get_structure (message);
                const gchar *name = gst_structure_get_name (s);

                if (strcmp (name, "cutter") == 0) {
                    gst_structure_get_clock_time (s, "timestamp", &timestamp);
                    const GValue *value;
                    value=gst_structure_get_value (s, "above");
                    bool isSilent=!g_value_get_boolean(value);

                    //if we detect a falling edge, set EndPostion to this
                    if (isSilent)
                        m_EndPosition=QTime(0,0).addMSecs( static_cast<uint>( ( timestamp / GST_MSECOND ) )); // nanosec -> msec
                    else
                    {
                        //if this is the first rising edge, set StartPosition
                        if (m_StartPosition==QTime(0,0) && m_EndPosition==m_MaxPosition)
                            m_StartPosition=QTime(0,0).addMSecs( static_cast<uint>( ( timestamp / GST_MSECOND ) )); // nanosec -> msec

                        //if we detect a rising edge, set EndPostion to track end
                        m_EndPosition=m_MaxPosition;
                    }
                    //qDebug() << __PRETTY_FUNCTION__ <<QTime(0,0).addMSecs( static_cast<uint>( ( timestamp / GST_MSECOND ) ))<< " silent:" << isSilent;
                }
            break;
          }

        case GST_MESSAGE_TAG:{

                const GstStructure *s = gst_message_get_structure (message);
                const GValue *value;
                value=gst_structure_get_value (s, "replaygain-track-gain");
                if (value){
                    m_GainDB = g_value_get_double (value);
                    //qDebug() << "Gain-db:" << gain_db;
                    //qDebug() << "Gain-norm:" << pow (10, m_GainDB / 20);
                }
            }

        default:
                break;
        }

}
Exemplo n.º 14
0
static void
gst_hls_sink_handle_message (GstBin * bin, GstMessage * message)
{
  GstHlsSink *sink = GST_HLS_SINK_CAST (bin);

  switch (message->type) {
    case GST_MESSAGE_ELEMENT:
    {
      const char *filename;
      GstClockTime running_time, duration;
      gboolean discont = FALSE;
      gchar *entry_location;
      const GstStructure *structure;

      structure = gst_message_get_structure (message);
      if (strcmp (gst_structure_get_name (structure), "GstMultiFileSink"))
        break;

      filename = gst_structure_get_string (structure, "filename");
      gst_structure_get_clock_time (structure, "running-time", &running_time);
      duration = running_time - sink->last_running_time;
      sink->last_running_time = running_time;

      GST_INFO_OBJECT (sink, "COUNT %d", sink->index);
      if (sink->playlist_root == NULL)
        entry_location = g_path_get_basename (filename);
      else {
        gchar *name = g_path_get_basename (filename);
        entry_location = g_build_filename (sink->playlist_root, name, NULL);
        g_free (name);
      }

      gst_m3u8_playlist_add_entry (sink->playlist, entry_location,
          NULL, duration, sink->index, discont);
      g_free (entry_location);

      gst_hls_sink_write_playlist (sink);

      /* multifilesink is starting a new file. It means that upstream sent a key
       * unit and we can schedule the next key unit now.
       */
      sink->waiting_fku = FALSE;
      schedule_next_key_unit (sink);

      /* multifilesink is an internal implementation detail. If applications
       * need a notification, we should probably do our own message */
      GST_DEBUG_OBJECT (bin, "dropping message %" GST_PTR_FORMAT, message);
      gst_message_unref (message);
      message = NULL;
      break;
    }
    case GST_MESSAGE_EOS:{
      sink->playlist->end_list = TRUE;
      gst_hls_sink_write_playlist (sink);
      break;
    }
    default:
      break;
  }

  if (message)
    GST_BIN_CLASS (parent_class)->handle_message (bin, message);
}
// get spectrum messages and delay them
static gboolean on_message(GstBus *bus, GstMessage *message, gpointer data)
{
	base *base_object = data;
	GstElement *spectrum = GST_ELEMENT(base_object->spectrum_element->obj);
	gst_object_ref(spectrum);

	GstElement *message_element = GST_ELEMENT(GST_MESSAGE_SRC(message));
	gst_object_ref(message_element);

	if (message_element == spectrum)
	{
		GstClockTime waittime = GST_CLOCK_TIME_NONE;
		const GstStructure *message_structure = gst_message_get_structure(message);

		// determine waittime
		GstClockTime timestamp, duration;

		if (
			   gst_structure_get_clock_time(message_structure, "running-time", &timestamp)
			&& gst_structure_get_clock_time(message_structure, "duration", &duration)
		)
		{
			/* wait for middle of buffer */
			waittime = timestamp + duration/2;
		}
		else if (gst_structure_get_clock_time(message_structure, "endtime", &timestamp))
		{
			waittime = timestamp;
		}

		// delay message
		if (GST_CLOCK_TIME_IS_VALID(waittime))
		{
			GstClockTime basetime = gst_element_get_base_time(spectrum);
			GstClockID clock_id = gst_clock_new_single_shot_id(base_object->sync_clock, basetime+waittime);
			spectrum_message *mess = g_malloc(sizeof(spectrum_message));

			// set bands and threshold
			g_object_get(message_element, "bands", &(mess->bands), "threshold", &(mess->threshold), NULL);

			// set start and duration
			GstClockTime streamtime, duration;
			gst_structure_get_clock_time(message_structure, "stream-time", &streamtime);
			gst_structure_get_clock_time(message_structure, "duration", &duration);

			mess->start = (gfloat)streamtime / GST_SECOND;
			mess->duration = (gfloat)duration / GST_SECOND;

			// set rate
			GstPad *sink = gst_element_get_static_pad(GST_ELEMENT(base_object->spectrum_element->obj), "sink");
			GstCaps *caps = gst_pad_get_negotiated_caps(sink);
			gst_object_unref(sink);

			GstStructure *caps_structure = gst_caps_get_structure(caps, 0);
			gst_structure_get_int(caps_structure, "rate", &(mess->rate));
			gst_caps_unref(caps);

			// set magnitudes
			const GValue *list = gst_structure_get_value(message_structure, "magnitude");

			PyGILState_STATE gstate = PyGILState_Ensure();

			int i;
			mess->magnitudes = PyList_New(mess->bands);
			for (i=0; i < (mess->bands); i++)
			{
				const GValue *value = gst_value_list_get_value(list, i);
				gfloat f = g_value_get_float(value);
				PyList_SetItem(mess->magnitudes, i, Py_BuildValue("f", f));
			}

			PyGILState_Release(gstate);

			// set gobj
			GObject *gobj = (base_object->gobj).obj;
			g_assert(gobj != NULL);
			g_object_ref(gobj);
			mess->gobj = gobj;

			// delay message
			gst_clock_id_wait_async(clock_id, delayed_spectrum_update, mess);

			gst_clock_id_unref(clock_id);
		}
	}

	gst_object_unref(spectrum);
	gst_object_unref(message_element);

	return TRUE;
}