示例#1
0
static int priv_set_remote_sdp(SscMedia *self, const gchar *str)
{
  su_home_t *home = self->sm_home;
  const char *pa_error;
  int res = 0, dlen = strlen(str);

  g_debug(__func__);

  if (self->sm_sdp_remote)
    sdp_parser_free(self->sm_sdp_remote);

  /* XXX: only update if SDP has really changed */
  /* g_message("parsing SDP:\n%s\n---", str); */

  self->sm_sdp_remote = sdp_parse(home, str, dlen, sdp_f_insane);
  pa_error = sdp_parsing_error(self->sm_sdp_remote);
  if (pa_error) {
    g_warning("%s: error parsing SDP: %s\n", __func__, pa_error);
    res = -1;
  }
  else {
    if (self->sm_sdp_remote_str) 
      g_free(self->sm_sdp_remote_str);
  }

  return res;
}
static void mrcp_sofia_on_session_ready(
						int                   status,
						mrcp_sofia_agent_t   *sofia_agent,
						nua_handle_t         *nh,
						mrcp_sofia_session_t *sofia_session,
						sip_t const          *sip,
						tagi_t                tags[])
{
	const char *local_sdp_str = NULL, *remote_sdp_str = NULL;
	mrcp_session_descriptor_t *descriptor = NULL;

	tl_gets(tags, 
			SOATAG_LOCAL_SDP_STR_REF(local_sdp_str),
			SOATAG_REMOTE_SDP_STR_REF(remote_sdp_str),
			TAG_END());

	if(remote_sdp_str) {
		sdp_parser_t *parser = NULL;
		sdp_session_t *sdp = NULL;
		apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Remote SDP\n%s", remote_sdp_str);

		parser = sdp_parse(sofia_session->home,remote_sdp_str,(int)strlen(remote_sdp_str),0);
		sdp = sdp_session(parser);
		descriptor = mrcp_descriptor_generate_by_sdp_session(sdp,sofia_session->session->pool);
		sdp_parser_free(parser);
	}

	mrcp_session_answer(sofia_session->session,descriptor);
}
static void mrcp_sofia_on_resource_discover(
						int                   status,
						mrcp_sofia_agent_t   *sofia_agent,
						nua_handle_t         *nh,
						mrcp_sofia_session_t *sofia_session,
						sip_t const          *sip,
						tagi_t                tags[])
{
	mrcp_session_t *session = sofia_session->session;
	if(session) {
		const char *remote_sdp_str = NULL;
		mrcp_session_descriptor_t *descriptor = NULL;

		if(sip->sip_payload) {
			remote_sdp_str = sip->sip_payload->pl_data;
		}
		
		if(remote_sdp_str) {
			sdp_parser_t *parser = NULL;
			sdp_session_t *sdp = NULL;
			apt_obj_log(APT_LOG_MARK,APT_PRIO_INFO,session->obj,"Resource Discovery SDP %s\n%s", 
				session->name,
				remote_sdp_str);

			parser = sdp_parse(sofia_session->home,remote_sdp_str,(int)strlen(remote_sdp_str),0);
			sdp = sdp_session(parser);
			descriptor = mrcp_descriptor_generate_by_sdp_session(sdp,NULL,session->pool);
			descriptor->response_code = status;
			sdp_parser_free(parser);
		}

		mrcp_session_discover_response(session,descriptor);
	}
}
示例#4
0
/* Pre-parse SDP: is this SDP valid? how many audio/video lines? */
janus_sdp *janus_sdp_preparse(const char *jsep_sdp, int *audio, int *video) {
	sdp_parser_t *parser = sdp_parse(home, jsep_sdp, strlen(jsep_sdp), 0);
	sdp_session_t *parsed_sdp = sdp_session(parser);
	if(!parsed_sdp) {
		JANUS_DEBUG("  Error parsing SDP? %s\n", sdp_parsing_error(parser));
		sdp_parser_free(parser);
		/* Invalid SDP */
		return NULL;
	}
	sdp_media_t *m = parsed_sdp->sdp_media;
	while(m) {
		if(m->m_type == sdp_media_audio) {
			*audio = *audio + 1;
		} else if(m->m_type == sdp_media_video) {
			*video = *video + 1;
		}
		m = m->m_next;
	}
	janus_sdp *sdp = (janus_sdp *)calloc(1, sizeof(janus_sdp));
	if(sdp == NULL) {
		JANUS_DEBUG("Memory error!\n");
		return NULL;
	}

	sdp->parser = parser;
	sdp->sdp = parsed_sdp;
	return sdp;
}
static void mrcp_sofia_on_resource_discover(
						int                   status,
						mrcp_sofia_agent_t   *sofia_agent,
						nua_handle_t         *nh,
						mrcp_sofia_session_t *sofia_session,
						sip_t const          *sip,
						tagi_t                tags[])
{
	mrcp_session_t *session = sofia_session->session;
	if(session) {
		const char *remote_sdp_str = NULL;
		mrcp_session_descriptor_t *descriptor = NULL;

		tl_gets(tags, 
				SOATAG_REMOTE_SDP_STR_REF(remote_sdp_str),
				TAG_END());

		if(remote_sdp_str) {
			sdp_parser_t *parser = NULL;
			sdp_session_t *sdp = NULL;
			apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Resource Discovery SDP %s\n%s", 
				session->name,
				remote_sdp_str);

			parser = sdp_parse(sofia_session->home,remote_sdp_str,(int)strlen(remote_sdp_str),0);
			sdp = sdp_session(parser);
			descriptor = mrcp_descriptor_generate_by_sdp_session(sdp,NULL,session->pool);
			sdp_parser_free(parser);
		}

		mrcp_session_discover_response(session,descriptor);
	}
}
示例#6
0
/*
 * sipsdp_create_from_buf()
 *
 * Parse buffer into common SDP structure
 *
 * Returns: NULL if non-recoverable error encountered
 *
 */
cc_sdp_t *
sipsdp_create_from_buf (char *buf, uint32_t nbytes, cc_sdp_t *sdp)
{
    const char *fname = "sipsdp_create_from_buf";
    cc_sdp_t *sip_info = NULL;

    if (!buf) {
        return (NULL);
    }

    if (sdp) {
        sip_info = sdp;
    } else {
        sipsdp_src_dest_create(CCSIP_DEST_SDP_BIT | CCSIP_SRC_SDP_BIT,
                               &sip_info);
    }

    if (!sip_info) {
        /*
         * make sure that the src_sdp and dest_sdp are
         * valid as well.
         */
        return (NULL);
    }


    if (sdp_parse(sip_info->dest_sdp, &buf, (uint16_t)nbytes) != SDP_SUCCESS) {
        sipsdp_src_dest_free(CCSIP_DEST_SDP_BIT | CCSIP_SRC_SDP_BIT,
                             &sip_info);
        CCSIP_DEBUG_ERROR(SIP_F_PREFIX"Error parsing SDP\n", fname);
        return (NULL);
    }

    return (sip_info);
}
示例#7
0
/** Generate MRCP descriptor by RTSP request */
MRCP_DECLARE(mrcp_session_descriptor_t*) mrcp_descriptor_generate_by_rtsp_request(
											const rtsp_message_t *request,
											const char *force_destination_ip,
											const apr_table_t *resource_map,
											apr_pool_t *pool,
											su_home_t *home)
{
	mrcp_session_descriptor_t *descriptor = NULL;
	const char *resource_name = mrcp_name_get_by_rtsp_name(
		resource_map,
		request->start_line.common.request_line.resource_name);
	if(!resource_name) {
		return NULL;
	}
	
	if(request->start_line.common.request_line.method_id == RTSP_METHOD_SETUP) {
		if(rtsp_header_property_check(&request->header.property_set,RTSP_HEADER_FIELD_CONTENT_TYPE) == TRUE &&
			rtsp_header_property_check(&request->header.property_set,RTSP_HEADER_FIELD_CONTENT_LENGTH) == TRUE &&
			request->body.buf) {
			
			sdp_parser_t *parser;
			sdp_session_t *sdp;

			parser = sdp_parse(home,request->body.buf,request->body.length,0);
			sdp = sdp_session(parser);
			if(sdp) {
				descriptor = mrcp_session_descriptor_create(pool);
				mrcp_descriptor_generate_by_sdp_session(descriptor,sdp,force_destination_ip,pool);
			}
			else {
				apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Parse SDP Message");
			}
			sdp_parser_free(parser);
		}
		else {
			/* create default descriptor in case RTSP SETUP contains no SDP */
			mpf_rtp_media_descriptor_t *media;
			descriptor = mrcp_session_descriptor_create(pool);
			media = apr_palloc(pool,sizeof(mpf_rtp_media_descriptor_t));
			mpf_rtp_media_descriptor_init(media);
			media->state = MPF_MEDIA_ENABLED;
			media->id = mrcp_session_audio_media_add(descriptor,media);
			if(rtsp_header_property_check(&request->header.property_set,RTSP_HEADER_FIELD_TRANSPORT) == TRUE) {
				media->port = request->header.transport.client_port_range.min;
				media->ip = request->header.transport.destination;
			}
		}

		if(descriptor) {
			apt_string_assign(&descriptor->resource_name,resource_name,pool);
			descriptor->resource_state = TRUE;
		}
	}
	else if(request->start_line.common.request_line.method_id == RTSP_METHOD_TEARDOWN) {
		descriptor = mrcp_session_descriptor_create(pool);
		apt_string_assign(&descriptor->resource_name,resource_name,pool);
		descriptor->resource_state = FALSE;
	}
	return descriptor;
}
示例#8
0
static int sdp_read_header(AVFormatContext *s,
                           AVFormatParameters *ap)
{
    RTSPState *rt = s->priv_data;
    RTSPStream *rtsp_st;
    int size, i, err;
    char *content;
    char url[1024];
    AVStream *st;

    /* read the whole sdp file */
    /* XXX: better loading */
    content = av_malloc(SDP_MAX_SIZE);
    size = get_buffer(s->pb, content, SDP_MAX_SIZE - 1);
    if (size <= 0) {
        av_free(content);
        return AVERROR_INVALIDDATA;
    }
    content[size] ='\0';

    sdp_parse(s, content);
    av_free(content);

    /* open each RTP stream */
    for(i=0;i<rt->nb_rtsp_streams;i++) {
        rtsp_st = rt->rtsp_streams[i];

        snprintf(url, sizeof(url), "rtp://%s:%d?localport=%d&ttl=%d",
                 inet_ntoa(rtsp_st->sdp_ip),
                 rtsp_st->sdp_port,
                 rtsp_st->sdp_port,
                 rtsp_st->sdp_ttl);
        if (url_open(&rtsp_st->rtp_handle, url, URL_RDWR) < 0) {
            err = AVERROR_INVALIDDATA;
            goto fail;
        }
        /* open the RTP context */
        st = NULL;
        if (rtsp_st->stream_index >= 0)
            st = s->streams[rtsp_st->stream_index];
        if (!st)
            s->ctx_flags |= AVFMTCTX_NOHEADER;
        rtsp_st->rtp_ctx = rtp_parse_open(s, st, rtsp_st->rtp_handle, rtsp_st->sdp_payload_type, &rtsp_st->rtp_payload_data);
        if (!rtsp_st->rtp_ctx) {
            err = AVERROR(ENOMEM);
            goto fail;
        } else {
            if(rtsp_st->dynamic_handler) {
                rtsp_st->rtp_ctx->dynamic_protocol_context= rtsp_st->dynamic_protocol_context;
                rtsp_st->rtp_ctx->parse_packet= rtsp_st->dynamic_handler->parse_packet;
            }
        }
    }
    return 0;
 fail:
    rtsp_close_streams(rt);
    return err;
}
示例#9
0
/** Generate MRCP descriptor by RTSP response */
MRCP_DECLARE(mrcp_session_descriptor_t*) mrcp_descriptor_generate_by_rtsp_response(
											const rtsp_message_t *request, 
											const rtsp_message_t *response, 
											const char *force_destination_ip,
											const apr_table_t *resource_map, 
											apr_pool_t *pool, 
											su_home_t *home)
{
	mrcp_session_descriptor_t *descriptor = NULL;
	const char *resource_name = mrcp_name_get_by_rtsp_name(
		resource_map,
		request->start_line.common.request_line.resource_name);
	if(!resource_name) {
		return NULL;
	}

	if(request->start_line.common.request_line.method_id == RTSP_METHOD_SETUP) {
		if(rtsp_header_property_check(&response->header,RTSP_HEADER_FIELD_CONTENT_TYPE) == TRUE &&
			rtsp_header_property_check(&response->header,RTSP_HEADER_FIELD_CONTENT_LENGTH) == TRUE &&
			response->body.buf) {

			sdp_parser_t *parser;
			sdp_session_t *sdp;

			parser = sdp_parse(home,response->body.buf,response->body.length,0);
			sdp = sdp_session(parser);
			if(sdp) {
				descriptor = mrcp_session_descriptor_create(pool);
				mrcp_descriptor_generate_by_sdp_session(descriptor,sdp,force_destination_ip,pool);

				apt_string_assign(&descriptor->resource_name,resource_name,pool);
				descriptor->resource_state = TRUE;
				descriptor->response_code = response->start_line.common.status_line.status_code;
			}
			else {
				apt_log(APT_LOG_MARK,APT_PRIO_WARNING,"Failed to Parse SDP Message");
			}

			sdp_parser_free(parser);
		}
		else {
			descriptor = mrcp_session_descriptor_create(pool);
			apt_string_assign(&descriptor->resource_name,resource_name,pool);
			descriptor->resource_state = FALSE;
		}
	}
	else if(request->start_line.common.request_line.method_id == RTSP_METHOD_TEARDOWN) {
		descriptor = mrcp_session_descriptor_create(pool);
		apt_string_assign(&descriptor->resource_name,resource_name,pool);
		descriptor->resource_state = FALSE;
	}
	return descriptor;
}
示例#10
0
/*
v=0
o=mhandley 2890844526 2890842807 IN IP4 126.16.64.4
s=SDP Seminar
i=A Seminar on the session description protocol
u=http://www.cs.ucl.ac.uk/staff/M.Handley/sdp.03.ps
[email protected] (Mark Handley)
c=IN IP4 224.2.17.12/127
t=2873397496 2873404696
a=recvonly
m=audio 3456 RTP/AVP 0
m=video 2232 RTP/AVP 31
m=whiteboard 32416 UDP WB
a=orient:portrait
*/
int rtsp_client_sdp(struct rtsp_client_t* rtsp, const char* content)
{
	int i, j, n, count;
	int formats[N_MEDIA_FORMAT];
	struct rtsp_media_t* media;
	void* sdp;

	sdp = sdp_parse(content);
	if (!sdp)
		return -1;

	count = sdp_media_count(sdp);
	if(count > N_MEDIA)
	{
		rtsp->media_ptr = (struct rtsp_media_t*)malloc(sizeof(struct rtsp_media_t)*(count-N_MEDIA));
		if(!rtsp->media_ptr)
		{
			sdp_destroy(sdp);
			return ENOMEM;
		}
		memset(rtsp->media_ptr, 0, sizeof(struct rtsp_media_t)*(count-N_MEDIA));
	}

	rtsp->media_count = count;

	// rfc 2326 C.1.1 Control URL (p80)
	// If found at the session level, the attribute indicates the URL for aggregate control
	rtsp->aggregate = rtsp_media_aggregate_control_enable(sdp);
	rtsp_get_session_uri(sdp, rtsp->aggregate_uri, sizeof(rtsp->aggregate_uri), rtsp->uri, rtsp->baseuri, rtsp->location);

	for(i = 0; i < count; i++)
	{
		media = rtsp_get_media(rtsp, i);
		//media->cseq = rand();

		// RTSP2326 C.1.1 Control URL
		rtsp_get_media_uri(sdp, i, media->uri, sizeof(media->uri), rtsp->aggregate_uri);

		n = sdp_media_formats(sdp, i, formats, N_MEDIA_FORMAT);
		media->avformat_count = n > N_MEDIA_FORMAT ? N_MEDIA_FORMAT : n;
		for(j = 0; j < media->avformat_count; j++)
		{
			media->avformats[j].fmt = formats[j];
		}

		// update media encoding
		sdp_media_attribute_list(sdp, i, NULL, rtsp_media_onattr, media);		
	}

	sdp_destroy(sdp);
	return 0;
}
示例#11
0
UniquePtr<Sdp>
SipccSdpParser::Parse(const std::string &sdpText)
{
  ClearParseErrors();

  sdp_conf_options_t *sipcc_config = sdp_init_config();
  if (!sipcc_config) {
    return UniquePtr<Sdp>();
  }

  sdp_nettype_supported(sipcc_config, SDP_NT_INTERNET, true);
  sdp_addrtype_supported(sipcc_config, SDP_AT_IP4, true);
  sdp_addrtype_supported(sipcc_config, SDP_AT_IP6, true);
  sdp_transport_supported(sipcc_config, SDP_TRANSPORT_RTPAVP, true);
  sdp_transport_supported(sipcc_config, SDP_TRANSPORT_RTPAVPF, true);
  sdp_transport_supported(sipcc_config, SDP_TRANSPORT_RTPSAVP, true);
  sdp_transport_supported(sipcc_config, SDP_TRANSPORT_RTPSAVPF, true);
  sdp_transport_supported(sipcc_config, SDP_TRANSPORT_UDPTLSRTPSAVP, true);
  sdp_transport_supported(sipcc_config, SDP_TRANSPORT_UDPTLSRTPSAVPF, true);
  sdp_transport_supported(sipcc_config, SDP_TRANSPORT_TCPTLSRTPSAVP, true);
  sdp_transport_supported(sipcc_config, SDP_TRANSPORT_TCPTLSRTPSAVPF, true);
  sdp_transport_supported(sipcc_config, SDP_TRANSPORT_DTLSSCTP, true);
  sdp_require_session_name(sipcc_config, false);

  sdp_config_set_error_handler(sipcc_config, &sipcc_sdp_parser_error_handler,
                               this);

  // Takes ownership of |sipcc_config| iff it succeeds
  sdp_t *sdp = sdp_init_description(sipcc_config);
  if (!sdp) {
    sdp_free_config(sipcc_config);
    return UniquePtr<Sdp>();
  }

  const char *rawString = sdpText.c_str();
  sdp_result_e sdpres = sdp_parse(sdp, rawString, sdpText.length());
  if (sdpres != SDP_SUCCESS) {
    sdp_free_description(sdp);
    return UniquePtr<Sdp>();
  }

  UniquePtr<SipccSdp> sipccSdp(new SipccSdp);

  bool success = sipccSdp->Load(sdp, *this);
  sdp_free_description(sdp);
  if (!success) {
    return UniquePtr<Sdp>();
  }

  return UniquePtr<Sdp>(Move(sipccSdp));
}
static void mrcp_sofia_on_call_receive(mrcp_sofia_agent_t   *sofia_agent,
									   nua_handle_t         *nh,
									   mrcp_sofia_session_t *sofia_session,
									   sip_t const          *sip,
									   tagi_t                tags[])
{
	apt_bool_t status = FALSE;
	const char *remote_sdp_str = NULL;
	mrcp_session_descriptor_t *descriptor;

	if(!sofia_session) {
		sofia_session = mrcp_sofia_session_create(sofia_agent,nh);
		if(!sofia_session) {
			nua_respond(nh, SIP_488_NOT_ACCEPTABLE, TAG_END());
			return;
		}
	}

	descriptor = mrcp_session_descriptor_create(sofia_session->session->pool);

	tl_gets(tags, 
			SOATAG_REMOTE_SDP_STR_REF(remote_sdp_str),
			TAG_END());

	if(remote_sdp_str) {
		sdp_parser_t *parser = NULL;
		sdp_session_t *sdp = NULL;
		apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Remote SDP "APT_NAMESID_FMT"\n%s",
			sofia_session->session->name,
			MRCP_SESSION_SID(sofia_session->session),
			remote_sdp_str);

		parser = sdp_parse(sofia_session->home,remote_sdp_str,(int)strlen(remote_sdp_str),0);
		sdp = sdp_session(parser);
		status = mrcp_descriptor_generate_by_sdp_session(descriptor,sdp,NULL,sofia_session->session->pool);
		sdp_parser_free(parser);
	}

	if(status == FALSE) {
		nua_respond(nh, SIP_400_BAD_REQUEST, TAG_END());
		return;
	}

	mrcp_session_offer(sofia_session->session,descriptor);
}
static void mrcp_sofia_on_call_receive(mrcp_sofia_agent_t   *sofia_agent,
									   nua_handle_t         *nh,
									   mrcp_sofia_session_t *sofia_session,
									   sip_t const          *sip,
									   tagi_t                tags[])
{
	int offer_recv = 0, answer_recv = 0, offer_sent = 0, answer_sent = 0;
	const char *local_sdp_str = NULL, *remote_sdp_str = NULL;
	mrcp_session_descriptor_t *descriptor = NULL;

	tl_gets(tags, 
			NUTAG_OFFER_RECV_REF(offer_recv),
			NUTAG_ANSWER_RECV_REF(answer_recv),
			NUTAG_OFFER_SENT_REF(offer_sent),
			NUTAG_ANSWER_SENT_REF(answer_sent),
			SOATAG_LOCAL_SDP_STR_REF(local_sdp_str),
			SOATAG_REMOTE_SDP_STR_REF(remote_sdp_str),
			TAG_END());
	
	if(!sofia_session) {
		sofia_session = mrcp_sofia_session_create(sofia_agent,nh);
		if(!sofia_session) {
			nua_respond(nh, SIP_488_NOT_ACCEPTABLE, TAG_END());
			return;
		}
	}

	if(remote_sdp_str) {
		sdp_parser_t *parser = NULL;
		sdp_session_t *sdp = NULL;
		apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Remote SDP\n%s", remote_sdp_str);

		parser = sdp_parse(sofia_session->home,remote_sdp_str,(int)strlen(remote_sdp_str),0);
		sdp = sdp_session(parser);		
		descriptor = mrcp_descriptor_generate_by_sdp_session(sdp,NULL,sofia_session->session->pool);
		sdp_parser_free(parser);
	}

	if(!descriptor) {
		nua_respond(nh, SIP_400_BAD_REQUEST, TAG_END());
		return;
	}

	mrcp_session_offer(sofia_session->session,descriptor);
}
示例#14
0
/** Generate resource discovery descriptor by RTSP response */
MRCP_DECLARE(mrcp_session_descriptor_t*) mrcp_resource_discovery_response_generate(
											const rtsp_message_t *request, 
											const rtsp_message_t *response,
											const apr_table_t *resource_map,
											apr_pool_t *pool,
											su_home_t *home)
{
	mrcp_session_descriptor_t *descriptor = NULL;
	const char *resource_name = mrcp_name_get_by_rtsp_name(
					resource_map,
					request->start_line.common.request_line.resource_name);
	if(!resource_name) {
		return NULL;
	}
	
	descriptor = mrcp_session_descriptor_create(pool);
	apt_string_assign(&descriptor->resource_name,resource_name,pool);
	
	if(rtsp_header_property_check(&response->header,RTSP_HEADER_FIELD_CONTENT_TYPE) == TRUE &&
		rtsp_header_property_check(&response->header,RTSP_HEADER_FIELD_CONTENT_LENGTH) == TRUE &&
		response->body.buf) {

		sdp_parser_t *parser;
		sdp_session_t *sdp;

		parser = sdp_parse(home,response->body.buf,response->body.length,0);
		sdp = sdp_session(parser);
		if(sdp) {
			mrcp_descriptor_generate_by_sdp_session(descriptor,sdp,0,pool);
			descriptor->resource_state = TRUE;
			descriptor->response_code = response->start_line.common.status_line.status_code;
		}
		else {
			apt_string_assign(&descriptor->resource_name,resource_name,pool);
			descriptor->resource_state = TRUE;
		}

		sdp_parser_free(parser);
	}
	else {
		descriptor->resource_state = FALSE;
	}
	return descriptor;
}
示例#15
0
/** Generate MRCP descriptor by RTSP response */
MRCP_DECLARE(mrcp_session_descriptor_t*) mrcp_descriptor_generate_by_rtsp_response(const rtsp_message_t *request, const rtsp_message_t *response, apr_pool_t *pool, su_home_t *home)
{
	mrcp_session_descriptor_t *descriptor = NULL;
	const char *resource_name = request->start_line.common.request_line.resource_name;
	if(!resource_name) {
		return NULL;
	}
	
	if(request->start_line.common.request_line.method_id == RTSP_METHOD_SETUP) {
		if(rtsp_header_property_check(&response->header.property_set,RTSP_HEADER_FIELD_CONTENT_TYPE) == TRUE &&
			rtsp_header_property_check(&response->header.property_set,RTSP_HEADER_FIELD_CONTENT_LENGTH) == TRUE &&
			response->body.buf) {
			
			sdp_parser_t *parser;
			sdp_session_t *sdp;

			parser = sdp_parse(home,response->body.buf,response->body.length,0);
			sdp = sdp_session(parser);

			descriptor = mrcp_descriptor_generate_by_sdp_session(sdp,pool);
			if(descriptor) {
				apt_string_assign(&descriptor->resource_name,resource_name,pool);
				descriptor->resource_state = TRUE;
			}
			
			sdp_parser_free(parser);
		}
		else {
			descriptor = mrcp_session_descriptor_create(pool);
			if(descriptor) {
				apt_string_assign(&descriptor->resource_name,resource_name,pool);
				descriptor->resource_state = FALSE;
			}
		}
	}
	else if(request->start_line.common.request_line.method_id == RTSP_METHOD_TEARDOWN) {
		descriptor = mrcp_session_descriptor_create(pool);
		if(descriptor) {
			apt_string_assign(&descriptor->resource_name,resource_name,pool);
			descriptor->resource_state = FALSE;
		}
	}
	return descriptor;
}
示例#16
0
/* Pre-parse SDP: is this SDP valid? how many audio/video lines? any features to take into account? */
janus_sdp *janus_sdp_preparse(const char *jsep_sdp, int *audio, int *video, int *data, int *bundle, int *rtcpmux, int *trickle) {
	if(!jsep_sdp || !audio || !video || !data || !bundle || !rtcpmux || !trickle) {
		JANUS_LOG(LOG_ERR, "  Can't preparse, invalid arduments\n");
		return NULL;
	}
	sdp_parser_t *parser = sdp_parse(home, jsep_sdp, strlen(jsep_sdp), 0);
	sdp_session_t *parsed_sdp = sdp_session(parser);
	if(!parsed_sdp) {
		JANUS_LOG(LOG_ERR, "  Error parsing SDP? %s\n", sdp_parsing_error(parser));
		sdp_parser_free(parser);
		/* Invalid SDP */
		return NULL;
	}
	sdp_media_t *m = parsed_sdp->sdp_media;
	while(m) {
		if(m->m_type == sdp_media_audio && m->m_port > 0) {
			*audio = *audio + 1;
		} else if(m->m_type == sdp_media_video && m->m_port > 0) {
			*video = *video + 1;
		}
		m = m->m_next;
	}
#ifdef HAVE_SCTP
	*data = (strstr(jsep_sdp, "DTLS/SCTP") && !strstr(jsep_sdp, " 0 DTLS/SCTP")) ? 1 : 0;	/* FIXME This is a really hacky way of checking... */
#else
	*data = 0;
#endif
	*bundle = strstr(jsep_sdp, "a=group:BUNDLE") ? 1 : 0;	/* FIXME This is a really hacky way of checking... */
	*rtcpmux = strstr(jsep_sdp, "a=rtcp-mux") ? 1 : 0;	/* FIXME Should we make this check per-medium? */
	//~ *trickle = (strstr(jsep_sdp, "trickle") || strstr(jsep_sdp, "google-ice") || strstr(jsep_sdp, "Mozilla")) ? 1 : 0;	/* FIXME This is a really hacky way of checking... */
	/* FIXME We're assuming trickle is always supported, see https://github.com/meetecho/janus-gateway/issues/83 */
	*trickle = 1;
	janus_sdp *sdp = (janus_sdp *)calloc(1, sizeof(janus_sdp));
	if(sdp == NULL) {
		JANUS_LOG(LOG_FATAL, "Memory error!\n");
		return NULL;
	}

	sdp->parser = parser;
	sdp->sdp = parsed_sdp;
	return sdp;
}
static void mrcp_sofia_on_session_ready(
						int                   status,
						mrcp_sofia_agent_t   *sofia_agent,
						nua_handle_t         *nh,
						mrcp_sofia_session_t *sofia_session,
						sip_t const          *sip,
						tagi_t                tags[])
{
	mrcp_session_t *session = sofia_session->session;
	if(session) {
		const char *local_sdp_str = NULL, *remote_sdp_str = NULL;
		mrcp_session_descriptor_t *descriptor = NULL;

		tl_gets(tags, 
				SOATAG_LOCAL_SDP_STR_REF(local_sdp_str),
				SOATAG_REMOTE_SDP_STR_REF(remote_sdp_str),
				TAG_END());

		if(remote_sdp_str) {
			sdp_parser_t *parser = NULL;
			sdp_session_t *sdp = NULL;
			const char *force_destination_ip = NULL;
			apt_log(APT_LOG_MARK,APT_PRIO_INFO,"Remote SDP "APT_NAMESID_FMT"\n%s",
				session->name,
				MRCP_SESSION_SID(session),
				remote_sdp_str);

			parser = sdp_parse(sofia_session->home,remote_sdp_str,(int)strlen(remote_sdp_str),0);
			sdp = sdp_session(parser);
			if(sofia_session->sip_settings->force_destination == TRUE) {
				force_destination_ip = sofia_session->sip_settings->server_ip;
			}
			descriptor = mrcp_descriptor_generate_by_sdp_session(sdp,force_destination_ip,session->pool);
			sdp_parser_free(parser);
		}

		mrcp_session_answer(session,descriptor);
	}
}
示例#18
0
static int rtsp_read_header(AVFormatContext *s,
                            AVFormatParameters *ap)
{
    RTSPState *rt = s->priv_data;
    char host[1024], path[1024], tcpname[1024], cmd[2048];
    URLContext *rtsp_hd;
    int port, i, j, ret, err;
    RTSPHeader reply1, *reply = &reply1;
    unsigned char *content = NULL;
    RTSPStream *rtsp_st;
    int protocol_mask;
    AVStream *st;

    /* extract hostname and port */
    url_split(NULL, 0, NULL, 0,
              host, sizeof(host), &port, path, sizeof(path), s->filename);
    if (port < 0)
        port = RTSP_DEFAULT_PORT;

    /* open the tcp connexion */
    snprintf(tcpname, sizeof(tcpname), "tcp://%s:%d", host, port);
    if (url_open(&rtsp_hd, tcpname, URL_RDWR) < 0)
        return AVERROR_IO;
    rt->rtsp_hd = rtsp_hd;
    rt->seq = 0;

    /* describe the stream */
    snprintf(cmd, sizeof(cmd),
             "DESCRIBE %s RTSP/1.0\r\n"
             "Accept: application/sdp\r\n",
             s->filename);
    rtsp_send_cmd(s, cmd, reply, &content);
    if (!content) {
        err = AVERROR_INVALIDDATA;
        goto fail;
    }
    if (reply->status_code != RTSP_STATUS_OK) {
        err = AVERROR_INVALIDDATA;
        goto fail;
    }

    /* now we got the SDP description, we parse it */
    ret = sdp_parse(s, (const char *)content);
    av_freep(&content);
    if (ret < 0) {
        err = AVERROR_INVALIDDATA;
        goto fail;
    }

    protocol_mask = rtsp_default_protocols;

    /* for each stream, make the setup request */
    /* XXX: we assume the same server is used for the control of each
       RTSP stream */

    for(j = RTSP_RTP_PORT_MIN, i = 0; i < rt->nb_rtsp_streams; ++i) {
        char transport[2048];

        rtsp_st = rt->rtsp_streams[i];

        /* compute available transports */
        transport[0] = '\0';

        /* RTP/UDP */
        if (protocol_mask & (1 << RTSP_PROTOCOL_RTP_UDP)) {
            char buf[256];

            /* first try in specified port range */
            if (RTSP_RTP_PORT_MIN != 0) {
                while(j <= RTSP_RTP_PORT_MAX) {
                    snprintf(buf, sizeof(buf), "rtp://?localport=%d", j);
                    if (url_open(&rtsp_st->rtp_handle, buf, URL_RDONLY) == 0) {
                        j += 2; /* we will use two port by rtp stream (rtp and rtcp) */
                        goto rtp_opened;
                    }
                }
            }

/*            then try on any port
**            if (url_open(&rtsp_st->rtp_handle, "rtp://", URL_RDONLY) < 0) {
**                err = AVERROR_INVALIDDATA;
**                goto fail;
**            }
*/

        rtp_opened:
            port = rtp_get_local_port(rtsp_st->rtp_handle);
            if (transport[0] != '\0')
                pstrcat(transport, sizeof(transport), ",");
            snprintf(transport + strlen(transport), sizeof(transport) - strlen(transport) - 1,
                     "RTP/AVP/UDP;unicast;client_port=%d-%d",
                     port, port + 1);
        }

        /* RTP/TCP */
        else if (protocol_mask & (1 << RTSP_PROTOCOL_RTP_TCP)) {
            if (transport[0] != '\0')
                pstrcat(transport, sizeof(transport), ",");
            snprintf(transport + strlen(transport), sizeof(transport) - strlen(transport) - 1,
                     "RTP/AVP/TCP");
        }

        else if (protocol_mask & (1 << RTSP_PROTOCOL_RTP_UDP_MULTICAST)) {
            if (transport[0] != '\0')
                pstrcat(transport, sizeof(transport), ",");
            snprintf(transport + strlen(transport),
                     sizeof(transport) - strlen(transport) - 1,
                     "RTP/AVP/UDP;multicast");
        }
        snprintf(cmd, sizeof(cmd),
                 "SETUP %s RTSP/1.0\r\n"
                 "Transport: %s\r\n",
                 rtsp_st->control_url, transport);
        rtsp_send_cmd(s, cmd, reply, NULL);
        if (reply->status_code != RTSP_STATUS_OK ||
            reply->nb_transports != 1) {
            err = AVERROR_INVALIDDATA;
            goto fail;
        }

        /* XXX: same protocol for all streams is required */
        if (i > 0) {
            if (reply->transports[0].protocol != rt->protocol) {
                err = AVERROR_INVALIDDATA;
                goto fail;
            }
        } else {
            rt->protocol = reply->transports[0].protocol;
        }

        /* close RTP connection if not choosen */
        if (reply->transports[0].protocol != RTSP_PROTOCOL_RTP_UDP &&
            (protocol_mask & (1 << RTSP_PROTOCOL_RTP_UDP))) {
            url_close(rtsp_st->rtp_handle);
            rtsp_st->rtp_handle = NULL;
        }

        switch(reply->transports[0].protocol) {
        case RTSP_PROTOCOL_RTP_TCP:
            rtsp_st->interleaved_min = reply->transports[0].interleaved_min;
            rtsp_st->interleaved_max = reply->transports[0].interleaved_max;
            break;

        case RTSP_PROTOCOL_RTP_UDP:
            {
                char url[1024];

                /* XXX: also use address if specified */
                snprintf(url, sizeof(url), "rtp://%s:%d",
                         host, reply->transports[0].server_port_min);
                if (rtp_set_remote_url(rtsp_st->rtp_handle, url) < 0) {
                    err = AVERROR_INVALIDDATA;
                    goto fail;
                }
            }
            break;
        case RTSP_PROTOCOL_RTP_UDP_MULTICAST:
            {
                char url[1024];
                int ttl;

                ttl = reply->transports[0].ttl;
                if (!ttl)
                    ttl = 16;
                snprintf(url, sizeof(url), "rtp://%s:%d?multicast=1&ttl=%d",
                         host,
                         reply->transports[0].server_port_min,
                         ttl);
                if (url_open(&rtsp_st->rtp_handle, url, URL_RDONLY) < 0) {
                    err = AVERROR_INVALIDDATA;
                    goto fail;
                }
            }
            break;
        }
        /* open the RTP context */
        st = NULL;
        if (rtsp_st->stream_index >= 0)
            st = s->streams[rtsp_st->stream_index];
        if (!st)
            s->ctx_flags |= AVFMTCTX_NOHEADER;
        rtsp_st->rtp_ctx = rtp_parse_open(s, st, rtsp_st->sdp_payload_type, &rtsp_st->rtp_payload_data);

        if (!rtsp_st->rtp_ctx) {
            err = AVERROR_NOMEM;
            goto fail;
        }
    }

    /* use callback if available to extend setup */
    if (ff_rtsp_callback) {
        if (ff_rtsp_callback(RTSP_ACTION_CLIENT_SETUP, rt->session_id,
                             NULL, 0, rt->last_reply) < 0) {
            err = AVERROR_INVALIDDATA;
            goto fail;
        }
    }


    rt->state = RTSP_STATE_IDLE;
    rt->seek_timestamp = 0; /* default is to start stream at position
                               zero */
    if (ap->initial_pause) {
        /* do not start immediately */
    } else {
        if (rtsp_read_play(s) < 0) {
            err = AVERROR_INVALIDDATA;
            goto fail;
        }
    }
    return 0;
 fail:
    rtsp_close_streams(rt);
    av_freep(&content);
    url_close(rt->rtsp_hd);
    return err;
}
示例#19
0
int main(int argc, char **argv){


	/* create a rtp session, we will assign unique value to identify */
	err = rtp_create(&sid);	
	if (err) {
		err_handle(err);
	}

	sdp_parse(sid, argv);	/* parse the sdp file */

        /* The application will sleep "rtp_start_time" time if "rtp_start_time" > 0 when the application is start.
         *
         * NOTE! This is not the same with Start Time in NCTUns
         * EX:  if the Start Time in NCTUn is 5, and rtp_start_time is 3,
         *      then the real time to startup the applicaion is 8.
         */
	if (rtp_start_time > 0) {
		usleep( ((int) rtp_start_time * 1000000) );
	}

        initial_session(argc, argv, sid);	/* set local receive addr, CNAME, and startup the connectoin */

        if (!trans_mode) {      /* throughput is static */
                if (is_audio)                           /* media type is audio */
                        delay   = (ms_pkt / 1000.);
                else
                        delay   = (1. / framerate);

                /* bytes of each packet = ((bits/sample) / 8 ) * (clock rate) * ( each delay of packet in sec ) */
                packet_size = (int) ( (bits_per_sample / 8.) * sampling_rate * delay);
                if (RTP_MAX_PKT_SIZE < packet_size) {
                        fprintf(stderr, "The packet size is bigger than RTP_MAX_PKT_SIZE\n");
                        exit(1);
                }
        }

	/* original_bw = min_bw = 50, so we use the same pkt size */
	minbw_pktsize = packet_size;
	
	printf("bits_per_sample = %lf, (bits_per_sample/8.) = %lf\n", bits_per_sample, (bits_per_sample/8.));
	printf("sampling_rate = %lf\n", sampling_rate);
	printf("delay = %lf\n", delay);
	printf("packet_size = %d\n", packet_size);
	
	/* the bandwidth wa are using, 30 = frames/sec */
	cur_bw = get_cur_bw(packet_size);
	
	err = rtp_get_sour_rtpsocket(sid, &rtp_sockt);
	if (err) {
		err_handle(err);
	}
	err = rtp_get_sour_rtcpsocket(sid, &rtcp_sockt);
	if (err) {
		err_handle(err);
	}	
	
	if (rtp_sockt > nfds || rtcp_sockt > nfds) {
		if (rtp_sockt > rtcp_sockt)
			nfds = rtp_sockt;
		else
			nfds = rtcp_sockt;
	}
	
	FD_ZERO(&afds);
	FD_ZERO(&rfds);
	FD_SET(rtp_sockt, &afds);
	FD_SET(rtcp_sockt, &afds);
	
	gettimeofday(&start_tv, NULL);
	starttime = (start_tv.tv_sec + start_tv.tv_usec / 1000000.);
	nexttime = starttime;
	
	rtp_interval = rtp_stop_time - rtp_start_time;
	
	printf("rtp_interval = %f\n", rtp_interval);
	fflush(stdout);
	
	while (rtp_interval >= 0) {
		
		memcpy(&rfds, &afds, sizeof(rfds));
		
		if (RTP_MAX_PKT_SIZE < packet_size){
			fprintf(stderr, "RTP_MAX_PKT_SIZE < reads\n");
			continue;
		}
		
		addtimestamp = ((int) packet_size * (bits_per_sample / 8.) );

		err = rtp_send(sid, marker, addtimestamp, codec_num, (int8 *)sendbuf, packet_size);
		if (err) {
			err_handle(err);
		}
		
		marker = 0;	/* not the first packet of talkspurt */
		rtp_interval -= delay;
		nexttime += delay;
		gettimeofday(&now_tv, NULL);
		now = (now_tv.tv_sec + now_tv.tv_usec / 1000000.);
		
		err = get_rtcp_timeout(sid, &timeout_tv);
		if (err) {
			err_handle(err);
		}
		
		while (now < nexttime) {	/* send next packet until now >= nexttime */
		
			//printf("now = %lf\n", now);
			//printf("nexttime = %lf\n", nexttime);
			
			if (time_expire(&timeout_tv, &now_tv)) { 
				
				err = rtp_check_on_expire();
				if (err) {
					err_handle(err);
				}
				
				err = get_rtcp_timeout(sid, &timeout_tv);
				if (err) {
					err_handle(err);
				}
				printf("timeval_to_double(timeout_tv) = %lf\n", timeval_to_double(timeout_tv));	
			}
			
			/* BECAREFUL, if we disable RTCP, the timeval we get will be 0 */
			if (timeval_to_double(timeout_tv) == 0 || nexttime < timeval_to_double(timeout_tv)) {
				nexttime_tv = double_to_timeval(nexttime - now);
			}
			else {
				nexttime_tv = double_to_timeval(timeval_to_double(timeout_tv) - now);
			}
			
			if (select(nfds + 1, &rfds, (fd_set *)0, (fd_set *)0, &nexttime_tv) < 0) {
				if (errno == EINTR)
					continue;
				else {	
					printf("nexttime_tv.tv_sec = %ld\n", nexttime_tv.tv_sec);
					printf("nexttime_tv.tv_usec = %ld\n", nexttime_tv.tv_usec);
					printf("select error: %d\n", errno);
					//exit(1);
				}
			}
			
			if (FD_ISSET(rtp_sockt, &rfds)) {

				err = on_receive(sid, rtp_sockt, recvbuf, &recbuflen);
				if (err) {
					err_handle(err);
				}	
			}
			else if (FD_ISSET(rtcp_sockt, &rfds)) {
			
				err = on_receive(sid, rtcp_sockt, recvbuf, &recbuflen);
				if (err) {
					err_handle(err);
				}
				
				adapt_bw(get_recent_recv_loosrate(sid, &ssrc));
			}
			
			gettimeofday(&now_tv, NULL);
			now = (now_tv.tv_sec + now_tv.tv_usec / 1000000.);
		} // while(now < nexttime)
	} // while (interval)
	
	err = rtp_close_connection(sid, reason);
	if (err) {
		err_handle(err);
	}
	
	err = rtp_delete(sid);
	if (err) {
		err_handle(err);
	}
			
	return 0;
}
示例#20
0
/*
 * [ application_name local_ip local_port cname sdp_file [-t trace_file] ]
 */
