⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 network_service.c

📁 一个用于智能手机的多媒体库适合S60 WinCE的跨平台开发库
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *			GPAC - Multimedia Framework C SDK * *			Copyright (c) Jean Le Feuvre 2000-2005 *					All rights reserved * *  This file is part of GPAC / Media terminal sub-project * *  GPAC is free software; you can redistribute it and/or modify *  it under the terms of the GNU Lesser General Public License as published by *  the Free Software Foundation; either version 2, or (at your option) *  any later version. *    *  GPAC is distributed in the hope that it will be useful, *  but WITHOUT ANY WARRANTY; without even the implied warranty of *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *  GNU Lesser General Public License for more details. *    *  You should have received a copy of the GNU Lesser General Public *  License along with this library; see the file COPYING.  If not, write to *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  * */#include <gpac/internal/terminal_dev.h>#include <gpac/network.h>#define GET_TERM()	GF_Terminal *term = (GF_Terminal *) user_priv; if (!term) return;static GFINLINE GF_Channel *gf_term_get_channel(GF_ClientService *service, LPNETCHANNEL ns){	GF_Channel *ch = (GF_Channel *)ns;	if (!service || !ch) return NULL;	if (ch->chan_id != (u32) ch) return NULL;	if (ch->service != service) return NULL;	return ch;}static void term_on_message(void *user_priv, GF_ClientService *service, GF_Err error, const char *message){	GET_TERM();	/*check for UDP timeout*/	if (error==GF_IP_UDP_TIMEOUT) {		const char *sOpt = gf_cfg_get_key(term->user->config, "Network", "AutoReconfigUDP");		if (sOpt && !stricmp(sOpt, "yes")) {			sOpt = gf_cfg_get_key(term->user->config, "Network", "UDPNotAvailable");			/*if option is already set don't bother try reconfig*/			if (!sOpt || stricmp(sOpt, "yes")) {				char szMsg[1024];				sprintf(szMsg, "!! UDP down (%s) - Retrying with TCP !!\n", message);				gf_term_message(term, service->url, szMsg, GF_OK);				/*reload scene*/				if (term->reload_url) free(term->reload_url);				term->reload_state = 1;				term->reload_url = strdup(term->root_scene->root_od->net_service->url);				gf_cfg_set_key(term->user->config, "Network", "UDPNotAvailable", "yes");				return;			}		}	}	gf_term_message(term, service->url, message, error);}static void term_on_connect(void *user_priv, GF_ClientService *service, LPNETCHANNEL netch, GF_Err err){	GF_Channel *ch;	GF_ObjectManager *root;	GET_TERM();	root = service->owner;	if (root && (root->net_service != service)) {		gf_term_message(term, service->url, "Incomaptible module type", GF_SERVICE_ERROR);		return;	}	/*this is service connection*/	if (!netch) {		if (err) {			char msg[5000];			sprintf(msg, "Cannot open %s", service->url);			gf_term_message(term, service->url, msg, err);			/*destroy service only if attached*/			if (root) {				gf_term_lock_net(term, 1);				service->ifce->CloseService(service->ifce);				root->net_service = NULL;				service->owner = NULL;				/*depends on module: some module could forget to call gf_term_on_disconnect */				if ( gf_list_del_item(term->net_services, service) >= 0) {					/*and queue for destroy*/					gf_list_add(term->net_services_to_remove, service);				}				gf_term_lock_net(term, 0);				if (!root->parentscene) {					GF_Event evt;					evt.type = GF_EVENT_CONNECT;					evt.connect.is_connected = 0;					GF_USER_SENDEVENT(term->user, &evt);				} else {					/*try to reinsert OD for VRML/X3D with multiple URLs:					1- first remove from parent scene without destroying object, this will trigger a re-setup					if other URLs are present					2- then destroy object*/					gf_is_remove_object(root->parentscene, root, 0);					gf_odm_disconnect(root, 1);				}				return;			}		}		if (!root) {			/*channel service connect*/			u32 i;			GF_ChannelSetup *cs;			GF_List *ODs = gf_list_new();			gf_term_lock_net(term, 1);			i=0;			while ((cs = (GF_ChannelSetup*)gf_list_enum(term->channels_pending, &i))) {				if (cs->ch->service != service) continue;				gf_list_rem(term->channels_pending, i-1);				i--;				/*even if error do setup (channel needs to be deleted)*/				if (gf_odm_post_es_setup(cs->ch, cs->dec, err) == GF_OK) {					if (cs->ch->odm && (gf_list_find(ODs, cs->ch->odm)==-1) ) gf_list_add(ODs, cs->ch->odm);				}				free(cs);			}			gf_term_lock_net(term, 0);			/*finally setup all ODs concerned (we do this later in case of scalability)*/			while (gf_list_count(ODs)) {				GF_ObjectManager *odm = (GF_ObjectManager*)gf_list_get(ODs, 0);				gf_list_rem(ODs, 0);				/*force re-setup*/				gf_is_setup_object(odm->parentscene, odm);			}			gf_list_del(ODs);		} else {			/*setup od*/			gf_odm_setup_entry_point(root, NULL);		}		/*load cache if requested*/		if (!err && term->enable_cache) {			err = gf_term_service_cache_load(service);			/*not a fatal error*/			if (err) gf_term_message(term, "GPAC Cache", "Cannot load cache", err);		}	}	/*this is channel connection*/	ch = gf_term_get_channel(service, netch);	if (!ch) return;	/*confirm channel connection even if error - this allow playback of objects even if not all streams are setup	*/	gf_term_lock_net(term, 1);	gf_es_on_connect(ch);	gf_term_lock_net(term, 0);	if (err) {		gf_term_message(term, service->url, "Channel Connection Failed", err);		ch->es_state = GF_ESM_ES_UNAVAILABLE;//		return;	}	/*Plays request are skiped until all channels are connected. We send a PLAY on the objecy in case 		1-OD user has requested a play 		2-this is a channel of the root OD	*/	if ( (ch->odm->mo && ch->odm->mo->num_open) 		|| !ch->odm->parentscene	) {		gf_odm_start(ch->odm);	}#if 0	else if (ch->odm->codec && ch->odm->codec->ck && ch->odm->codec->ck->no_time_ctrl) {		gf_odm_play(ch->odm);	}#endif}static void term_on_disconnect(void *user_priv, GF_ClientService *service, LPNETCHANNEL netch, GF_Err response){	GF_ObjectManager *root;	GF_Channel *ch;	GET_TERM();	/*may be null upon destroy*/	root = service->owner;	if (root && (root->net_service != service)) {		if (root->net_service) gf_term_message(term, service->url, "Incompatible module type", GF_SERVICE_ERROR);		return;	}	/*this is service disconnect*/	if (!netch) {		gf_term_lock_net(term, 1);		/*unregister from valid services*/		if (gf_list_del_item(term->net_services, service)>=0) {			/*and queue for destroy*/			gf_list_add(term->net_services_to_remove, service);		}		gf_term_lock_net(term, 0);		return;	}	/*this is channel disconnect*/	/*no notif in case of failure for disconnection*/	ch = gf_term_get_channel(service, netch);	if (!ch) return;	/*signal channel state*/	ch->es_state = GF_ESM_ES_DISCONNECTED;}static void term_on_slp_recieved(void *user_priv, GF_ClientService *service, LPNETCHANNEL netch, char *data, u32 data_size, GF_SLHeader *hdr, GF_Err reception_status){	GF_Channel *ch;	GET_TERM();	ch = gf_term_get_channel(service, netch);	if (!ch) return;		if (reception_status==GF_EOS) {		gf_es_on_eos(ch);		return;	}	/*otherwise dispatch with error code*/	gf_es_receive_sl_packet(service, ch, data, data_size, hdr, reception_status);}static void term_on_media_add(void *user_priv, GF_ClientService *service, GF_Descriptor *media_desc, Bool no_scene_check){	GF_InlineScene *is;	GF_ObjectManager *odm, *root;	GF_ObjectDescriptor *od;	GET_TERM();	root = service->owner;	is = root->subscene ? root->subscene : root->parentscene;	GF_LOG(GF_LOG_DEBUG, GF_LOG_SERVICE, ("[Service %s] %s\n", service->url, media_desc ? "Adding new media object" : "Regenerating scene graph"));	if (!media_desc) {		if (!no_scene_check) gf_is_regenerate(is);		return;	}	switch (media_desc->tag) {	case GF_ODF_OD_TAG:	case GF_ODF_IOD_TAG:		if (root && (root->net_service == service)) {			od = (GF_ObjectDescriptor *) media_desc;			break;		}	default:		gf_odf_desc_del(media_desc);		return;	}	gf_term_lock_net(term, 1);	odm = gf_is_find_odm(is, od->objectDescriptorID);	/*remove the old OD*/	if (odm) gf_odm_disconnect(odm, 1);	odm = gf_odm_new();	odm->OD = od;	odm->term = term;	odm->parentscene = is;	odm->flags |= GF_ODM_NOT_IN_OD_STREAM;	gf_list_add(is->ODlist, odm);	gf_term_lock_net(term, 0);	gf_odm_setup_object(odm, service);	/*OD inserted by service: resetup scene*/	if (!no_scene_check && is->is_dynamic_scene) gf_is_regenerate(is);}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) return;				od_list = NULL;		if (service->owner->parentscene) od_list = service->owner->parentscene->ODlist;		else if (service->owner->subscene) od_list = service->owner->subscene->ODlist;		if (!od_list) return;		i=0;		while ((odm = (GF_ObjectManager*)gf_list_enum(od_list, &i))) {			u32 j, count;			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->IsEndOfStream) continue;				if (ch->clock->Buffering) continue;				if (ch->es_state != GF_ESM_ES_RUNNING) 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->AU_Count > 2)  && ((u32) ch->BufferTime<com->buffer.occupancy))					com->buffer.occupancy = ch->BufferTime;			}		}		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_USER_SENDEVENT(term->user, &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);		gf_term_lock_net(term, 0);		return;	/*time mapping (TS to media-time)*/	case GF_NET_CHAN_MAP_TIME:		ch->seed_ts = com->map_time.timestamp;		ch->ts_offset = (u32) (com->map_time.media_time*1000);		/*		if (gf_es_owns_clock(ch)) {			ch->ts_offset = (u32) (com->map_time.media_time*1000);		} else {			ch->ts_offset = gf_clock_time(ch->clock);		}		*/		gf_es_map_time(ch, com->map_time.reset_buffers);		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;	}}Bool net_check_interface(GF_InputService *ifce){	if (!ifce->CanHandleURL) return 0;	if (!ifce->ConnectService) return 0;	if (!ifce->CloseService) return 0;	if (!ifce->ConnectChannel) return 0;	if (!ifce->DisconnectChannel) return 0;	if (!ifce->GetServiceDescriptor) return 0;	if (!ifce->ServiceCommand) return 0;	return 1;}static void fetch_mime_io(void *dnld, GF_NETIO_Parameter *parameter){	/*this is correct, however some shoutcast servers don't understand HEAD and don't reply at all	so don't use HEAD*/#if 0	/*only get the content type*/	if (parameter->msg_type==GF_NETIO_GET_METHOD) parameter->name = "HEAD";#endif}static char *get_mime_type(GF_Terminal *term, const char *url, GF_Err *ret_code){	char *mime_type;	GF_DownloadSession * sess;	(*ret_code) = GF_OK;	if (strnicmp(url, "http", 4)) return NULL;	sess = gf_dm_sess_new(term->downloader, (char *) url, GF_NETIO_SESSION_NOT_THREADED, fetch_mime_io, NULL, ret_code);	if (!sess) {		if (strstr(url, "rtsp://") || strstr(url, "rtp://") || strstr(url, "udp://") || strstr(url, "tcp://") ) (*ret_code) = GF_OK;		return NULL;	}	mime_type = (char *) gf_dm_sess_mime_type(sess);	if (mime_type) mime_type = strdup(mime_type);	else *ret_code = gf_dm_sess_last_error(sess);	gf_dm_sess_del(sess);	return mime_type;}static Bool check_extension(char *szExtList, char *szExt){	char szExt2[50];	if (szExtList[0] != '"') return 0;	szExtList += 1;	while (1) {		u32 i = 0;		while ((szExtList[0] != ' ') && (szExtList[0] != '"')) {			szExt2[i] = szExtList[0];			i++;			szExtList++;		}		szExt2[i] = 0;		if (!strncmp(szExt, szExt2, strlen(szExt2))) return 1;		if (szExtList[0]=='"') break;		else szExtList++;	}	return 0;}static GF_InputService *gf_term_can_handle_service(GF_Terminal *term, const char *url, const char *parent_url, Bool no_mime_check, char **out_url, GF_Err *ret_code){	u32 i;	GF_Err e;	char *sURL, *ext, *mime_type;	char szExt[50];	GF_InputService *ifce;	GF_LOG(GF_LOG_DEBUG, GF_LOG_MEDIA, ("[Terminal] Looking for plugin for URL %s\n", url));	*out_url = NULL;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -