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

📄 audio.c

📁 xmms-1.2.10.tar.gz学习使用的就下吧
💻 C
📖 第 1 页 / 共 2 页
字号:
/*  XMMS - ALSA output plugin *  Copyright (C) 2001-2003 Matthieu Sozeau <mattam@altern.org> *  Copyright (C) 1998-2003  Peter Alm, Mikael Alm, Olle Hallnas, *                           Thomas Nilsson and 4Front Technologies *  Copyright (C) 1999-2004  Haavard Kvaalen * *  This program is free software; you can redistribute it and/or modify *  it under the terms of the GNU General Public License as published by *  the Free Software Foundation; either version 2 of 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 of *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *  GNU General Public License for more details. * *  You should have received a copy of the GNU General Public License *  along with this program; if not, write to the Free Software *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */#include "alsa.h"#include <ctype.h>#include <libxmms/xconvert.h>static snd_pcm_t		*alsa_pcm 	    = NULL;static snd_pcm_status_t		*alsa_status 	    = NULL;static snd_pcm_channel_area_t   *areas              = NULL;static snd_output_t		*logs 		    = NULL;static int 			 alsa_bps 	    = 0;static guint64			 alsa_total_written = 0;/* Set/Get volume */static snd_mixer_elem_t 	*pcm_element 	    = NULL;static snd_mixer_t 		*mixer 		    = NULL;static gboolean mmap, force_start, going, paused;static gpointer buffer;static int alsa_can_pause;struct snd_format {	unsigned int rate;	unsigned int channels;	snd_pcm_format_t format;	AFormat xmms_format;};static struct snd_format *inputf = NULL;static struct snd_format *effectf = NULL;static struct snd_format *outputf = NULL;static int alsa_setup(struct snd_format *f);static void alsa_mmap_audio(char *data, int length);static void alsa_write_audio(gpointer data, int length);static struct snd_format * snd_format_from_xmms(AFormat fmt, int rate, int channels);static struct xmms_convert_buffers *convertb;static convert_func_t alsa_convert_func;static convert_channel_func_t alsa_stereo_convert_func;static convert_freq_func_t alsa_frequency_convert_func;static const struct {	AFormat xmms;	snd_pcm_format_t alsa;} format_table[] ={{FMT_S16_LE, SND_PCM_FORMAT_S16_LE}, {FMT_S16_BE, SND_PCM_FORMAT_S16_BE}, {FMT_S16_NE,#ifdef WORDS_BIGENDIAN  SND_PCM_FORMAT_S16_BE#else  SND_PCM_FORMAT_S16_LE#endif }, {FMT_U16_LE, SND_PCM_FORMAT_U16_LE}, {FMT_U16_BE, SND_PCM_FORMAT_U16_BE}, {FMT_U16_NE,#ifdef WORDS_BIGENDIAN  SND_PCM_FORMAT_U16_BE#else  SND_PCM_FORMAT_U16_LE#endif }, {FMT_U8, SND_PCM_FORMAT_U8}, {FMT_S8, SND_PCM_FORMAT_S8},};static void debug(char *str, ...) G_GNUC_PRINTF(1, 2);static void debug(char *str, ...){	va_list args;	if (alsa_cfg.debug)	{		va_start(args, str);		g_logv(NULL, G_LOG_LEVEL_MESSAGE, str, args);		va_end(args);	}}int alsa_playing(void){	if (!going || paused)		return FALSE;	return(snd_pcm_state(alsa_pcm) == SND_PCM_STATE_RUNNING);}static void xrun_recover(void){	int err;	if (alsa_cfg.debug)	{		snd_pcm_status_alloca(&alsa_status);		if ((err = snd_pcm_status(alsa_pcm, alsa_status)) < 0)			g_warning("xrun_recover(): snd_pcm_status() failed");		else		{			printf("Status:\n");			snd_pcm_status_dump(alsa_status, logs);		}	}	if (snd_pcm_state(alsa_pcm) == SND_PCM_STATE_XRUN)	{		if ((err = snd_pcm_prepare(alsa_pcm)) < 0)			g_warning("xrun_recover(): snd_pcm_prepare() failed.");	}}static snd_pcm_sframes_t alsa_get_avail(void){	snd_pcm_sframes_t ret;	if ((ret = snd_pcm_avail_update(alsa_pcm)) == -EPIPE)		xrun_recover();	else if (ret < 0)	{		g_warning("alsa_get_avail(): snd_pcm_avail_update() failed: %s",			  snd_strerror(-ret));		return 0;	}	else		return ret;	if ((ret = snd_pcm_avail_update(alsa_pcm)) < 0)	{		g_warning("alsa_get_avail(): snd_pcm_avail_update() failed: %s",			  snd_strerror(-ret));		return 0;	}	return ret;}int alsa_free(void){	if (paused)		return 0;	else	{		int err;		if (force_start &&		    snd_pcm_state(alsa_pcm) == SND_PCM_STATE_PREPARED)		{			if ((err = snd_pcm_start(alsa_pcm)) < 0)				g_warning("alsa_free(): snd_pcm_start() "					  "failed: %s", snd_strerror(-err));			else				debug("Stream started");		}		force_start = TRUE;		return snd_pcm_frames_to_bytes(alsa_pcm, alsa_get_avail());	}}void alsa_pause(short p){	debug("alsa_pause");	if (p)		paused = TRUE;	if (alsa_can_pause)		snd_pcm_pause(alsa_pcm, p);	else if (p)		snd_pcm_drop(alsa_pcm);	if (!p)		paused = FALSE;}void alsa_close(void){	int err, started;	debug("Closing device");	started = going;	going = 0;	pcm_element = NULL;	if (mixer)	{		snd_mixer_close(mixer);		mixer = NULL;	}	if (alsa_pcm != NULL)	{		if (started)			if ((err = snd_pcm_drop(alsa_pcm)) < 0)				g_warning("alsa_pcm_drop() failed: %s",					  snd_strerror(-err));		if ((err = snd_pcm_close(alsa_pcm)) < 0)			g_warning("alsa_pcm_close() failed: %s",				  snd_strerror(-err));		alsa_pcm = NULL;	}	if (mmap) {		g_free(buffer);		buffer = NULL;		g_free(areas);		areas = NULL;	}	xmms_convert_buffers_destroy(convertb);	convertb = NULL;	g_free(inputf);	inputf = NULL;	g_free(effectf);	effectf = NULL;	alsa_save_config();	debug("Device closed");}static void alsa_reopen(struct snd_format *f){	unsigned int tmp = alsa_get_written_time();	if (alsa_pcm != NULL)	{		snd_pcm_close(alsa_pcm);		alsa_pcm = NULL;	}	if (mmap) {		g_free(buffer);		buffer = NULL;				g_free(areas);		areas = NULL;	}	if (alsa_setup(f) < 0)		g_warning("Failed to reopen the audio device");	alsa_total_written = tmp;	snd_pcm_prepare(alsa_pcm);}void alsa_flush(int time){	alsa_total_written = (guint64) time * alsa_bps / 1000;}static void parse_mixer_name(char *str, char **name, int *index){	char *end;	while (isspace(*str))		str++;	if ((end = strchr(str, ',')) != NULL)	{		*name = g_strndup(str, end - str);		end++;		*index = atoi(end);	}	else	{		*name = g_strdup(str);		*index = 0;	}}int alsa_get_mixer(snd_mixer_t **mixer, int card) {	char *dev;	int err;		debug("alsa_get_mixer");		dev = g_strdup_printf("hw:%i", card);	if ((err = snd_mixer_open(mixer, 0)) < 0)	{		g_warning("alsa_get_mixer(): Failed to open empty mixer: %s",			  snd_strerror(-err));		mixer = NULL;		return -1;	}	if ((err = snd_mixer_attach(*mixer, dev)) < 0)	{		g_warning("alsa_get_mixer(): Attaching to mixer %s failed: %s",			  dev, snd_strerror(-err));		return -1;	}	if ((err = snd_mixer_selem_register(*mixer, NULL, NULL)) < 0)	{		g_warning("alsa_get_mixer(): Failed to register mixer: %s",			  snd_strerror(-err));		return -1;	}	if ((err = snd_mixer_load(*mixer)) < 0)	{		g_warning("alsa_get_mixer(): Failed to load mixer: %s",			  snd_strerror(-err));		return -1;	}		g_free(dev);	return (*mixer != NULL);}	snd_mixer_elem_t* alsa_get_mixer_elem(snd_mixer_t *mixer, char *name, int index){	snd_mixer_selem_id_t *selem_id;	snd_mixer_elem_t* elem;	snd_mixer_selem_id_alloca(&selem_id);	if (index != -1)		snd_mixer_selem_id_set_index(selem_id, index);	if (name != NULL)		snd_mixer_selem_id_set_name(selem_id, name);	elem = snd_mixer_find_selem(mixer, selem_id);		return elem;}int alsa_setup_mixer(void){	char *name;	long int a, b;	long alsa_min_vol, alsa_max_vol;	int err, index;	debug("alsa_setup_mixer");		if ((err = alsa_get_mixer(&mixer, alsa_cfg.mixer_card)) < 0)		return err;	parse_mixer_name(alsa_cfg.mixer_device, &name, &index);		pcm_element = alsa_get_mixer_elem(mixer, name, index);		g_free(name);		if (!pcm_element)	{		g_warning("alsa_setup_mixer(): Failed to find mixer element: %s",			  alsa_cfg.mixer_device);		return -1;	}	/*	 * Work around a bug in alsa-lib up to 1.0.0rc2 where the	 * new range don't take effect until the volume is changed.	 * This hack should be removed once we depend on Alsa 1.0.0.	 */	snd_mixer_selem_get_playback_volume(pcm_element,					    SND_MIXER_SCHN_FRONT_LEFT, &a);	snd_mixer_selem_get_playback_volume(pcm_element,					    SND_MIXER_SCHN_FRONT_RIGHT, &b);	snd_mixer_selem_get_playback_volume_range(pcm_element,						  &alsa_min_vol, &alsa_max_vol);	snd_mixer_selem_set_playback_volume_range(pcm_element, 0, 100);	if (alsa_max_vol == 0)	{		pcm_element = NULL;		return -1;	}	if (!alsa_cfg.soft_volume)		alsa_set_volume(a * 100 / alsa_max_vol, b * 100 / alsa_max_vol);	debug("alsa_setup_mixer: end");	return 0;}void alsa_get_volume(int *l, int *r){	static gboolean first = TRUE;	long ll = *l, lr = *r;	if (first)	{		alsa_setup_mixer();		first = !first;	}	if (!pcm_element)		return;	snd_mixer_handle_events(mixer);	if (alsa_cfg.soft_volume)	{		*l = alsa_cfg.vol.left;		*r = alsa_cfg.vol.right;	}	else	{		snd_mixer_selem_get_playback_volume(pcm_element,						    SND_MIXER_SCHN_FRONT_LEFT,						    &ll);		snd_mixer_selem_get_playback_volume(pcm_element,						    SND_MIXER_SCHN_FRONT_RIGHT,						    &lr);		*l = ll;		*r = lr;	}}void alsa_set_volume(int l, int r){	if (!pcm_element)		return;	if (alsa_cfg.soft_volume)	{		alsa_cfg.vol.left = l;		alsa_cfg.vol.right = r;	}	else	{		snd_mixer_selem_set_playback_volume(pcm_element,						    SND_MIXER_SCHN_FRONT_LEFT, l);		snd_mixer_selem_set_playback_volume(pcm_element,						    SND_MIXER_SCHN_FRONT_RIGHT, r);	}}int alsa_get_output_time(void){	snd_pcm_sframes_t delay;	ssize_t db = 0;	if (!going)		return 0;	if (!snd_pcm_delay(alsa_pcm, &delay))		db = snd_pcm_frames_to_bytes(alsa_pcm, delay);		if (db < alsa_total_written)		return ((alsa_total_written - db) * 1000 / alsa_bps);	return 0;}int alsa_get_written_time(void){	return (alsa_total_written * 1000 / alsa_bps);}#define STEREO_ADJUST(type, type2, endian)					\do {										\	type *ptr = data;							\	for (i = 0; i < length; i += 4)						\	{									\		*ptr = type2##_TO_##endian(type2##_FROM_## endian(*ptr) *	\					   alsa_cfg.vol.left / 100);		\		ptr++;								\		*ptr = type2##_TO_##endian(type2##_FROM_##endian(*ptr) *	\					   alsa_cfg.vol.right / 100);		\		ptr++;								\	}									\} while (0)#define MONO_ADJUST(type, type2, endian)					\do {										\	type *ptr = data;							\	for (i = 0; i < length; i += 4)						\	{									\		*ptr = type2##_TO_##endian(type2##_FROM_## endian(*ptr) *	\					   vol / 100);				\		ptr++;								\	}									\} while (0)#define VOLUME_ADJUST(type, type2, endian)		\do {							\	if (channels == 2)				\		STEREO_ADJUST(type, type2, endian);	\	else						\		MONO_ADJUST(type, type2, endian);	\} while (0)	#define STEREO_ADJUST8(type)				\do {							\

⌨️ 快捷键说明

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