int main(int argc, char **argv){

       /* create a rtp session, we will assign unique value to identify */
        err = rtp_create(&sid);
        if (err) {
                err_handle(err);
        }

        sdp_parse(sid, argv);	/* parse the sdp file */

	/* The application will sleep "rtp_start_time" time if "rtp_start_time" > 0 when the application is start. 
	 *
	 * NOTE! This is not the same with Start Time in NCTUns 
	 * EX:	if the Start Time in NCTUn is 5, and rtp_start_time is 3, 
	 * 	then the real time to startup the applicaion is 8.
	 */
        if (rtp_start_time > 0) 
                usleep( ((int) rtp_start_time * 1000000) );

        initial_session(argc, argv, sid);	/* set local receive addr, CNAME, and startup the connectoin */

        if (is_audio) 				/* media type is audio */
                delay   = (ms_pkt / 1000.);
        else 
                delay   = (1. / framerate);

	err = rtp_get_sour_rtpsocket(sid, &rtp_sockt);		/* get source rtp socket */
	if (err)
		err_handle(err);
	err = rtp_get_sour_rtcpsocket(sid, &rtcp_sockt);	/* get source rtcp socket */
	if (err)
		err_handle(err);
	
	if (rtp_sockt > nfds || rtcp_sockt > nfds) {
		if (rtp_sockt > rtcp_sockt)
			nfds = rtp_sockt;
		else
			nfds = rtcp_sockt;
	}
	
	FD_ZERO(&afds);
	FD_ZERO(&rfds);
	FD_SET(rtp_sockt, &afds);
	FD_SET(rtcp_sockt, &afds);
	
	gettimeofday(&start_tv, NULL);
	starttime = (start_tv.tv_sec + start_tv.tv_usec / 1000000.);
	now = starttime;
	
	rtp_interval = rtp_stop_time - rtp_start_time;
	
        /* bytes of each packet = ((bits/sample) / 8 ) * (clock rate) * ( each delay of packet in sec ) */
        // packet_size = (int) ( (bits_per_sample / 8.) * sampling_rate * delay);
	
	while ((now - starttime) <= rtp_interval) {
		
		memcpy(&rfds, &afds, sizeof(rfds));
		
		err = get_rtcp_timeout(sid, &timeout_tv);		/* get the send_rtcp_packet time */
		if (err) 
			err_handle(err);
		
		if (time_expire(&timeout_tv, &now_tv)) { 
				
			err = rtp_check_on_expire();			/* rtcp on_expire */
			if (err) 
				err_handle(err);
			
			err = get_rtcp_timeout(sid, &timeout_tv);	/* get the send_rtcp_packet time */
			if (err) 
				err_handle(err);
		}
			
		nexttime_tv = double_to_timeval(timeval_to_double(timeout_tv) - now);
			
		if (select(nfds + 1, &rfds, (fd_set *)0, (fd_set *)0, &nexttime_tv) < 0) {
			if (errno == EINTR)
				continue;
			else {	
				printf("nexttime_tv.tv_sec = %ld\n", nexttime_tv.tv_sec);
				printf("nexttime_tv.tv_usec = %ld\n", nexttime_tv.tv_usec);
				printf("select error: %d\n", errno);
			}
		}
		
		if (FD_ISSET(rtp_sockt, &rfds)) {
			err = on_receive(sid, rtp_sockt, recvbuf, &recbuflen);
			if (err) 
				err_handle(err);
		}
		else if (FD_ISSET(rtcp_sockt, &rfds)) {
			
			err = on_receive(sid, rtcp_sockt, recvbuf, &recbuflen);
			if (err) 
				err_handle(err);
		}
		
		gettimeofday(&now_tv, NULL);
		now = (now_tv.tv_sec + now_tv.tv_usec / 1000000.);
		
	} // while ((now - starttime) <= rtp_interval)
	
	err = rtp_close_connection(sid, reason);
	if (err) {
		err_handle(err);
	}
	
	err = rtp_delete(sid);
	if (err) {
		err_handle(err);
	}
				
	return 0;
}
示例#21
0
 void ParseSdp(const std::string &sdp_str) {
   char *bufp = const_cast<char *>(sdp_str.data());
   ResetSdp();
   ASSERT_EQ(sdp_parse(sdp_ptr_, &bufp, sdp_str.size()), SDP_SUCCESS);
 }
