/*process describe reply*/ void RP_ProcessDescribe(RTPSession *sess, RTSPCommand *com, M4Err e) { RTPStream *ch; ChannelDescribe *ch_desc; ch = NULL; ch_desc = com->user_data; if (e) goto exit; switch (sess->rtsp_rsp->ResponseCode) { //TODO handle all 3xx codes (redirections) case NC_RTSP_Multiple_Choice: e = ch_desc ? M4ChannelNotFound : M4URLNotFound; goto exit; case NC_RTSP_Not_Found: e = M4URLNotFound; goto exit; case NC_RTSP_OK: break; default: //we should have a basic error code mapping here e = M4ServiceError; goto exit; } ch = NULL; if (ch_desc) { ch = RP_FindChannel(sess->owner, ch_desc->channel, ch_desc->ES_ID, ch_desc->esd_url, 0); } else { NM_OnMessage(sess->owner->service, M4OK, "Connected"); } /*error on loading SDP is done internally*/ RP_LoadSDP(sess->owner, sess->rtsp_rsp->body, sess->rtsp_rsp->Content_Length, ch); if (!ch_desc) goto exit; if (!ch) { e = M4ChannelNotFound; goto exit; } e = RP_SetupChannel(ch, ch_desc); exit: if (e) { if (!ch_desc) { NM_OnConnect(sess->owner->service, NULL, e); } else if (ch) { RP_ConfirmChannelConnect(ch, e); } else { NM_OnConnect(sess->owner->service, ch_desc->channel, e); } } if (ch_desc) free(ch_desc); com->user_data = NULL; }
/*send describe*/ void RP_Describe(RTPSession *sess, char *esd_url, LPNETCHANNEL channel) { RTPStream *ch; ChannelDescribe *ch_desc; RTSPCommand *com; /*locate the channel by URL - if we have one, this means the channel is already described this happens when 2 ESD with URL use the same RTSP service - skip describe and send setup*/ if (esd_url || channel) { ch = RP_FindChannel(sess->owner, channel, 0, esd_url, 0); if (ch) { if (!ch->channel) ch->channel = channel; ch_desc = malloc(sizeof(ChannelDescribe)); ch_desc->esd_url = esd_url ? strdup(esd_url) : NULL; ch_desc->channel = channel; RP_SetupChannel(ch, ch_desc); if (esd_url) free(ch_desc->esd_url); free(ch_desc); return; } /*channel not found, send describe on service*/ } /*send describe*/ com = RTSP_NewCommand(); com->method = strdup(RTSP_DESCRIBE); if (channel || esd_url) { com->Accept = strdup("application/sdp"); com->ControlString = esd_url ? strdup(esd_url) : NULL; ch_desc = malloc(sizeof(ChannelDescribe)); ch_desc->esd_url = esd_url ? strdup(esd_url) : NULL; ch_desc->channel = channel; com->user_data = ch_desc; } else { //always accept both SDP and IOD com->Accept = strdup("application/sdp, application/mpeg4-iod"); // com->Accept = strdup("application/sdp"); } com->Bandwidth = sess->owner->bandwidth; MX_P(sess->owner->mx); ChainAddEntry(sess->rtsp_commands, com); MX_V(sess->owner->mx); }
/*filter describe commands in case of ESD URLs*/ Bool RP_PreprocessDescribe(RTPSession *sess, RTSPCommand *com) { RTPStream *ch; ChannelDescribe *ch_desc; /*not a channel describe*/ if (!com->user_data) { NM_OnMessage(sess->owner->service, M4OK, "Connecting..."); return 1; } ch_desc = (ChannelDescribe *)com->user_data; ch = RP_FindChannel(sess->owner, NULL, ch_desc->ES_ID, ch_desc->esd_url, 0); if (!ch) return 1; /*channel has been described already, skip describe and send setup directly*/ RP_SetupChannel(ch, ch_desc); if (ch_desc->esd_url) free(ch_desc->esd_url); free(ch_desc); return 0; }
void RP_LoadSDP(RTPClient *rtp, char *sdp_text, u32 sdp_len, RTPStream *stream) { GF_Err e; u32 i; GF_SDPInfo *sdp; Bool is_isma_1, has_iod; char *iod_str; GF_X_Attribute *att; is_isma_1 = 0; iod_str = NULL; sdp = gf_sdp_info_new(); e = gf_sdp_info_parse(sdp, sdp_text, sdp_len); if (e == GF_OK) e = RP_SetupSDP(rtp, sdp, stream); /*root SDP, attach service*/ if (! stream) { /*look for IOD*/ if (e==GF_OK) { i=0; while ((att = (GF_X_Attribute*)gf_list_enum(sdp->Attributes, &i))) { if (!iod_str && !strcmp(att->Name, "mpeg4-iod") ) iod_str = att->Value; if (!is_isma_1 && !strcmp(att->Name, "isma-compliance") ) { if (!stricmp(att->Value, "1,1.0,1")) is_isma_1 = 1; } } /*force iod reconstruction with ISMA to use proper clock dependencies*/ if (is_isma_1) iod_str = NULL; /*some folks have weird notions of MPEG-4 systems, they use hardcoded IOD with AAC ESD even when streaming AMR...*/ if (iod_str) { RTPStream *ch; i=0; while ((ch = (RTPStream *)gf_list_enum(rtp->channels, &i))) { if ((ch->depacketizer->payt==GF_RTP_PAYT_AMR) || (ch->depacketizer->payt==GF_RTP_PAYT_AMR_WB) ) { iod_str = NULL; break; } } } if (!iod_str) { RTPStream *ch; Bool needs_iod = 0; i=0; while ((ch = (RTPStream *)gf_list_enum(rtp->channels, &i))) { if ((ch->depacketizer->payt==GF_RTP_PAYT_MPEG4) && (ch->depacketizer->sl_map.StreamType==GF_STREAM_SCENE) // || ((ch->depacketizer->payt==GF_RTP_PAYT_3GPP_DIMS) && (ch->depacketizer->sl_map.StreamType==GF_STREAM_SCENE)) ) { needs_iod = 1; break; } } if (needs_iod) { rtp->session_desc = (GF_Descriptor *)RP_GetChannelOD(ch, 0); } } if (iod_str) e = RP_SDPLoadIOD(rtp, iod_str); } /*attach service*/ has_iod = rtp->session_desc ? 1 : 0; gf_term_on_connect(rtp->service, NULL, e); if (!e && !has_iod && !rtp->media_type) RP_SetupObjects(rtp); rtp->media_type = 0; } /*channel SDP */ else { if (e) { gf_term_on_connect(rtp->service, stream->channel, e); stream->status = RTP_Unavailable; } else { /*connect*/ RP_SetupChannel(stream, NULL); } } /*store SDP for later session migration*/ if (sdp) { char *buf=NULL; gf_sdp_info_write(sdp, &buf); if (buf) { rtp->session_state_data = gf_malloc(sizeof(char) * (strlen("data:application/sdp,") + strlen(buf) + 1) ); strcpy(rtp->session_state_data, "data:application/sdp,"); strcat(rtp->session_state_data, buf); gf_free(buf); } gf_sdp_info_del(sdp); } }