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

📄 audio_mixer.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 / Scene Rendering 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/renderer_dev.h>/*max number of channels we support in mixer*/#define GF_SR_MAX_CHANNELS	16/*	Notes about the mixer:	1- spatialization is out of scope for the mixer (eg that's the sound node responsability)	2- mixing is performed by resampling input source & deinterleaving its channels into dedicated buffer.	We could directly deinterleave in the main mixer ouput buffer, but this would prevent any future 	gain correction.*/typedef struct{	GF_AudioInterface *src;	s32 *ch_buf[GF_SR_MAX_CHANNELS];	/*resampled buffer*/	u32 buffer_size;	u32 bytes_per_sec;		Bool has_prev;	s32 last_channels[GF_SR_MAX_CHANNELS];	u32 in_bytes_used, out_samples_written, out_samples_to_write;	Fixed speed;	Fixed pan[6];} MixerInput;struct __audiomix{	/*src*/	GF_List *sources;	/*output config*/	u32 sample_rate;	u32 nb_channels;	u32 bits_per_sample;	u32 channel_cfg;	GF_Mutex *mx;	/*if set forces stereo/mono*/	Bool force_channel_out;	/*set to true by mixer when detecting an audio config change*/	Bool must_reconfig;	Bool isEmpty;	/*set to non null if this outputs directly to the driver, in which case audio formats have to be checked*/	struct _audio_render *ar;	s32 *output;	u32 output_size;};GF_AudioMixer *gf_mixer_new(struct _audio_render *ar){	GF_AudioMixer *am;	am = (GF_AudioMixer *) malloc(sizeof(GF_AudioMixer));	if (!am) return NULL;	memset(am, 0, sizeof(GF_AudioMixer));	am->mx = gf_mx_new();	am->sources = gf_list_new();	am->isEmpty = 1;	am->ar = ar;	am->sample_rate = 44100;	am->bits_per_sample = 16;	am->nb_channels = 2;	am->output = NULL;	am->output_size = 0;	return am;}Bool gf_mixer_must_reconfig(GF_AudioMixer *am) {	return am->must_reconfig;}void gf_mixer_del(GF_AudioMixer *am){	gf_list_del(am->sources);	gf_mx_del(am->mx);	if (am->output) free(am->output);	free(am);}void gf_mixer_remove_all(GF_AudioMixer *am){	u32 j;	gf_mixer_lock(am, 1);	while (gf_list_count(am->sources)) {		MixerInput *in = (MixerInput *)gf_list_get(am->sources, 0);		gf_list_rem(am->sources, 0);		for (j=0; j<GF_SR_MAX_CHANNELS; j++) {			if (in->ch_buf[j]) free(in->ch_buf[j]);		}		free(in);	}	am->isEmpty = 1,	gf_mixer_lock(am, 0);}Bool gf_mixer_is_src_present(GF_AudioMixer *am, GF_AudioInterface *ifce){	MixerInput *in;	u32 i = 0;	while ((in = (MixerInput *)gf_list_enum(am->sources, &i))) {		if (in->src == ifce) return 1;	}	return 0;}u32 gf_mixer_get_src_count(GF_AudioMixer *am){	return gf_list_count(am->sources);}void gf_mixer_force_chanel_out(GF_AudioMixer *am, u32 num_channels){	am->force_channel_out = 1;	am->nb_channels = num_channels;}u32 gf_mixer_get_block_align(GF_AudioMixer *am){	return am->nb_channels*am->bits_per_sample/8;}void gf_mixer_lock(GF_AudioMixer *am, Bool lockIt){	//GF_LOG(GF_LOG_DEBUG, GF_LOG_CORE, ("[AudioRender] Thread ID %d is %s the audio mixer\n", gf_th_id(), lockIt ? "locking" : "unlocking" ));	if (lockIt) {		gf_mx_p(am->mx);	} else {		gf_mx_v(am->mx);	}}void gf_mixer_add_input(GF_AudioMixer *am, GF_AudioInterface *src){	MixerInput *in;	if (gf_mixer_is_src_present(am, src)) return;	gf_mixer_lock(am, 1);	GF_SAFEALLOC(in, MixerInput);	in->src = src;	gf_list_add(am->sources, in);	am->must_reconfig = 1;	am->isEmpty = 0;	gf_mixer_lock(am, 0);}void gf_mixer_remove_input(GF_AudioMixer *am, GF_AudioInterface *src){	u32 i, j, count;	if (am->isEmpty) return;	gf_mixer_lock(am, 1);	count = gf_list_count(am->sources);	for (i=0; i<count; i++) {		MixerInput *in = (MixerInput *)gf_list_get(am->sources, i);		if (in->src != src) continue;		gf_list_rem(am->sources, i);		for (j=0; j<GF_SR_MAX_CHANNELS; j++) {			if (in->ch_buf[j]) free(in->ch_buf[j]);		}		free(in);		break;	}	am->isEmpty = gf_list_count(am->sources) ? 0 : 1;	/*we don't ask for reconfig when removing a node*/	gf_mixer_lock(am, 0);}static GF_Err get_best_samplerate(GF_AudioMixer *am, u32 *out_sr, u32 *out_ch, u32 *out_bps){	if (!am->ar) return GF_OK;	if (!am->ar->audio_out || !am->ar->audio_out->QueryOutputSampleRate) return GF_OK;	return am->ar->audio_out->QueryOutputSampleRate(am->ar->audio_out, out_sr, out_ch, out_bps);}void gf_mixer_get_config(GF_AudioMixer *am, u32 *outSR, u32 *outCH, u32 *outBPS, u32 *outChCfg){	(*outBPS) = am->bits_per_sample;	(*outCH) = am->nb_channels;	(*outSR) = am->sample_rate;	(*outChCfg) = am->channel_cfg;}void gf_mixer_set_config(GF_AudioMixer *am, u32 outSR, u32 outCH, u32 outBPS, u32 outChCfg){	if ((am->bits_per_sample == outBPS) && (am->nb_channels == outCH) 		&& (am->sample_rate==outSR) && (am->channel_cfg == outChCfg)) return;	gf_mixer_lock(am, 1);	am->bits_per_sample = outBPS;	if (!am->force_channel_out) am->nb_channels = outCH;	if (get_best_samplerate(am, &outSR, &outCH, &outBPS) == GF_OK) {		am->sample_rate = outSR;		if (outCH>2) am->channel_cfg = outChCfg;		else if (outCH==2) am->channel_cfg = GF_AUDIO_CH_FRONT_LEFT | GF_AUDIO_CH_FRONT_RIGHT;		else am->channel_cfg = GF_AUDIO_CH_FRONT_LEFT;	}	/*if main mixer recfg output*/	if (am->ar)	am->ar->need_reconfig = 1;	gf_mixer_lock(am, 0);}Bool gf_mixer_reconfig(GF_AudioMixer *am){	u32 i, count, numInit, max_sample_rate, max_channels, max_bps, cfg_changed, ch_cfg;	gf_mixer_lock(am, 1);	if (am->isEmpty || !am->must_reconfig) {		gf_mixer_lock(am, 0);		return 0;	}	numInit = 0;	max_sample_rate = am->sample_rate;	max_channels = am->nb_channels;	max_bps = am->bits_per_sample;	cfg_changed = 0;	ch_cfg = 0;	max_sample_rate = 0,	count = gf_list_count(am->sources);	assert(count);	for (i=0; i<count; i++) {		Bool has_cfg;		MixerInput *in = (MixerInput *) gf_list_get(am->sources, i);		has_cfg = in->src->GetConfig(in->src, 1);		if (has_cfg) {			/*check same cfg...*/			if (in->src->sr * in->src->chan * in->src->bps == 8*in->bytes_per_sec) {				numInit++;				continue;			}		} else continue;		/*update out cfg*/		if ((count==1) && (max_sample_rate != in->src->sr)) {//			cfg_changed = 1;			max_sample_rate = in->src->sr;		} else if (max_sample_rate<in->src->sr) {//			cfg_changed = 1;			max_sample_rate = in->src->sr;		}		if ((count==1) && (max_bps!=in->src->bps)) {			cfg_changed = 1;			max_bps = in->src->bps;		} else if (max_bps<in->src->bps) {			cfg_changed = 1;			max_bps = in->src->bps;		}		if (!am->force_channel_out) {			if ((count==1) && (max_channels!=in->src->chan)) {				cfg_changed = 1;				max_channels = in->src->chan;				if (in->src->chan>2) ch_cfg |= in->src->ch_cfg;			} else if (max_channels < in->src->chan) {				cfg_changed = 1;				max_channels = in->src->chan;				if (in->src->chan>2) ch_cfg |= in->src->ch_cfg;			}		}		numInit++;		in->bytes_per_sec = in->src->sr * in->src->chan * in->src->bps / 8;		/*cfg has changed, we must reconfig everything*/		if (cfg_changed || (max_sample_rate != am->sample_rate) ) {			in->has_prev = 0;			memset(&in->last_channels, 0, sizeof(s16)*GF_SR_MAX_CHANNELS);		}	}		if (cfg_changed || (max_sample_rate && (max_sample_rate != am->sample_rate)) ) {		if (max_channels>2) {			if (ch_cfg != am->channel_cfg) {				/*recompute num channel based on all input channels*/				max_channels = 0;				if (ch_cfg & GF_AUDIO_CH_FRONT_LEFT) max_channels ++;				if (ch_cfg & GF_AUDIO_CH_FRONT_RIGHT) max_channels ++;				if (ch_cfg & GF_AUDIO_CH_FRONT_CENTER) max_channels ++;				if (ch_cfg & GF_AUDIO_CH_LFE) max_channels ++;				if (ch_cfg & GF_AUDIO_CH_BACK_LEFT) max_channels ++;				if (ch_cfg & GF_AUDIO_CH_BACK_RIGHT) max_channels ++;				if (ch_cfg & GF_AUDIO_CH_BACK_CENTER) max_channels ++;				if (ch_cfg & GF_AUDIO_CH_SIDE_LEFT) max_channels ++;				if (ch_cfg & GF_AUDIO_CH_SIDE_RIGHT) max_channels ++;			}		} else {			ch_cfg = GF_AUDIO_CH_FRONT_LEFT;			if (max_channels==2) ch_cfg |= GF_AUDIO_CH_FRONT_RIGHT;		}		gf_mixer_set_config(am, max_sample_rate, max_channels, max_bps, ch_cfg);	}		if (numInit == count) am->must_reconfig = 0;	gf_mixer_lock(am, 0);	return cfg_changed;}static GFINLINE u32 get_channel_out_pos(u32 in_ch, u32 out_cfg){	u32 i, cfg, pos;	pos = 0;	for (i=0; i<9; i++) {		cfg = 1<<(i);		if (out_cfg & cfg) {			if (cfg == in_ch) return pos;			pos++;		}	}	return GF_SR_MAX_CHANNELS;}/*this is crude, we'd need a matrix or something*/static GFINLINE void am_map_channels(s32 *inChan, u32 nb_in, u32 in_cfg, u32 nb_out, u32 out_cfg){	u32 i;	if (nb_in==1) {		/*mono to stereo*/		if (nb_out==2) {			inChan[1] = inChan[0];		}		else if (nb_out>2) {			/*if center channel use it (we assume we always have stereo channels)*/			if (out_cfg & GF_AUDIO_CH_FRONT_CENTER) {				inChan[2] = inChan[0];				inChan[0] = 0;				for (i=3; i<nb_out; i++) inChan[i] = 0;			} else {				/*mono to stereo*/				inChan[1] = inChan[0];				for (i=2; i<nb_out; i++) inChan[i] = 0;			}		}	} else if (nb_in==2) {		if (nb_out==1) {			inChan[0] = (inChan[0]+inChan[1])/2;		} else {			for (i=2; i<nb_out; i++) inChan[i] = 0;		}	}	/*same output than input channels, nothing to reorder*/	/*more output than input channels*/	else if (nb_in<nb_out) {		s32 bckup[GF_SR_MAX_CHANNELS];		u32 pos;		u32 cfg = in_cfg;		u32 ch = 0;		memcpy(bckup, inChan, sizeof(s32)*nb_in);		for (i=0; i<nb_in; i++) {			/*get first in channel*/			while (! (cfg & 1)) {				ch++;				cfg>>=1;

⌨️ 快捷键说明

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