示例#22
0
static const char *call_offer_answer_ng(bencode_item_t *input, struct callmaster *m,
		bencode_item_t *output, enum call_opmode opmode)
{
	str sdp, fromtag, totag = STR_NULL, callid;
	char *errstr;
	GQueue parsed = G_QUEUE_INIT;
	GQueue streams = G_QUEUE_INIT;
	struct call *call;
	struct call_monologue *monologue;
	int ret;
	struct sdp_ng_flags flags;
	struct sdp_chopper *chopper;

	if (!bencode_dictionary_get_str(input, "sdp", &sdp))
		return "No SDP body in message";
	if (!bencode_dictionary_get_str(input, "call-id", &callid))
		return "No call-id in message";
	if (!bencode_dictionary_get_str(input, "from-tag", &fromtag))
		return "No from-tag in message";
	if (opmode == OP_ANSWER) {
		if (!bencode_dictionary_get_str(input, "to-tag", &totag))
			return "No to-tag in message";
	}
	//bencode_dictionary_get_str(input, "via-branch", &viabranch);

	if (sdp_parse(&sdp, &parsed))
		return "Failed to parse SDP";

	call_ng_process_flags(&flags, input);
	flags.opmode = opmode;

	errstr = "Incomplete SDP specification";
	if (sdp_streams(&parsed, &streams, &flags))
		goto out;

	call = call_get_opmode(&callid, m, opmode);
	errstr = "Unknown call-id";
	if (!call)
		goto out;

	/* At least the random ICE strings are contained within the call struct, so we
	 * need to hold a ref until we're done sending the reply */
	call_bencode_hold_ref(call, output);

	monologue = call_get_mono_dialogue(call, &fromtag, &totag);
	errstr = "Invalid dialogue association";
	if (!monologue) {
		rwlock_unlock_w(&call->master_lock);
		obj_put(call);
		goto out;
	}

	chopper = sdp_chopper_new(&sdp);
	bencode_buffer_destroy_add(output->buffer, (free_func_t) sdp_chopper_destroy, chopper);
	ret = monologue_offer_answer(monologue, &streams, &flags);
	if (!ret)
		ret = sdp_replace(chopper, &parsed, monologue->active_dialogue, &flags);

	rwlock_unlock_w(&call->master_lock);
	redis_update(call, m->conf.redis);
	obj_put(call);

	errstr = "Error rewriting SDP";
	if (ret)
		goto out;

	bencode_dictionary_add_iovec(output, "sdp", &g_array_index(chopper->iov, struct iovec, 0),
		chopper->iov_num, chopper->str_len);
	bencode_dictionary_add_string(output, "result", "ok");

	errstr = NULL;
out:
	sdp_free(&parsed);
	streams_free(&streams);

	return errstr;
}
示例#23
0
char *janus_sdp_anonymize(const char *sdp) {
	if(sdp == NULL)
		return NULL;
	//~ su_home_t home[1] = { SU_HOME_INIT(home) };
	sdp_session_t *anon = NULL;
	sdp_parser_t *parser = sdp_parse(home, sdp, strlen(sdp), 0);
	if(!(anon = sdp_session(parser))) {
		JANUS_DEBUG("Error parsing/merging SDP: %s\n", sdp_parsing_error(parser));
		return NULL;
	}
		//~ /* o= */
	//~ if(anon->sdp_origin && anon->sdp_origin->o_username) {
		//~ free(anon->sdp_origin->o_username);
		//~ anon->sdp_origin->o_username = strdup("JANUS");
	//~ }
		/* c= */
	if(anon->sdp_connection && anon->sdp_connection->c_address) {
		//~ free(anon->sdp_connection->c_address);
		anon->sdp_connection->c_address = strdup("1.1.1.1");
	}
		/* a= */
	if(anon->sdp_attributes) {
		/* FIXME These are attributes we handle ourselves, the plugins don't need them */
		while(sdp_attribute_find(anon->sdp_attributes, "ice-ufrag"))
			sdp_attribute_remove(&anon->sdp_attributes, "ice-ufrag");
		while(sdp_attribute_find(anon->sdp_attributes, "ice-pwd"))
			sdp_attribute_remove(&anon->sdp_attributes, "ice-pwd");
		while(sdp_attribute_find(anon->sdp_attributes, "ice-options"))
			sdp_attribute_remove(&anon->sdp_attributes, "ice-options");
		while(sdp_attribute_find(anon->sdp_attributes, "fingerprint"))
			sdp_attribute_remove(&anon->sdp_attributes, "fingerprint");
		while(sdp_attribute_find(anon->sdp_attributes, "group"))
			sdp_attribute_remove(&anon->sdp_attributes, "group");
		while(sdp_attribute_find(anon->sdp_attributes, "msid-semantic"))
			sdp_attribute_remove(&anon->sdp_attributes, "msid-semantic");
	}
		/* m= */
	int a_sendrecv = 0, v_sendrecv = 0;
	if(anon->sdp_media) {
		int audio = 0, video = 0;
		sdp_media_t *m = anon->sdp_media;
		while(m) {
			if(m->m_type == sdp_media_audio) {
				audio++;
				m->m_port = audio == 1 ? 1 : 0;
			} else if(m->m_type == sdp_media_video) {
				video++;
				m->m_port = audio == 1 ? 1 : 0;
			} else {
				m->m_port = 0;
			}
				/* c= */
			if(m->m_connections) {
				sdp_connection_t *c = m->m_connections;
				while(c) {
					if(c->c_address) {
						//~ free(c->c_address);
						c->c_address = strdup("1.1.1.1");
					}
					c = c->c_next;
				}
			}
				/* a= */
			if(m->m_attributes) {
				/* FIXME These are attributes we handle ourselves, the plugins don't need them */
				while(sdp_attribute_find(m->m_attributes, "ice-ufrag"))
					sdp_attribute_remove(&m->m_attributes, "ice-ufrag");
				while(sdp_attribute_find(m->m_attributes, "ice-pwd"))
					sdp_attribute_remove(&m->m_attributes, "ice-pwd");
				while(sdp_attribute_find(m->m_attributes, "ice-options"))
					sdp_attribute_remove(&m->m_attributes, "ice-options");
				while(sdp_attribute_find(m->m_attributes, "crypto"))
					sdp_attribute_remove(&m->m_attributes, "crypto");
				while(sdp_attribute_find(m->m_attributes, "fingerprint"))
					sdp_attribute_remove(&m->m_attributes, "fingerprint");
				while(sdp_attribute_find(m->m_attributes, "setup"))
					sdp_attribute_remove(&m->m_attributes, "setup");
				while(sdp_attribute_find(m->m_attributes, "connection"))
					sdp_attribute_remove(&m->m_attributes, "connection");
				while(sdp_attribute_find(m->m_attributes, "group"))
					sdp_attribute_remove(&m->m_attributes, "group");
				while(sdp_attribute_find(m->m_attributes, "msid-semantic"))
					sdp_attribute_remove(&m->m_attributes, "msid-semantic");
				while(sdp_attribute_find(m->m_attributes, "rtcp"))
					sdp_attribute_remove(&m->m_attributes, "rtcp");
				while(sdp_attribute_find(m->m_attributes, "rtcp-mux"))
					sdp_attribute_remove(&m->m_attributes, "rtcp-mux");
				while(sdp_attribute_find(m->m_attributes, "candidate"))
					sdp_attribute_remove(&m->m_attributes, "candidate");
				while(sdp_attribute_find(m->m_attributes, "ssrc"))
					sdp_attribute_remove(&m->m_attributes, "ssrc");
				while(sdp_attribute_find(m->m_attributes, "extmap"))	/* TODO Actually implement RTP extensions */
					sdp_attribute_remove(&m->m_attributes, "extmap");
			}
			/* FIXME sendrecv hack: sofia-sdp doesn't print sendrecv, but we want it to */
			if(m->m_mode == sdp_sendrecv) {
				m->m_mode = sdp_inactive;
				if(m->m_type == sdp_media_audio)
					a_sendrecv = 1;
				else if(m->m_type == sdp_media_video)
					v_sendrecv = 1;
			}
			m = m->m_next;
		}
	}
	char buf[BUFSIZE];
	sdp_printer_t *printer = sdp_print(home, anon, buf, BUFSIZE, 0);
	if(sdp_message(printer)) {
		int retval = sdp_message_size(printer);
		sdp_printer_free(printer);
		/* FIXME Take care of the sendrecv hack */
		if(a_sendrecv || v_sendrecv) {
			char *replace = strstr(buf, "a=inactive");
			while(replace != NULL) {
				memcpy(replace, "a=sendrecv", strlen("a=sendrecv"));
				replace++;
				replace = strstr(replace, "a=inactive");
			}
		}
		JANUS_PRINT(" -------------------------------------------\n");
		JANUS_PRINT("  >> Anonymized (%zu --> %d bytes)\n", strlen(sdp), retval);
		JANUS_PRINT(" -------------------------------------------\n");
		JANUS_PRINT("%s\n", buf);
		return g_strdup(buf);
	} else {
		JANUS_DEBUG("Error anonymizing SDP: %s\n", sdp_printing_error(printer));
		return NULL;
	}
}
示例#24
0
char *janus_sdp_merge(janus_ice_handle *handle, const char *origsdp) {
	if(handle == NULL || origsdp == NULL)
		return NULL;
	//~ su_home_t home[1] = { SU_HOME_INIT(home) };
	sdp_session_t *anon = NULL;
	sdp_parser_t *parser = sdp_parse(home, origsdp, strlen(origsdp), 0);
	if(!(anon = sdp_session(parser))) {
		JANUS_DEBUG("[%"SCNu64"] Error parsing/merging SDP: %s\n", handle->handle_id, sdp_parsing_error(parser));
		return NULL;
	}
	/* Prepare SDP to merge */
	gchar buffer[200];
	memset(buffer, 0, 200);
	char *sdp = (char*)calloc(BUFSIZE, sizeof(char));
	if(sdp == NULL) {
		JANUS_DEBUG("Memory error!\n");
		return NULL;
	}
	sdp[0] = '\0';
	/* Version v= */
	g_strlcat(sdp,
		"v=0\r\n", BUFSIZE);
	/* Origin o= */
	if(anon->sdp_origin) {
		g_sprintf(buffer,
			"o=%s %"SCNu64" %"SCNu64" IN IP4 127.0.0.1\r\n",	/* FIXME Should we fix the address? */
				anon->sdp_origin->o_username ? anon->sdp_origin->o_username : "******",
				anon->sdp_origin->o_id, anon->sdp_origin->o_version);
		g_strlcat(sdp, buffer, BUFSIZE);
	} else {
		gint64 sessid = g_get_monotonic_time();
		gint64 version = sessid;	/* FIXME This needs to be increased when it changes, so time should be ok */
		g_sprintf(buffer,
			"o=%s %"SCNi64" %"SCNi64" IN IP4 127.0.0.1\r\n",	/* FIXME Should we fix the address? */
				"-", sessid, version);
		g_strlcat(sdp, buffer, BUFSIZE);
	}
	/* Session name s= */
	g_sprintf(buffer,
		"s=%s\r\n", anon->sdp_subject ? anon->sdp_subject : "Meetecho Janus");
	g_strlcat(sdp, buffer, BUFSIZE);
	/* Timing t= */
	g_sprintf(buffer,
		"t=%lu %lu\r\n", anon->sdp_time ? anon->sdp_time->t_start : 0, anon->sdp_time ? anon->sdp_time->t_stop : 0);
	g_strlcat(sdp, buffer, BUFSIZE);
	/* Any global bandwidth? */
	//~ if(anon->sdp_bandwidths) {
		//~ g_sprintf(buffer,
			//~ "b=%s:%"SCNu64"\r\n",
				//~ anon->sdp_bandwidths->b_modifier_name ? anon->sdp_bandwidths->b_modifier_name : "AS",
				//~ anon->sdp_bandwidths->b_value);
		//~ g_strlcat(sdp, buffer, BUFSIZE);
	//~ }
	/* msid-semantic: add new global attribute */
	g_strlcat(sdp,
		"a=msid-semantic: WMS janus\r\n",
		BUFSIZE);
	//~ /* Connection c= (global) */
	//~ if(anon->sdp_connection) {
		//~ g_sprintf(buffer,
			//~ "c=IN IP4 %s\r\n", janus_get_local_ip());
		//~ g_strlcat(sdp, buffer, BUFSIZE);
	//~ }
	/* DTLS fingerprint a= (global) */
	g_sprintf(buffer,
		"a=fingerprint:sha-256 %s\r\n", janus_dtls_get_local_fingerprint());
	g_strlcat(sdp, buffer, BUFSIZE);
	/* Copy other global attributes, if any */
	if(anon->sdp_attributes) {
		sdp_attribute_t *a = anon->sdp_attributes;
		while(a) {
			if(a->a_value == NULL) {
				g_sprintf(buffer,
					"a=%s\r\n", a->a_name);
				g_strlcat(sdp, buffer, BUFSIZE);
			} else {
				g_sprintf(buffer,
					"a=%s:%s\r\n", a->a_name, a->a_value);
				g_strlcat(sdp, buffer, BUFSIZE);
			}
			a = a->a_next;
		}
	}
	/* Media lines now */
	if(anon->sdp_media) {
		int audio = 0, video = 0;
		sdp_media_t *m = anon->sdp_media;
		janus_ice_stream *stream = NULL;
		while(m) {
			if(m->m_type == sdp_media_audio) {
				audio++;
				if(audio > 1 || !handle->audio_id) {
					JANUS_DEBUG("[%"SCNu64"] Skipping audio line (we have %d audio lines, and the id is %d)\n", handle->handle_id, audio, handle->audio_id);
					g_strlcat(sdp, "m=audio 0 RTP/SAVPF 0\r\n", BUFSIZE);
					m = m->m_next;
					continue;
				}
				/* Audio */
				stream = g_hash_table_lookup(handle->streams, GUINT_TO_POINTER(handle->audio_id));
				if(stream == NULL) {
					JANUS_DEBUG("[%"SCNu64"] Skipping audio line (invalid stream %d)\n", handle->handle_id, handle->audio_id);
					g_strlcat(sdp, "m=audio 0 RTP/SAVPF 0\r\n", BUFSIZE);
					m = m->m_next;
					continue;
				}
				g_strlcat(sdp, "m=audio ARTPP RTP/SAVPF", BUFSIZE);
			} else if(m->m_type == sdp_media_video) {
				video++;
				if(video > 1 || !handle->video_id) {
					JANUS_DEBUG("[%"SCNu64"] Skipping video line (we have %d video lines, and the id is %d)\n", handle->handle_id, video, handle->video_id);
					g_strlcat(sdp, "m=video 0 RTP/SAVPF 0\r\n", BUFSIZE);
					m = m->m_next;
					continue;
				}
				/* Video */
				stream = g_hash_table_lookup(handle->streams, GUINT_TO_POINTER(handle->video_id));
				if(stream == NULL) {
					JANUS_DEBUG("[%"SCNu64"] Skipping video line (invalid stream %d)\n", handle->handle_id, handle->audio_id);
					g_strlcat(sdp, "m=video 0 RTP/SAVPF 0\r\n", BUFSIZE);
					m = m->m_next;
					continue;
				}
				g_strlcat(sdp, "m=video VRTPP RTP/SAVPF", BUFSIZE);
			} else {
				JANUS_DEBUG("[%"SCNu64"] Skipping unsupported media line...\n", handle->handle_id);
				g_sprintf(buffer,
					"m=%s 0 %s 0\r\n",
					m->m_type_name, m->m_proto_name);
				g_strlcat(sdp, buffer, BUFSIZE);
				m = m->m_next;
				continue;
			}
			/* Add formats now */
			if(!m->m_rtpmaps) {
				JANUS_PRINT("[%"SCNu64"] No RTP maps?? trying formats...\n", handle->handle_id);
				if(!m->m_format) {
					JANUS_DEBUG("[%"SCNu64"] No formats either?? this sucks!\n", handle->handle_id);
					g_strlcat(sdp, " 0", BUFSIZE);	/* FIXME Won't work apparently */
				} else {
					sdp_list_t *fmt = m->m_format;
					while(fmt) {
						g_sprintf(buffer, " %s", fmt->l_text);
						g_strlcat(sdp, buffer, BUFSIZE);
						fmt = fmt->l_next;
					}
				}
			} else {
				sdp_rtpmap_t *r = m->m_rtpmaps;
				while(r) {
					g_sprintf(buffer, " %d", r->rm_pt);
					g_strlcat(sdp, buffer, BUFSIZE);
					r = r->rm_next;
				}
			}
			g_strlcat(sdp, "\r\n", BUFSIZE);
			/* Any bandwidth? */
			if(m->m_bandwidths) {
				g_sprintf(buffer,
					"b=%s:%lu\r\n",	/* FIXME Are we doing this correctly? */
						m->m_bandwidths->b_modifier_name ? m->m_bandwidths->b_modifier_name : "AS",
						m->m_bandwidths->b_value);
				g_strlcat(sdp, buffer, BUFSIZE);
			}
			/* Media connection c= */
			//~ if(m->m_connections) {
				g_sprintf(buffer,
					"c=IN IP4 %s\r\n", janus_get_local_ip());
				g_strlcat(sdp, buffer, BUFSIZE);
			//~ }
			/* What is the direction? */
			switch(m->m_mode) {
				case sdp_inactive:
					g_strlcat(sdp, "a=inactive\r\n", BUFSIZE);
					break;
				case sdp_sendonly:
					g_strlcat(sdp, "a=sendonly\r\n", BUFSIZE);
					break;
				case sdp_recvonly:
					g_strlcat(sdp, "a=recvonly\r\n", BUFSIZE);
					break;
				case sdp_sendrecv:
				default:
					g_strlcat(sdp, "a=sendrecv\r\n", BUFSIZE);
					break;
			}
			/* RTCP */
			g_sprintf(buffer, "a=rtcp:%s IN IP4 %s\r\n",
				m->m_type == sdp_media_audio ? "ARTCP" : "VRTCP", janus_get_local_ip());
			g_strlcat(sdp, buffer, BUFSIZE);
			/* RTP maps */
			if(m->m_rtpmaps) {
				sdp_rtpmap_t *rm = NULL;
				for(rm = m->m_rtpmaps; rm; rm = rm->rm_next) {
					g_sprintf(buffer, "a=rtpmap:%u %s/%lu%s%s\r\n",
						rm->rm_pt, rm->rm_encoding, rm->rm_rate,
						rm->rm_params ? "/" : "", 
						rm->rm_params ? rm->rm_params : "");
					g_strlcat(sdp, buffer, BUFSIZE);
				}
				for(rm = m->m_rtpmaps; rm; rm = rm->rm_next) {
					if(rm->rm_fmtp) {
						g_sprintf(buffer, "a=fmtp:%u %s\r\n", rm->rm_pt, rm->rm_fmtp);
						g_strlcat(sdp, buffer, BUFSIZE);
					}
				}
			}
			/* ICE ufrag and pwd, DTLS setup and connection a= */
			gchar *ufrag = NULL;
			gchar *password = NULL;
			nice_agent_get_local_credentials(handle->agent, stream->stream_id, &ufrag, &password);
			memset(buffer, 0, 100);
			g_sprintf(buffer,
				"a=ice-ufrag:%s\r\n"
				"a=ice-pwd:%s\r\n"
				"a=setup:%s\r\n"
				"a=connection:new\r\n",
					ufrag, password,
					janus_get_dtls_srtp_role(stream->dtls_role));
			g_strlcat(sdp, buffer, BUFSIZE);
			/* Copy existing media attributes, if any */
			if(m->m_attributes) {
				sdp_attribute_t *a = m->m_attributes;
				while(a) {
					if(a->a_value == NULL) {
						g_sprintf(buffer,
							"a=%s\r\n", a->a_name);
						g_strlcat(sdp, buffer, BUFSIZE);
					} else {
						g_sprintf(buffer,
							"a=%s:%s\r\n", a->a_name, a->a_value);
						g_strlcat(sdp, buffer, BUFSIZE);
					}
					a = a->a_next;
				}
			}
			/* Add last attributes, rtcp and ssrc (msid) */
			if(m->m_type == sdp_media_audio) {
				g_sprintf(buffer,
					//~ "a=rtcp:ARTCP IN IP4 %s\r\n"
					"a=ssrc:%i cname:janusaudio\r\n"
					"a=ssrc:%i msid:janus janusa0\r\n"
					"a=ssrc:%i mslabel:janus\r\n"
					"a=ssrc:%i label:janusa0\r\n",
						//~ janus_get_local_ip(),
						stream->ssrc, stream->ssrc, stream->ssrc, stream->ssrc);
				g_strlcat(sdp, buffer, BUFSIZE);
			} else if(m->m_type == sdp_media_video) {
				g_sprintf(buffer,
					//~ "a=rtcp:VRTCP IN IP4 %s\r\n"
					"a=ssrc:%i cname:janusvideo\r\n"
					"a=ssrc:%i msid:janus janusv0\r\n"
					"a=ssrc:%i mslabel:janus\r\n"
					"a=ssrc:%i label:janusv0\r\n",
						//~ janus_get_local_ip(),
						stream->ssrc, stream->ssrc, stream->ssrc, stream->ssrc);
				g_strlcat(sdp, buffer, BUFSIZE);
			}
			/* And now the candidates */
			janus_ice_setup_candidate(handle, sdp, stream->stream_id, 1);
			janus_ice_setup_candidate(handle, sdp, stream->stream_id, 2);
			/* Next */
			m = m->m_next;
		}
	}
	JANUS_PRINT(" -------------------------------------------\n");
	JANUS_PRINT("  >> Merged (%zu --> %zu bytes)\n", strlen(origsdp), strlen(sdp));
	JANUS_PRINT(" -------------------------------------------\n");
	JANUS_PRINT("%s\n", sdp);
	return sdp;
}
示例#25
0
int main(int argc, char **argv){

        /* setting commad line information */
        local_ip        = argv[1];
        local_port      = atoi(argv[2]);
        cname           = argv[3];
        proto           = udp;

	/* create a rtp session, we will assign unique value to identify */
	err = rtp_create(&sid);	
	if (err) {
		err_handle(err);
	}

	sdp_parse(sid, argv);

	if (rtp_start_time > 0) {
		usleep( ((int) rtp_start_time * 1000000) );
	}

        if ((i = initial_session(argc, argv, sid))) {
                printf("WARNING : initial_session warning = %d\n", i);
        }
        else {
                printf("initial_session is ok\n");
        }

	if (is_audio) {
		delay	= (ms_pkt / 1000.);
	}
	else {
		delay	= (1. / framerate);	// unit: ms/sec. we assume that 300 samples/frame, 
	}

	/* bytes of each packet = ((bits/sample) / 8 ) * (clock rate) * ( each delay of packet in sec ) */
	packet_size = (int) ( bits_per_sample * sampling_rate * delay / 8.);
	
	/* original_bw = min_bw = 50, so we use the same pkt size */
	minbw_pktsize = packet_size;
	
	printf("bits_per_sample = %lf, (bits_per_sample/8.) = %lf\n", bits_per_sample, (bits_per_sample/8.));
	printf("sampling_rate = %lf\n", sampling_rate);
	printf("delay = %lf\n", delay);
	printf("packet_size = %d\n", packet_size);
	fflush(stdout);
	
	/* the bandwidth wa are using, 30 = frames/sec */
	cur_bw = get_cur_bw(packet_size);
	
	err = rtp_get_sour_rtpsocket(sid, &rtp_sockt);
	if (err) {
		err_handle(err);
	}
	err = rtp_get_sour_rtcpsocket(sid, &rtcp_sockt);
	if (err) {
		err_handle(err);
	}	
	
	if (rtp_sockt > nfds || rtcp_sockt > nfds) {
		if (rtp_sockt > rtcp_sockt)
			nfds = rtp_sockt;
		else
			nfds = rtcp_sockt;
	}
	
	FD_ZERO(&afds);
	FD_ZERO(&rfds);
	FD_SET(rtp_sockt, &afds);
	FD_SET(rtcp_sockt, &afds);
	
	gettimeofday(&start_tv, NULL);
	starttime = (start_tv.tv_sec + start_tv.tv_usec / 1000000.);
	nexttime = starttime;
	
	rtp_interval = rtp_stop_time - rtp_start_time;
	
	printf("rtp_interval = %f\n", rtp_interval);
	fflush(stdout);
	
	while (rtp_interval >= 0) {
		
		memcpy(&rfds, &afds, sizeof(rfds));
		
		if (RTP_MAX_PKT_SIZE < packet_size){
			fprintf(stderr, "RTP_MAX_PKT_SIZE < reads\n");
			continue;
		}
		
		addtimestamp = ((int) packet_size * (bits_per_sample / 8.) );

		err = rtp_send(sid, marker, addtimestamp, codec_num, (int8 *)sendbuf, packet_size);
		if (err) {
			err_handle(err);
		}
		
		marker = 0;	/* not the first packet of talkspurt */
		rtp_interval -= delay;
		nexttime += delay;
		gettimeofday(&now_tv, NULL);
		now = (now_tv.tv_sec + now_tv.tv_usec / 1000000.);
		
		err = get_rtcp_timeout(sid, &timeout_tv);
		if (err) {
			err_handle(err);
		}
		
		while (now < nexttime) {	/* send next packet until now >= nexttime */
		
			//printf("now = %lf\n", now);
			//printf("nexttime = %lf\n", nexttime);
			
			if (time_expire(&timeout_tv, &now_tv)) { 
				
				err = rtp_check_on_expire();
				if (err) {
					err_handle(err);
				}
				
				err = get_rtcp_timeout(sid, &timeout_tv);
				if (err) {
					err_handle(err);
				}
				printf("timeval_to_double(timeout_tv) = %lf\n", timeval_to_double(timeout_tv));	
			}
			
			/* BECAREFUL, if we disable RTCP, the timeval we get will be 0 */
			if (timeval_to_double(timeout_tv) == 0 || nexttime < timeval_to_double(timeout_tv)) {
				nexttime_tv = double_to_timeval(nexttime - now);
			}
			else {
				nexttime_tv = double_to_timeval(timeval_to_double(timeout_tv) - now);
			}
			
			if (select(nfds + 1, &rfds, (fd_set *)0, (fd_set *)0, &nexttime_tv) < 0) {
				if (errno == EINTR)
					continue;
				else {	
					printf("nexttime_tv.tv_sec = %ld\n", nexttime_tv.tv_sec);
					printf("nexttime_tv.tv_usec = %ld\n", nexttime_tv.tv_usec);
					printf("select error: %d\n", errno);
					//exit(1);
				}
			}
			
			if (FD_ISSET(rtp_sockt, &rfds)) {

				err = on_receive(sid, rtp_sockt, recvbuf, &recbuflen);
				if (err) {
					err_handle(err);
				}	
			}
			else if (FD_ISSET(rtcp_sockt, &rfds)) {
			
				err = on_receive(sid, rtcp_sockt, recvbuf, &recbuflen);
				if (err) {
					err_handle(err);
				}
				
				adapt_bw(get_recent_recv_loosrate(sid, &ssrc));
			}
			
			gettimeofday(&now_tv, NULL);
			now = (now_tv.tv_sec + now_tv.tv_usec / 1000000.);
		} // while(now < nexttime)
	} // while (interval)
	
	err = rtp_close_connection(sid, reason);
	if (err) {
		err_handle(err);
	}
	
	err = rtp_delete(sid);
	if (err) {
		err_handle(err);
	}
			
	return 0;
}
示例#26
0
static int rtsp_read_header(AVFormatContext *s,
                            AVFormatParameters *ap)
{
    RTSPState *rt = s->priv_data;
    char host[1024], path[1024], tcpname[1024], cmd[2048], *option_list, *option;
    URLContext *rtsp_hd;
    int port, ret, err;
    RTSPHeader reply1, *reply = &reply1;
    unsigned char *content = NULL;
    int protocol_mask = 0;

    /* extract hostname and port */
    url_split(NULL, 0, NULL, 0,
              host, sizeof(host), &port, path, sizeof(path), s->filename);
    if (port < 0)
        port = RTSP_DEFAULT_PORT;

    /* search for options */
    option_list = strchr(path, '?');
    if (option_list) {
        /* remove the options from the path */
        *option_list++ = 0;
        while(option_list) {
            /* move the option pointer */
            option = option_list;
            option_list = strchr(option_list, '&');
            if (option_list)
                *(option_list++) = 0;
            /* handle the options */
            if (strcmp(option, "udp") == 0)
                protocol_mask = (1<< RTSP_PROTOCOL_RTP_UDP);
            else if (strcmp(option, "multicast") == 0)
                protocol_mask = (1<< RTSP_PROTOCOL_RTP_UDP_MULTICAST);
            else if (strcmp(option, "tcp") == 0)
                protocol_mask = (1<< RTSP_PROTOCOL_RTP_TCP);
        }
    }

    if (!protocol_mask)
        protocol_mask = (1 << RTSP_PROTOCOL_RTP_LAST) - 1;

    /* open the tcp connexion */
    snprintf(tcpname, sizeof(tcpname), "tcp://%s:%d", host, port);
    if (url_open(&rtsp_hd, tcpname, URL_RDWR) < 0)
        return AVERROR(EIO);
    rt->rtsp_hd = rtsp_hd;
    rt->seq = 0;

    /* describe the stream */
    snprintf(cmd, sizeof(cmd),
             "DESCRIBE %s RTSP/1.0\r\n"
             "Accept: application/sdp\r\n",
             s->filename);
    rtsp_send_cmd(s, cmd, reply, &content);
    if (!content) {
        err = AVERROR_INVALIDDATA;
        goto fail;
    }
    if (reply->status_code != RTSP_STATUS_OK) {
        err = AVERROR_INVALIDDATA;
        goto fail;
    }

    /* now we got the SDP description, we parse it */
    ret = sdp_parse(s, (const char *)content);
    av_freep(&content);
    if (ret < 0) {
        err = AVERROR_INVALIDDATA;
        goto fail;
    }

    do {
        int protocol = ff_log2_tab[protocol_mask & ~(protocol_mask - 1)];

        err = make_setup_request(s, host, port, protocol);
        if (err < 0)
            goto fail;
        protocol_mask &= ~(1 << protocol);
        if (protocol_mask == 0 && err == 1) {
            err = AVERROR(FF_NETERROR(EPROTONOSUPPORT));
            goto fail;
        }
    } while (err);

    rt->state = RTSP_STATE_IDLE;
    rt->seek_timestamp = 0; /* default is to start stream at position
                               zero */
    if (ap->initial_pause) {
        /* do not start immediately */
    } else {
        if (rtsp_read_play(s) < 0) {
            err = AVERROR_INVALIDDATA;
            goto fail;
        }
    }
    return 0;
 fail:
    rtsp_close_streams(rt);
    av_freep(&content);
    url_close(rt->rtsp_hd);
    return err;
}
示例#27
0
char *janus_sdp_anonymize(const char *sdp) {
	if(sdp == NULL)
		return NULL;
	sdp_session_t *anon = NULL;
	sdp_parser_t *parser = sdp_parse(home, sdp, strlen(sdp), 0);
	if(!(anon = sdp_session(parser))) {
		JANUS_LOG(LOG_ERR, "Error parsing/merging SDP: %s\n", sdp_parsing_error(parser));
		sdp_parser_free(parser);
		return NULL;
	}
	/* c= */
	if(anon->sdp_connection && anon->sdp_connection->c_address) {
		anon->sdp_connection->c_address = "1.1.1.1";
	}
	/* a= */
	if(anon->sdp_attributes) {
		/* These are attributes we handle ourselves, the plugins don't need them */
		while(sdp_attribute_find(anon->sdp_attributes, "ice-ufrag"))
			sdp_attribute_remove(&anon->sdp_attributes, "ice-ufrag");
		while(sdp_attribute_find(anon->sdp_attributes, "ice-pwd"))
			sdp_attribute_remove(&anon->sdp_attributes, "ice-pwd");
		while(sdp_attribute_find(anon->sdp_attributes, "ice-options"))
			sdp_attribute_remove(&anon->sdp_attributes, "ice-options");
		while(sdp_attribute_find(anon->sdp_attributes, "fingerprint"))
			sdp_attribute_remove(&anon->sdp_attributes, "fingerprint");
		while(sdp_attribute_find(anon->sdp_attributes, "group"))
			sdp_attribute_remove(&anon->sdp_attributes, "group");
		while(sdp_attribute_find(anon->sdp_attributes, "msid-semantic"))
			sdp_attribute_remove(&anon->sdp_attributes, "msid-semantic");
	}
		/* m= */
	if(anon->sdp_media) {
		int audio = 0, video = 0;
#ifdef HAVE_SCTP
		int data = 0;
#endif
		sdp_media_t *m = anon->sdp_media;
		while(m) {
			if(m->m_type == sdp_media_audio && m->m_port > 0) {
				audio++;
				m->m_port = audio == 1 ? 1 : 0;
			} else if(m->m_type == sdp_media_video && m->m_port > 0) {
				video++;
				m->m_port = video == 1 ? 1 : 0;
#ifdef HAVE_SCTP
			} else if(m->m_type == sdp_media_application) {
				if(m->m_proto_name != NULL && !strcasecmp(m->m_proto_name, "DTLS/SCTP") && m->m_port != 0) {
					data++;
					m->m_port = data == 1 ? 1 : 0;
				} else {
					m->m_port = 0;
				}
#endif
			} else {
				m->m_port = 0;
			}
				/* c= */
			if(m->m_connections) {
				sdp_connection_t *c = m->m_connections;
				while(c) {
					if(c->c_address) {
						c->c_address = "1.1.1.1";
					}
					c = c->c_next;
				}
			}
				/* a= */
			if(m->m_attributes) {
				/* These are attributes we handle ourselves, the plugins don't need them */
				while(sdp_attribute_find(m->m_attributes, "ice-ufrag"))
					sdp_attribute_remove(&m->m_attributes, "ice-ufrag");
				while(sdp_attribute_find(m->m_attributes, "ice-pwd"))
					sdp_attribute_remove(&m->m_attributes, "ice-pwd");
				while(sdp_attribute_find(m->m_attributes, "ice-options"))
					sdp_attribute_remove(&m->m_attributes, "ice-options");
				while(sdp_attribute_find(m->m_attributes, "crypto"))
					sdp_attribute_remove(&m->m_attributes, "crypto");
				while(sdp_attribute_find(m->m_attributes, "fingerprint"))
					sdp_attribute_remove(&m->m_attributes, "fingerprint");
				while(sdp_attribute_find(m->m_attributes, "setup"))
					sdp_attribute_remove(&m->m_attributes, "setup");
				while(sdp_attribute_find(m->m_attributes, "connection"))
					sdp_attribute_remove(&m->m_attributes, "connection");
				while(sdp_attribute_find(m->m_attributes, "group"))
					sdp_attribute_remove(&m->m_attributes, "group");
				while(sdp_attribute_find(m->m_attributes, "mid"))
					sdp_attribute_remove(&m->m_attributes, "mid");
				while(sdp_attribute_find(m->m_attributes, "msid"))
					sdp_attribute_remove(&m->m_attributes, "msid");
				while(sdp_attribute_find(m->m_attributes, "msid-semantic"))
					sdp_attribute_remove(&m->m_attributes, "msid-semantic");
				while(sdp_attribute_find(m->m_attributes, "rtcp"))
					sdp_attribute_remove(&m->m_attributes, "rtcp");
				while(sdp_attribute_find(m->m_attributes, "rtcp-mux"))
					sdp_attribute_remove(&m->m_attributes, "rtcp-mux");
				while(sdp_attribute_find(m->m_attributes, "candidate"))
					sdp_attribute_remove(&m->m_attributes, "candidate");
				while(sdp_attribute_find(m->m_attributes, "ssrc"))
					sdp_attribute_remove(&m->m_attributes, "ssrc");
				while(sdp_attribute_find(m->m_attributes, "ssrc-group"))
					sdp_attribute_remove(&m->m_attributes, "ssrc-group");
				while(sdp_attribute_find(m->m_attributes, "extmap"))	/* TODO Actually implement RTP extensions */
					sdp_attribute_remove(&m->m_attributes, "extmap");
				while(sdp_attribute_find(m->m_attributes, "sctpmap"))
					sdp_attribute_remove(&m->m_attributes, "sctpmap");
			}
			if(m->m_type != sdp_media_application && m->m_mode == sdp_sendrecv) {
				/* FIXME sendrecv hack: sofia-sdp doesn't print sendrecv, but we want it to */
				sdp_attribute_t *fakedir = calloc(1, sizeof(sdp_attribute_t));
				fakedir->a_size = sizeof(sdp_attribute_t);
				fakedir->a_name = g_strdup("jfmod");
				fakedir->a_value = g_strdup("sr");
				sdp_attribute_append(&m->m_attributes, fakedir);
			}
			m = m->m_next;
		}
	}
	char buf[BUFSIZE];
	sdp_printer_t *printer = sdp_print(home, anon, buf, BUFSIZE, 0);
	if(sdp_message(printer)) {
		int retval = sdp_message_size(printer);
		sdp_printer_free(printer);
		sdp_parser_free(parser);
		/* FIXME Take care of the sendrecv hack, if needed */
		char *replace = strstr(buf, "a=jfmod:sr");
		while(replace != NULL) {
			memcpy(replace, "a=sendrecv", strlen("a=sendrecv"));
			replace++;
			replace = strstr(replace, "a=jfmod:sr");
		}
		JANUS_LOG(LOG_VERB, " -------------------------------------------\n");
		JANUS_LOG(LOG_VERB, "  >> Anonymized (%zu --> %d bytes)\n", strlen(sdp), retval);
		JANUS_LOG(LOG_VERB, " -------------------------------------------\n");
		JANUS_LOG(LOG_VERB, "%s\n", buf);
		return g_strdup(buf);
	} else {
		JANUS_LOG(LOG_ERR, "Error anonymizing SDP: %s\n", sdp_printing_error(printer));
		sdp_printer_free(printer);
		sdp_parser_free(parser);
		return NULL;
	}
}
示例#28
0
char *janus_sdp_merge(janus_ice_handle *handle, const char *origsdp) {
	if(handle == NULL || origsdp == NULL)
		return NULL;
	sdp_session_t *anon = NULL;
	sdp_parser_t *parser = sdp_parse(home, origsdp, strlen(origsdp), 0);
	if(!(anon = sdp_session(parser))) {
		JANUS_LOG(LOG_ERR, "[%"SCNu64"] Error parsing/merging SDP: %s\n", handle->handle_id, sdp_parsing_error(parser));
		sdp_parser_free(parser);
		return NULL;
	}
	/* Prepare SDP to merge */
	gchar buffer[512];
	memset(buffer, 0, 512);
	char *sdp = (char*)calloc(BUFSIZE, sizeof(char));
	if(sdp == NULL) {
		JANUS_LOG(LOG_FATAL, "Memory error!\n");
		sdp_parser_free(parser);
		return NULL;
	}
	sdp[0] = '\0';
	/* FIXME Any Plan B to take into account? */
	int planb = strstr(origsdp, "a=planb:") ? 1 : 0;
	if(planb) {
		janus_flags_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_PLAN_B);
	} else {
		janus_flags_clear(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_PLAN_B);
	}
	/* Version v= */
	g_strlcat(sdp,
		"v=0\r\n", BUFSIZE);
	/* Origin o= */
	if(anon->sdp_origin) {
		g_snprintf(buffer, 512,
			"o=%s %"SCNu64" %"SCNu64" IN IP4 127.0.0.1\r\n",	/* FIXME Should we fix the address? */
				anon->sdp_origin->o_username ? anon->sdp_origin->o_username : "******",
				anon->sdp_origin->o_id, anon->sdp_origin->o_version);
		g_strlcat(sdp, buffer, BUFSIZE);
	} else {
		gint64 sessid = janus_get_monotonic_time();
		gint64 version = sessid;	/* FIXME This needs to be increased when it changes, so time should be ok */
		g_snprintf(buffer, 512,
			"o=%s %"SCNi64" %"SCNi64" IN IP4 127.0.0.1\r\n",	/* FIXME Should we fix the address? */
				"-", sessid, version);
		g_strlcat(sdp, buffer, BUFSIZE);
	}
	/* Session name s= */
	if(anon->sdp_subject && strlen(anon->sdp_subject) > 0) {
		g_snprintf(buffer, 512, "s=%s\r\n", anon->sdp_subject);
	} else {
		g_snprintf(buffer, 512, "s=%s\r\n", "Meetecho Janus");
	}
	g_strlcat(sdp, buffer, BUFSIZE);
	/* Timing t= */
	g_snprintf(buffer, 512,
		"t=%lu %lu\r\n", anon->sdp_time ? anon->sdp_time->t_start : 0, anon->sdp_time ? anon->sdp_time->t_stop : 0);
	g_strlcat(sdp, buffer, BUFSIZE);
	/* ICE Full or Lite? */
	if(janus_ice_is_ice_lite_enabled()) {
		/* Janus is acting in ICE Lite mode, advertize this */
		g_strlcat(sdp, "a=ice-lite\r\n", BUFSIZE);
	}
	/* bundle: add new global attribute */
	int audio = (strstr(origsdp, "m=audio") != NULL);
	int video = (strstr(origsdp, "m=video") != NULL);
