Exemplo n.º 1
0
static void
kms_remb_remote_update (KmsRembRemote * rm,
    KmsRTCPPSFBAFBREMBPacket * remb_packet)
{
  if (remb_packet->n_ssrcs == 0) {
    GST_WARNING_OBJECT (KMS_REMB_BASE (rm)->rtpsess,
        "REMB packet without any SSRC");
    return;
  } else if (remb_packet->n_ssrcs > 1) {
    GST_WARNING_OBJECT (KMS_REMB_BASE (rm)->rtpsess,
        "REMB packet with %" G_GUINT32_FORMAT " SSRCs."
        " A inconsistent management could take place", remb_packet->n_ssrcs);
  }

  if (!rm->probed) {
    /* FIXME: if no event is sent until this condition,
     * the restriction of this br will be removed by event manager
     * in 10secs*/
    if ((remb_packet->bitrate < REMB_ON_CONNECT)
        && (remb_packet->bitrate >= rm->remb)) {
      rm->remb = remb_packet->bitrate;
      return;
    }

    rm->probed = TRUE;
  }

  send_remb_event (rm, remb_packet->bitrate, remb_packet->ssrcs[0]);
  rm->remb = remb_packet->bitrate;
}
Exemplo n.º 2
0
static void
kms_remb_remote_update (KmsRembRemote * rm,
    KmsRTCPPSFBAFBREMBPacket * remb_packet)
{
  guint32 br_send;

  if (remb_packet->n_ssrcs == 0) {
    GST_WARNING_OBJECT (KMS_REMB_BASE (rm)->rtpsess,
        "REMB packet without any SSRC");
    return;
  } else if (remb_packet->n_ssrcs > 1) {
    GST_WARNING_OBJECT (KMS_REMB_BASE (rm)->rtpsess,
        "REMB packet with %" G_GUINT32_FORMAT " SSRCs."
        " A inconsistent management could take place", remb_packet->n_ssrcs);
  }

  br_send = remb_packet->bitrate;
  if (!rm->probed) {
    if ((remb_packet->bitrate < rm->remb_on_connect)
        && (remb_packet->bitrate >= rm->remb)) {
      GST_DEBUG_OBJECT (KMS_REMB_BASE (rm)->rtpsess,
          "Not probed: sending remb_on_connect value");
      br_send = rm->remb_on_connect;
      rm->remb = remb_packet->bitrate;
    } else {
      rm->probed = TRUE;
    }
  }

  send_remb_event (rm, br_send, remb_packet->ssrcs[0]);
  rm->remb = remb_packet->bitrate;
}
Exemplo n.º 3
0
static void
send_remb_event (KmsRembRemote * rm, guint bitrate, guint ssrc)
{
  GstEvent *event;
  guint br, min = 0, max = 0;

  /* TODO: use g_atomic */
  if (rm->pad_event == NULL) {
    return;
  }

  br = bitrate;

  if (rm->min_bw > 0) {
    min = rm->min_bw * 1000;
    br = MAX (br, min);
  }

  if (rm->max_bw > 0) {
    max = rm->max_bw * 1000;
    br = MIN (br, max);
  }

  GST_TRACE_OBJECT (KMS_REMB_BASE (rm)->rtpsess,
      "bitrate: %" G_GUINT32_FORMAT ", ssrc: %" G_GUINT32_FORMAT
      ", range [%" G_GUINT32_FORMAT ", %" G_GUINT32_FORMAT
      "], event bitrate: %" G_GUINT32_FORMAT, bitrate, ssrc, min, max, br);

  event = kms_utils_remb_event_upstream_new (br, ssrc);
  gst_pad_push_event (rm->pad_event, event);
}
Exemplo n.º 4
0
KmsRembLocal *
kms_remb_local_create (GObject * rtpsess, guint session, guint remote_ssrc,
    guint min_bw, guint max_bw)
{
  KmsRembLocal *rl = g_slice_new0 (KmsRembLocal);

  g_object_set_data (rtpsess, KMS_REMB_LOCAL, rl);
  rl->base.signal_id = g_signal_connect (rtpsess, "on-sending-rtcp",
      G_CALLBACK (on_sending_rtcp), NULL);

  kms_remb_base_create (KMS_REMB_BASE (rl), session, rtpsess);

  rl->remote_ssrc = remote_ssrc;
  rl->min_bw = min_bw;
  rl->max_bw = max_bw;

  rl->probed = FALSE;
  rl->remb = REMB_MAX;
  rl->threshold = REMB_MAX;
  rl->lineal_factor = DEFAULT_REMB_LINEAL_FACTOR_MIN;

  rl->packets_recv_interval_top = DEFAULT_REMB_PACKETS_RECV_INTERVAL_TOP;
  rl->exponential_factor = DEFAULT_REMB_EXPONENTIAL_FACTOR;
  rl->lineal_factor_min = DEFAULT_REMB_LINEAL_FACTOR_MIN;
  rl->lineal_factor_grade = DEFAULT_REMB_LINEAL_FACTOR_GRADE;
  rl->decrement_factor = DEFAULT_REMB_DECREMENT_FACTOR;
  rl->threshold_factor = DEFAULT_REMB_THRESHOLD_FACTOR;
  rl->up_losses = DEFAULT_REMB_UP_LOSSES;

  return rl;
}
Exemplo n.º 5
0
static void
kms_remb_remote_update_target_ssrcs_stats (KmsRembRemote * rm,
    KmsRTCPPSFBAFBREMBPacket * remb_packet)
{
  guint i;

  for (i = 0; i < remb_packet->n_ssrcs; i++) {
    kms_remb_base_update_stats (KMS_REMB_BASE (rm), remb_packet->ssrcs[i],
        remb_packet->bitrate);
  }
}
Exemplo n.º 6
0
void
kms_remb_remote_destroy (KmsRembRemote * rm)
{
  if (rm == NULL) {
    return;
  }

  if (rm->pad_event != NULL) {
    g_object_unref (rm->pad_event);
  }

  kms_remb_base_destroy (KMS_REMB_BASE (rm));

  g_slice_free (KmsRembRemote, rm);
}
Exemplo n.º 7
0
void
kms_remb_local_destroy (KmsRembLocal * rl)
{
  if (rl == NULL) {
    return;
  }

  if (rl->event_manager != NULL) {
    kms_utils_remb_event_manager_destroy (rl->event_manager);
  }

  kms_remb_base_destroy (KMS_REMB_BASE (rl));

  g_slice_free (KmsRembLocal, rl);
}
Exemplo n.º 8
0
static void
process_psfb_afb (GObject * sess, guint ssrc, GstBuffer * fci_buffer)
{
  KmsRembRemote *rm;
  KmsRTCPPSFBAFBBuffer afb_buffer = { NULL, };
  KmsRTCPPSFBAFBPacket afb_packet;
  KmsRTCPPSFBAFBREMBPacket remb_packet;
  KmsRTCPPSFBAFBType type;

  if (!G_IS_OBJECT (sess)) {
    GST_WARNING ("Invalid session object");
    return;
  }

  rm = g_object_get_data (sess, KMS_REMB_REMOTE);

  if (!rm) {
    GST_WARNING ("Invalid RembRemote");
    return;
  }

  if (!kms_rtcp_psfb_afb_buffer_map (fci_buffer, GST_MAP_READ, &afb_buffer)) {
    GST_WARNING_OBJECT (fci_buffer, "Buffer cannot be mapped");
    return;
  }

  if (!kms_rtcp_psfb_afb_get_packet (&afb_buffer, &afb_packet)) {
    GST_WARNING_OBJECT (fci_buffer, "Cannot get RTCP PSFB AFB packet");
    goto end;
  }

  type = kms_rtcp_psfb_afb_packet_get_type (&afb_packet);
  switch (type) {
    case KMS_RTCP_PSFB_AFB_TYPE_REMB:
      kms_rtcp_psfb_afb_remb_get_packet (&afb_packet, &remb_packet);
      kms_remb_remote_update (rm, &remb_packet);
      kms_remb_base_update_stats (KMS_REMB_BASE (rm), ssrc,
          remb_packet.bitrate);
      break;
    default:
      break;
  }

end:
  kms_rtcp_psfb_afb_buffer_unmap (&afb_buffer);
}
Exemplo n.º 9
0
KmsRembRemote *
kms_remb_remote_create (GObject * rtpsess, guint session, guint local_ssrc,
    guint min_bw, guint max_bw, GstPad * pad)
{
  KmsRembRemote *rm = g_slice_new0 (KmsRembRemote);

  g_object_set_data (rtpsess, KMS_REMB_REMOTE, rm);
  rm->base.signal_id = g_signal_connect (rtpsess, "on-feedback-rtcp",
      G_CALLBACK (on_feedback_rtcp), NULL);

  kms_remb_base_create (KMS_REMB_BASE (rm), session, rtpsess);

  rm->local_ssrc = local_ssrc;
  rm->min_bw = min_bw;
  rm->max_bw = max_bw;

  rm->pad_event = g_object_ref (pad);
  gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM,
      send_remb_event_probe, rm, NULL);

  return rm;
}
Exemplo n.º 10
0
KmsRembLocal *
kms_remb_local_create (GObject * rtpsess, guint session, guint remote_ssrc,
    guint min_bw, guint max_bw)
{
  KmsRembLocal *rl = g_slice_new0 (KmsRembLocal);

  g_object_set_data (rtpsess, KMS_REMB_LOCAL, rl);
  rl->base.signal_id = g_signal_connect (rtpsess, "on-sending-rtcp",
      G_CALLBACK (on_sending_rtcp), NULL);

  kms_remb_base_create (KMS_REMB_BASE (rl), session, rtpsess);

  rl->remote_ssrc = remote_ssrc;
  rl->min_bw = min_bw;
  rl->max_bw = max_bw;

  rl->probed = FALSE;
  rl->remb = REMB_MAX;
  rl->threshold = REMB_MAX;
  rl->lineal_factor = REMB_LINEAL_FACTOR_MIN;

  return rl;
}
Exemplo n.º 11
0
static gboolean
get_video_recv_info (KmsRembLocal * rl,
    guint64 * bitrate, guint * fraction_lost, guint64 * packets_rcv_interval)
{
  GValueArray *arr = NULL;
  GValue *val;
  guint i;
  gboolean ret = FALSE;

  if (!KMS_REMB_BASE (rl)->rtpsess) {
    GST_WARNING ("Session object does not exist");
    return ret;
  }

  g_object_get (KMS_REMB_BASE (rl)->rtpsess, "sources", &arr, NULL);

  if (arr == NULL) {
    GST_WARNING ("Sources array not found");
    return ret;
  }

  for (i = 0; i < arr->n_values; i++) {
    GObject *source;
    guint ssrc;
    GstStructure *s;

    val = g_value_array_get_nth (arr, i);
    source = g_value_get_object (val);
    g_object_get (source, "ssrc", &ssrc, "stats", &s, NULL);

    GST_TRACE_OBJECT (source, "source ssrc: %u", ssrc);
    GST_TRACE_OBJECT (KMS_REMB_BASE (rl)->rtpsess, "stats: %" GST_PTR_FORMAT,
        s);

    if (ssrc == rl->remote_ssrc) {
      GstClockTime current_time;
      guint64 octets_received, packets_received;

      if (!gst_structure_get_uint64 (s, "bitrate", bitrate)) {
        break;
      }
      if (!gst_structure_get_uint64 (s, "octets-received", &octets_received)) {
        break;
      }
      if (!gst_structure_get_uint (s, "sent-rb-fractionlost", fraction_lost)) {
        break;
      }
      if (!gst_structure_get_uint64 (s, "packets-received", &packets_received)) {
        break;
      }

      current_time = kms_utils_get_time_nsecs ();

      if (rl->last_time != 0) {
        GstClockTime elapsed = current_time - rl->last_time;
        guint64 bytes_handled = octets_received - rl->last_octets_received;

        *bitrate =
            gst_util_uint64_scale (bytes_handled, 8 * GST_SECOND, elapsed);
        GST_TRACE_OBJECT (KMS_REMB_BASE (rl)->rtpsess,
            "Elapsed %" G_GUINT64_FORMAT " bytes %" G_GUINT64_FORMAT ", rate %"
            G_GUINT64_FORMAT, elapsed, bytes_handled, *bitrate);
      }

      rl->last_time = current_time;
      rl->last_octets_received = octets_received;

      *packets_rcv_interval = packets_received - rl->last_packets_received;
      rl->last_packets_received = packets_received;

      ret = TRUE;
    }

    gst_structure_free (s);

    if (ret) {
      break;
    }
  }

  g_value_array_free (arr);

  return ret;
}
Exemplo n.º 12
0
static void
on_sending_rtcp (GObject * sess, GstBuffer * buffer, gboolean is_early,
    gboolean * do_not_supress)
{
  KmsRembLocal *rl;
  KmsRTCPPSFBAFBREMBPacket remb_packet;
  GstRTCPBuffer rtcp = { NULL, };
  GstRTCPPacket packet;
  guint packet_ssrc;

  rl = g_object_get_data (sess, KMS_REMB_LOCAL);

  if (!rl) {
    GST_WARNING ("Invalid RembLocal");
    return;
  }

  if (is_early) {
    return;
  }

  if (!gst_rtcp_buffer_map (buffer, GST_MAP_READWRITE, &rtcp)) {
    GST_WARNING_OBJECT (sess, "Cannot map buffer to RTCP");
    return;
  }

  if (!gst_rtcp_buffer_add_packet (&rtcp, GST_RTCP_TYPE_PSFB, &packet)) {
    GST_WARNING_OBJECT (sess, "Cannot add RTCP packet");
    goto end;
  }

  if (!kms_remb_local_update (rl)) {
    goto end;
  }

  remb_packet.bitrate = rl->remb;
  if (rl->event_manager != NULL) {
    guint remb_local_max;

    remb_local_max = kms_utils_remb_event_manager_get_min (rl->event_manager);
    if (remb_local_max > 0) {
      GST_TRACE_OBJECT (sess, "REMB local max: %" G_GUINT32_FORMAT,
          remb_local_max);
      remb_packet.bitrate = MIN (remb_local_max, rl->remb);
    }
  }

  if (rl->min_bw > 0) {
    remb_packet.bitrate = MAX (remb_packet.bitrate, rl->min_bw * 1000);
  } else {
    remb_packet.bitrate = MAX (remb_packet.bitrate, REMB_MIN);
  }

  remb_packet.n_ssrcs = 1;
  remb_packet.ssrcs[0] = rl->remote_ssrc;
  g_object_get (sess, "internal-ssrc", &packet_ssrc, NULL);
  if (!kms_rtcp_psfb_afb_remb_marshall_packet (&packet, &remb_packet,
          packet_ssrc)) {
    gst_rtcp_packet_remove (&packet);
  }

  GST_TRACE_OBJECT (sess, "Sending REMB (bitrate: %" G_GUINT32_FORMAT
      ", ssrc: %" G_GUINT32_FORMAT ")", remb_packet.bitrate, rl->remote_ssrc);

  kms_remb_base_update_stats (KMS_REMB_BASE (rl), rl->remote_ssrc,
      remb_packet.bitrate);

end:
  gst_rtcp_buffer_unmap (&rtcp);
}
Exemplo n.º 13
0
static gboolean
kms_remb_local_update (KmsRembLocal * rl)
{
  guint64 bitrate, packets_rcv_interval;
  guint fraction_lost, packets_rcv_interval_top;

  if (!get_video_recv_info (rl, &bitrate, &fraction_lost,
          &packets_rcv_interval)) {
    return FALSE;
  }

  if (!rl->probed) {
    if (bitrate == 0) {
      return FALSE;
    }

    rl->remb = bitrate;
    rl->probed = TRUE;
  }

  packets_rcv_interval_top =
      MAX (rl->packets_recv_interval_top, packets_rcv_interval);
  rl->fraction_lost_record =
      (rl->fraction_lost_record * (packets_rcv_interval_top -
          packets_rcv_interval) +
      fraction_lost * packets_rcv_interval) / packets_rcv_interval_top;
  rl->max_br = MAX (rl->max_br, bitrate);

  if (rl->avg_br == 0) {
    rl->avg_br = bitrate;
  } else {
    rl->avg_br = (rl->avg_br * 7 + bitrate) / 8;
  }

  GST_TRACE_OBJECT (KMS_REMB_BASE (rl)->rtpsess,
      "packets_rcv_interval: %" G_GUINT64_FORMAT ", fraction_lost_record: %"
      G_GUINT64_FORMAT, packets_rcv_interval, rl->fraction_lost_record);

  if (rl->fraction_lost_record == 0) {
    gint remb_base, remb_new;

    remb_base = MIN (rl->remb, rl->max_br);

    if (remb_base < rl->threshold) {
      GST_TRACE_OBJECT (KMS_REMB_BASE (rl)->rtpsess, "A.1) Exponential (%f)",
          rl->exponential_factor);
      remb_new = remb_base * (1 + rl->exponential_factor);
    } else {
      GST_TRACE_OBJECT (KMS_REMB_BASE (rl)->rtpsess,
          "A.2) Lineal (%" G_GUINT32_FORMAT ")", rl->lineal_factor);
      remb_new = remb_base + rl->lineal_factor;
    }

    rl->remb = MAX (rl->remb, remb_new);
  } else {
    gint remb_base, lineal_factor_new;

    remb_base = MAX (rl->remb, rl->avg_br);
    rl->threshold = remb_base * rl->threshold_factor;
    lineal_factor_new = (remb_base - rl->threshold) / rl->lineal_factor_grade;
    rl->lineal_factor = MAX (rl->lineal_factor_min, lineal_factor_new);

    if (rl->fraction_lost_record < rl->up_losses) {
      GST_TRACE_OBJECT (KMS_REMB_BASE (rl)->rtpsess, "B) Assumable losses");

      rl->remb = MIN (rl->remb, rl->max_br);
    } else {
      GST_TRACE_OBJECT (KMS_REMB_BASE (rl)->rtpsess, "C) Too losses");

      rl->remb = remb_base * rl->decrement_factor;
      rl->fraction_lost_record = 0;
      rl->max_br = 0;
      rl->avg_br = 0;
    }
  }

  if (rl->max_bw > 0) {
    rl->remb = MIN (rl->remb, rl->max_bw * 1000);
  }

  GST_TRACE_OBJECT (KMS_REMB_BASE (rl)->rtpsess,
      "REMB: %" G_GUINT32_FORMAT ", TH: %" G_GUINT32_FORMAT
      ", fraction_lost: %d, fraction_lost_record: %" G_GUINT64_FORMAT
      ", bitrate: %" G_GUINT64_FORMAT "," " max_br: %" G_GUINT32_FORMAT
      ", avg_br: %" G_GUINT32_FORMAT, rl->remb, rl->threshold, fraction_lost,
      rl->fraction_lost_record, bitrate, rl->max_br, rl->avg_br);

  return TRUE;
}
Exemplo n.º 14
0
static gboolean
kms_remb_local_update (KmsRembLocal * rl)
{
  guint64 bitrate;
  guint fraction_lost;

  if (!get_video_recv_info (rl, &bitrate, &fraction_lost)) {
    return FALSE;
  }

  if (!rl->probed) {
    if (bitrate == 0) {
      return FALSE;
    }

    rl->remb = bitrate;
    rl->probed = TRUE;
  }

  rl->max_br = MAX (rl->max_br, bitrate);

  if (rl->avg_br == 0) {
    rl->avg_br = bitrate;
  } else {
    rl->avg_br = (rl->avg_br * 7 + bitrate) / 8;
  }

  if (fraction_lost == 0) {
    gint remb_base, remb_new;

    remb_base = MIN (rl->remb, rl->max_br);

    if (remb_base < rl->threshold) {
      GST_TRACE_OBJECT (KMS_REMB_BASE (rl)->rtpsess, "A.1) Exponential (%f)",
          REMB_EXPONENTIAL_FACTOR);
      remb_new = remb_base * (1 + REMB_EXPONENTIAL_FACTOR);
    } else {
      GST_TRACE_OBJECT (KMS_REMB_BASE (rl)->rtpsess,
          "A.2) Lineal (%" G_GUINT32_FORMAT ")", rl->lineal_factor);
      remb_new = remb_base + rl->lineal_factor;
    }

    rl->remb = MAX (rl->remb, remb_new);
  } else if (fraction_lost < REMB_UP_LOSSES) {
    GST_TRACE_OBJECT (KMS_REMB_BASE (rl)->rtpsess, "B) Assumable losses");

    rl->remb = MIN (rl->remb, rl->max_br);
    rl->threshold = rl->remb * REMB_THRESHOLD_FACTOR;
  } else {
    gint remb_base, lineal_factor_new;

    GST_TRACE_OBJECT (KMS_REMB_BASE (rl)->rtpsess, "C) Too losses");

    remb_base = MAX (rl->remb, rl->avg_br);
    rl->remb = remb_base * REMB_DECREMENT_FACTOR;
    rl->threshold = remb_base * REMB_THRESHOLD_FACTOR;
    lineal_factor_new = (remb_base - rl->threshold) / REMB_LINEAL_FACTOR_GRADE;
    rl->lineal_factor = MAX (REMB_LINEAL_FACTOR_MIN, lineal_factor_new);
    rl->max_br = 0;
    rl->avg_br = 0;
  }

  if (rl->max_bw > 0) {
    rl->remb = MIN (rl->remb, rl->max_bw * 1000);
  }

  GST_TRACE_OBJECT (KMS_REMB_BASE (rl)->rtpsess,
      "REMB: %" G_GUINT32_FORMAT ", TH: %" G_GUINT32_FORMAT
      ", fraction_lost: %d, bitrate: %" G_GUINT64_FORMAT "," " max_br: %"
      G_GUINT32_FORMAT ", avg_br: %" G_GUINT32_FORMAT, rl->remb,
      rl->threshold, fraction_lost, bitrate, rl->max_br, rl->avg_br);

  return TRUE;
}