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

📄 audio.c

📁 xmms-1.2.10.tar.gz学习使用的就下吧
💻 C
📖 第 1 页 / 共 2 页
字号:
/****************************************************************************** * * Solaris audio plugin for XMMS *  * This file contains most of the audio routines for talking to the sound * device.  * *****************************************************************************/#include "Sun.h"#include "config.h"#include <pthread.h>#include <stropts.h>#include <unistd.h>#include <errno.h>#include <sys/file.h>#include <strings.h>#include <sys/modctl.h>#include <glib.h>#include <libxmms/util.h>#include <pthread.h>/*****************************************************************************//* This is the maximum data we're willing to send to the audio device and   when we should refill it. */#define SUN_AUDIO_CACHE 16384/*****************************************************************************/static char *buffer_ptr = NULL;static char *buffer_end = NULL;static char *buffer_read = NULL;static char *buffer_write = NULL;static int buffer_len = 0;static pthread_mutex_t buflock = PTHREAD_MUTEX_INITIALIZER;static gint time_offset = 0;static gint byte_offset = 0;static gboolean paused = FALSE;static gboolean playing = FALSE;static gboolean aopen = FALSE;static gboolean prebuffer, remove_prebuffer;static int prebuffer_size;static volatile gint flush = -1;static gint audiofd = -2;static audio_info_t adinfo;static pthread_t buffer_thread;static uint_t audio_scount = 0;static struct {    gboolean is_signed;    gboolean is_bigendian;    uint_t sample_rate;    uint_t channels;    uint_t precision;    gint bps;    gint output_precision;} stream_attrs;static AFormat input_format;/*****************************************************************************/void abuffer_shutdown(void);/*****************************************************************************/static char *get_audiodev(void){	if (sun_cfg.always_audiodev)	{		char * audiodev;		audiodev = getenv("AUDIODEV");		if (audiodev != NULL)			return audiodev;	}	return (sun_cfg.audio_device);}/* The hack in the following function relieves us of using audiotool/audiocontrol *//* in order to switch to internal CD port when playing CD Audio. 	*/int ctlfd = -1; /* Global file descriptor for /dev/audioctl usage */		int init_ctlfd(void){	char *ctlname;	int port, monitor;	audio_info_t info;	audio_device_t device;		/* Get audio device name */	ctlname = g_strconcat(get_audiodev(), "ctl", NULL);		/* Open audio control device, audio device may be in use already */    	if ((ctlfd = open(ctlname, O_RDONLY, 0)) < 0)	{		g_free(ctlname);		return -1;	}	g_free(ctlname);		/* Get audio device characteristics */	if (ioctl(ctlfd, AUDIO_GETDEV, &device) < 0)	{		close(ctlfd);		ctlfd = -1;		return -1;	}		/* We can apply the trick only for sound cards using Sun driver */		if (strcmp(device.name, "SUNW,CS4231") &&	    strcmp(device.name, "SUNW,sb16") &&	    strcmp(device.name, "SUNW,sbpro"))		return 0; /* Sun driver is not used, but it's okay */	/* Use an internal CD port if the device has one, or use line-in port */	if (ioctl(ctlfd, AUDIO_GETINFO, &info) < 0)	{        	close(ctlfd);        	ctlfd = -1;        	return -1;	}	if (info.record.avail_ports & AUDIO_INTERNAL_CD_IN) 		port = AUDIO_INTERNAL_CD_IN;	else		port = AUDIO_LINE_IN;	monitor = info.monitor_gain;		/* Initialize info structure */	AUDIO_INITINFO(&info);			/* Set port */	info.record.port = port;		/* Set monitor volume so that CD sound is audible. */	/* My tests shows that 3 is a minimum value (MZ). */	if (monitor < 3)		info.monitor_gain = AUDIO_MAX_GAIN / 2;		/* Apply changes to audio control device */	if (ioctl(ctlfd, AUDIO_SETINFO, &info) < 0)		perror(get_audiodev());		return 0;}static void audio_yield(void){	audio_info_t info;	ioctl(audiofd, AUDIO_GETINFO, &info);	while (playing && (flush == -1) && ((info.play.eof + 10) < audio_scount))	{	        xmms_usleep(10000);	        ioctl(audiofd, AUDIO_GETINFO, &info);	}}static void audio_play(char *bufferP, int length){	int written;	while (playing && (flush == -1) && (length > 0))	{		written = write(audiofd, bufferP, length);		if (written > 0)		{			length -= written;			bufferP += written;			if (write(audiofd, NULL, 0) == 0)			{				audio_scount++;				audio_yield();			}		}		else		{		        xmms_usleep(10000);		}	}}gint abuffer_get_written_time(void){	if (!playing)		return 0;    	return ((double)byte_offset * 1000.0) / stream_attrs.bps;}gint abuffer_get_output_time(void){	if (!aopen || !playing)		return 0;    	ioctl(audiofd, AUDIO_GETINFO, &adinfo);	return time_offset + ((double)adinfo.play.samples * 1000) / adinfo.play.sample_rate;}gint abuffer_used(void){	int retval;	pthread_mutex_lock(&buflock);	if(buffer_write >= buffer_read)		retval = buffer_write - buffer_read;	else		retval = buffer_len - (buffer_read - buffer_write);	pthread_mutex_unlock(&buflock);	return retval;}/* * Doesn't free the buffer. Just returns the number of bytes * in the buffer available to write. */gint abuffer_free(void){	int retval;	/*	 * Two calls to this function without a write in between,	 * means we are at the end of the stream so stop prebuffering.	 */	if (remove_prebuffer && prebuffer)	{		prebuffer = FALSE;		remove_prebuffer = FALSE;	}	if (prebuffer)		remove_prebuffer = TRUE;	/* Find the amount of buffer free (circular buffer) */	pthread_mutex_lock(&buflock);	if(buffer_write >= buffer_read)		retval = buffer_len - (buffer_write - buffer_read) - 1;	else		retval = buffer_read - buffer_write - 1;	pthread_mutex_unlock(&buflock);	return retval;}/***************************************************************************//* This copies data into the buffer, dependant on the endian-ness and sign *//***************************************************************************/void dsp_memcpy(void *dst, void *src, int len){	/**********************************************************************	 * Whether or not we have to do translations rather depends on the	 * architecture; use WORDS_BIGENDIAN to define this for us.  We want	 * this bit as optimal as is humanely possible as it is called quite	 * often; try to catch the common situation first, and less common at	 * the end.	 ***********************************************************************	 * In order to keep the flow as fast as possibly, there are few 'else'	 * statements; instead, we use a 'return' call to get out of here.	 **********************************************************************/#if WORDS_BIGENDIAN	if (stream_attrs.is_bigendian && stream_attrs.is_signed)#else /* WORDS_BIGENDIAN */	if (!stream_attrs.is_bigendian && stream_attrs.is_signed)#endif /* WORDS_BIGENDIAN */	{		/* this is the default; simply copy the data over */		memcpy(dst, src, len);		return;	}/* We have either to make an endian transformation or a sign transformation   or possibly both; which one(s)?  */#if WORDS_BIGENDIAN	if (!stream_attrs.is_bigendian)#else /* WORDS_BIGENDIAN */	if (stream_attrs.is_bigendian)#endif /* WORDS_BIGENDIAN */	{		/*		 * Endian tranformation required		 * Note that since the endianness for 8 bit samples is set to native,		 * we can assume we have a 16 bit sample What we cannot assume is the		 * sign of the data 		 */		guint16 *csrc = src, *csend = (guint16 *) ((char *) src + len);		guint16 *cdst = dst;		while (csrc < csend)		{			*cdst = GUINT16_SWAP_LE_BE(*csrc);			if (!stream_attrs.is_signed)				*cdst = (*cdst) ^ (1 << 15);			csrc++;			cdst++;		}		return;	}	/* Native endianess */	/* (!stream_attrs.is_signed) */	if (stream_attrs.precision == 16)	{		guint16 *csrc = src, *csend = (guint16 *) ((char *) src + len);		gint16 *cdst = dst;		while (csrc < csend)		{			*cdst++ = (*csrc) ^ (1 << 15);			csrc++;		}	}	else	{		guint8 *csrc = src, *csend = (guint8 *) ((char *) src + len);		gint8 *cdst = dst;		while (csrc < csend)		{			*cdst++ = (*csrc) ^  (1 << 7);			csrc++;		}	}}    gint abuffer_write_sub(void *ptr, gint length){	/* Amount to end of buffer */	int bdiff = buffer_end - buffer_write;	/* Amount of space needed or max space avail if we don't have space */	int amt = MIN(length, abuffer_free());	/* Update the byte offset */	byte_offset += amt;	/* Fill the buffer */	if (bdiff < amt)	{		dsp_memcpy(buffer_write, ptr, bdiff);		dsp_memcpy(buffer_ptr, (char *) ptr + bdiff, amt - bdiff);		pthread_mutex_lock(&buflock);		buffer_write = buffer_ptr + amt - bdiff;		pthread_mutex_unlock(&buflock);	}	else	{		dsp_memcpy(buffer_write, ptr, amt);		pthread_mutex_lock(&buflock);		buffer_write += amt;		pthread_mutex_unlock(&buflock);	}	/* Return the amount actually written */	return amt;}void abuffer_write(void *ptr, gint length){	char *iptr; 	gint amt;	void *tmp_buf;	gint tmp_buf_size;	gboolean need_free = FALSE;	AFormat new_format;	gint new_frequency, new_channels;	EffectPlugin *ep;	remove_prebuffer = FALSE;		new_format = input_format;	new_frequency = stream_attrs.sample_rate;	new_channels = stream_attrs.channels;		ep = get_current_effect_plugin();	if (effects_enabled() && ep && ep->query_format)	{		ep->query_format(&new_format,&new_frequency,&new_channels);	}		if (effects_enabled() && ep && ep->mod_samples)		length = ep->mod_samples(&ptr,length, input_format, stream_attrs.sample_rate , stream_attrs.channels);	if (new_format != input_format || new_frequency !=stream_attrs.sample_rate  || new_channels != stream_attrs.channels)	{		/* FIXME: This is in effect a flush.  Need to recalulate buffer_offset and time_offset *//*  		time_offset += (gint) ((output_bytes * 1000) / stream_attrs.bps); *//*  		output_bytes = 0; *//*  		oss_setup_format(new_format, new_frequency, new_channels); *//*  		stream_attrs.sample_rate = new_frequency; *//*  		stream_attrs.channels = new_channels; *//*  		close(fd); *//*  		fd = open(device_name,O_WRONLY); *//*  		oss_set_audio_params(); */		/* FIXME: This is leaking memory */		abuffer_open(new_format, new_frequency, new_channels);			}	/* Check if we're downsizing/upsizing the stream */	if (stream_attrs.precision != stream_attrs.output_precision)	{		gint i;		/* Flag we have allocated memory for the end */		need_free = TRUE;		if (stream_attrs.output_precision == 16)		{			/* scaling 8 => 16 */			gint8 *src = (gint8*) ptr;			gint16 *target;			tmp_buf_size = 2 * length;			tmp_buf = g_malloc(tmp_buf_size);			target = (gint16*)tmp_buf;			for (i = 0; i < length; i++)			{				target[i] = (gint16)(src[i] ^ 128) * 256;			}		}		else		{			/* scaling 16 => 8 */			gint16 *src = (gint16*) ptr;			gint8 *target;			/* note that length should be even, so no rounding req'd */			tmp_buf_size = length / 2;			tmp_buf = g_malloc(tmp_buf_size);			target = (gint8*) tmp_buf;			for (i = 0; i < length; i++)			{				target[i] = ((gint8) (src[i] / 256)) ^ 128;			}		}	}	else	{		tmp_buf = ptr;		tmp_buf_size = length;	}	iptr = tmp_buf;	/* Loop till all the data is consumed */	while (tmp_buf_size > 0)	{		/* Write out the first section */		amt = abuffer_write_sub(iptr, tmp_buf_size);		iptr += amt;		tmp_buf_size -= amt;	}	if (need_free)		g_free(tmp_buf);}void abuffer_close(void){	/* Stop the playing */	playing = FALSE;	/* Rejoin the thread */	pthread_join(buffer_thread, NULL);}void abuffer_flush(gint ftime){	flush = ftime;	/* Wait till  */	while (flush != -1)		xmms_usleep(10000);}void abuffer_pause(short p){	if (p)		paused = TRUE;	else		paused = FALSE;}gint abuffer_startup(void){	/* Open audio device if it's not already open */	if (audiofd < 0)	{		if ((audiofd = open(get_audiodev(), O_WRONLY )) == -1)		{			perror("xmms Solaris Output plugin");			return 1;		}	}	else	{		fprintf(stderr, "xmms: Warning: Attempted to reopen audio device.\n");	}	/* Initialise audio device */	abuffer_set_audio_params();	

⌨️ 快捷键说明

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