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

📄 cdaudio.c

📁 xmms-1.2.10.tar.gz学习使用的就下吧
💻 C
📖 第 1 页 / 共 2 页
字号:
/*  XMMS - Cross-platform multimedia player *  Copyright (C) 1998-2003  Peter Alm, Mikael Alm, Olle Hallnas, *                           Thomas Nilsson and 4Front Technologies *  Copyright (C) 1999-2003  Haavard Kvaalen <havardk@xmms.org> * *  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 "cdaudio.h"#include <pthread.h>#include <errno.h>#include "xmms/i18n.h"#include "libxmms/util.h"#include "libxmms/titlestring.h"#ifdef CDROMSTOP# define XMMS_STOP CDROMSTOP#elif defined CDIOCSTOP# define XMMS_STOP CDIOCSTOP#else# error "No stop ioctl"#endif#ifdef CDIOCPAUSE# define XMMS_PAUSE CDIOCPAUSE#elif defined CDROMPAUSE# define XMMS_PAUSE CDROMPAUSE#else# error "No pause ioctl"#endif#ifdef CDIOCRESUME# define XMMS_RESUME CDIOCRESUME#elif defined CDROMRESUME# define XMMS_RESUME CDROMRESUME#else# error "No resume ioctl"#endif/* * Distributions should not patch this, but instead use the * --with-cdda-device=path and --with-cdda-dir=path configure options. */#ifndef CDDA_DEVICE# ifdef HAVE_SYS_CDIO_H#  ifdef __FreeBSD__#   define CDDA_DEVICE "/dev/acd0"#  elif defined __OpenBSD__#   define CDDA_DEVICE "/dev/cd0c"#  else#   define CDDA_DEVICE "/vol/dev/aliases/cdrom0"#  endif# else#   define CDDA_DEVICE "/dev/cdrom"# endif#endif#ifndef CDDA_DIRECTORY# ifdef HAVE_SYS_CDIO_H#  ifdef __FreeBSD__#   define CDDA_DIRECTORY "/cdrom"#  elif defined __OpenBSD__#   define CDDA_DIRECTORY "/cdrom"#  else#   define CDDA_DIRECTORY "/cdrom/cdrom0"#  endif# else#   define CDDA_DIRECTORY "/mnt/cdrom"# endif#endifstatic char * cdda_get_title(cdda_disc_toc_t *toc, int track);static gboolean stop_timeout(gpointer data);static void cdda_init(void);static int is_our_file(char *filename);static GList *scan_dir(char *dir);static void play_file(char *filename);static void stop(void);static void cdda_pause(short p);static void seek(int time);static int get_time(void);static void get_song_info(char *filename, char **title, int *length);static void get_volume(int *l, int *r);static void set_volume(int l, int r);static void cleanup(void);void cdda_fileinfo(char *filename);InputPlugin cdda_ip ={	NULL,	NULL,	NULL, /* Description */	cdda_init,	NULL,				/* about */	cdda_configure,	is_our_file,	scan_dir,	play_file,	stop,	cdda_pause,	seek,	NULL,				/* set_eq */	get_time,	get_volume,	set_volume,	cleanup,	NULL,				/* obsolete */	NULL,				/* add_vis_pcm */	NULL,				/* set_info, filled in by xmms */	NULL,				/* set_info_text, filled in by xmms */	get_song_info,	NULL, /*  cdda_fileinfo, */	/* file_info_box */	NULL				/* output plugin handle */};CDDAConfig cdda_cfg;static struct {	struct driveinfo drive;	cdda_disc_toc_t cd_toc;	int track;	int fd;	gboolean playing;} cdda_playing;static struct {	pthread_t thread;	gboolean audio_error, eof;	int seek;	} dae_data;static gboolean is_paused;static int pause_time;struct timeout {	int id;	char *device;};static GList *timeout_list;/* Time to delay stop command in 1/10 second */#define STOP_DELAY 20InputPlugin *get_iplugin_info(void){	cdda_ip.description = g_strdup_printf(_("CD Audio Player %s"), VERSION);	return &cdda_ip;}static void cdda_init(void){	ConfigFile *cfgfile;	struct driveinfo *drive = g_malloc0(sizeof(struct driveinfo));	int ndrives = 1, i;	cdda_playing.fd = -1;	memset(&cdda_cfg, 0, sizeof(CDDAConfig));#ifdef HAVE_OSS  	drive->mixer = CDDA_MIXER_OSS;	drive->oss_mixer = SOUND_MIXER_CD;#endif	cfgfile = xmms_cfg_open_default_file();	/* These names are used for backwards compatibility */	xmms_cfg_read_string(cfgfile, "CDDA", "device", &drive->device);	xmms_cfg_read_string(cfgfile, "CDDA", "directory", &drive->directory);	xmms_cfg_read_int(cfgfile, "CDDA", "mixer", &drive->mixer);	xmms_cfg_read_int(cfgfile, "CDDA", "readmode", &drive->dae);	if (!drive->device)		drive->device = g_strdup(CDDA_DEVICE);	if (!drive->directory)		drive->directory = g_strdup(CDDA_DIRECTORY);	cdda_cfg.drives = g_list_append(cdda_cfg.drives, drive);	xmms_cfg_read_int(cfgfile, "CDDA", "num_drives", &ndrives);  	for (i = 1; i < ndrives; i++)	{		char label[20];		drive = g_malloc0(sizeof(struct driveinfo));		sprintf(label, "device%d", i);		xmms_cfg_read_string(cfgfile, "CDDA", label, &drive->device);				sprintf(label, "directory%d", i);		xmms_cfg_read_string(cfgfile, "CDDA", label, &drive->directory);		sprintf(label, "mixer%d", i);		xmms_cfg_read_int(cfgfile, "CDDA", label, &drive->mixer);		sprintf(label, "readmode%d", i);		xmms_cfg_read_int(cfgfile, "CDDA", label, &drive->dae);		cdda_cfg.drives = g_list_append(cdda_cfg.drives, drive);	}	xmms_cfg_read_boolean(cfgfile, "CDDA", "title_override", &cdda_cfg.title_override);	xmms_cfg_read_string(cfgfile, "CDDA", "name_format", &cdda_cfg.name_format);	xmms_cfg_read_boolean(cfgfile, "CDDA", "use_cddb", &cdda_cfg.use_cddb);	xmms_cfg_read_string(cfgfile, "CDDA", "cddb_server", &cdda_cfg.cddb_server);#ifdef WITH_CDINDEX	xmms_cfg_read_boolean(cfgfile, "CDDA", "use_cdin", &cdda_cfg.use_cdin);#else	cdda_cfg.use_cdin = FALSE;#endif	xmms_cfg_read_string(cfgfile, "CDDA", "cdin_server", &cdda_cfg.cdin_server);	xmms_cfg_free(cfgfile);	if (!cdda_cfg.cdin_server)		cdda_cfg.cdin_server = g_strdup("www.cdindex.org");	if (!cdda_cfg.cddb_server)		cdda_cfg.cddb_server = g_strdup(CDDB_DEFAULT_SERVER);	if (!cdda_cfg.name_format)		cdda_cfg.name_format = g_strdup("%p - %t");}struct driveinfo* cdda_find_drive(char *filename){	GList *node;		for (node = cdda_cfg.drives; node; node = node->next)	{		struct driveinfo *d = node->data;		if (!strncmp(d->directory, filename, strlen(d->directory)))			return d;	}	return NULL;}static void timeout_destroy(struct timeout *entry){	g_free(entry->device);	g_free(entry);	timeout_list = g_list_remove(timeout_list, entry);}static void timeout_remove_for_device(char *device){	GList *node;	for (node = timeout_list; node; node = node->next)	{		struct timeout *t = node->data;		if (!strcmp(t->device, device))		{			gtk_timeout_remove(t->id);			timeout_destroy(t);			return;		}	}}static void cleanup(void){	while (timeout_list)	{		struct timeout *t = timeout_list->data;		gtk_timeout_remove(t->id);		stop_timeout(t);	}	cddb_quit();}static int is_our_file(char *filename){	char *ext;	if (cdda_find_drive(filename) == NULL)		return FALSE;	ext = strrchr(filename, '.');	if (ext && !strcasecmp(ext, ".cda"))		return TRUE;	return FALSE;}static gboolean is_mounted(char * device_name){#if defined(HAVE_MNTENT_H) || defined(HAVE_GETMNTINFO)  	char devname[256];  	struct stat st;#if defined(HAVE_MNTENT_H) 	FILE *mounts; 	struct mntent *mnt;#elif defined(HAVE_GETMNTINFO) 	struct statfs *fsp; 	int entries;#endif	if (lstat(device_name, &st) < 0)		return -1;	if (S_ISLNK(st.st_mode))		readlink(device_name, devname, 256);	else		strncpy(devname, device_name, 256);#if defined(HAVE_MNTENT_H)			if ((mounts = setmntent(MOUNTED, "r")) == NULL)		return TRUE;	while ((mnt = getmntent(mounts)) != NULL)	{		if (strcmp(mnt->mnt_fsname, devname) == 0)		{			endmntent(mounts);			return TRUE;		}	}	endmntent(mounts);#elif defined(HAVE_GETMNTINFO) 	entries = getmntinfo(&fsp, MNT_NOWAIT); 	if (entries < 0) 		return NULL;		while (entries-- > 0)	{		if (!strcmp(fsp->f_mntfromname, devname))			return TRUE;		fsp++;	}#endif                            #endif	return FALSE;}static GList *scan_dir(char *dir){	GList *list = NULL;	int i;	cdda_disc_toc_t toc;	struct driveinfo *drive;	if ((drive = cdda_find_drive(dir)) == NULL)		return NULL;	if (!cdda_get_toc(&toc, drive->device))		return NULL;	for (i = toc.last_track; i >= toc.first_track; i--)		if (!toc.track[i].flags.data_track)			list = g_list_prepend(list, g_strdup_printf("Track %02d.cda", i));	return list;}guint cdda_calculate_track_length(cdda_disc_toc_t *toc, int track){	if (track == toc->last_track)		return (LBA(toc->leadout) - LBA(toc->track[track]));	else		return (LBA(toc->track[track + 1]) - LBA(toc->track[track]));}static void *dae_play_loop(void *arg){	char *buffer = g_malloc(CD_FRAMESIZE_RAW * CDDA_DAE_FRAMES);	int pos = LBA(cdda_playing.cd_toc.track[cdda_playing.track]);	int end, frames;	if (cdda_playing.track == cdda_playing.cd_toc.last_track)		end = LBA(cdda_playing.cd_toc.leadout);	else		end = LBA(cdda_playing.cd_toc.track[cdda_playing.track + 1]);	while (cdda_playing.playing)	{		int left;		char *data;		if (dae_data.seek != -1)		{			cdda_ip.output->flush(dae_data.seek * 1000);			pos = LBA(cdda_playing.cd_toc.track[cdda_playing.track])				+ dae_data.seek * 75;			dae_data.seek = -1;			dae_data.eof = FALSE;		}		frames = MIN(CDDA_DAE_FRAMES, end - pos);		if (frames == 0)			dae_data.eof = TRUE;		if (dae_data.eof)		{			xmms_usleep(30000);			continue;		}		frames = read_audio_data(cdda_playing.fd, pos,					 frames, buffer);		if (frames <= 0)		{			int err = -frames;			if (err == EOPNOTSUPP)				dae_data.eof = TRUE;			else			{				/*				 * If the read failed, skip ahead to				 * avoid getting stuck on scratches				 * and such.				 */				g_message("read_audio_data() failed:  %s (%d)",					  strerror(err), err);				pos += MIN(CDDA_DAE_FRAMES, end - pos);			}			continue;		}		left = frames * CD_FRAMESIZE_RAW;		data = buffer;		while (cdda_playing.playing && left > 0 && dae_data.seek == -1)		{			int cur = MIN(512 * 2 * 2, left);			cdda_ip.add_vis_pcm(cdda_ip.output->written_time(),					    FMT_S16_LE, 2, cur, data);			while (cdda_ip.output->buffer_free() < cur &&			       cdda_playing.playing && dae_data.seek == -1)				xmms_usleep(30000);			if (cdda_playing.playing && dae_data.seek == -1)				cdda_ip.output->write_audio(data, cur);			left -= cur;			data += cur;		}		pos += frames;	}	cdda_ip.output->buffer_free();	cdda_ip.output->buffer_free();	g_free(buffer);	return NULL;}static void dae_play(void){	if (cdda_ip.output->open_audio(FMT_S16_LE, 44100, 2) == 0)	{		dae_data.audio_error = TRUE;		cdda_playing.playing = FALSE;		return;	}	dae_data.seek = -1;	dae_data.eof = FALSE;	dae_data.audio_error = FALSE;	pthread_create(&dae_data.thread, NULL, dae_play_loop, NULL);}static void play_file(char *filename){	char *tmp;	struct driveinfo *drive;	int track;	int track_len;	if ((drive = cdda_find_drive(filename)) == NULL)		return;	if (is_mounted(drive->device))		return;	tmp = strrchr(filename, '/');	if (tmp)		tmp++;	else		tmp = filename;	if (!sscanf(tmp, "Track %d.cda", &track))		return;	if (!cdda_get_toc(&cdda_playing.cd_toc, drive->device) ||	    cdda_playing.cd_toc.track[track].flags.data_track ||	    track < cdda_playing.cd_toc.first_track ||	    track > cdda_playing.cd_toc.last_track)		return;	if ((cdda_playing.fd = open(drive->device, CDOPENFLAGS)) == -1)		return;	track_len = cdda_calculate_track_length(&cdda_playing.cd_toc, track);	cdda_ip.set_info(cdda_get_title(&cdda_playing.cd_toc, track),			 (track_len  * 1000) / 75, 44100 * 2 * 2 * 8, 44100, 2);	memcpy(&cdda_playing.drive, drive, sizeof (struct driveinfo)); #ifndef CDDA_HAS_READAUDIO	cdda_playing.drive.dae = FALSE;#endif	cdda_playing.track = track;	is_paused = FALSE;	timeout_remove_for_device(drive->device);	cdda_playing.playing = TRUE;	if (drive->dae)		dae_play();	else		seek(0);}static char * cdda_get_title(cdda_disc_toc_t *toc, int track){	static guint32 cached_id;	static cdinfo_t cdinfo;	static pthread_mutex_t title_mutex = PTHREAD_MUTEX_INITIALIZER;	TitleInput *input;	guint32 disc_id;	char *title;	disc_id = cdda_cddb_compute_discid(toc);		/*	 * We want to avoid looking up a album from two threads simultaneously.	 * This can happen since we are called both from the main-thread and	 * from the playlist-thread.	 */		pthread_mutex_lock(&title_mutex);	if (!(disc_id == cached_id && cdinfo.is_valid))	{		/*		 * We try to look up the disc again if the info is not		 * valid.  The user might have configured a new server		 * in the meantime.		 */		cdda_cdinfo_flush(&cdinfo);		cached_id = disc_id;		if (!cdda_cdinfo_read_file(disc_id, &cdinfo))		{			if (cdda_cfg.use_cddb)				cdda_cddb_get_info(toc, &cdinfo);			if (cdinfo.is_valid)				cdda_cdinfo_write_file(disc_id, &cdinfo);		}	}	XMMS_NEW_TITLEINPUT(input);	cdda_cdinfo_get(&cdinfo, track, &input->performer, &input->album_name,			&input->track_name);	pthread_mutex_unlock(&title_mutex);		input->track_number = track;	input->file_name = input->file_path = 	    g_strdup_printf(_("CD Audio Track %02u"), track);	input->file_ext = "cda";	title =  xmms_get_titlestring(cdda_cfg.title_override ?				      cdda_cfg.name_format :				      xmms_get_gentitle_format(), input);	g_free(input->file_name);	g_free(input);	if (!title)		title = g_strdup_printf(_("CD Audio Track %02u"), track);	return title;}static gboolean stop_timeout(gpointer data){	int fd;	struct timeout *to = data;	fd = open(to->device, CDOPENFLAGS);	if (fd != -1)	{		ioctl(fd, XMMS_STOP, 0);		close(fd);	}	timeout_destroy(to);	return FALSE;}static void stop(void){	struct timeout *to_info;	if (cdda_playing.fd < 0)		return;	cdda_playing.playing = FALSE;		if (cdda_playing.drive.dae)

⌨️ 快捷键说明

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