📄 rtp_signaling.c
字号:
/* * GPAC - Multimedia Framework C SDK * * Copyright (c) Jean Le Feuvre 2000-2005 * All rights reserved * * This file is part of GPAC / RTP input module * * GPAC is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * GPAC is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * */#include "rtp_in.h"Bool channel_is_valid(RTPClient *rtp, RTPStream *ch){ u32 i=0; RTPStream *st; while ((st = (RTPStream *)gf_list_enum(rtp->channels, &i))) { if (st == ch) return 1; } return 0;}void RP_StopChannel(RTPStream *ch){ if (!ch || !ch->rtsp) return; ch->flags &= ~RTP_SKIP_NEXT_COM; ch->status = RTP_Disconnected; //remove interleaved if (gf_rtp_is_interleaved(ch->rtp_ch)) { gf_rtsp_unregister_interleave(ch->rtsp->session, gf_rtp_get_low_interleave_id(ch->rtp_ch)); }}/*this prevent sending teardown on session with running channels*/Bool RP_SessionActive(RTPStream *ch){ RTPStream *ach; u32 i, count; i = count = 0; while ((ach = (RTPStream *)gf_list_enum(ch->owner->channels, &i))) { if (ach->rtsp != ch->rtsp) continue; /*count only active channels*/ if (ach->status == RTP_Running) count++; } return count ? 1 : 0;}static void RP_QueueCommand(RTSPSession *sess, RTPStream *ch, GF_RTSPCommand *com, Bool needs_sess_id){ if (needs_sess_id) { switch (sess->owner->stream_control_type) { case RTSP_CONTROL_INDEPENDENT: if (!ch) com->Session = sess->session_id; else com->Session = ch->session_id; break; default: com->Session = sess->session_id; break; } } if (gf_mx_try_lock(sess->owner->mx)) { gf_list_add(sess->rtsp_commands, com); gf_mx_v(sess->owner->mx); } else { gf_list_add(sess->rtsp_commands, com); }}/* channel setup functions */void RP_Setup(RTPStream *ch){ GF_RTSPCommand *com; GF_RTSPTransport *trans; com = gf_rtsp_command_new(); com->method = strdup(GF_RTSP_SETUP); //setup ports if unicast non interleaved if (gf_rtp_is_unicast(ch->rtp_ch) && (ch->owner->transport_mode != 1) && !gf_rtp_is_interleaved(ch->rtp_ch) ) { u16 def_first_port = 0; const char *opt = gf_modules_get_option((GF_BaseInterface *) gf_term_get_service_interface(ch->owner->service), "Streaming", "ForceFirstPort"); if (opt) def_first_port = atoi(opt); gf_rtp_set_ports(ch->rtp_ch, def_first_port); } trans = gf_rtsp_transport_clone(gf_rtp_get_transport(ch->rtp_ch)); /*override transport*/ if (ch->rtsp->flags & RTSP_FORCE_INTER) { if (trans->Profile) free(trans->Profile); trans->Profile = strdup(GF_RTSP_PROFILE_RTP_AVP_TCP); gf_rtp_setup_transport(ch->rtp_ch, trans, NULL); } if (trans->source) { free(trans->source); trans->source = NULL; } /*some servers get confused when trying to resetup on the same remote ports, so reset info*/ trans->port_first = trans->port_last = 0; trans->SSRC = 0; /*turn off interleaving in case of re-setup, some servers don't like it (we still signal it through RTP/AVP/TCP profile so it's OK)*/ trans->IsInterleaved = 0; gf_list_add(com->Transports, trans); if (strlen(ch->control)) com->ControlString = strdup(ch->control); com->user_data = ch; ch->status = RTP_WaitingForAck; RP_QueueCommand(ch->rtsp, ch, com, 1);}/*filter setup if no session (rtp only)*/GF_Err RP_SetupChannel(RTPStream *ch, ChannelDescribe *ch_desc){ GF_Err resp; /*assign ES_ID of the channel*/ if (ch_desc && !ch->ES_ID && ch_desc->ES_ID) ch->ES_ID = ch_desc->ES_ID; ch->status = RTP_Setup; /*assign channel handle if not done*/ if (ch_desc && ch->channel) { assert(ch->channel == ch_desc->channel); } else if (!ch->channel) { assert(ch_desc); assert(ch_desc->channel); ch->channel = ch_desc->channel; } /*no session , setup for pure rtp*/ if (!ch->rtsp) { ch->flags |= RTP_CONNECTED; /*init rtp*/ resp = RP_InitStream(ch, 0), /*send confirmation to user*/ RP_ConfirmChannelConnect(ch, resp); } else { RP_Setup(ch); } return GF_OK;}void RP_ProcessSetup(RTSPSession *sess, GF_RTSPCommand *com, GF_Err e){ RTPStream *ch; u32 i; GF_RTSPTransport *trans; ch = (RTPStream *)com->user_data; if (e) goto exit; switch (sess->rtsp_rsp->ResponseCode) { case NC_RTSP_OK: break; case NC_RTSP_Not_Found: e = GF_STREAM_NOT_FOUND; goto exit; default: e = GF_SERVICE_ERROR; goto exit; } e = GF_SERVICE_ERROR; if (!ch) goto exit; /*assign session ID*/ switch (sess->owner->stream_control_type) { case RTSP_CONTROL_INDEPENDENT: if (!sess->rtsp_rsp->Session) { e = GF_SERVICE_ERROR; goto exit; } if (!ch->session_id) ch->session_id = strdup(sess->rtsp_rsp->Session); assert(!sess->session_id); break; default: if (!sess->rtsp_rsp->Session) { e = GF_SERVICE_ERROR; goto exit; } if (!sess->session_id) sess->session_id = strdup(sess->rtsp_rsp->Session); assert(!ch->session_id); break; } /*transport setup: break at the first correct transport */ i=0; while ((trans = (GF_RTSPTransport *)gf_list_enum(sess->rtsp_rsp->Transports, &i))) { /*copy over previous ports (hack for some servers overriding client ports)*/ const char *opt = gf_modules_get_option((GF_BaseInterface *) gf_term_get_service_interface(ch->owner->service), "Streaming", "ForceClientPorts"); if (opt && !stricmp(opt, "yes")) gf_rtp_get_ports(ch->rtp_ch, &trans->client_port_first, &trans->client_port_last); e = gf_rtp_setup_transport(ch->rtp_ch, trans, gf_rtsp_get_server_name(sess->session)); if (!e) break; } if (e) goto exit; e = RP_InitStream(ch, 0); if (e) goto exit; ch->status = RTP_Connected; //in case this is TCP channel, setup callbacks ch->flags &= ~RTP_INTERLEAVED; if (gf_rtp_is_interleaved(ch->rtp_ch)) { ch->flags |= RTP_INTERLEAVED; gf_rtsp_set_interleave_callback(sess->session, RP_DataOnTCP); }exit: /*confirm only on first connect, otherwise this is a re-SETUP of the rtsp session, not the channel*/ if (! (ch->flags & RTP_CONNECTED) ) { ch->flags |= RTP_CONNECTED; RP_ConfirmChannelConnect(ch, e); } com->user_data = NULL;}/* session/channel describe functions *//*filter describe commands in case of ESD URLs*/Bool RP_PreprocessDescribe(RTSPSession *sess, GF_RTSPCommand *com){ RTPStream *ch; ChannelDescribe *ch_desc; /*not a channel describe*/ if (!com->user_data) { gf_term_on_message(sess->owner->service, GF_OK, "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;}/*process describe reply*/GF_Err RP_ProcessDescribe(RTSPSession *sess, GF_RTSPCommand *com, GF_Err e){ RTPStream *ch; ChannelDescribe *ch_desc; ch = NULL; ch_desc = (ChannelDescribe *)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 ? GF_STREAM_NOT_FOUND : GF_URL_ERROR; goto exit; case NC_RTSP_Not_Found: e = GF_URL_ERROR; goto exit; case NC_RTSP_OK: break; default: //we should have a basic error code mapping here e = GF_SERVICE_ERROR; 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 { gf_term_on_message(sess->owner->service, GF_OK, "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 = GF_STREAM_NOT_FOUND; goto exit; } e = RP_SetupChannel(ch, ch_desc);exit: com->user_data = NULL; if (e) { if (!ch_desc) { return e; } else if (ch) { RP_ConfirmChannelConnect(ch, e); } else { gf_term_on_connect(sess->owner->service, ch_desc->channel, e); } } if (ch_desc) free(ch_desc); return GF_OK;}/*send describe*/void RP_Describe(RTSPSession *sess, char *esd_url, LPNETCHANNEL channel){ const char *opt; RTPStream *ch; ChannelDescribe *ch_desc; GF_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 = (ChannelDescribe *)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 = gf_rtsp_command_new(); com->method = strdup(GF_RTSP_DESCRIBE); if (channel || esd_url) { com->Accept = strdup("application/sdp"); com->ControlString = esd_url ? strdup(esd_url) : NULL; ch_desc = (ChannelDescribe *)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"); } /*need better tuning ...*/ opt = (char *) gf_modules_get_option((GF_BaseInterface *) gf_term_get_service_interface(sess->owner->service), "Network", "Bandwidth"); if (opt && !stricmp(opt, "yes")) com->Bandwidth = atoi(opt); RP_QueueCommand(sess, NULL, com, 0);}/* channel control functions *//*remove command if session is using aggregated control*/Bool RP_PreprocessUserCom(RTSPSession *sess, GF_RTSPCommand *com){ ChannelControl *ch_ctrl; RTPStream *ch; GF_Err e; Bool skip_it; ch_ctrl = NULL; if (strcmp(com->method, GF_RTSP_TEARDOWN)) ch_ctrl = (ChannelControl *)com->user_data; if (!ch_ctrl) return 1; ch = ch_ctrl->ch; if (!channel_is_valid(sess->owner, ch)) { free(ch_ctrl); com->user_data = NULL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -