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; } } } }
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); }
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; } }
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"); } } }