示例#1
0
static GF_Err FFD_CloseService(GF_InputService *plug)
{
	FFDemux *ffd = plug->priv;

	ffd->is_running = 0;

#ifndef FF_API_CLOSE_INPUT_FILE
	if (ffd->ctx) av_close_input_file(ffd->ctx);
#else
	if (ffd->ctx) avformat_close_input(&ffd->ctx);
#endif

	ffd->ctx = NULL;
	ffd->audio_ch = ffd->video_ch = NULL;
	ffd->audio_run = ffd->video_run = 0;

	if (ffd->dnload) {
		if (ffd->is_running) {
			while (!ffd->is_running) gf_sleep(1);
			ffd->is_running = 0;
		}
		gf_service_download_del(ffd->dnload);
		ffd->dnload = NULL;
	}
	if (ffd->buffer) gf_free(ffd->buffer);
	ffd->buffer = NULL;

	gf_service_disconnect_ack(ffd->service, NULL, GF_OK);
#ifdef FFMPEG_DUMP_REMOTE
	if (ffd->outdbg) fclose(ffd->outdbg);
#endif
	return GF_OK;
}
示例#2
0
文件: read.c 项目: dragonlucian/gpac
GF_Err ISOR_DisconnectChannel(GF_InputService *plug, LPNETCHANNEL channel)
{
	ISOMChannel *ch;
	GF_Err e;
	ISOMReader *read;
	if (!plug || !plug->priv) return GF_SERVICE_ERROR;
	read = (ISOMReader *) plug->priv;
	if (!read->mov) return GF_SERVICE_ERROR;

	gf_mx_p(read->segment_mutex);
	e = GF_OK;
	ch = isor_get_channel(read, channel);
	assert(ch);
	if (!ch) {
		e = GF_STREAM_NOT_FOUND;
		goto exit;
	}
	/*signal the service is broken but still process the delete*/
	isor_delete_channel(read, ch);
	assert(!isor_get_channel(read, channel));

exit:
	if (read->input->query_proxy && read->input->proxy_udta && read->input->proxy_type) {
		send_proxy_command(read, 1, 0, e, NULL, channel);
	} else {
		gf_service_disconnect_ack(read->service, channel, e);
	}
	gf_mx_v(read->segment_mutex);
	return e;
}
示例#3
0
static GF_Err VTT_CloseService(GF_InputService *plug)
{
	VTTIn *vttin;
	if (!plug)	return GF_BAD_PARAM;

	vttin = (VTTIn *)plug->priv;
	if (!vttin)	return GF_BAD_PARAM;

	//if (vttin->szFile) {
	//	gf_delete_file(vttin->szFile);
	//	gf_free(vttin->szFile);
	//}
	//vttin->szFile = NULL;

	if (vttin->dnload) {
		gf_service_download_del(vttin->dnload);
	}
	vttin->dnload = NULL;

	if (vttin->service) {
		gf_service_disconnect_ack(vttin->service, NULL, GF_OK);
	}
	vttin->service = NULL;

	return GF_OK;
}
示例#4
0
文件: libplayer.c 项目: Bevara/GPAC
GF_Err LIBPLAYER_DisconnectChannel(GF_InputService *plug, LPNETCHANNEL channel)
{
	LibPlayerIn *read = (LibPlayerIn *) plug->priv;
	GF_LOG(GF_LOG_DEBUG, GF_LOG_MODULE, ("[LibPlayerIN] instance %d disconnect channel\n", read->player_id));
	gf_service_disconnect_ack(read->service, channel, GF_OK);
	return GF_OK;
}
示例#5
0
文件: read.c 项目: dragonlucian/gpac
GF_Err ISOR_CloseService(GF_InputService *plug)
{
	GF_Err reply;
	ISOMReader *read;
	if (!plug || !plug->priv) return GF_SERVICE_ERROR;
	read = (ISOMReader *) plug->priv;
	reply = GF_OK;

	read->disconnected = GF_TRUE;

	while (gf_list_count(read->channels)) {
		ISOMChannel *ch = (ISOMChannel *)gf_list_get(read->channels, 0);
		gf_list_rem(read->channels, 0);
		isor_delete_channel(read, ch);
	}

	if (read->dnload) gf_service_download_del(read->dnload);
	read->dnload = NULL;

	if (read->mov) gf_isom_close(read->mov);
	read->mov = NULL;

	if (read->input->query_proxy && read->input->proxy_udta && read->input->proxy_type) {
		send_proxy_command(read, GF_TRUE, GF_FALSE, reply, NULL, NULL);
	} else {
		gf_service_disconnect_ack(read->service, NULL, reply);
	}
	return GF_OK;
}
示例#6
0
文件: libplayer.c 项目: Bevara/GPAC
GF_Err LIBPLAYER_CloseService(GF_InputService *plug)
{
	LibPlayerIn *read = (LibPlayerIn *) plug->priv;

#ifndef TEST_LIBPLAYER
	// only disconnect if
	if (read->player_type == PLAYER_FILE) {
		player_playback_stop(read->player);
		fprintf(stderr, "[LibPlayerIN]player_playback_stop for instance %d\n", read->player_id);
		player_uninit(read->player);
		fprintf(stderr, "[LibPlayerIN]player_uninit for instance %d\n", read->player_id);
		read->player = NULL;
		libplayer_id--;

		read->state = 0;

		gf_service_disconnect_ack(read->service, NULL, GF_OK);
		GF_LOG(GF_LOG_DEBUG, GF_LOG_MODULE, ("[LibPlayerIn] Closing libplayer instance %d\n", read->player_id));



		// channel zapping dvb case, don't disconnect service
	} else {
		GF_LOG(GF_LOG_DEBUG, GF_LOG_MODULE, ("[LibPlayerIn] Don't close service libplayer instance %d, use this instance for channel zapping\n", read->player_id));
	}

	return GF_OK;
#endif
}
示例#7
0
文件: dummy_in.c 项目: drakeguan/gpac
GF_Err DC_CloseService(GF_InputService *plug)
{
	DCReader *read = (DCReader *) plug->priv;
	if (read->dnload) gf_service_download_del(read->dnload);
	read->dnload = NULL;
	gf_service_disconnect_ack(read->service, NULL, GF_OK);
	return GF_OK;
}
示例#8
0
文件: dummy_in.c 项目: drakeguan/gpac
GF_Err DC_DisconnectChannel(GF_InputService *plug, LPNETCHANNEL channel)
{
	Bool had_ch;
	DCReader *read = (DCReader *) plug->priv;

	had_ch = DC_RemoveChannel(read, channel);
	gf_service_disconnect_ack(read->service, channel, had_ch ? GF_OK : GF_STREAM_NOT_FOUND);
	return GF_OK;
}
示例#9
0
文件: mse_in.c 项目: Brilon314/gpac
/* Indicate that the media source object is unused anymore */
static GF_Err MSE_CloseService(GF_InputService *plug)
{
	GF_MSE_In *msein = (GF_MSE_In*) plug->priv;
	assert( msein );
	GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[MSE_IN] Received Close Service request on Service %p from terminal for URL '%s'\n", msein->mediasource->service, msein->mediasource->blobURI));
	if (msein->mediasource) {
		gf_service_disconnect_ack(msein->mediasource->service, NULL, GF_OK);
		gf_mse_mediasource_del(msein->mediasource, GF_FALSE);
		msein->mediasource = NULL;
	}
	return GF_OK;
}
示例#10
0
文件: img_in.c 项目: ARSekkat/gpac
static GF_Err IMG_DisconnectChannel(GF_InputService *plug, LPNETCHANNEL channel)
{
	GF_Err e = GF_STREAM_NOT_FOUND;
	IMGLoader *read = (IMGLoader *)plug->priv;

	if (read->ch == channel) {
		read->ch = NULL;
		e = GF_OK;
	}
	gf_service_disconnect_ack(read->service, channel, e);
	return GF_OK;
}
示例#11
0
static GF_Err AC3_CloseService(GF_InputService *plug)
{
	AC3Reader *read = plug->priv;
	if (read->stream) fclose(read->stream);
	read->stream = NULL;
	if (read->dnload) gf_service_download_del(read->dnload);
	read->dnload = NULL;

	if (read->data) gf_free(read->data);
	read->data = NULL;
	gf_service_disconnect_ack(read->service, NULL, GF_OK);
	return GF_OK;
}
示例#12
0
static GF_Err VTT_DisconnectChannel(GF_InputService *plug, LPNETCHANNEL channel)
{
	VTTIn *vttin = (VTTIn *)plug->priv;
	GF_Err e = GF_STREAM_NOT_FOUND;

	if (!vttin)	return GF_BAD_PARAM;

	if (vttin->channel == channel) {
		vttin->channel = NULL;
		e = GF_OK;
	}
	gf_service_disconnect_ack(vttin->service, channel, e);
	return GF_OK;
}
示例#13
0
static GF_Err AC3_DisconnectChannel(GF_InputService *plug, LPNETCHANNEL channel)
{
	AC3Reader *read = plug->priv;

	GF_Err e = GF_STREAM_NOT_FOUND;
	if (read->ch == channel) {
		read->ch = NULL;
		if (read->data) gf_free(read->data);
		read->data = NULL;
		e = GF_OK;
	}
	gf_service_disconnect_ack(read->service, channel, e);
	return GF_OK;
}
示例#14
0
文件: mpd_in.c 项目: claudiordgz/gpac
GF_Err MPD_CloseService(GF_InputService *plug)
{
	GF_MPD_In *mpdin = (GF_MPD_In*) plug->priv;
	assert( mpdin );
	GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[MPD_IN] Received Close Service (%p) request from terminal\n", mpdin->service));

	mpdin->closed = 1;

	if (mpdin->dash)
		gf_dash_close(mpdin->dash);

	gf_service_disconnect_ack(mpdin->service, NULL, GF_OK);

	return GF_OK;
}
示例#15
0
文件: img_in.c 项目: ARSekkat/gpac
static GF_Err IMG_CloseService(GF_InputService *plug)
{
	IMGLoader *read;
	if (!plug)
		return GF_BAD_PARAM;
	read = (IMGLoader *)plug->priv;
	if (!read)
		return GF_BAD_PARAM;
	if (read->stream) gf_fclose(read->stream);
	read->stream = NULL;
	if (read->dnload) gf_service_download_del(read->dnload);
	read->dnload = NULL;
	if (read->service)
		gf_service_disconnect_ack(read->service, NULL, GF_OK);
	return GF_OK;
}
示例#16
0
文件: saf_in.c 项目: Bevara/GPAC
static GF_Err SAF_DisconnectChannel(GF_InputService *plug, LPNETCHANNEL channel)
{
	SAFChannel *ch;
	SAFIn *read = (SAFIn *)plug->priv;

	GF_Err e = GF_STREAM_NOT_FOUND;
	ch = saf_get_channel(read, 0, channel);
	if (ch) {
		gf_list_del_item(read->channels, ch);
		if (ch->esd) gf_odf_desc_del((GF_Descriptor*)ch->esd);
		gf_free(ch);
		e = GF_OK;
	}
	gf_service_disconnect_ack(read->service, channel, e);
	return GF_OK;
}
示例#17
0
文件: rtp_in.c 项目: redfox-qu/gpac
static GF_Err RP_DisconnectChannel(GF_InputService *plug, LPNETCHANNEL channel)
{
    RTPStream *ch;
    RTPClient *priv = (RTPClient *)plug->priv;

    GF_LOG(GF_LOG_DEBUG, GF_LOG_RTP, ("[RTP] Disconnecting channel @%08x\n", channel));

    ch = RP_FindChannel(priv, channel, 0, NULL, 0);
    if (!ch) return GF_STREAM_NOT_FOUND;
    gf_mx_p(priv->mx);
    /*disconnect stream BUT DO NOT DELETE IT since we don't store SDP*/
    ch->flags &= ~RTP_CONNECTED;
    ch->channel = NULL;
    gf_mx_v(priv->mx);
    gf_service_disconnect_ack(priv->service, channel, GF_OK);
    return GF_OK;
}
示例#18
0
文件: rtp_in.c 项目: redfox-qu/gpac
static GF_Err RP_CloseService(GF_InputService *plug)
{
    u32 i;
    const char *opt;
    RTSPSession *sess;
    RTPClient *rtp = (RTPClient *)plug->priv;
    GF_LOG(GF_LOG_DEBUG, GF_LOG_RTP, ("[RTP] Closing service\n"));

    RP_FlushCommands(rtp);

    if (rtp->session_migration) {
        opt = gf_modules_get_option((GF_BaseInterface *) plug, "Streaming", "SessionMigrationPause");
        if (opt && !strcmp(opt, "yes")) {
            GF_NetworkCommand com;
            com.command_type = GF_NET_CHAN_PAUSE;
            com.base.on_channel = NULL;
            /*send pause on all sessions*/
            i=0;
            while ((sess = (RTSPSession *)gf_list_enum(rtp->sessions, &i))) {
                RP_UserCommand(sess, NULL, &com);
            }
        }
        RP_SaveSessionState(rtp);
    } else {
        /*remove session state file*/
        if (rtp->session_state_data) {
            gf_free(rtp->session_state_data);
            rtp->session_state_data = NULL;
        }

        /*send teardown on all sessions*/
        i=0;
        while ((sess = (RTSPSession *)gf_list_enum(rtp->sessions, &i))) {
            RP_Teardown(sess, NULL);
        }
    }
    RP_FlushCommands(rtp);

    /*shutdown thread*/
    if (rtp->th_state==1) rtp->th_state = 0;

    /*confirm close*/
    gf_service_disconnect_ack(rtp->service, NULL, GF_OK);
    return GF_OK;
}
示例#19
0
static GF_Err FFD_DisconnectChannel(GF_InputService *plug, LPNETCHANNEL channel)
{
	GF_Err e;
	FFDemux *ffd = plug->priv;

	e = GF_STREAM_NOT_FOUND;
	if (ffd->audio_ch == channel) {
		e = GF_OK;
		ffd->audio_ch = NULL;
		ffd->audio_run = 0;
	}
	else if (ffd->video_ch == channel) {
		e = GF_OK;
		ffd->video_ch = NULL;
		ffd->video_run = 0;
	}
	gf_service_disconnect_ack(ffd->service, channel, e);
	return GF_OK;
}
示例#20
0
文件: saf_in.c 项目: Bevara/GPAC
static GF_Err SAF_CloseService(GF_InputService *plug)
{
	SAFIn *read = (SAFIn *)plug->priv;

	if (read->th) {
		if (read->run_state == 1) {
			read->run_state=0;
			while (read->run_state!=2) gf_sleep(2);
		}
		gf_th_del(read->th);
		read->th = NULL;
	}

	if (read->stream) fclose(read->stream);
	read->stream = NULL;
	if (read->dnload) gf_service_download_del(read->dnload);
	read->dnload = NULL;
	gf_service_disconnect_ack(read->service, NULL, GF_OK);
	return GF_OK;
}
示例#21
0
/* Callback functions used by a media parser when parsing events happens */
GF_Err gf_mse_proxy(GF_InputService *parser, GF_NetworkCommand *command)
{
	if (!parser || !command || !parser->proxy_udta) {
		return GF_BAD_PARAM;
	} else {
		GF_HTML_SourceBuffer *sb = (GF_HTML_SourceBuffer *)parser->proxy_udta;
		switch (command->command_type) {
		case GF_NET_SERVICE_QUERY_INIT_RANGE:
			break;
		case GF_NET_SERVICE_QUERY_NEXT:
			/* The parser is asking for the next media segment in the buffer,
			   check for the media time and give the right one */
		{
			GF_HTML_ArrayBuffer *buffer;
			/* The input buffer should not be modified by append operations at the same time, no need to protect access */
			buffer = (GF_HTML_ArrayBuffer *)gf_list_get(sb->input_buffer, 0);
			if (buffer) {
				command->url_query.discontinuity_type = 0;
				command->url_query.current_download = GF_FALSE;
				command->url_query.start_range = 0;
				command->url_query.end_range = 0;
				command->url_query.switch_start_range = 0;
				command->url_query.switch_end_range = 0;
				command->url_query.next_url_init_or_switch_segment = NULL;
				if (buffer->is_init) {
					GF_HTML_ArrayBuffer *next = (GF_HTML_ArrayBuffer *)gf_list_get(sb->input_buffer, 1);
					command->url_query.discontinuity_type = 1;
					if (next) {
						GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[MSE] Next segment to parse %s with init \n", next->url, buffer->url));
						command->url_query.next_url = next->url;
						command->url_query.next_url_init_or_switch_segment = buffer->url;
						gf_list_rem(sb->input_buffer, 0);
						gf_list_rem(sb->input_buffer, 0);
					} else {
						GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[MSE] Only one init segment to parse %s, need to wait\n", buffer->url));
						command->url_query.next_url = NULL;
					}
				} else {
					GF_LOG(GF_LOG_DEBUG, GF_LOG_DASH, ("[MSE] Next segment to parse %s\n", buffer->url));
					command->url_query.next_url = buffer->url;
					gf_list_rem(sb->input_buffer, 0);
				}
				sb->prev_buffer = buffer;
			} else {
				command->url_query.next_url = NULL;
				command->url_query.discontinuity_type = 0;
			}
		}
		break;
		case GF_NET_SERVICE_STATUS_PROXY:
			/* The parser is informing the proxy about its status changes:
			    - new track found
				- all tracks parsed
				- connect/disconnect
				- */
			if (command->status.is_add_media) {
				if (command->status.desc) {
					gf_mse_source_buffer_store_track_desc(sb, (GF_ObjectDescriptor *)command->status.desc);
				} else {
					/* this is the last add media, we can switch updating to false */
					/* the first init segment was correctly processed */
					gf_mse_source_buffer_set_update(sb, GF_FALSE);
					/* TODO: set active tracks and send addsourcebuffer event */
					/* TODO: send media loadedmetadata event */
				}
				gf_service_declare_media(sb->mediasource->service, command->status.desc, (command->status.desc ? GF_TRUE : GF_FALSE));
			}
			/* general connection/disconnection messages from the media parser (not track related) */
			else if (!command->status.channel) {
				/* connection message */
				if (!command->status.is_disconnect) {
					if (command->status.e == GF_OK) {
						/* nothing needs to be done. Setup is done with final add media */
						sb->parser_connected = GF_TRUE;
						sb->mediasource->durationType = DURATION_INFINITY;
						gf_mse_source_buffer_setup_tracks(sb);
					} else {
						/* wrong first init segment */
						/* TODO: fire an error event */
					}
					gf_service_connect_ack(sb->mediasource->service, command->status.channel, command->status.e);
				} else {
					gf_service_disconnect_ack(sb->mediasource->service, command->status.channel, command->status.e);
				}
			}
			/* channel (track related) specific connection/disconnection messages from the media parser */
			else {
				if (!command->status.is_disconnect) {
					gf_service_connect_ack(sb->mediasource->service, command->status.channel, command->status.e);
				} else {
					gf_service_disconnect_ack(sb->mediasource->service, command->status.channel, command->status.e);
				}
			}
			break;
		default:
			gf_service_command(sb->mediasource->service, command, GF_OK);
			break;
		}
		return GF_OK;
	}
}
示例#22
0
文件: mpd_in.c 项目: claudiordgz/gpac
GF_Err mpdin_dash_io_on_dash_event(GF_DASHFileIO *dashio, GF_DASHEventType dash_evt, s32 group_idx, GF_Err error_code)
{
	GF_Err e;
	u32 i;
	GF_MPD_In *mpdin = (GF_MPD_In *)dashio->udta;

	if (dash_evt==GF_DASH_EVENT_PERIOD_SETUP_ERROR) {
		if (!mpdin->connection_ack_sent) {
			mpdin->fn_connect_ack(mpdin->service, NULL, error_code);
			mpdin->connection_ack_sent= GF_TRUE;
		}
		return GF_OK;
	}

	if (dash_evt==GF_DASH_EVENT_SELECT_GROUPS) {
		const char *opt;
		//configure buffer in dynamic mode without low latency: we indicate how much the player will buffer
		if (gf_dash_is_dynamic_mpd(mpdin->dash) && !mpdin->use_low_latency) {
			u32 buffer_ms = 0;
			const char *opt = gf_modules_get_option((GF_BaseInterface *)mpdin->plug, "Network", "BufferLength");
			if (opt) buffer_ms = atoi(opt);

			//use min buffer from MPD
			if (mpdin->buffer_mode>=MPDIN_BUFFER_MIN) {
				u32 mpd_buffer_ms = gf_dash_get_min_buffer_time(mpdin->dash);
				if (mpd_buffer_ms > buffer_ms)
					buffer_ms = mpd_buffer_ms;
			}

			if (buffer_ms) {
				gf_dash_set_user_buffer(mpdin->dash, buffer_ms);
			}
		}
		//let the player decide which group to play: we declare everything

		//however select the default languague
		opt = gf_modules_get_option((GF_BaseInterface *)mpdin->plug, "Systems", "LanguageName");
		if (opt)
			gf_dash_groups_set_language(mpdin->dash, opt);

		return GF_OK;
	}

	/*for all selected groups, create input service and connect to init/first segment*/
	if (dash_evt==GF_DASH_EVENT_CREATE_PLAYBACK) {
		/*select input services if possible*/
		for (i=0; i<gf_dash_get_group_count(mpdin->dash); i++) {
			const char *mime, *init_segment;
			//let the player decide which group to play
			if (!gf_dash_is_group_selectable(mpdin->dash, i))
				continue;

			mime = gf_dash_group_get_segment_mime(mpdin->dash, i);
			init_segment = gf_dash_group_get_segment_init_url(mpdin->dash, i, NULL, NULL);
			e = MPD_LoadMediaService(mpdin, i, mime, init_segment);
			if (e != GF_OK) {
				gf_dash_group_select(mpdin->dash, i, 0);
			} else {
				u32 w, h;
				/*connect our media service*/
				GF_MPDGroup *group = gf_dash_get_group_udta(mpdin->dash, i);
				gf_dash_group_get_video_info(mpdin->dash, i, &w, &h);
				if (w && h && w>mpdin->width && h>mpdin->height) {
					mpdin->width = w;
					mpdin->height = h;
				}

				e = group->segment_ifce->ConnectService(group->segment_ifce, mpdin->service, init_segment);
				if (e) {
					GF_LOG(GF_LOG_WARNING, GF_LOG_DASH, ("[MPD_IN] Unable to connect input service to %s\n", init_segment));
					gf_dash_group_select(mpdin->dash, i, 0);
				} else {
					group->service_connected = 1;
				}
				if (mpdin->closed) return GF_OK;
			}
		}

		if (!mpdin->connection_ack_sent) {
			mpdin->fn_connect_ack(mpdin->service, NULL, GF_OK);
			mpdin->connection_ack_sent=1;
		}

		//we had a seek outside of the period we were setting up, during period setup !
		//request the seek again from the player
		if (mpdin->seek_request>=0) {
			GF_NetworkCommand com;
			memset(&com, 0, sizeof(GF_NetworkCommand));
			com.command_type = GF_NET_SERVICE_SEEK;
			com.play.start_range = mpdin->seek_request;
			mpdin->seek_request = 0;
			gf_service_command(mpdin->service, &com, GF_OK);
		}
		return GF_OK;
	}

	/*for all running services, stop service*/
	if (dash_evt==GF_DASH_EVENT_DESTROY_PLAYBACK) {

		mpdin->service->subservice_disconnect = 1;
		gf_service_disconnect_ack(mpdin->service, NULL, GF_OK);
		mpdin->service->subservice_disconnect = 2;

		for (i=0; i<gf_dash_get_group_count(mpdin->dash); i++) {
			GF_MPDGroup *group = gf_dash_get_group_udta(mpdin->dash, i);
			if (!group) continue;
			if (group->segment_ifce) {
				if (group->service_connected) {
					group->segment_ifce->CloseService(group->segment_ifce);
					group->service_connected = 0;
				}
				gf_modules_close_interface((GF_BaseInterface *) group->segment_ifce);
			}
			gf_free(group);
			gf_dash_set_group_udta(mpdin->dash, i, NULL);
		}
		mpdin->service->subservice_disconnect = 0;
		return GF_OK;
	}

	if (dash_evt==GF_DASH_EVENT_BUFFERING) {
		u32 tot, done;
		gf_dash_get_buffer_info(mpdin->dash, &tot, &done);
		fprintf(stderr, "DASH: Buffering %g%% out of %d ms\n", (100.0*done)/tot, tot);
		return GF_OK;
	}
	if (dash_evt==GF_DASH_EVENT_SEGMENT_AVAILABLE) {
		if (group_idx>=0) {
			GF_MPDGroup *group = gf_dash_get_group_udta(mpdin->dash, group_idx);
			if (group) MPD_NotifyData(group, 0);
		}
		return GF_OK;
	}
	if (dash_evt==GF_DASH_EVENT_QUALITY_SWITCH) {
		if (group_idx>=0) {
			GF_MPDGroup *group = gf_dash_get_group_udta(mpdin->dash, group_idx);
			if (group) {
				GF_NetworkCommand com;
				memset(&com, 0, sizeof(GF_NetworkCommand) );

				com.command_type = GF_NET_SERVICE_EVENT;
				com.send_event.evt.type = GF_EVENT_QUALITY_SWITCHED;
				gf_service_command(mpdin->service, &com, GF_OK);
			}
		}
		return GF_OK;
	}
	if (dash_evt==GF_DASH_EVENT_TIMESHIFT_OVERFLOW) {
		GF_NetworkCommand com;
		com.command_type = GF_NET_SERVICE_EVENT;
		com.send_event.evt.type = (group_idx>=0) ? GF_EVENT_TIMESHIFT_OVERFLOW : GF_EVENT_TIMESHIFT_UNDERRUN;
		gf_service_command(mpdin->service, &com, GF_OK);
	}
	if (dash_evt==GF_DASH_EVENT_TIMESHIFT_UPDATE) {
		GF_NetworkCommand com;
		com.command_type = GF_NET_SERVICE_EVENT;
		com.send_event.evt.type = GF_EVENT_TIMESHIFT_UPDATE;
		gf_service_command(mpdin->service, &com, GF_OK);
	}

	return GF_OK;
}