Exemplo n.º 1
0
void RP_SaveSessionState(RTPClient *rtp)
{
	GF_Err e;
	char *sdp_buf;
	const char *opt;
	GF_X_Attribute*att;
	u32 i, j;
	GF_SDPInfo *sdp;
	RTSPSession *sess = NULL;

	if (!rtp->session_state_data) return;

	sdp_buf = rtp->session_state_data + strlen("data:application/sdp,");
	sdp = gf_sdp_info_new();
	e = gf_sdp_info_parse(sdp, sdp_buf, (u32) strlen(sdp_buf) );

	for (i=0; i<gf_list_count(rtp->channels); i++) {
		GF_SDPMedia *media = NULL;
		RTPStream *ch = gf_list_get(rtp->channels, i);
		if (!ch->control) continue;

		for (j=0; j<gf_list_count(sdp->media_desc); j++) {
			u32 k;
			GF_SDPMedia *med = (GF_SDPMedia*)gf_list_get(sdp->media_desc, j);

			for (k=0; k<gf_list_count(med->Attributes); k++) {
				att = (GF_X_Attribute*)gf_list_get(med->Attributes, k);
				if (!stricmp(att->Name, "control") && (strstr(att->Value, ch->control)!=NULL) ) {
					media = med;
					break;
				}
			}
			if (media)
				break;
		}
		if (!media) continue;

		if (ch->rtp_ch->net_info.IsUnicast) {
			char szPorts[4096];
			u16 porta, portb;
			media->PortNumber = ch->rtp_ch->net_info.client_port_first;

			/*remove x-server-port extension*/
			for (j=0; j<gf_list_count(media->Attributes); j++) {
				att = (GF_X_Attribute*)gf_list_get(media->Attributes, j);
				if (!stricmp(att->Name, "x-stream-state") ) {
					gf_free(att->Name);
					gf_free(att->Value);
					gf_free(att);
					gf_list_rem(media->Attributes, j);
				}
			}
			ch->current_start += gf_rtp_get_current_time(ch->rtp_ch);

			GF_SAFEALLOC(att, GF_X_Attribute);
			att->Name = gf_strdup("x-stream-state");
			porta = ch->rtp_ch->net_info.port_first ? ch->rtp_ch->net_info.port_first : ch->rtp_ch->net_info.client_port_first;
			portb = ch->rtp_ch->net_info.port_last ? ch->rtp_ch->net_info.port_last : ch->rtp_ch->net_info.client_port_last;

			sprintf(szPorts, "server-port=%d-%d;ssrc=%X;npt=%g;seq=%d;rtptime=%d",
				porta,
				portb,
				ch->rtp_ch->SenderSSRC,
				ch->current_start,
				ch->rtp_ch->rtp_first_SN,
				ch->rtp_ch->rtp_time
			);
			att->Value = gf_strdup(szPorts);
			gf_list_add(media->Attributes, att);

			if (ch->rtsp)
				sess = ch->rtsp;
		} else {
			media->PortNumber = ch->rtp_ch->net_info.port_first;
		}

	}
	/*remove x-server-port/x-session-id extension*/
	for (j=0; j<gf_list_count(sdp->Attributes); j++) {
		att = (GF_X_Attribute*)gf_list_get(sdp->Attributes, j);
		if (!stricmp(att->Name, "x-session-id") || !stricmp(att->Name, "x-session-name")
		) {
			gf_free(att->Name);
			gf_free(att->Value);
			gf_free(att);
			gf_list_rem(sdp->Attributes, j);
		}
	}
	if (sess) {
		char szURL[4096];

		if (sess->session_id) {
			GF_SAFEALLOC(att, GF_X_Attribute);
			att->Name = gf_strdup("x-session-id");
			att->Value = gf_strdup(sess->session_id);
			gf_list_add(sdp->Attributes, att);
		}

		GF_SAFEALLOC(att, GF_X_Attribute);
		att->Name = gf_strdup("x-session-name");
		sprintf(szURL, "rtsp://%s:%d/%s", sess->session->Server, sess->session->Port, sess->session->Service);
		att->Value = gf_strdup(szURL);
		gf_list_add(sdp->Attributes, att);
	}

	gf_free(rtp->session_state_data);
	sdp_buf = NULL;
	gf_sdp_info_write(sdp, &sdp_buf);
	if (sdp_buf) {
		rtp->session_state_data = gf_malloc(sizeof(char) * (strlen("data:application/sdp,") + strlen(sdp_buf) + 1) );
		strcpy(rtp->session_state_data, "data:application/sdp,");
		strcat(rtp->session_state_data, sdp_buf);
		gf_free(sdp_buf);
	}


	gf_sdp_info_del(sdp);


	opt = (char *) gf_modules_get_option((GF_BaseInterface *) gf_term_get_service_interface(rtp->service), "Streaming", "SessionMigrationServer");
	if (opt) {
		if (rtp->dnload) gf_term_download_del(rtp->dnload);
		rtp->dnload = NULL;

		if (strnicmp(opt, "http://", 7)) {
			rtp->dnload = gf_term_download_new(rtp->service, opt, GF_NETIO_SESSION_NOT_THREADED, MigrateSDP_NetIO, rtp);
			while (1) {
				char buffer[100];
				u32 read;
				e = gf_dm_sess_fetch_data(rtp->dnload, buffer, 100, &read);
				if (e && (e!=GF_IP_NETWORK_EMPTY)) break;
			}
			gf_term_download_del(rtp->dnload);
			rtp->dnload = NULL;
		} else {
			FILE *f = gf_f64_open(opt, "wt");
			if (f) {
				sdp_buf = rtp->session_state_data + strlen("data:application/sdp,");
				gf_fwrite(sdp_buf, 1, strlen(sdp_buf), f);
				fclose(f);
			} else {
				e = GF_IO_ERR;
			}
		}
		if (e<0) {
			gf_term_on_message(sess->owner->service, e, "Error saving session state");
		}
	}
}
Exemplo n.º 2
0
void RP_ProcessRTP(RTPStream *ch, char *pck, u32 size)
{
	GF_NetworkCommand com;
	GF_Err e;
	GF_RTPHeader hdr;
	u32 PayloadStart;
	ch->rtp_bytes += size;

	/*first decode RTP*/
	e = gf_rtp_decode_rtp(ch->rtp_ch, pck, size, &hdr, &PayloadStart);

	/*corrupted or NULL data*/
	if (e || (PayloadStart >= size)) {
		//gf_term_on_sl_packet(ch->owner->service, ch->channel, NULL, 0, NULL, GF_CORRUPTED_DATA);
		return;
	}

	/*if we must notify some timing, do it now. If the channel has no range, this should NEVER be called*/
	if (ch->check_rtp_time /*&& gf_rtp_is_active(ch->rtp_ch)*/) {
		Double ch_time;

		/*it may happen that we still receive packets from a previous "play" request. If this is the case,
		filter until we reach the indicated rtptime*/
		if (ch->rtp_ch->rtp_time
		        && (ch->rtp_ch->rtp_first_SN > hdr.SequenceNumber)
		        && (ch->rtp_ch->rtp_time < hdr.TimeStamp)
		   ) {
			GF_LOG(GF_LOG_WARNING, GF_LOG_RTP, ("[RTP] Rejecting too early packet (TS %d vs signaled rtp time %d - diff %d ms)\n",
			                                    hdr.TimeStamp, ch->rtp_ch->rtp_time, ((hdr.TimeStamp - ch->rtp_ch->rtp_time)*1000) / ch->rtp_ch->TimeScale));
			return;
		}

		ch_time = gf_rtp_get_current_time(ch->rtp_ch);

		/*this is the first packet on the channel (no PAUSE)*/
		if (ch->check_rtp_time == RTP_SET_TIME_RTP) {
			/*Note: in a SEEK with RTSP, the rtp-info time given by the server is
			the rtp time of the desired range. But the server may (and should) send from
			the previous I frame on video, so the time of the first rtp packet after
			a SEEK can actually be less than CurrentStart. We don't drop these
			packets in order to see the maximum video. We could drop it, this would mean
			wait for next RAP...*/

			memset(&com, 0, sizeof(com));
			com.command_type = GF_NET_CHAN_MAP_TIME;
			com.base.on_channel = ch->channel;
			if (ch->rtsp) {
				com.map_time.media_time = ch->current_start + ch_time;
			} else {
				com.map_time.media_time = 0;
			}

			com.map_time.timestamp = hdr.TimeStamp;
			com.map_time.reset_buffers = 0;
			gf_term_on_command(ch->owner->service, &com, GF_OK);

			GF_LOG(GF_LOG_INFO, GF_LOG_RTP, ("[RTP] Mapping RTP Time seq %d TS %d Media Time %g - rtp info seq %d TS %d\n",
			                                 hdr.SequenceNumber, hdr.TimeStamp, com.map_time.media_time, ch->rtp_ch->rtp_first_SN, ch->rtp_ch->rtp_time
			                                ));

			/*skip RTCP clock init when RTSP is used*/
			if (ch->rtsp) ch->rtcp_init = 1;

//			if (ch->depacketizer->payt==GF_RTP_PAYT_H264_AVC) ch->depacketizer->flags |= GF_RTP_AVC_WAIT_RAP;
		}
		/*this is RESUME on channel, filter packet based on time (darwin seems to send
		couple of packet before)
		do not fetch if we're below 10 ms or <0, because this means we already have
		this packet - as the PAUSE is issued with the RTP currentTime*/
		else if (ch_time <= 0.021) {
			return;
		}
		ch->check_rtp_time = RTP_SET_TIME_NONE;
	}

	gf_rtp_depacketizer_process(ch->depacketizer, &hdr, pck + PayloadStart, size - PayloadStart);

	/*last check: signal EOS if we're close to end range in case the server do not send RTCP BYE*/
	if ((ch->flags & RTP_HAS_RANGE) && !(ch->flags & RTP_EOS) ) {
		/*also check last CTS*/
		Double ts = (Double) ((u32) ch->depacketizer->sl_hdr.compositionTimeStamp - hdr.TimeStamp);
		ts /= gf_rtp_get_clockrate(ch->rtp_ch);
		if (ABSDIFF(ch->range_end, (ts + ch->current_start + gf_rtp_get_current_time(ch->rtp_ch)) ) < 0.2) {
			ch->flags |= RTP_EOS;
			ch->stat_stop_time = gf_sys_clock();
			gf_term_on_sl_packet(ch->owner->service, ch->channel, NULL, 0, NULL, GF_EOS);
		}
	}
}