#ifdef HAVE_SCTP
	int data = (strstr(origsdp, "DTLS/SCTP") && !strstr(origsdp, " 0 DTLS/SCTP"));
#else
	int data = 0;
#endif
	g_strlcat(sdp, "a=group:BUNDLE", BUFSIZE);
	if(audio) {
		g_snprintf(buffer, 512,
			" %s", handle->audio_mid ? handle->audio_mid : "audio");
		g_strlcat(sdp, buffer, BUFSIZE);
	}
	if(video) {
		g_snprintf(buffer, 512,
			" %s", handle->video_mid ? handle->video_mid : "video");
		g_strlcat(sdp, buffer, BUFSIZE);
	}
	if(data) {
		g_snprintf(buffer, 512,
			" %s", handle->data_mid ? handle->data_mid : "data");
		g_strlcat(sdp, buffer, BUFSIZE);
	}
	g_strlcat(sdp, "\r\n", BUFSIZE);
	/* msid-semantic: add new global attribute */
	g_strlcat(sdp,
		"a=msid-semantic: WMS janus\r\n",
		BUFSIZE);
	char wms[BUFSIZE];
	memset(wms, 0, BUFSIZE);
	g_strlcat(wms, "WMS", BUFSIZE);
	/* Copy other global attributes, if any */
	if(anon->sdp_attributes) {
		sdp_attribute_t *a = anon->sdp_attributes;
		while(a) {
			if(a->a_value == NULL) {
				g_snprintf(buffer, 512,
					"a=%s\r\n", a->a_name);
				g_strlcat(sdp, buffer, BUFSIZE);
			} else {
				g_snprintf(buffer, 512,
					"a=%s:%s\r\n", a->a_name, a->a_value);
				g_strlcat(sdp, buffer, BUFSIZE);
			}
			a = a->a_next;
		}
	}
	gboolean ipv6 = strstr(janus_get_public_ip(), ":") != NULL;
	/* Media lines now */
	if(anon->sdp_media) {
		int audio = 0, video = 0;
#ifdef HAVE_SCTP
		int data = 0;
#endif
		sdp_media_t *m = anon->sdp_media;
		janus_ice_stream *stream = NULL;
		while(m) {
			if(m->m_type == sdp_media_audio && m->m_port > 0) {
				audio++;
				if(audio > 1 || !handle->audio_id) {
					JANUS_LOG(LOG_WARN, "[%"SCNu64"] Skipping audio line (we have %d audio lines, and the id is %d)\n", handle->handle_id, audio, handle->audio_id);
					g_strlcat(sdp, "m=audio 0 RTP/SAVPF 0\r\n", BUFSIZE);
					/* FIXME Adding a c-line anyway because otherwise Firefox complains? ("c= connection line not specified for every media level, validation failed") */
					g_snprintf(buffer, 512,
						"c=IN %s %s\r\n", ipv6 ? "IP6" : "IP4", janus_get_public_ip());
					g_strlcat(sdp, buffer, BUFSIZE);
					m = m->m_next;
					continue;
				}
				/* Audio */
				stream = g_hash_table_lookup(handle->streams, GUINT_TO_POINTER(handle->audio_id));
				if(stream == NULL) {
					JANUS_LOG(LOG_WARN, "[%"SCNu64"] Skipping audio line (invalid stream %d)\n", handle->handle_id, handle->audio_id);
					g_strlcat(sdp, "m=audio 0 RTP/SAVPF 0\r\n", BUFSIZE);
					/* FIXME Adding a c-line anyway because otherwise Firefox complains? ("c= connection line not specified for every media level, validation failed") */
					g_snprintf(buffer, 512,
						"c=IN %s %s\r\n", ipv6 ? "IP6" : "IP4", janus_get_public_ip());
					g_strlcat(sdp, buffer, BUFSIZE);
					m = m->m_next;
					continue;
				}
				g_strlcat(sdp, "m=audio 1 RTP/SAVPF", BUFSIZE);
			} else if(m->m_type == sdp_media_video && m->m_port > 0) {
				video++;
				gint id = handle->video_id;
				if(id == 0 && janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_BUNDLE))
					id = handle->audio_id > 0 ? handle->audio_id : handle->video_id;
				if(video > 1 || !id) {
					JANUS_LOG(LOG_WARN, "[%"SCNu64"] Skipping video line (we have %d video lines, and the id is %d)\n", handle->handle_id, video,
						janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_BUNDLE) ? handle->audio_id : handle->video_id);
					g_strlcat(sdp, "m=video 0 RTP/SAVPF 0\r\n", BUFSIZE);
					/* FIXME Adding a c-line anyway because otherwise Firefox complains? ("c= connection line not specified for every media level, validation failed") */
					g_snprintf(buffer, 512,
						"c=IN %s %s\r\n", ipv6 ? "IP6" : "IP4", janus_get_public_ip());
					g_strlcat(sdp, buffer, BUFSIZE);
					m = m->m_next;
					continue;
				}
				/* Video */
				stream = g_hash_table_lookup(handle->streams, GUINT_TO_POINTER(id));
				if(stream == NULL) {
					JANUS_LOG(LOG_WARN, "[%"SCNu64"] Skipping video line (invalid stream %d)\n", handle->handle_id, id);
					g_strlcat(sdp, "m=video 0 RTP/SAVPF 0\r\n", BUFSIZE);
					/* FIXME Adding a c-line anyway because otherwise Firefox complains? ("c= connection line not specified for every media level, validation failed") */
					g_snprintf(buffer, 512,
						"c=IN %s %s\r\n", ipv6 ? "IP6" : "IP4", janus_get_public_ip());
					g_strlcat(sdp, buffer, BUFSIZE);
					m = m->m_next;
					continue;
				}
				g_strlcat(sdp, "m=video 1 RTP/SAVPF", BUFSIZE);
#ifdef HAVE_SCTP
			} else if(m->m_type == sdp_media_application) {
				/* Is this SCTP for DataChannels? */
				if(m->m_port > 0 && m->m_proto_name != NULL && !strcasecmp(m->m_proto_name, "DTLS/SCTP") && m->m_port > 0) {
					/* Yep */
					data++;
					gint id = handle->data_id;
					if(id == 0 && janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_BUNDLE))
						id = handle->audio_id > 0 ? handle->audio_id : handle->video_id;
					if(data > 1 || !id) {
						JANUS_LOG(LOG_WARN, "[%"SCNu64"] Skipping SCTP line (we have %d SCTP lines, and the id is %d)\n", handle->handle_id, data, id);
						g_snprintf(buffer, 512,
							"m=%s 0 %s 0\r\n",
							m->m_type_name, m->m_proto_name);
						g_strlcat(sdp, buffer, BUFSIZE);
						/* FIXME Adding a c-line anyway because otherwise Firefox complains? ("c= connection line not specified for every media level, validation failed") */
						g_snprintf(buffer, 512,
							"c=IN %s %s\r\n", ipv6 ? "IP6" : "IP4", janus_get_public_ip());
						g_strlcat(sdp, buffer, BUFSIZE);
						m = m->m_next;
						continue;
					}
					/* SCTP */
					stream = g_hash_table_lookup(handle->streams, GUINT_TO_POINTER(id));
					if(stream == NULL) {
						JANUS_LOG(LOG_WARN, "[%"SCNu64"] Skipping SCTP line (invalid stream %d)\n", handle->handle_id, id);
						g_snprintf(buffer, 512,
							"m=%s 0 %s 0\r\n",
							m->m_type_name, m->m_proto_name);
						g_strlcat(sdp, buffer, BUFSIZE);
						/* FIXME Adding a c-line anyway because otherwise Firefox complains? ("c= connection line not specified for every media level, validation failed") */
						g_snprintf(buffer, 512,
							"c=IN %s %s\r\n", ipv6 ? "IP6" : "IP4", janus_get_public_ip());
						g_strlcat(sdp, buffer, BUFSIZE);
						m = m->m_next;
						continue;
					}
					g_strlcat(sdp, "m=application 1 DTLS/SCTP", BUFSIZE);
				} else {
					JANUS_LOG(LOG_WARN, "[%"SCNu64"] Skipping unsupported application media line...\n", handle->handle_id);
					g_snprintf(buffer, 512,
						"m=%s 0 %s 0\r\n",
						m->m_type_name, m->m_proto_name);
					g_strlcat(sdp, buffer, BUFSIZE);
					m = m->m_next;
					continue;
				}
