Beispiel #1
0
void RP_ReadStream(RTPStream *ch)
{
	u32 size, tot_size;

	if (!ch->rtp_ch) return;

	/*NOTE: A weird bug on windows wrt to select(): if both RTP and RTCP are in the same loop
	there is a hudge packet drop on RTP. We therefore split RTP and RTCP reading, this is not a big
	deal as the RTCP traffic is far less than RTP, and we should never have more than one RTCP
	packet reading per RTP reading loop
	NOTE2: a better implementation would be to use select() to get woken up...
	*/
	tot_size = 0;

	while (1) {
		size = gf_rtp_read_rtcp(ch->rtp_ch, ch->buffer, RTP_BUFFER_SIZE);
		if (!size) break;
		tot_size += size;
		RP_ProcessRTCP(ch, ch->buffer, size);
	}

	while (1) {
		size = gf_rtp_read_rtp(ch->rtp_ch, ch->buffer, RTP_BUFFER_SIZE);
		if (!size) break;
		tot_size += size;
		RP_ProcessRTP(ch, ch->buffer, size);
	}
	/*and send the report*/
	if (ch->flags & RTP_ENABLE_RTCP) gf_rtp_send_rtcp_report(ch->rtp_ch, SendTCPData, ch);

	if (tot_size) ch->owner->udp_time_out = 0;

	/*detect timeout*/
	if (ch->owner->udp_time_out) {
		if (!ch->last_udp_time) {
			ch->last_udp_time = gf_sys_clock();
		} else if (ch->rtp_ch->net_info.IsUnicast && !(ch->flags & RTP_MOBILEIP) ) {
			u32 diff = gf_sys_clock() - ch->last_udp_time;
			if (diff >= ch->owner->udp_time_out) {
				char szMessage[1024];
				GF_LOG(GF_LOG_WARNING, GF_LOG_RTP, ("[RTP] UDP Timeout after %d ms\n", diff));
				sprintf(szMessage, "No data received in %d ms", diff);
				gf_term_on_message(ch->owner->service, GF_IP_UDP_TIMEOUT, szMessage);
				ch->status = RTP_Unavailable;
			}
		}
	}
}
Beispiel #2
0
void RP_SendFailure(RTSPSession *sess, GF_RTSPCommand *com, GF_Err e)
{
	char sMsg[1000];
	sprintf(sMsg, "Cannot send %s", com->method);
	gf_term_on_message(sess->owner->service, e, sMsg);
}
Beispiel #3
0
GF_EXPORT
void gf_term_download_update_stats(GF_DownloadSession * sess)
{
	GF_ClientService *serv;
	const char *szURI;
	u32 total_size, bytes_done, net_status, bytes_per_sec;

	if (!sess) return;

	gf_dm_sess_get_stats(sess, NULL, &szURI, &total_size, &bytes_done, &bytes_per_sec, &net_status);
	serv = (GF_ClientService *)gf_dm_sess_get_private(sess);
	switch (net_status) {
	case GF_NETIO_SETUP:
		gf_term_on_message(serv, GF_OK, "Connecting");
		break;
	case GF_NETIO_CONNECTED:
		gf_term_on_message(serv, GF_OK, "Connected");
		break;
	case GF_NETIO_WAIT_FOR_REPLY:
		gf_term_on_message(serv, GF_OK, "Waiting for reply...");
		break;
	case GF_NETIO_PARSE_REPLY:
		gf_term_on_message(serv, GF_OK, "Starting download...");
		break;
	case GF_NETIO_DATA_EXCHANGE:
		/*notify some connection / ...*/
		if (total_size) {
			GF_Event evt;
			evt.type = GF_EVENT_PROGRESS;
			evt.progress.progress_type = 1;
			evt.progress.service = szURI;
			evt.progress.total = total_size;
			evt.progress.done = bytes_done;
			evt.progress.bytes_per_seconds = bytes_per_sec;
			gf_term_send_event(serv->term, &evt);
		}
		GF_LOG(GF_LOG_DEBUG, GF_LOG_NETWORK, ("[HTTP] %s received %d / %d\n", szURI, bytes_done, total_size));
		gf_term_service_media_event_with_download(serv->owner, GF_EVENT_MEDIA_PROGRESS, bytes_done, total_size, bytes_per_sec);

		/*JLF fix this*/
		if (0&& (serv->download_rebuffer || serv->auto_rebuffer) && serv->owner && !(serv->owner->flags & GF_ODM_DESTROYED) && serv->owner->duration) {
			GF_Clock *ck = gf_odm_get_media_clock(serv->owner);
			Double download_percent, playback_percent, adj_percent;
			download_percent = 100 * bytes_done;
			download_percent /= total_size;

			playback_percent = 100 * serv->owner->current_time;
			playback_percent /= serv->owner->duration;
			if (serv->auto_rebuffer)
				adj_percent = 0.0;
			else
				adj_percent = 100.0 * serv->download_rebuffer / serv->owner->duration;

			if (playback_percent >= download_percent) {
				if (gf_clock_is_started(ck)) {
					GF_LOG(GF_LOG_INFO, GF_LOG_NETWORK, ("[HTTP Resource] Played %d %% but downloaded %d %% - Pausing\n", (u32) playback_percent, (u32) download_percent));
					if (!serv->is_paused) {
						serv->is_paused = 1;
						mediacontrol_pause(serv->owner);
					}
					gf_term_service_media_event(serv->owner, GF_EVENT_MEDIA_WAITING);
					gf_term_on_message(serv, GF_OK, "HTTP Buffering ...");
				}
			} else if (playback_percent + adj_percent <= download_percent) {
				Double time_to_play = 0;
				Double time_to_download = 0;
				/*automatic rebuffer: make sure we can finish playback before resuming*/
				if (serv->auto_rebuffer) {
					if (bytes_per_sec) {
						time_to_download = 1000.0*(total_size - bytes_done);
						time_to_download /= bytes_per_sec;
					}
					time_to_play = (Double) serv->owner->duration;
					time_to_play -= serv->owner->current_time;
				}
				if ((time_to_download<=time_to_play) && !gf_clock_is_started(ck)) {
					GF_LOG(GF_LOG_INFO, GF_LOG_NETWORK, ("[HTTP Resource] Played %d %% and downloaded %d %% - Resuming\n", (u32) playback_percent, (u32) download_percent));
					if (serv->auto_rebuffer) {
						GF_LOG(GF_LOG_INFO, GF_LOG_NETWORK, ("[HTTP Resource] Auto-rebuffer done: should be done downloading in %d ms and remains %d ms to play\n", (u32) time_to_download, (u32) (serv->owner->duration - serv->owner->current_time) ));
					}
					gf_term_service_media_event(serv->owner, GF_EVENT_MEDIA_PLAYING);
					if (serv->is_paused) {
						serv->is_paused = 0;
						mediacontrol_resume(serv->owner);
					}
					gf_term_on_message(serv, GF_OK, "HTTP Resuming playback");
				}
			}
		}
		break;
	case GF_NETIO_DATA_TRANSFERED:
		gf_term_service_media_event(serv->owner, GF_EVENT_MEDIA_LOAD_DONE);
		if (serv->owner && !(serv->owner->flags & GF_ODM_DESTROYED) && serv->owner->duration) {
			GF_Clock *ck = gf_odm_get_media_clock(serv->owner);
			if (!gf_clock_is_started(ck)) {
				GF_LOG(GF_LOG_INFO, GF_LOG_NETWORK, ("[HTTP Resource] Done retrieving file - resuming playback\n"));
				if (serv->is_paused) {
					serv->is_paused = 0;
					mediacontrol_resume(serv->owner);
				}
			}
		}
		break;
	}
}
Beispiel #4
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");
		}
	}
}