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

📄 alsa.c

📁 linphone 网络电话 linphone 网络电话 linphone 网络电话
💻 C
📖 第 1 页 / 共 2 页
字号:
/*mediastreamer2 library - modular sound and video processing and streamingCopyright (C) 2006  Simon MORLAT (simon.morlat@linphone.org)This program is free software; you can redistribute it and/ormodify it under the terms of the GNU General Public Licenseas published by the Free Software Foundation; either version 2of the License, or (at your option) any later version.This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with this program; if not, write to the Free SoftwareFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.*/#include <alsa/asoundlib.h>#include "mediastreamer2/msfilter.h"#include "mediastreamer2/mssndcard.h"/*uncomment the following line if you have problems with an alsa driverhaving sound quality trouble:*//*#define EPIPE_BUGFIX 1*/static MSSndCard * alsa_card_new(int id);static MSSndCard *alsa_card_duplicate(MSSndCard *obj);static MSFilter * ms_alsa_read_new(const char *dev);static MSFilter * ms_alsa_write_new(const char *dev);struct _AlsaData{	char *pcmdev;	char *mixdev;};typedef struct _AlsaData AlsaData;static int alsa_set_params(snd_pcm_t *pcm_handle, int rw, int bits, int stereo, int rate){	snd_pcm_hw_params_t *hwparams=NULL;	snd_pcm_sw_params_t *swparams=NULL;	int dir;	uint exact_uvalue;	unsigned long exact_ulvalue;	int channels;	int periods=8;	int periodsize=256;	int err;	int format;		/* Allocate the snd_pcm_hw_params_t structure on the stack. */	snd_pcm_hw_params_alloca(&hwparams);		/* Init hwparams with full configuration space */	if (snd_pcm_hw_params_any(pcm_handle, hwparams) < 0) {		ms_warning("alsa_set_params: Cannot configure this PCM device.\n");		return -1;	}		if (snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) {		ms_warning("alsa_set_params: Error setting access.\n");		return -1;	}	/* Set sample format */	format=SND_PCM_FORMAT_S16;	if (snd_pcm_hw_params_set_format(pcm_handle, hwparams, format) < 0) {		ms_warning("alsa_set_params: Error setting format.\n");		return -1;	}	/* Set number of channels */	if (stereo) channels=2;	else channels=1;	if (snd_pcm_hw_params_set_channels(pcm_handle, hwparams, channels) < 0) {		ms_warning("alsa_set_params: Error setting channels.\n");		return -1;	}	/* Set sample rate. If the exact rate is not supported */	/* by the hardware, use nearest possible rate.         */ 	exact_uvalue=rate;	dir=0;	if ((err=snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &exact_uvalue, &dir))<0){		ms_warning("alsa_set_params: Error setting rate to %i:%s",rate,snd_strerror(err));		return -1;	}	if (dir != 0) {		ms_warning("alsa_set_params: The rate %d Hz is not supported by your hardware.\n "		"==> Using %d Hz instead.\n", rate, exact_uvalue);	}	/* choose greater period size when rate is high */	periodsize=periodsize*(rate/8000);			/* Set buffer size (in frames). The resulting latency is given by */	/* latency = periodsize * periods / (rate * bytes_per_frame)     */	/* set period size */	exact_ulvalue=periodsize;	dir=0;	if (snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, &exact_ulvalue, &dir) < 0) {		ms_warning("alsa_set_params: Error setting period size.\n");		return -1;	}	if (dir != 0) {		ms_warning("alsa_set_params: The period size %d is not supported by your hardware.\n "		"==> Using %d instead.\n", periodsize, (int)exact_ulvalue);	}	periodsize=exact_ulvalue;	/* Set number of periods. Periods used to be called fragments. */ 	exact_uvalue=periods;	dir=0;	if (snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, &exact_uvalue, &dir) < 0) {		ms_warning("alsa_set_params: Error setting periods.\n");		return -1;	}	if (dir != 0) {		ms_warning("alsa_set_params: The number of periods %d is not supported by your hardware.\n "		"==> Using %d instead.\n", periods, exact_uvalue);	}	/* Apply HW parameter settings to */	/* PCM device and prepare device  */	if ((err=snd_pcm_hw_params(pcm_handle, hwparams)) < 0) {		ms_warning("alsa_set_params: Error setting HW params:%s",snd_strerror(err));		return -1;	}	/*prepare sw params */	if (rw){		snd_pcm_sw_params_alloca(&swparams);		snd_pcm_sw_params_current(pcm_handle, swparams);		if ((err=snd_pcm_sw_params_set_start_threshold(pcm_handle, swparams,periodsize*2 ))<0){			ms_warning("alsa_set_params: Error setting start threshold:%s",snd_strerror(err));			return -1;		}		if ((err=snd_pcm_sw_params(pcm_handle, swparams))<0){			ms_warning("alsa_set_params: Error setting SW params:%s",snd_strerror(err));			return -1;		}	}	return 0;	}#ifdef EPIPE_BUGFIXstatic void alsa_fill_w (snd_pcm_t *pcm_handle){	snd_pcm_hw_params_t *hwparams=NULL;	int channels;        snd_pcm_uframes_t buffer_size;	int buffer_size_bytes;	void *buffer;	/* Allocate the snd_pcm_hw_params_t structure on the stack. */	snd_pcm_hw_params_alloca(&hwparams);	snd_pcm_hw_params_current(pcm_handle, hwparams);	/* get channels */	snd_pcm_hw_params_get_channels (hwparams, &channels);	/* get buffer size */	snd_pcm_hw_params_get_buffer_size (hwparams, &buffer_size);	/* fill half */	buffer_size /= 2;	/* allocate buffer assuming 2 bytes per sample */	buffer_size_bytes = buffer_size * channels * 2;	buffer = alloca (buffer_size_bytes);	memset (buffer, 0, buffer_size_bytes);	/* write data */	snd_pcm_writei(pcm_handle, buffer, buffer_size);}#endifstatic snd_pcm_t * alsa_open_r(const char *pcmdev,int bits,int stereo,int rate){	snd_pcm_t *pcm_handle;	int err;	ms_message("alsa_open_r: opening %s at %iHz, bits=%i, stereo=%i",pcmdev,rate,bits,stereo);	if (snd_pcm_open(&pcm_handle, pcmdev,SND_PCM_STREAM_CAPTURE,SND_PCM_NONBLOCK) < 0) {		ms_warning("alsa_open_r: Error opening PCM device %s\n",pcmdev );		return NULL;	}	if (alsa_set_params(pcm_handle,0,bits,stereo,rate)<0){		snd_pcm_close(pcm_handle);		return NULL;	}	err=snd_pcm_start(pcm_handle);	if (err<0){		ms_warning("snd_pcm_start() failed: %s", snd_strerror(err));	}	return pcm_handle;}static snd_pcm_t * alsa_open_w(const char *pcmdev,int bits,int stereo,int rate){	snd_pcm_t *pcm_handle;		if (snd_pcm_open(&pcm_handle, pcmdev,SND_PCM_STREAM_PLAYBACK,SND_PCM_NONBLOCK) < 0) {		ms_warning("alsa_open_w: Error opening PCM device %s\n",pcmdev );		return NULL;	}	if (alsa_set_params(pcm_handle,1,bits,stereo,rate)<0){		snd_pcm_close(pcm_handle);		return NULL;	}	return pcm_handle;}static int alsa_read(snd_pcm_t *handle,unsigned char *buf,int nsamples){	int err;	err=snd_pcm_readi(handle,buf,nsamples);	if (err<0) {		if (err==-EPIPE){			snd_pcm_prepare(handle);			err=snd_pcm_readi(handle,buf,nsamples);			if (err<0) ms_warning("alsa_read: snd_pcm_readi() failed:%s.",snd_strerror(err));		}else if (err!=-EWOULDBLOCK){			ms_warning("alsa_read: snd_pcm_readi() failed:%s.",snd_strerror(err));		}	}else if (err==0){		ms_warning("alsa_read: snd_pcm_readi() returned 0");	}	return err;}static int alsa_write(snd_pcm_t *handle,unsigned char *buf,int nsamples){	int err;	if ((err=snd_pcm_writei(handle,buf,nsamples))<0){		if (err==-EPIPE){			snd_pcm_prepare(handle);#ifdef EPIPE_BUGFIX			alsa_fill_w (handle);#endif			err=snd_pcm_writei(handle,buf,nsamples);			if (err<0) ms_warning("alsa_card_write: Error writing sound buffer (nsamples=%i):%s",nsamples,snd_strerror(err));		}else if (err!=-EWOULDBLOCK){			ms_warning("alsa_card_write: snd_pcm_writei() failed:%s.",snd_strerror(err));		}	}else if (err!=nsamples) {		ms_debug("Only %i samples written instead of %i",err,nsamples);	}	return err;}static snd_mixer_t *alsa_mixer_open(const char *mixdev){	snd_mixer_t *mixer=NULL;	int err;	err=snd_mixer_open(&mixer,0);	if (err<0){		ms_warning("Could not open alsa mixer: %s",snd_strerror(err));		return NULL;	}	if ((err = snd_mixer_attach (mixer, mixdev)) < 0){		ms_warning("Could not attach mixer to card: %s",snd_strerror(err));		snd_mixer_close(mixer);		return NULL;	}	if ((err = snd_mixer_selem_register (mixer, NULL, NULL)) < 0){		ms_warning("snd_mixer_selem_register: %s",snd_strerror(err));		snd_mixer_close(mixer);		return NULL;	}	if ((err = snd_mixer_load (mixer)) < 0){		ms_warning("snd_mixer_load: %s",snd_strerror(err));		snd_mixer_close(mixer);		return NULL;	}	return mixer;}static void alsa_mixer_close(snd_mixer_t *mix){	snd_mixer_close(mix);}typedef enum {CAPTURE, PLAYBACK, CAPTURE_SWITCH, PLAYBACK_SWITCH} MixerAction;static int get_mixer_element(snd_mixer_t *mixer,const char *name, MixerAction action){	long value=0;	const char *elemname;	snd_mixer_elem_t *elem;	int err;	long sndMixerPMin=0;	long sndMixerPMax=0;	long newvol=0;	elem=snd_mixer_first_elem(mixer);	while (elem!=NULL){		elemname=snd_mixer_selem_get_name(elem);		//g_message("Found alsa mixer element %s.",elemname);		if (strcmp(elemname,name)==0){			switch (action){				case CAPTURE:				if (snd_mixer_selem_has_capture_volume(elem)){					snd_mixer_selem_get_capture_volume_range(elem, &sndMixerPMin, &sndMixerPMax);					err=snd_mixer_selem_get_capture_volume(elem,SND_MIXER_SCHN_UNKNOWN,&newvol);					newvol-=sndMixerPMin;					value=(100*newvol)/(sndMixerPMax-sndMixerPMin);					if (err<0) ms_warning("Could not get capture volume for %s:%s",name,snd_strerror(err));					//else ms_message("Succesfully get capture level for %s.",elemname);					break;				}				break;				case PLAYBACK:				if (snd_mixer_selem_has_playback_volume(elem)){					snd_mixer_selem_get_playback_volume_range(elem, &sndMixerPMin, &sndMixerPMax);					err=snd_mixer_selem_get_playback_volume(elem,SND_MIXER_SCHN_FRONT_LEFT,&newvol);					newvol-=sndMixerPMin;					value=(100*newvol)/(sndMixerPMax-sndMixerPMin);					if (err<0) ms_warning("Could not get playback volume for %s:%s",name,snd_strerror(err));					//else g_message("Succesfully get playback level for %s.",elemname);					break;				}				break;				case CAPTURE_SWITCH:								break;				case PLAYBACK_SWITCH:				break;			}		}		elem=snd_mixer_elem_next(elem);	}		return value;}static void set_mixer_element(snd_mixer_t *mixer,const char *name, int level,MixerAction action){	const char *elemname;	snd_mixer_elem_t *elem;	long sndMixerPMin=0;	long sndMixerPMax=0;	long newvol=0;		elem=snd_mixer_first_elem(mixer);		while (elem!=NULL){		elemname=snd_mixer_selem_get_name(elem);		//g_message("Found alsa mixer element %s.",elemname);		if (strcmp(elemname,name)==0){			switch(action){				case CAPTURE:				if (snd_mixer_selem_has_capture_volume(elem)){					snd_mixer_selem_get_capture_volume_range(elem, &sndMixerPMin, &sndMixerPMax);					newvol=(((sndMixerPMax-sndMixerPMin)*level)/100)+sndMixerPMin;					snd_mixer_selem_set_capture_volume_all(elem,newvol);					//g_message("Succesfully set capture level for %s.",elemname);					return;				}				break;				case PLAYBACK:				if (snd_mixer_selem_has_playback_volume(elem)){					snd_mixer_selem_get_playback_volume_range(elem, &sndMixerPMin, &sndMixerPMax);					newvol=(((sndMixerPMax-sndMixerPMin)*level)/100)+sndMixerPMin;					snd_mixer_selem_set_playback_volume_all(elem,newvol);					//g_message("Succesfully set playback level for %s.",elemname);					return;				}				break;				case CAPTURE_SWITCH:				if (snd_mixer_selem_has_capture_switch(elem)){					snd_mixer_selem_set_capture_switch_all(elem,level);					//g_message("Succesfully set capture switch for %s.",elemname);				}				break;				case PLAYBACK_SWITCH:

⌨️ 快捷键说明

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