#endif
			} else {
				JANUS_LOG(LOG_WARN, "[%"SCNu64"] Skipping disabled/unsupported media line...\n", handle->handle_id);
				g_snprintf(buffer, 512,
					"m=%s 0 %s 0\r\n",
					m->m_type_name, m->m_proto_name);
				g_strlcat(sdp, buffer, BUFSIZE);
				/* FIXME Adding a c-line anyway because otherwise Firefox complains? ("c= connection line not specified for every media level, validation failed") */
				g_snprintf(buffer, 512,
					"c=IN %s %s\r\n", ipv6 ? "IP6" : "IP4", janus_get_public_ip());
				g_strlcat(sdp, buffer, BUFSIZE);
				m = m->m_next;
				continue;
			}
			/* Add formats now */
			if(!m->m_rtpmaps) {
				JANUS_LOG(LOG_VERB, "[%"SCNu64"] No RTP maps?? trying formats...\n", handle->handle_id);
				if(!m->m_format) {
					JANUS_LOG(LOG_ERR, "[%"SCNu64"] No formats either?? this sucks!\n", handle->handle_id);
					g_strlcat(sdp, " 0", BUFSIZE);	/* FIXME Won't work apparently */
				} else {
					sdp_list_t *fmt = m->m_format;
					while(fmt) {
						g_snprintf(buffer, 512, " %s", fmt->l_text);
						g_strlcat(sdp, buffer, BUFSIZE);
						fmt = fmt->l_next;
					}
				}
			} else {
				sdp_rtpmap_t *r = m->m_rtpmaps;
				while(r) {
					g_snprintf(buffer, 512, " %d", r->rm_pt);
					g_strlcat(sdp, buffer, BUFSIZE);
					r = r->rm_next;
				}
			}
			g_strlcat(sdp, "\r\n", BUFSIZE);
			/* Media connection c= */
			g_snprintf(buffer, 512,
				"c=IN %s %s\r\n", ipv6 ? "IP6" : "IP4", janus_get_public_ip());
			g_strlcat(sdp, buffer, BUFSIZE);
			/* Any bandwidth? */
			if(m->m_bandwidths) {
				g_snprintf(buffer, 512,
					"b=%s:%lu\r\n",	/* FIXME Are we doing this correctly? */
						m->m_bandwidths->b_modifier_name ? m->m_bandwidths->b_modifier_name : "AS",
						m->m_bandwidths->b_value);
				g_strlcat(sdp, buffer, BUFSIZE);
			}
			/* a=mid:(audio|video|data) */
			switch(m->m_type) {
				case sdp_media_audio:
					g_snprintf(buffer, 512, "a=mid:%s\r\n", handle->audio_mid ? handle->audio_mid : "audio");
					break;
				case sdp_media_video:
					g_snprintf(buffer, 512, "a=mid:%s\r\n", handle->video_mid ? handle->video_mid : "video");
					break;
#ifdef HAVE_SCTP
				case sdp_media_application:
					/* FIXME sctpmap and webrtc-datachannel should be dynamic */
					g_snprintf(buffer, 512, "a=mid:%s\r\na=sctpmap:5000 webrtc-datachannel 16\r\n",
						handle->data_mid ? handle->data_mid : "data");
					break;
#endif
				default:
					break;
			}
			g_strlcat(sdp, buffer, BUFSIZE);
			if(m->m_type != sdp_media_application) {
				/* What is the direction? */
				switch(m->m_mode) {
					case sdp_sendonly:
						g_strlcat(sdp, "a=sendonly\r\n", BUFSIZE);
						break;
					case sdp_recvonly:
						g_strlcat(sdp, "a=recvonly\r\n", BUFSIZE);
						break;
					case sdp_inactive:
						g_strlcat(sdp, "a=inactive\r\n", BUFSIZE);
						break;
					case sdp_sendrecv:
					default:
						g_strlcat(sdp, "a=sendrecv\r\n", BUFSIZE);
						break;
				}
				/* rtcp-mux */
				g_snprintf(buffer, 512, "a=rtcp-mux\n");
				g_strlcat(sdp, buffer, BUFSIZE);
				/* RTP maps */
				if(m->m_rtpmaps) {
					sdp_rtpmap_t *rm = NULL;
					for(rm = m->m_rtpmaps; rm; rm = rm->rm_next) {
						g_snprintf(buffer, 512, "a=rtpmap:%u %s/%lu%s%s\r\n",
							rm->rm_pt, rm->rm_encoding, rm->rm_rate,
							rm->rm_params ? "/" : "", 
							rm->rm_params ? rm->rm_params : "");
						g_strlcat(sdp, buffer, BUFSIZE);
					}
					for(rm = m->m_rtpmaps; rm; rm = rm->rm_next) {
						if(rm->rm_fmtp) {
							g_snprintf(buffer, 512, "a=fmtp:%u %s\r\n", rm->rm_pt, rm->rm_fmtp);
							g_strlcat(sdp, buffer, BUFSIZE);
						}
					}
				}
			}
			/* ICE ufrag and pwd, DTLS fingerprint setup and connection a= */
			gchar *ufrag = NULL;
			gchar *password = NULL;
			nice_agent_get_local_credentials(handle->agent, stream->stream_id, &ufrag, &password);
			memset(buffer, 0, 100);
			g_snprintf(buffer, 512,
				"a=ice-ufrag:%s\r\n"
				"a=ice-pwd:%s\r\n"
				"a=ice-options:trickle\r\n"
				"a=fingerprint:sha-256 %s\r\n"
				"a=setup:%s\r\n"
				"a=connection:new\r\n",
					ufrag, password,
					janus_dtls_get_local_fingerprint(),
					janus_get_dtls_srtp_role(stream->dtls_role));
			if(ufrag != NULL)
				g_free(ufrag);
			ufrag = NULL;
			if(password != NULL)
				g_free(password);
			password = NULL;
			g_strlcat(sdp, buffer, BUFSIZE);
			/* Copy existing media attributes, if any */
			if(m->m_attributes) {
				sdp_attribute_t *a = m->m_attributes;
				while(a) {
					if(!strcmp(a->a_name, "planb")) {
						/* Skip the fake planb attribute, it's for internal use only */
						a = a->a_next;
						continue;
					}
					if(a->a_value == NULL) {
						g_snprintf(buffer, 512,
							"a=%s\r\n", a->a_name);
						g_strlcat(sdp, buffer, BUFSIZE);
					} else {
						g_snprintf(buffer, 512,
							"a=%s:%s\r\n", a->a_name, a->a_value);
						g_strlcat(sdp, buffer, BUFSIZE);
					}
					a = a->a_next;
				}
			}
			/* Add last attributes, rtcp and ssrc (msid) */
			if(!planb) {
				/* Single SSRC */
				if(m->m_type == sdp_media_audio && m->m_mode != sdp_inactive && m->m_mode != sdp_recvonly) {
					g_snprintf(buffer, 512,
						"a=ssrc:%"SCNu32" cname:janusaudio\r\n"
						"a=ssrc:%"SCNu32" msid:janus janusa0\r\n"
						"a=ssrc:%"SCNu32" mslabel:janus\r\n"
						"a=ssrc:%"SCNu32" label:janusa0\r\n",
							stream->audio_ssrc, stream->audio_ssrc, stream->audio_ssrc, stream->audio_ssrc);
					g_strlcat(sdp, buffer, BUFSIZE);
				} else if(m->m_type == sdp_media_video && m->m_mode != sdp_inactive && m->m_mode != sdp_recvonly) {
					g_snprintf(buffer, 512,
						"a=ssrc:%"SCNu32" cname:janusvideo\r\n"
						"a=ssrc:%"SCNu32" msid:janus janusv0\r\n"
						"a=ssrc:%"SCNu32" mslabel:janus\r\n"
						"a=ssrc:%"SCNu32" label:janusv0\r\n",
							stream->video_ssrc, stream->video_ssrc, stream->video_ssrc, stream->video_ssrc);
					g_strlcat(sdp, buffer, BUFSIZE);
				}
			} else {
				/* Multiple SSRCs */
				char mslabel[255];
				memset(mslabel, 0, 255);
				if(m->m_attributes) {
					char id[256];
					uint32_t ssrc = 0;
					sdp_attribute_t *a = m->m_attributes;
					while(a) {
						if(a->a_name == NULL || a->a_value == NULL || strcmp(a->a_name, "planb")) {
							a = a->a_next;
							continue;
						}
						if(sscanf(a->a_value, "%255s %"SCNu32"", id, &ssrc) != 2) {
							JANUS_LOG(LOG_ERR, "Error parsing 'planb' attribute, skipping it...\n");
							a = a->a_next;
							continue;
						}
						JANUS_LOG(LOG_VERB, "Parsing 'planb' attribute: %s\n", a->a_value);
						/* Add proper SSRC attributes */
						if(m->m_type == sdp_media_audio) {
							g_snprintf(buffer, 512,
								"a=ssrc:%"SCNu32" cname:%saudio\r\n"
								"a=ssrc:%"SCNu32" msid:%s %sa0\r\n"
								"a=ssrc:%"SCNu32" mslabel:%s\r\n"
								"a=ssrc:%"SCNu32" label:%sa0\r\n",
									ssrc, id, ssrc, id, id, ssrc, id, ssrc, id);
						} else if(m->m_type == sdp_media_video) {
							g_snprintf(buffer, 512,
								"a=ssrc:%"SCNu32" cname:%svideo\r\n"
								"a=ssrc:%"SCNu32" msid:%s %sv0\r\n"
								"a=ssrc:%"SCNu32" mslabel:%s\r\n"
								"a=ssrc:%"SCNu32" label:%sv0\r\n",
									ssrc, id, ssrc, id, id, ssrc, id, ssrc, id);
						}
						g_strlcat(sdp, buffer, BUFSIZE);
						/* Add to msid-semantic, if needed */
						if(!strstr(wms, id)) {
							g_snprintf(mslabel, 255, " %s", id);
							g_strlcat(wms, mslabel, BUFSIZE);
						}
						/* Go on */
						a = a->a_next;
					}
				}
			}
			/* And now the candidates */
			janus_ice_candidates_to_sdp(handle, sdp, stream->stream_id, 1);
			if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_RTCPMUX) &&
					m->m_type != sdp_media_application)
				janus_ice_candidates_to_sdp(handle, sdp, stream->stream_id, 2);
			/* Next */
			m = m->m_next;
		}
	}

	/* Do we need to update the msid-semantic attribute? */
	if(planb) {
		sdp = janus_string_replace(sdp, "WMS janus", wms);
	}
	
	sdp_parser_free(parser);

	JANUS_LOG(LOG_VERB, " -------------------------------------------\n");
	JANUS_LOG(LOG_VERB, "  >> Merged (%zu --> %zu bytes)\n", strlen(origsdp), strlen(sdp));
	JANUS_LOG(LOG_VERB, " -------------------------------------------\n");
	JANUS_LOG(LOG_VERB, "%s\n", sdp);

	return sdp;
}