static void term_on_command(void *user_priv, GF_ClientService *service, GF_NetworkCommand *com, GF_Err response) { GF_Channel *ch; GET_TERM(); if (com->command_type==GF_NET_BUFFER_QUERY) { GF_List *od_list; u32 i; GF_ObjectManager *odm; com->buffer.max = 0; com->buffer.min = com->buffer.occupancy = (u32) -1; if (!service->owner) { com->buffer.occupancy = 0; return; } /*browse all channels in the scene, running on this service, and get buffer info*/ od_list = NULL; if (service->owner->subscene) { od_list = service->owner->subscene->resources; } else if (service->owner->parentscene) { od_list = service->owner->parentscene->resources; } if (!od_list) { com->buffer.occupancy = 0; return; } /*get exclusive access to media scheduler, to make sure ODs are not being manipulated*/ gf_mx_p(term->mm_mx); if (!gf_list_count(od_list)) GF_LOG(GF_LOG_WARNING, GF_LOG_MEDIA, ("[ODM] No object manager found for the scene (URL: %s), buffer occupancy will remain unchanged\n", service->url)); i=0; while ((odm = (GF_ObjectManager*)gf_list_enum(od_list, &i))) { u32 j, count; if (!odm->codec) continue; count = gf_list_count(odm->channels); for (j=0; j<count; j++) { GF_Channel *ch = (GF_Channel *)gf_list_get(odm->channels, j); if (ch->service != service) continue; if (ch->es_state != GF_ESM_ES_RUNNING) continue; if (/*!ch->MaxBuffer || */ch->dispatch_after_db || ch->bypass_sl_and_db || ch->IsEndOfStream) continue; //perform buffer management only on base layer -this is because we don't signal which ESs are on/off in the underlying service ... if (ch->esd->dependsOnESID) continue; if (ch->MaxBuffer>com->buffer.max) com->buffer.max = ch->MaxBuffer; if (ch->MinBuffer<com->buffer.min) com->buffer.min = ch->MinBuffer; if (ch->IsClockInit && (u32) ch->BufferTime < com->buffer.occupancy) { /*if we don't have more units (compressed or not) than requested max for the composition memory, request more data*/ if (odm->codec->CB->UnitCount + ch->AU_Count <= odm->codec->CB->Capacity) { // com->buffer.occupancy = 0; com->buffer.occupancy = ch->BufferTime; } else { com->buffer.occupancy = ch->BufferTime; } } } } gf_mx_v(term->mm_mx); // fprintf(stderr, "Buffer occupancy %d\n", com->buffer.occupancy); if (com->buffer.occupancy==(u32) -1) com->buffer.occupancy = 0; return; } if (com->command_type==GF_NET_SERVICE_INFO) { GF_Event evt; evt.type = GF_EVENT_METADATA; gf_term_send_event(term, &evt); return; } if (!com->base.on_channel) return; ch = gf_term_get_channel(service, com->base.on_channel); if (!ch) return; switch (com->command_type) { /*SL reconfiguration*/ case GF_NET_CHAN_RECONFIG: gf_term_lock_net(term, 1); gf_es_reconfig_sl(ch, &com->cfg.sl_config, com->cfg.use_m2ts_sections); gf_term_lock_net(term, 0); return; /*time mapping (TS to media-time)*/ case GF_NET_CHAN_MAP_TIME: if (ch->esd->dependsOnESID) { //ignore everything } else { u32 i; GF_LOG(GF_LOG_DEBUG, GF_LOG_SYNC, ("[SyncLayer] ES%d: before mapping: seed TS %d - TS offset %d\n", ch->esd->ESID, ch->seed_ts, ch->ts_offset)); ch->seed_ts = com->map_time.timestamp; ch->ts_offset = (u32) (com->map_time.media_time*1000); GF_LOG(GF_LOG_INFO, GF_LOG_SYNC, ("[SyncLayer] ES%d: mapping TS "LLD" to media time %f - current time %d\n", ch->esd->ESID, com->map_time.timestamp, com->map_time.media_time, gf_clock_time(ch->clock))); GF_LOG(GF_LOG_DEBUG, GF_LOG_SYNC, ("[SyncLayer] ES%d: after mapping: seed TS %d - TS offset %d\n", ch->esd->ESID, ch->seed_ts, ch->ts_offset)); if (com->map_time.reset_buffers) { gf_es_reset_buffers(ch); } /*if we were reassembling an AU, do not perform clock init check when dispatching it since we computed its timestamps according to the previous clock origin*/ else { gf_mx_p(ch->mx); ch->skip_time_check_for_pending = 1; gf_mx_v(ch->mx); } /*if the channel is the clock, force a re-init*/ if (gf_es_owns_clock(ch)) { ch->IsClockInit = 0; gf_clock_reset(ch->clock); } else if (ch->odm->flags & GF_ODM_INHERIT_TIMELINE) { ch->IsClockInit = 0; // ch->ts_offset -= ch->seed_ts*1000/ch->ts_res; } for (i=0; i<gf_list_count(ch->odm->channels); i++) { GF_Channel *a_ch = gf_list_get(ch->odm->channels, i); if (ch==a_ch) continue; if (! a_ch->esd->dependsOnESID) continue; a_ch->seed_ts = ch->seed_ts; a_ch->IsClockInit = 0; a_ch->ts_offset = ch->ts_offset; } } break; /*duration changed*/ case GF_NET_CHAN_DURATION: gf_odm_set_duration(ch->odm, ch, (u32) (1000*com->duration.duration)); break; case GF_NET_CHAN_BUFFER_QUERY: if (ch->IsEndOfStream) { com->buffer.max = com->buffer.min = com->buffer.occupancy = 0; } else { com->buffer.max = ch->MaxBuffer; com->buffer.min = ch->MinBuffer; com->buffer.occupancy = ch->BufferTime; } break; case GF_NET_CHAN_DRM_CFG: gf_term_lock_net(term, 1); gf_es_config_drm(ch, &com->drm_cfg); gf_term_lock_net(term, 0); return; case GF_NET_CHAN_GET_ESD: gf_term_lock_net(term, 1); com->cache_esd.esd = ch->esd; com->cache_esd.is_iod_stream = (ch->odm->subscene /*&& (ch->odm->subscene->root_od==ch->odm)*/) ? 1 : 0; gf_term_lock_net(term, 0); return; default: return; } }
static void term_on_command(GF_ClientService *service, GF_NetworkCommand *com, GF_Err response) { GF_Channel *ch; GF_Terminal *term = service->term; if (com->command_type==GF_NET_BUFFER_QUERY) { GF_Scene *scene; u32 i, max_buffer_time; GF_ObjectManager *odm; com->buffer.max = 0; com->buffer.min = com->buffer.occupancy = (u32) -1; com->buffer.buffering = GF_FALSE; if (!service->owner) { com->buffer.occupancy = 0; return; } /*browse all channels in the scene, running on this service, and get buffer info*/ scene = NULL; if (service->owner->subscene) { scene = service->owner->subscene; } else if (service->owner->parentscene) { scene = service->owner->parentscene; } if (!scene) { com->buffer.occupancy = 0; return; } /*get exclusive access to scene resources , to make sure ODs are not being inserted/remove*/ gf_mx_p(scene->mx_resources); max_buffer_time=0; if (!gf_list_count(scene->resources)) GF_LOG(GF_LOG_WARNING, GF_LOG_MEDIA, ("[ODM] No object manager found for the scene (URL: %s), buffer occupancy will remain unchanged\n", service->url)); i=0; while ((odm = (GF_ObjectManager*)gf_list_enum(scene->resources, &i))) { gather_buffer_level(odm, service, com, &max_buffer_time); } gf_mx_v(scene->mx_resources); if (com->buffer.occupancy==(u32) -1) com->buffer.occupancy = 0; //in bench mode return the 1 if one of the buffer is full (eg sleep until all buffers are not full), 0 otherwise if (term->bench_mode) { com->buffer.occupancy = (max_buffer_time>com->buffer.max) ? 2 : 0; com->buffer.max = 1; com->buffer.min = 0; } return; } if (com->command_type==GF_NET_SERVICE_INFO) { GF_Event evt; evt.type = GF_EVENT_METADATA; gf_term_send_event(term, &evt); return; } if (com->command_type==GF_NET_SERVICE_MEDIA_CAP_QUERY) { gf_sc_get_av_caps(term->compositor, &com->mcaps.width, &com->mcaps.height, &com->mcaps.display_bit_depth, &com->mcaps.audio_bpp, &com->mcaps.channels, &com->mcaps.sample_rate); return; } if (com->command_type==GF_NET_SERVICE_EVENT) { /*check for UDP timeout*/ if (com->send_event.evt.message.error == GF_IP_UDP_TIMEOUT) { const char *sOpt = gf_cfg_get_key(term->user->config, "Network", "AutoReconfigUDP"); if (sOpt && !stricmp(sOpt, "yes")) { char szMsg[1024]; sprintf(szMsg, "!! UDP down (%s) - Retrying with TCP !!\n", com->send_event.evt.message.message); gf_term_message(term, service->url, szMsg, GF_IP_NETWORK_FAILURE); /*reload scene - FIXME this shall work on inline nodes, not on the root !*/ if (term->reload_url) gf_free(term->reload_url); term->reload_state = 1; term->reload_url = gf_strdup(term->root_scene->root_od->net_service->url); gf_cfg_set_key(term->user->config, "Network", "UDPNotAvailable", "yes"); return; } } com->send_event.res = 0; gf_term_send_event(term, &com->send_event.evt); return; } if (com->command_type==GF_NET_ASSOCIATED_CONTENT_LOCATION) { GF_Scene *scene = NULL; if (service->owner->subscene) { scene = service->owner->subscene; } else if (service->owner->parentscene) { scene = service->owner->parentscene; } if (scene) gf_scene_register_associated_media(scene, &com->addon_info); return; } if (com->command_type==GF_NET_ASSOCIATED_CONTENT_TIMING) { GF_Scene *scene = NULL; if (service->owner->subscene) { scene = service->owner->subscene; } else if (service->owner->parentscene) { scene = service->owner->parentscene; } if (scene) gf_scene_notify_associated_media_timeline(scene, &com->addon_time); return; } if (com->command_type==GF_NET_SERVICE_SEEK) { GF_Scene *scene = NULL; if (service->owner->subscene) { scene = service->owner->subscene; } else if (service->owner->parentscene) { scene = service->owner->parentscene; } if (scene && scene->is_dynamic_scene) { gf_sc_lock(term->compositor, 1); gf_scene_restart_dynamic(scene, (u64) (com->play.start_range*1000), 0, 0); gf_sc_lock(term->compositor, 0); } return; } if (com->command_type == GF_NET_SERVICE_CODEC_STAT_QUERY) { GF_List *od_list; u32 i; GF_ObjectManager *odm; com->codec_stat.avg_dec_time = 0; com->codec_stat.max_dec_time = 0; com->codec_stat.irap_avg_dec_time = 0; com->codec_stat.irap_max_dec_time = 0; if (!service->owner) return; /*browse all channels in the scene, running on this service, and get codec stat*/ od_list = NULL; if (service->owner->subscene) { od_list = service->owner->subscene->resources; } else if (service->owner->parentscene) { od_list = service->owner->parentscene->resources; } if (!od_list) return; /*get exclusive access to media scheduler, to make sure ODs are not being manipulated*/ i=0; while ((odm = (GF_ObjectManager*)gf_list_enum(od_list, &i))) { u32 avg_dec_time; /*the decoder statistics are reliable only if we decoded at least 1s*/ if (!odm->codec || !odm->codec->nb_dec_frames || (odm->codec->ck->speed > 0 ? odm->codec->stat_start + 1000 > odm->codec->last_unit_dts : odm->codec->stat_start - 1000 < odm->codec->last_unit_dts)) continue; avg_dec_time = (u32) (odm->codec->total_dec_time / odm->codec->nb_dec_frames); if (avg_dec_time > com->codec_stat.avg_dec_time) { com->codec_stat.avg_dec_time = avg_dec_time; com->codec_stat.max_dec_time = odm->codec->max_dec_time; com->codec_stat.irap_avg_dec_time = odm->codec->nb_iframes ? (u32) (odm->codec->total_iframes_time / odm->codec->nb_iframes) : 0; com->codec_stat.irap_max_dec_time = odm->codec->max_iframes_time; } if (odm->codec->codec_reset) { com->codec_stat.codec_reset = GF_TRUE; odm->codec->codec_reset = GF_FALSE; } com->codec_stat.decode_only_rap = odm->codec->decode_only_rap ? GF_TRUE : GF_FALSE; } return; } if (!com->base.on_channel) return; ch = gf_term_get_channel(service, com->base.on_channel); if (!ch) return; switch (com->command_type) { /*SL reconfiguration*/ case GF_NET_CHAN_RECONFIG: gf_term_lock_net(term, 1); gf_es_reconfig_sl(ch, &com->cfg.sl_config, com->cfg.use_m2ts_sections); gf_term_lock_net(term, 0); return; case GF_NET_CHAN_SET_MEDIA_TIME: if (gf_es_owns_clock(ch) || !ch->clock->has_media_time_shift) { Double mtime = com->map_time.media_time; if (ch->clock->clock_init) { Double t = (Double) com->map_time.timestamp; t /= ch->esd->slConfig->timestampResolution; t -= ((Double) ch->clock->init_time) /1000; mtime += t; } ch->clock->media_time_at_init = (u32) (1000*mtime); ch->clock->has_media_time_shift = 1; } return; /*time mapping (TS to media-time)*/ case GF_NET_CHAN_MAP_TIME: if (ch->esd->dependsOnESID) { //ignore everything } else { u32 i; GF_LOG(GF_LOG_DEBUG, GF_LOG_SYNC, ("[SyncLayer] ES%d: before mapping: seed TS %d - TS offset %d\n", ch->esd->ESID, ch->seed_ts, ch->ts_offset)); ch->seed_ts = com->map_time.timestamp; ch->ts_offset = (u32) (com->map_time.media_time*1000); GF_LOG(GF_LOG_INFO, GF_LOG_SYNC, ("[SyncLayer] ES%d: mapping TS "LLD" to media time %f - current time %d\n", ch->esd->ESID, com->map_time.timestamp, com->map_time.media_time, gf_clock_time(ch->clock))); GF_LOG(GF_LOG_DEBUG, GF_LOG_SYNC, ("[SyncLayer] ES%d: after mapping: seed TS %d - TS offset %d\n", ch->esd->ESID, ch->seed_ts, ch->ts_offset)); if (com->map_time.reset_buffers) { gf_es_reset_buffers(ch); } /*if we were reassembling an AU, do not perform clock init check when dispatching it since we computed its timestamps according to the previous clock origin*/ else { gf_mx_p(ch->mx); ch->skip_time_check_for_pending = 1; gf_mx_v(ch->mx); } /*if the channel is the clock, force a re-init*/ if (gf_es_owns_clock(ch)) { ch->IsClockInit = 0; gf_clock_reset(ch->clock); } else if (ch->odm->flags & GF_ODM_INHERIT_TIMELINE) { ch->IsClockInit = 0; // ch->ts_offset -= ch->seed_ts*1000/ch->ts_res; } for (i=0; i<gf_list_count(ch->odm->channels); i++) { GF_Channel *a_ch = gf_list_get(ch->odm->channels, i); if (ch==a_ch) continue; if (! a_ch->esd->dependsOnESID) continue; a_ch->seed_ts = ch->seed_ts; a_ch->IsClockInit = 0; a_ch->ts_offset = ch->ts_offset; } } break; /*duration changed*/ case GF_NET_CHAN_DURATION: gf_odm_set_duration(ch->odm, ch, (u32) (1000*com->duration.duration)); break; case GF_NET_CHAN_BUFFER_QUERY: if (ch->IsEndOfStream) { com->buffer.max = com->buffer.min = com->buffer.occupancy = 0; } else { com->buffer.max = ch->MaxBuffer; com->buffer.min = ch->MinBuffer; com->buffer.occupancy = (u32) (ch->BufferTime / FIX2FLT(ch->clock->speed) ); } break; case GF_NET_CHAN_DRM_CFG: gf_term_lock_net(term, 1); gf_es_config_drm(ch, &com->drm_cfg); gf_term_lock_net(term, 0); return; case GF_NET_CHAN_GET_ESD: gf_term_lock_net(term, 1); com->cache_esd.esd = ch->esd; com->cache_esd.is_iod_stream = (ch->odm->subscene /*&& (ch->odm->subscene->root_od==ch->odm)*/) ? 1 : 0; gf_term_lock_net(term, 0); return; case GF_NET_CHAN_RESET: gf_es_reset_buffers(ch); break; case GF_NET_CHAN_PAUSE: ch->MaxBuffer = com->buffer.max; ch->MinBuffer = com->buffer.min; ch->BufferTime = com->buffer.max; gf_es_buffer_on(ch); break; case GF_NET_CHAN_RESUME: ch->BufferTime = ch->MaxBuffer; gf_es_update_buffering(ch, 1); gf_es_buffer_off(ch); break; case GF_NET_CHAN_BUFFER: ch->MaxBuffer = com->buffer.max; ch->MinBuffer = com->buffer.min; ch->BufferTime = com->buffer.occupancy; gf_es_update_buffering(ch, 1); break; default: return; } }