예제 #1
0
static const gchar *
kms_base_rtp_session_process_remote_ssrc (KmsBaseRtpSession * self,
    GstSDPMedia * remote_media, SdpMediaConfig * neg_mconf)
{
  const gchar *media_str = gst_sdp_media_get_media (remote_media);
  guint ssrc;

  ssrc = sdp_utils_media_get_fid_ssrc (remote_media, 0);
  if (ssrc == 0) {
    ssrc = sdp_utils_media_get_ssrc (remote_media);
  }

  if (g_strcmp0 (AUDIO_STREAM_NAME, media_str) == 0) {
    GST_DEBUG_OBJECT (self, "Add remote audio ssrc: %u", ssrc);
    self->remote_audio_ssrc = ssrc;
    self->audio_neg_mconf = neg_mconf;

    return AUDIO_RTP_SESSION_STR;
  } else if (g_strcmp0 (VIDEO_STREAM_NAME, media_str) == 0) {
    GST_DEBUG_OBJECT (self, "Add remote video ssrc: %u", ssrc);
    self->remote_video_ssrc = ssrc;
    self->video_neg_mconf = neg_mconf;

    return VIDEO_RTP_SESSION_STR;
  }

  GST_WARNING_OBJECT (self, "Media '%s' not supported", media_str);

  return NULL;
}
예제 #2
0
static SdpHandler *
kms_sdp_agent_get_handler_for_media (KmsSdpAgent * agent,
    const GstSDPMedia * media)
{
  GSList *l;

  for (l = agent->priv->handlers; l != NULL; l = l->next) {
    SdpHandler *sdp_handler;

    sdp_handler = l->data;

    if (g_strcmp0 (sdp_handler->media, gst_sdp_media_get_media (media)) != 0) {
      /* This handler can not manage this media */
      continue;
    }

    if (!kms_sdp_media_handler_manage_protocol (sdp_handler->handler,
            gst_sdp_media_get_proto (media))) {
      continue;
    }

    return sdp_handler;
  }

  return NULL;
}
예제 #3
0
GstSDPMedia *
kms_sdp_reject_media_handler_create_answer (KmsSdpMediaHandler * handler,
        const GstSDPMessage * msg, const GstSDPMedia * offer, GError ** error)
{
    GstSDPMedia *m = NULL;

    if (gst_sdp_media_new (&m) != GST_SDP_OK) {
        g_set_error (error, KMS_SDP_AGENT_ERROR, SDP_AGENT_UNEXPECTED_ERROR,
                     "Can not create '%s' media answer", gst_sdp_media_get_media (offer));
        goto error;
    }

    /* Create m-line */
    if (!KMS_SDP_MEDIA_HANDLER_GET_CLASS (handler)->init_answer (handler, offer,
            m, error)) {
        goto error;
    }

    /* Add attributes to m-line */
    if (!KMS_SDP_MEDIA_HANDLER_GET_CLASS (handler)->add_answer_attributes
            (handler, offer, m, error)) {
        goto error;
    }

    return m;

error:

    if (m != NULL) {
        gst_sdp_media_free (m);
    }

    return NULL;
}
예제 #4
0
static GstSDPMedia *
reject_media_answer (const GstSDPMedia * offered)
{
  GstSDPMedia *media;
  const gchar *mid;
  guint i, len;

  gst_sdp_media_new (&media);

  /* [rfc3264] To reject an offered stream, the port number in the */
  /* corresponding stream in the answer MUST be set to zero. Any   */
  /* media formats listed are ignored. */

  gst_sdp_media_set_media (media, gst_sdp_media_get_media (offered));
  gst_sdp_media_set_port_info (media, 0, 1);
  gst_sdp_media_set_proto (media, gst_sdp_media_get_proto (offered));

  len = gst_sdp_media_formats_len (offered);
  for (i = 0; i < len; i++) {
    const gchar *format;

    format = gst_sdp_media_get_format (offered, i);
    gst_sdp_media_insert_format (media, i, format);
  }

  /* [rfc5888] mid attribute must be present in answer as well */
  mid = gst_sdp_media_get_attribute_val (offered, "mid");
  if (mid == NULL) {
    return media;
  }

  gst_sdp_media_add_attribute (media, "mid", mid);

  return media;
}
예제 #5
0
static gboolean
kms_base_rtp_session_configure_connection (KmsBaseRtpSession * self,
    SdpMediaConfig * neg_mconf, SdpMediaConfig * remote_mconf, gboolean offerer)
{
  GstSDPMedia *neg_media = kms_sdp_media_config_get_sdp_media (neg_mconf);
  const gchar *neg_proto_str = gst_sdp_media_get_proto (neg_media);
  const gchar *neg_media_str = gst_sdp_media_get_media (neg_media);

  GstSDPMedia *remote_media = kms_sdp_media_config_get_sdp_media (remote_mconf);
  const gchar *remote_proto_str = gst_sdp_media_get_proto (remote_media);
  const gchar *remote_media_str = gst_sdp_media_get_media (remote_media);
  gboolean active;

  if (g_strcmp0 (neg_proto_str, remote_proto_str) != 0) {
    GST_WARNING_OBJECT (self,
        "Negotiated proto ('%s') not matching with remote proto ('%s')",
        neg_proto_str, remote_proto_str);
    return FALSE;
  }

  if (!kms_utils_contains_proto (neg_proto_str, "RTP")) {
    GST_DEBUG_OBJECT (self, "'%s' protocol does not need RTP connection",
        neg_proto_str);
    /* It cannot be managed here but could be managed by the child class */
    return FALSE;
  }

  if (g_strcmp0 (neg_media_str, remote_media_str) != 0) {
    GST_WARNING_OBJECT (self,
        "Negotiated media ('%s') not matching with remote media ('%s')",
        neg_media_str, remote_media_str);
    return FALSE;
  }

  if (kms_base_rtp_session_process_remote_ssrc (self, remote_media,
          neg_mconf) == NULL) {
    return TRUE;                /* It cannot be managed here but could be managed by the child class */
  }

  active = sdp_utils_media_is_active (neg_media, offerer);

  return kms_base_rtp_session_add_connection_for_session (self, neg_mconf,
      active);
}
예제 #6
0
static void
kms_rtp_endpoint_start_transport_send (KmsBaseSdpEndpoint *
    base_sdp_endpoint, gboolean offerer)
{
  KmsRtpEndpoint *self = KMS_RTP_ENDPOINT (base_sdp_endpoint);
  SdpMessageContext *remote_ctx =
      kms_base_sdp_endpoint_get_remote_sdp_ctx (base_sdp_endpoint);
  const GstSDPMessage *sdp =
      kms_sdp_message_context_get_sdp_message (remote_ctx);
  const GSList *item = kms_sdp_message_context_get_medias (remote_ctx);
  const GstSDPConnection *msg_conn = gst_sdp_message_get_connection (sdp);

  /* Chain up */
  KMS_BASE_SDP_ENDPOINT_CLASS (parent_class)->start_transport_send
      (base_sdp_endpoint, offerer);

  for (; item != NULL; item = g_slist_next (item)) {
    SdpMediaConfig *mconf = item->data;
    GstSDPMedia *media = kms_sdp_media_config_get_sdp_media (mconf);
    const GstSDPConnection *media_con;
    KmsRtpBaseConnection *conn;
    guint port;

    if (media->port == 0) {
      continue;
    }

    if (gst_sdp_media_connections_len (media) != 0) {
      media_con = gst_sdp_media_get_connection (media, 0);
    } else {
      media_con = msg_conn;
    }

    if (media_con == NULL || media_con->address == NULL
        || media_con->address[0] == '\0') {
      const gchar *media_str = gst_sdp_media_get_media (media);

      GST_WARNING_OBJECT (self, "Missing connection information for '%s'",
          media_str);
      continue;
    }

    conn = kms_rtp_endpoint_media_get_connection (self, mconf);
    if (conn == NULL) {
      continue;
    }

    port = gst_sdp_media_get_port (media);
    kms_rtp_base_connection_set_remote_info (conn,
        media_con->address, port, port + 1);
    /* TODO: get rtcp port from attr if it exists */
  }
}
예제 #7
0
static gboolean
test_response_sdp (GstRTSPClient * client, GstRTSPMessage * response,
    gboolean close, gpointer user_data)
{
  guint8 *data;
  guint size;
  GstSDPMessage *sdp_msg;
  const GstSDPMedia *sdp_media;
  const GstSDPBandwidth *bw;
  gint bandwidth_val = GPOINTER_TO_INT (user_data);

  fail_unless (gst_rtsp_message_get_body (response, &data, &size)
      == GST_RTSP_OK);
  gst_sdp_message_new (&sdp_msg);
  fail_unless (gst_sdp_message_parse_buffer (data, size, sdp_msg)
      == GST_SDP_OK);

  /* session description */
  /* v= */
  fail_unless (gst_sdp_message_get_version (sdp_msg) != NULL);
  /* o= */
  fail_unless (gst_sdp_message_get_origin (sdp_msg) != NULL);
  /* s= */
  fail_unless (gst_sdp_message_get_session_name (sdp_msg) != NULL);
  /* t=0 0 */
  fail_unless (gst_sdp_message_times_len (sdp_msg) == 0);

  /* verify number of medias */
  fail_unless (gst_sdp_message_medias_len (sdp_msg) == 1);

  /* media description */
  sdp_media = gst_sdp_message_get_media (sdp_msg, 0);
  fail_unless (sdp_media != NULL);

  /* m= */
  fail_unless (gst_sdp_media_get_media (sdp_media) != NULL);

  /* media bandwidth */
  if (bandwidth_val) {
    fail_unless (gst_sdp_media_bandwidths_len (sdp_media) == 1);
    bw = gst_sdp_media_get_bandwidth (sdp_media, 0);
    fail_unless (bw != NULL);
    fail_unless (g_strcmp0 (bw->bwtype, "AS") == 0);
    fail_unless (bw->bandwidth == bandwidth_val);
  } else {
    fail_unless (gst_sdp_media_bandwidths_len (sdp_media) == 0);
  }

  gst_sdp_message_free (sdp_msg);

  return TRUE;
}
예제 #8
0
static gboolean
create_media_answer (const GstSDPMedia * media, struct SdpAnswerData *data)
{
  KmsSdpAgent *agent = data->agent;
  GstSDPMedia *answer_media = NULL;
  SdpHandler *sdp_handler;
  GError **err = data->err;

  SDP_AGENT_LOCK (agent);

  sdp_handler = kms_sdp_agent_get_handler_for_media (agent, media);

  SDP_AGENT_UNLOCK (agent);

  if (sdp_handler == NULL) {
    GST_WARNING_OBJECT (agent,
        "No handler for '%s' media proto '%s' found",
        gst_sdp_media_get_media (media), gst_sdp_media_get_proto (media));
    goto answer;
  }

  answer_media = kms_sdp_media_handler_create_answer (sdp_handler->handler,
      data->ctx, media, err);

  if (answer_media == NULL) {
    return FALSE;
  }

answer:
  {
    SdpMediaConfig *mconf;
    gboolean do_call = TRUE;

    if (answer_media == NULL) {
      answer_media = reject_media_answer (media);
      do_call = FALSE;
    }

    mconf = kms_sdp_message_context_add_media (data->ctx, answer_media, err);
    if (mconf == NULL) {
      return FALSE;
    }

    if (do_call && data->agent->priv->configure_media_callback_data != NULL) {
      data->agent->priv->configure_media_callback_data->callback (data->agent,
          mconf, data->agent->priv->configure_media_callback_data->user_data);
    }

    return TRUE;
  }
}
예제 #9
0
static gboolean
kms_sdp_reject_media_handler_init_answer (KmsSdpMediaHandler * handler,
        const GstSDPMedia * offer, GstSDPMedia * answer, GError ** error)
{
    guint i, len;

    if (gst_sdp_media_set_media (answer,
                                 gst_sdp_media_get_media (offer)) != GST_SDP_OK) {
        g_set_error (error, KMS_SDP_AGENT_ERROR, SDP_AGENT_INVALID_PARAMETER,
                     "Can not set '%s' media ttribute", gst_sdp_media_get_media (offer));
        return FALSE;
    }

    if (gst_sdp_media_set_proto (answer,
                                 gst_sdp_media_get_proto (offer)) != GST_SDP_OK) {
        g_set_error (error, KMS_SDP_AGENT_ERROR, SDP_AGENT_INVALID_PARAMETER,
                     "Can not set proto '%s' attribute", gst_sdp_media_get_proto (offer));
        return FALSE;
    }

    if (gst_sdp_media_set_port_info (answer, 0, 1) != GST_SDP_OK) {
        g_set_error_literal (error, KMS_SDP_AGENT_ERROR,
                             SDP_AGENT_INVALID_PARAMETER, "Can not set port info attribute");
        return FALSE;
    }

    len = gst_sdp_media_formats_len (offer);
    for (i = 0; i < len; i++) {
        const gchar *format;

        format = gst_sdp_media_get_format (offer, i);
        gst_sdp_media_insert_format (answer, i, format);
    }

    return TRUE;
}
예제 #10
0
static gboolean
kms_sdp_rtp_avpf_media_handler_add_rtcp_fb_attrs (KmsSdpMediaHandler * handler,
    GstSDPMedia * media, GError ** error)
{
  const gchar *media_str;
  guint i;

  media_str = gst_sdp_media_get_media (media);

  if (g_strcmp0 (media_str, "video") != 0) {
    /* Only nack video rtcp_fb attributes are supported */
    /* [rfc4585] 4.2                                    */
    return TRUE;
  }

  for (i = 0;; i++) {
    const gchar *val;
    gchar **codec;

    val = gst_sdp_media_get_attribute_val_n (media, "rtpmap", i);

    if (val == NULL) {
      break;
    }

    codec = g_strsplit (val, " ", 0);
    if (!is_supported_encoder (codec[1] /* encoder */ )) {
      g_strfreev (codec);
      continue;
    }

    if (!kms_sdp_rtp_avpf_media_handler_rtcp_fb_attrs (handler, media,
            codec[0] /* format */ ,
            codec[1] /* encoder */ , error)) {
      g_strfreev (codec);
      return FALSE;
    }

    g_strfreev (codec);
  }

  return TRUE;
}
예제 #11
0
파일: media.c 프로젝트: dulton/hm-platform
static __inline__ void
rtp_session_attach_loop(RTP_Session *rtp_s)
{
	const gchar *media;
	gint w = LOOP_WEIGHT_AUDIO;

	if (rtp_s->interleaved)
		return;

	media = gst_sdp_media_get_media(rtp_s->m);
	if (media && strstr(media, "video"))	/* fix me */
	{
		w = LOOP_WEIGHT_VEDIO;
	}

	g_scheduler_add((GEvent*)rtp_s->rtp_src, w);

#ifdef CONFIG_RTCP_SUPPORT
	g_scheduler_add((GEvent*)rtp_s->rtcp_src, LOOP_WEIGHT_RTCP);
#endif
}
예제 #12
0
SdpMediaConfig *
kms_sdp_message_context_add_media (SdpMessageContext * ctx, GstSDPMedia * media,
    GError ** error)
{
  SdpMediaConfig *mconf;
  const gchar *media_type;
  gchar *mid;
  guint *counter;

  if (ctx->type == KMS_SDP_ANSWER && g_slist_length (ctx->groups) > 0 &&
      gst_sdp_media_get_attribute_val (media, "mid") == NULL) {
    g_set_error_literal (error, KMS_SDP_AGENT_ERROR, SDP_AGENT_UNEXPECTED_ERROR,
        "Missing mid attribute for media");
    return NULL;
  }

  if (configure_pending_mediaconfig (ctx, media, &mconf)) {
    return mconf;
  }

  media_type = gst_sdp_media_get_media (media);
  counter = g_hash_table_lookup (ctx->mids, media_type);

  if (counter == NULL) {
    /* No stored medias of this type yet */
    counter = g_slice_new0 (guint);
    g_hash_table_insert (ctx->mids, g_strdup (media_type), counter);
  }

  mid = g_strdup_printf ("%s%u", media_type, (*counter)++);

  mconf = kms_sdp_context_new_media_config (g_slist_length (ctx->medias), mid,
      media);

  ctx->medias = g_slist_append (ctx->medias, mconf);

  return mconf;
}
예제 #13
0
파일: media.c 프로젝트: dulton/hm-platform
static __inline__ RTP_Session *
rtp_session_create(RTSP_media *medium, const GstSDPMedia *m)
{
	RTSP_client_session *rtsp_s;
	gint err;
	RTP_Session *rtp_s;
	gchar *media;

	rtsp_s = (RTSP_client_session*)medium->rtsp_s;

	rtp_s = rtp_session_new(rtsp_s);
	if (!rtp_s)
	{
		return NULL;
	}

	rtp_s->m = (GstSDPMedia*)m;
	rtp_s->rtsp_s = rtsp_client_session_ref(rtsp_s);

#if 0
	const gchar *pt_value;
	pt_value = gst_sdp_media_get_attribute_val(m, "rtpmap");
	if (strstr(pt_value, "H264"))
	{
		rtp_s->pt = 96;
		rtp_s->parser = rtp_parser_create((gchar*)"H264");
		if (!rtp_s->parser)
		{
			fnc_log(FNC_LOG_ERR, "[FC] Init RTP parser failed, mime:'%s'", "H264");
			goto no_rtp_parser;
		}
	}
	else if (strstr(pt_value, "JPF-GENERIC"))
	{
		rtp_s->pt = 99;
		rtp_s->parser = rtp_parser_create((gchar*)"JPF-GENERIC");
		if (!rtp_s->parser)
		{
			fnc_log(FNC_LOG_ERR, "[FC] Init RTP parser failed, mime:'%s'", "JPF-GENERIC");
			goto no_rtp_parser;
		}		
	}
	else
	{
		goto no_rtp_parser;
	}
#else
	rtp_s->pt = 0;
	rtp_s->parser = rtp_parser_create((gchar*)"RTP-FAKE");
	if (!rtp_s->parser)
	{
		fnc_log(FNC_LOG_ERR, "[FC] Init RTP parser failed, mime:'%s'", "RTP");
		goto no_rtp_parser;
	}
#endif

	media = gst_sdp_media_get_media(m);
	if (!strcmp(media, "video"))
		rtp_s->stm_type = STM_VIDEO;
	else if (!strcmp(media, "audio"))
		rtp_s->stm_type = STM_AUDIO;
	else
		rtp_s->stm_type = STM_OTHER;

	err = rtp_s->parser->initialize(rtp_s, rtp_s->parser, rtp_s->pt);
	if (err)
	{
		rtp_parser_release(rtp_s->parser);
		goto no_rtp_parser;
	}

	rtp_s->ssrc = &rtp_s->rtp_ssrc_init;

	if (!rtp_s->interleaved)
	{
		rtp_s->rtp_src = rtp_session_create_event(rtp_s, R_EV_RTP, rtp_s->rtp_sock);
	
#ifdef CONFIG_RTCP_SUPPORT
		rtp_s->rtcp_src = rtp_session_create_event(rtp_s, R_EV_RTCP, rtp_s->rtcp_sock);
#endif
	}

	return rtp_s;

no_rtp_parser:
	rtp_session_free(rtp_s);
	return NULL;
}