📄 rtp_signaling.c
字号:
return 0; } assert(ch->rtsp == sess); assert(ch->channel==ch_ctrl->com.base.on_channel); if (sess->owner->stream_control_type == RTSP_CONTROL_INDEPENDENT) { /*re-SETUP failed*/ if (!ch->session_id) { e = GF_SERVICE_ERROR; goto err_exit; } com->Session = ch->session_id; return 1; } skip_it = 0; if (!com->Session) { /*re-SETUP failed*/ if (!strcmp(com->method, GF_RTSP_PLAY) || !strcmp(com->method, GF_RTSP_PAUSE)) { e = GF_SERVICE_ERROR; goto err_exit; } /*this is a stop, no need for SessionID just skip*/ skip_it = 1; } /*check if aggregation discards this command*/ if (skip_it || ( (sess->flags & RTSP_AGG_CONTROL) && (ch->flags & RTP_SKIP_NEXT_COM) )) { ch->flags &= ~RTP_SKIP_NEXT_COM; gf_term_on_command(sess->owner->service, &ch_ctrl->com, GF_OK); free(ch_ctrl); com->user_data = NULL; return 0; } return 1;err_exit: gf_rtsp_reset_aggregation(ch->rtsp->session); ch->status = RTP_Disconnected; ch->check_rtp_time = 0; gf_term_on_command(sess->owner->service, &ch_ctrl->com, e); free(ch_ctrl); com->user_data = NULL; return 0;}static void SkipCommandOnSession(RTPStream *ch){ u32 i; RTPStream *a_ch; if (!ch || (ch->flags & RTP_SKIP_NEXT_COM) || !(ch->rtsp->flags & RTSP_AGG_CONTROL) ) return; i=0; while ((a_ch = (RTPStream *)gf_list_enum(ch->owner->channels, &i))) { if ((ch == a_ch) || (a_ch->rtsp != ch->rtsp) ) continue; a_ch->flags |= RTP_SKIP_NEXT_COM; }}void RP_ProcessUserCommand(RTSPSession *sess, GF_RTSPCommand *com, GF_Err e){ ChannelControl *ch_ctrl; RTPStream *ch, *agg_ch; u32 i, count; GF_RTPInfo *info; ch_ctrl = (ChannelControl *)com->user_data; ch = ch_ctrl->ch; if (!channel_is_valid(sess->owner, ch)) { free(ch_ctrl); com->user_data = NULL; return; } assert(ch->channel==ch_ctrl->com.base.on_channel); /*some consistency checking: on interleaved sessions, some servers do NOT reply to the teardown. If our command is STOP just skip the error notif*/ if (e) { if (!strcmp(com->method, GF_RTSP_TEARDOWN)) { goto process_reply; } else { goto err_exit; } } switch (sess->rtsp_rsp->ResponseCode) { //handle all 3xx codes (redirections) case NC_RTSP_Method_Not_Allowed: e = GF_NOT_SUPPORTED; goto err_exit; case NC_RTSP_OK: break; default: //we should have a basic error code mapping here e = GF_SERVICE_ERROR; goto err_exit; }process_reply: gf_term_on_command(sess->owner->service, &ch_ctrl->com, GF_OK); if ( (ch_ctrl->com.command_type==GF_NET_CHAN_PLAY) || (ch_ctrl->com.command_type==GF_NET_CHAN_SET_SPEED) || (ch_ctrl->com.command_type==GF_NET_CHAN_RESUME) ) { //auto-detect any aggregated control if not done yet if (gf_list_count(sess->rtsp_rsp->RTP_Infos) > 1) { sess->flags |= RTSP_AGG_CONTROL; } //process all RTP infos count = gf_list_count(sess->rtsp_rsp->RTP_Infos); for (i=0;i<count; i++) { info = (GF_RTPInfo*)gf_list_get(sess->rtsp_rsp->RTP_Infos, i); agg_ch = RP_FindChannel(sess->owner, NULL, 0, info->url, 0); if (!agg_ch || (agg_ch->rtsp != sess) ) continue; /*channel is already playing*/ if (agg_ch->status == RTP_Running) { // gf_rtp_set_info_rtp(agg_ch->rtp_ch, info->seq, info->rtp_time, info->ssrc); // agg_ch->check_rtp_time = 1; continue; } /*if play/seeking we must send update RTP/NPT link*/ if (ch_ctrl->com.command_type != GF_NET_CHAN_RESUME) { agg_ch->check_rtp_time = 1; } /*this is used to discard RTP packets re-sent on resume*/ else { agg_ch->check_rtp_time = 2; } /* reset the buffers */ RP_InitStream(agg_ch, 1); gf_rtp_set_info_rtp(agg_ch->rtp_ch, info->seq, info->rtp_time, info->ssrc); agg_ch->status = RTP_Running; /*skip next play command on this channel if aggregated control*/ if (ch!=agg_ch && (ch->rtsp->flags & RTSP_AGG_CONTROL) ) agg_ch->flags |= RTP_SKIP_NEXT_COM; if (gf_rtp_is_interleaved(agg_ch->rtp_ch)) { gf_rtsp_register_interleave(sess->session, agg_ch, gf_rtp_get_low_interleave_id(agg_ch->rtp_ch), gf_rtp_get_hight_interleave_id(agg_ch->rtp_ch)); } } /*no rtp info (just in case), no time mapped - set to 0 and specify we're not interactive*/ if (!i) { ch->current_start = 0.0; ch->check_rtp_time = 1; RP_InitStream(ch, 1); ch->status = RTP_Running; if (gf_rtp_is_interleaved(ch->rtp_ch)) { gf_rtsp_register_interleave(sess->session, ch, gf_rtp_get_low_interleave_id(ch->rtp_ch), gf_rtp_get_hight_interleave_id(ch->rtp_ch)); } } ch->flags &= ~RTP_SKIP_NEXT_COM; } else if (ch_ctrl->com.command_type == GF_NET_CHAN_PAUSE) { SkipCommandOnSession(ch); ch->flags &= ~RTP_SKIP_NEXT_COM; } else if (ch_ctrl->com.command_type == GF_NET_CHAN_STOP) { assert(0); } free(ch_ctrl); com->user_data = NULL; return;err_exit: ch->status = RTP_Disconnected; gf_term_on_command(sess->owner->service, &ch_ctrl->com, e); gf_rtsp_reset_aggregation(ch->rtsp->session); ch->check_rtp_time = 0; free(ch_ctrl); com->user_data = NULL;}static void RP_FlushAndTearDown(RTSPSession *sess){ GF_RTSPCommand *com; gf_mx_p(sess->owner->mx); while (gf_list_count(sess->rtsp_commands)) { com = (GF_RTSPCommand *)gf_list_get(sess->rtsp_commands, 0); gf_list_rem(sess->rtsp_commands, 0); gf_rtsp_command_del(com); } if (sess->flags & RTSP_WAIT_REPLY) { GF_Err e; while (1) { e = gf_rtsp_get_response(sess->session, sess->rtsp_rsp); if (e!= GF_IP_NETWORK_EMPTY) break; } sess->flags &= ~RTSP_WAIT_REPLY; } gf_mx_v(sess->owner->mx); /*no private stack on teardown - shutdown now*/ com = gf_rtsp_command_new(); com->method = strdup(GF_RTSP_TEARDOWN); RP_QueueCommand(sess, NULL, com, 1);}void RP_UserCommand(RTSPSession *sess, RTPStream *ch, GF_NetworkCommand *command){ RTPStream *a_ch; ChannelControl *ch_ctrl; u32 i; GF_RTSPCommand *com; GF_RTSPRange *range; assert(ch->rtsp==sess); /*we may need to re-setup stream/session*/ if ( (command->command_type==GF_NET_CHAN_PLAY) || (command->command_type==GF_NET_CHAN_RESUME) || (command->command_type==GF_NET_CHAN_PAUSE)) { if (ch->status == RTP_Disconnected) { if ( (sess->owner->stream_control_type==RTSP_CONTROL_AGGREGATE) && (sess->flags & RTSP_AGG_CONTROL)) { i=0; while ((a_ch = (RTPStream *)gf_list_enum(sess->owner->channels, &i))) { if (a_ch->rtsp != sess) continue; if (a_ch->status == RTP_Disconnected) RP_Setup(a_ch); } } else { RP_Setup(ch); } } } com = gf_rtsp_command_new(); range = NULL; if ( (command->command_type==GF_NET_CHAN_PLAY) || (command->command_type==GF_NET_CHAN_RESUME) ) { range = gf_rtsp_range_new(); range->start = ch->range_start; range->end = ch->range_end; com->method = strdup(GF_RTSP_PLAY); /*specify pause range on resume - this is not mandatory but most servers need it*/ if (command->command_type==GF_NET_CHAN_RESUME) { range->start = ch->current_start; ch->stat_start_time -= ch->stat_stop_time; ch->stat_start_time += gf_sys_clock(); ch->stat_stop_time = 0; } else { range->start = ch->range_start; if (command->play.start_range>=0) range->start += command->play.start_range; range->end = ch->range_start; if (command->play.end_range >=0) { range->end += command->play.end_range; if (range->end > ch->range_end) range->end = ch->range_end; } ch->stat_start_time = gf_sys_clock(); ch->stat_stop_time = 0; } /*if aggregated the command is sent once, so store info at session level*/ if (ch->flags & RTP_SKIP_NEXT_COM) { ch->current_start = ch->rtsp->last_range; } else { ch->rtsp->last_range = range->start; ch->current_start = range->start; } /*some RTSP servers don't accept Range=npt:0.0- (for ex, broadcast only...), so skip it if: - a range was given in initial describe - the command is not a RESUME */ if (!(ch->flags & RTP_HAS_RANGE) && (command->command_type != GF_NET_CHAN_RESUME) ) { gf_rtsp_range_del(range); com->Range = NULL; } else { com->Range = range; } if (!(sess->flags & RTSP_AGG_CONTROL) && strlen(ch->control)) com->ControlString = strdup(ch->control); if (RP_SessionActive(ch)) { if (!com->ControlString && ch->control) com->ControlString = strdup(ch->control); } else { if ((sess->owner->stream_control_type!=RTSP_CONTROL_INDEPENDENT) && com->ControlString) { free(com->ControlString); com->ControlString=NULL; } } } else if (command->command_type==GF_NET_CHAN_PAUSE) { range = gf_rtsp_range_new(); range->start = ch->range_start; range->end = ch->range_end; com->method = strdup(GF_RTSP_PAUSE); /*update current time*/ ch->current_start += gf_rtp_get_current_time(ch->rtp_ch); range->start = ch->current_start; range->end = -1.0; com->Range = range; ch->stat_stop_time = gf_sys_clock(); } //nb: we could actually send a PAUSE in order to keep the session alive //but let's be nice to the server else if (command->command_type==GF_NET_CHAN_STOP) { ch->current_start = 0; ch->stat_stop_time = gf_sys_clock(); RP_StopChannel(ch); if (com) gf_rtsp_command_del(com); /*use stream-control*/ switch (ch->owner->stream_control_type) { case RTSP_CONTROL_AGGREGATE: /*last stream running*/ //if (!RP_SessionActive(ch)) RP_FlushAndTearDown(sess); break; /*FIXME - according to trhe current draft, the stream's session must be paused before ...*/ case RTSP_CONTROL_RTSP_V2: case RTSP_CONTROL_INDEPENDENT: default: RP_Teardown(sess, ch); break; } return; } else { gf_term_on_command(sess->owner->service, command, GF_NOT_SUPPORTED); gf_rtsp_command_del(com); return; } ch_ctrl = (ChannelControl *)malloc(sizeof(ChannelControl)); ch_ctrl->ch = ch; memcpy(&ch_ctrl->com, command, sizeof(GF_NetworkCommand)); com->user_data = ch_ctrl; RP_QueueCommand(sess, ch, com, 1); return;}/* session/channel teardown functions */void RP_ProcessTeardown(RTSPSession *sess, GF_RTSPCommand *com, GF_Err e){ RTPStream *ch = (RTPStream *)com->user_data; if (ch) { if (ch->session_id) free(ch->session_id); ch->session_id = NULL; } else { if (sess->session_id) free(sess->session_id); sess->session_id = NULL; }}void RP_Teardown(RTSPSession *sess, RTPStream *ch){ GF_RTSPCommand *com; switch (sess->owner->stream_control_type) { case RTSP_CONTROL_AGGREGATE: /*we need a session id*/ if (!sess->session_id) return; /*ignore teardown on channels*/ if ((sess->flags & RTSP_AGG_CONTROL) && ch) return; break; case RTSP_CONTROL_RTSP_V2: /*we need a session id*/ if (!sess->session_id) return; /*do not ignore teardown on channels*/ break; case RTSP_CONTROL_INDEPENDENT: /*todo*/ break; } com = gf_rtsp_command_new(); com->method = strdup(GF_RTSP_TEARDOWN); if (ch && ch->control && (sess->owner->stream_control_type == RTSP_CONTROL_RTSP_V2)) { com->ControlString = strdup(ch->control); com->user_data = ch; } RP_QueueCommand(sess, ch, com, 1);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -