Example #1
0
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;
	}
}
Example #2
0
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;
	}
}