⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rtp_signaling.c

📁 一个用于智能手机的多媒体库适合S60 WinCE的跨平台开发库
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *			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 + -