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

📄 audio_stacks.c

📁 一个用于智能手机的多媒体库适合S60 WinCE的跨平台开发库
💻 C
📖 第 1 页 / 共 2 页
字号:
	GF_AudioMixer *am;	Bool is_init, is_muted;	/*buffer audio data*/	char *buffer;	u32 buffer_size;	Bool done;	/*read/write position in buffer and associated read time (CTS)*/	u32 read_pos, write_pos, cur_cts;	/*list of audio children after a traverse*/	GF_List *new_inputs;} AudioBufferStack;/*we have no choice but always browsing the children, since a src can be replaced by a new onewithout the parent being modified. We just collect the src and check against the current mixer inputsto reset the mixer or not - the spec is not clear about that btw, shall rebuffering happen if a source is modified or not ...*/static void RenderAudioBuffer(GF_Node *node, void *rs, Bool is_destroy){	u32 j;	Bool update_mixer;	GF_ChildNodeItem *l;	GF_AudioGroup *parent;	AudioBufferStack *st = (AudioBufferStack *)gf_node_get_private(node);	M_AudioBuffer *ab = (M_AudioBuffer *)node;	GF_BaseEffect*eff = (GF_BaseEffect*) rs;	if (is_destroy) {		gf_sr_audio_unregister(&st->output);		if (st->time_handle.is_registered) 			gf_sr_unregister_time_node(st->output.compositor, &st->time_handle);		gf_mixer_del(st->am);		if (st->buffer) free(st->buffer);		gf_list_del(st->new_inputs);		free(st);		return;	}	parent = eff->audio_parent;	eff->audio_parent = (GF_AudioGroup *) st;	l = ab->children;	while (l) {		gf_node_render(l->node, eff);		l = l->next;	}	gf_mixer_lock(st->am, 1);	/*if no new inputs don't change mixer config*/	update_mixer = gf_list_count(st->new_inputs) ? 1 : 0;		if (gf_mixer_get_src_count(st->am) == gf_list_count(st->new_inputs)) {		u32 count = gf_list_count(st->new_inputs);		update_mixer = 0;		for (j=0; j<count; j++) {			GF_AudioInput *cur = (GF_AudioInput *)gf_list_get(st->new_inputs, j);			if (!gf_mixer_is_src_present(st->am, &cur->input_ifce)) {				update_mixer = 1;				break;			}		}	}	if (update_mixer) {		gf_mixer_remove_all(st->am);		gf_mixer_force_chanel_out(st->am, ab->numChan);	}	while (gf_list_count(st->new_inputs)) {		GF_AudioInput *src = (GF_AudioInput *)gf_list_get(st->new_inputs, 0);		gf_list_rem(st->new_inputs, 0);		if (update_mixer) gf_mixer_add_input(st->am, &src->input_ifce);	}	gf_mixer_lock(st->am, 0);	eff->audio_parent = parent;	/*Note the audio buffer is ALWAYS registered untill destroyed since buffer filling shall happen even when inactive*/	if (!st->output.register_with_parent || !st->output.register_with_renderer) 		gf_sr_audio_register(&st->output, eff);	/*store mute flag*/	st->is_muted = (eff->trav_flags & GF_SR_TRAV_SWITCHED_OFF);}static void AB_Activate(AudioBufferStack *st, M_AudioBuffer *ab){	ab->isActive = 1;	gf_node_event_out_str((GF_Node *)ab, "isActive");	/*rerender all graph to get parent audio group*/	gf_sr_invalidate(st->output.compositor, NULL);	st->done = 0;	st->read_pos = 0;}static void AB_Deactivate(AudioBufferStack *st, M_AudioBuffer *ab){	ab->isActive = 0;	gf_node_event_out_str((GF_Node *)ab, "isActive");	st->time_handle.needs_unregister = 1;}static void AB_UpdateTime(GF_TimeNode *tn){	Double time;	M_AudioBuffer *ab = (M_AudioBuffer *)tn->obj;	AudioBufferStack *st = (AudioBufferStack *)gf_node_get_private(tn->obj);	if (! ab->isActive) {		st->start_time = ab->startTime;	}	time = gf_node_get_scene_time(tn->obj);	if ((time<st->start_time) || (st->start_time<0)) return;		if (ab->isActive) {		if ( (ab->stopTime > st->start_time) && (time>=ab->stopTime)) {			AB_Deactivate(st, ab);			return;		}		/*THIS IS NOT NORMATIVE*/		if ( !ab->loop && st->done) {			AB_Deactivate(st, ab);			return;		}	}	if (!ab->isActive) AB_Activate(st, ab);}static char *AB_FetchFrame(void *callback, u32 *size, u32 audio_delay_ms){	u32 blockAlign;	AudioBufferStack *st = (AudioBufferStack *) gf_node_get_private( ((GF_AudioInput *) callback)->owner);	M_AudioBuffer *ab = (M_AudioBuffer*)st->output.owner;	if (!st->is_init) return NULL;	if (!st->buffer) {		st->done = 0;		st->buffer_size = (u32) ceil(FIX2FLT(ab->length) * st->output.input_ifce.bps*st->output.input_ifce.sr*st->output.input_ifce.chan/8);		blockAlign = gf_mixer_get_block_align(st->am);		/*BLOCK ALIGN*/		while (st->buffer_size%blockAlign) st->buffer_size++;		st->buffer = (char*)malloc(sizeof(char) * st->buffer_size);		memset(st->buffer, 0, sizeof(char) * st->buffer_size);		st->read_pos = st->write_pos = 0;	}	if (st->done) return NULL;	/*even if not active, fill the buffer*/	if (st->write_pos < st->buffer_size) {		u32 written;		while (1) {			/*just try to completely fill it*/			written = gf_mixer_get_output(st->am, st->buffer + st->write_pos, st->buffer_size - st->write_pos);			if (!written) break;			st->write_pos += written;			assert(st->write_pos<=st->buffer_size);		}	}	/*not playing*/	if (! ab->isActive) return NULL;	*size = st->write_pos - st->read_pos;	return st->buffer + st->read_pos;}static void AB_ReleaseFrame(void *callback, u32 nb_bytes){	AudioBufferStack *st = (AudioBufferStack *) gf_node_get_private( ((GF_AudioInput *) callback)->owner);	st->read_pos += nb_bytes;	assert(st->read_pos<=st->write_pos);	if (st->read_pos==st->write_pos) {		if (st->write_pos<st->buffer_size) {			/*reading faster than buffering - let's still attempt to fill the buffer*/#if 0			st->write_pos = st->buffer_size;			GF_LOG(GF_LOG_WARNING, GF_LOG_RENDER, ("[AudioBuffer] done playing before buffer filling done\n"));#endif		} else if ( ((M_AudioBuffer*)st->output.owner)->loop) {			st->read_pos = 0;		} else {			st->done = 1;		}	}}static Fixed AB_GetSpeed(void *callback){	M_AudioBuffer *ab = (M_AudioBuffer *) ((GF_AudioInput *) callback)->owner;	return ab->pitch;}static Bool AB_GetChannelVolume(void *callback, Fixed *vol){	GF_AudioInput *ai = (GF_AudioInput *) callback;	if (ai->snd->GetChannelVolume) {		return ai->snd->GetChannelVolume(ai->snd->owner, vol);	} else {		vol[0] = vol[1] = vol[2] = vol[3] = vol[4] = vol[5] = FIX_ONE;		return 0;	}}static Bool AB_IsMuted(void *callback){	AudioBufferStack *st = (AudioBufferStack *) gf_node_get_private( ((GF_AudioInput *) callback)->owner);	return st->is_muted;}static Bool AB_GetConfig(GF_AudioInterface *aifc, Bool for_reconf){	AudioBufferStack *st = (AudioBufferStack *) gf_node_get_private( ((GF_AudioInput *) aifc->callback)->owner);	if (gf_mixer_must_reconfig(st->am)) {		if (gf_mixer_reconfig(st->am)) {			if (st->buffer) free(st->buffer);			st->buffer = NULL;			st->buffer_size = 0;		}		gf_mixer_get_config(st->am, &aifc->sr, &aifc->chan, &aifc->bps, &aifc->ch_cfg);		st->is_init = (aifc->sr && aifc->chan && aifc->bps) ? 1 : 0;		assert(st->is_init);		if (!st->is_init) aifc->sr = aifc->chan = aifc->bps = aifc->ch_cfg = 0;		/*this will force invalidation*/		return (for_reconf && st->is_init) ? 1 : 0;	}	return st->is_init;}void AB_AddSource(GF_AudioGroup *_this, GF_AudioInput *src){	AudioBufferStack *st = (AudioBufferStack *)_this;	if (!src) return;	/*just collect the input, reconfig is done once all children are rendered*/	gf_list_add(st->new_inputs, src);}void setup_audiobufer(GF_AudioInput *ai, GF_Renderer *sr, GF_Node *node){	memset(ai, 0, sizeof(GF_AudioInput));	ai->owner = node;	ai->compositor = sr;	/*NEVER used for audio buffer*/	ai->stream = NULL;	/*setup io interface*/	ai->input_ifce.FetchFrame = AB_FetchFrame;	ai->input_ifce.ReleaseFrame = AB_ReleaseFrame;	ai->input_ifce.GetConfig = AB_GetConfig;	ai->input_ifce.GetChannelVolume = AB_GetChannelVolume;	ai->input_ifce.GetSpeed = AB_GetSpeed;	ai->input_ifce.IsMuted = AB_IsMuted;	ai->input_ifce.callback = ai;	ai->speed = FIX_ONE;}void InitAudioBuffer(GF_Renderer *sr, GF_Node *node){	AudioBufferStack *st;	GF_SAFEALLOC(st, AudioBufferStack);	/*use our private input*/	setup_audiobufer(&st->output, sr, node);	st->add_source = AB_AddSource;	st->time_handle.UpdateTimeNode = AB_UpdateTime;	st->time_handle.obj = node;	st->set_duration = 1;	st->am = gf_mixer_new(NULL);	st->new_inputs = gf_list_new();	gf_node_set_private(node, st);	gf_node_set_callback_function(node, RenderAudioBuffer);	gf_sr_register_time_node(sr, &st->time_handle);}void AudioBufferModified(GF_Node *node){	M_AudioBuffer *ab = (M_AudioBuffer *)node;	AudioBufferStack *st = (AudioBufferStack *) gf_node_get_private(node);	if (!st) return;	//update state if we're active	if (ab->isActive) 		AB_UpdateTime(&st->time_handle);	/*make sure we are still registered*/	if (!st->time_handle.is_registered && !st->time_handle.needs_unregister) 		gf_sr_register_time_node(st->output.compositor, &st->time_handle);	else		st->time_handle.needs_unregister = 0;}

⌨️ 快捷键说明

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