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

📄 core.c

📁 Aqualung is an advanced music player primarily targeted for the GNU/Linux operating system, but als
💻 C
📖 第 1 页 / 共 5 页
字号:
/*                                                     -*- linux-c -*-    Copyright (C) 2004 Tom Szilagyi    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., 675 Mass Ave, Cambridge, MA 02139, USA.    $Id: core.c,v 1.57 2006/10/02 17:50:26 peterszilagyi Exp $*/#include <config.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <errno.h>#include <unistd.h>#include <fcntl.h>#include <math.h>#include <time.h>#include <getopt.h>#include <time.h>#include <sys/time.h>#include <sys/stat.h>#include <libxml/xmlmemory.h>#include <libxml/parser.h>#ifdef _WIN32#include <glib.h>#else#include <pthread.h>#endif /* _WIN32 */#ifdef HAVE_SRC#include <samplerate.h>#endif /* HAVE_SRC */#ifdef HAVE_OSS#include <sys/ioctl.h>#include <sys/types.h>#ifdef __FreeBSD__#include <sys/soundcard.h>#else#include <linux/soundcard.h>#endif /* __FreeBSD__ */#endif /* HAVE_OSS */#ifdef HAVE_JACK#include <sys/mman.h>#include <jack/jack.h>#endif /* HAVE_JACK */#ifdef _WIN32#include <windows.h>#include <mmsystem.h>#endif /* _WIN32 */#include "common.h"#include "version.h"#include "rb.h"#include "options.h"#include "decoder/file_decoder.h"#include "transceiver.h"#include "gui_main.h"#include "plugin.h"#include "i18n.h"#include "core.h"extern options_t options;/* JACK data */#ifdef HAVE_JACKjack_client_t * jack_client;jack_port_t * out_L_port;jack_port_t * out_R_port;char * client_name = NULL;u_int32_t jack_nframes;int jack_is_shutdown;int auto_connect = 0;int default_ports = 1;char * user_port1 = NULL;char * user_port2 = NULL;#endif /* HAVE_JACK */const size_t sample_size = sizeof(float);gint playlist_state, browser_state;/* ALSA driver parameters */#ifdef HAVE_ALSAint nperiods = 0;int period = 0;#endif /* HAVE_ALSA *//* The name of the output device e.g. "/dev/dsp" or "plughw:0,0" */char * device_name = NULL;/***** disk thread stuff *****/unsigned long long sample_offset;status_t disk_thread_status;int output = 0; /* oss/alsa/jack */#ifdef HAVE_SRCint src_type = 4;int src_type_parsed = 0;#endif /* HAVE_SRC *//* Synchronization between disk thread and output thread */AQUALUNG_MUTEX_DECLARE_INIT(disk_thread_lock)AQUALUNG_COND_DECLARE_INIT(disk_thread_wake)rb_t * rb; /* this is the audio stream carrier ringbuffer */rb_t * rb_disk2out;/* Communication between gui thread and disk thread */rb_t * rb_gui2disk;rb_t * rb_disk2gui;/* Lock critical operations that could interfere with output thread */double left_gain = 1.0;double right_gain = 1.0;/* LADSPA stuff */float * l_buf = NULL;float * r_buf = NULL;#ifdef HAVE_LADSPAvolatile int plugin_lock = 0;unsigned long ladspa_buflen = 0;int n_plugins = 0;plugin_instance * plugin_vect[MAX_PLUGINS];#endif /* HAVE_LADSPA *//* remote control */extern int immediate_start;extern int aqualung_session_id;extern int aqualung_socket_fd;extern char aqualung_socket_filename[256];float convf(char * s) {        float val, pow;        int i, sign;        for (i = 0; s[i] == ' ' || s[i] == '\n' || s[i] == '\t'; i++);        sign = 1;        if (s[i] == '+' || s[i] == '-')                sign = (s[i++] == '+') ? 1 : -1;        for (val = 0; s[i] >= '0' && s[i] <= '9'; i++)                val = 10 * val + s[i] - '0';        if ((s[i] == '.') || (s[i] == ','))                i++;        for (pow = 1; s[i] >= '0' && s[i] <= '9'; i++) {                val = 10 * val + s[i] - '0';                pow *= 10;        }        return(sign * val / pow);}/* return 1 if conversion is possible, 0 if not */intsample_rates_ok(int out_SR, int file_SR) {#ifdef HAVE_SRC	float src_ratio;	src_ratio = 1.0 * out_SR / file_SR;	if (!src_is_valid_ratio(src_ratio) ||	    src_ratio > MAX_RATIO || src_ratio < 1.0/MAX_RATIO) {		fprintf(stderr, "core.c/sample_rates_ok(): too big difference between input and "			"output sample rate!\n");#else        if (out_SR != file_SR) {		fprintf(stderr,			"Input file's samplerate (%d Hz) and output samplerate (%d Hz) differ, "			"and\nAqualung is compiled without Sample Rate Converter support. To play "			"this file,\nyou have to build Aqualung with internal Sample Rate Converter "			"support,\nor set the playback sample rate to match the file's sample rate."			"\n", file_SR, out_SR);             #endif /* HAVE_SRC */		return 0;	}	return 1;}void *disk_thread(void * arg) {	thread_info_t * info = (thread_info_t *)arg;	file_decoder_t * fdec = NULL;	unsigned int n_read = 0;	unsigned int want_read;	int n_src = 0;	int n_src_prev = 0;	int end_of_file = 0;	double src_ratio = 1.0;	void * readbuf = malloc(MAX_RATIO * info->rb_size * 2 * sample_size);	void * framebuf = malloc(MAX_RATIO * info->rb_size * 2 * sample_size);	size_t n_space;	char send_cmd, recv_cmd;	char filename[RB_CONTROL_SIZE];	seek_t seek;	cue_t cue;	int i;#ifdef HAVE_SRC	int src_type_prev;	SRC_STATE * src_state;	SRC_DATA src_data;	int src_error;        if ((src_state = src_new(src_type, 2, &src_error)) == NULL) {		fprintf(stderr, "disk thread: error: src_new() failed: %s.\n",			src_strerror(src_error));		exit(1);	}	src_type_prev = src_type;#endif /* HAVE_SRC */	if ((fdec = file_decoder_new()) == NULL) {		fprintf(stderr, "disk thread: error: file_decoder_new() failed\n");		exit(1);	}	if ((!readbuf) || (!framebuf)) {		fprintf(stderr, "disk thread: malloc error\n");		exit(1);	}	AQUALUNG_MUTEX_LOCK(disk_thread_lock)	filename[0] = '\0';	while (1) {		recv_cmd = 0;		if (rb_read_space(rb_gui2disk) > 0) {			rb_read(rb_gui2disk, &recv_cmd, 1);			switch (recv_cmd) {			case CMD_CUE:				/* read the string */				while (rb_read_space(rb_gui2disk) < sizeof(cue_t))					;				rb_read(rb_gui2disk, (void *)&cue, sizeof(cue_t));								if (cue.filename != NULL) {					strncpy(filename, cue.filename, MAXLEN-1);					free(cue.filename);				} else {					filename[0] = '\0';				}				if (fdec->file_lib != 0)					file_decoder_close(fdec);				if (filename[0] != '\0') {					if (file_decoder_open(fdec, filename)) {						fdec->samples_left = 0;						info->is_streaming = 0;						end_of_file = 1;						send_cmd = CMD_FILEREQ;						rb_write(rb_disk2gui, &send_cmd, 1);						goto sleep;					} else if (!sample_rates_ok(info->out_SR, fdec->SR)) {						fdec->file_open = 1; /* to get close_file() working */						file_decoder_close(fdec);						fdec->file_open = 0;						fdec->samples_left = 0;						info->is_streaming = 0;						end_of_file = 1;						send_cmd = CMD_FILEREQ;						rb_write(rb_disk2gui, &send_cmd, 1);						goto sleep;					} else {						file_decoder_set_rva(fdec, cue.voladj);						info->in_SR_prev = info->in_SR;						info->in_SR = fdec->SR;						info->is_mono = (fdec->channels == 1) ? 1 : 0;						sample_offset = 0;						send_cmd = CMD_FILEINFO;						rb_write(rb_disk2gui, &send_cmd,								      sizeof(send_cmd));						rb_write(rb_disk2gui,								      (char *)&(fdec->fileinfo),								      sizeof(fileinfo_t));						info->is_streaming = 1;						end_of_file = 0;					}				} else { /* STOP */					info->is_streaming = 0;					/* send a FLUSH command to output thread to stop immediately */					send_cmd = CMD_FLUSH;					rb_write(rb_disk2out, &send_cmd, 1);					goto sleep;				}				break;			case CMD_STOPWOFL: /* STOP but first flush output ringbuffer. */				info->is_streaming = 0;				goto flush;				break;			case CMD_PAUSE:				info->is_streaming = 0;				/* send a FLUSH command to output thread */				send_cmd = CMD_FLUSH;				rb_write(rb_disk2out, &send_cmd, 1);				/* roll back sample_offset samples, if possible */				sample_offset = rb_read_space(rb) /					(2 * sample_size) * src_ratio;				if (sample_offset <				    fdec->fileinfo.total_samples - fdec->samples_left)					file_decoder_seek(fdec,					   fdec->fileinfo.total_samples - fdec->samples_left					   - sample_offset);				else				        file_decoder_seek(fdec, 0);				break;			case CMD_RESUME:				info->is_streaming = 1;				break;			case CMD_FINISH:				/* send FINISH to output thread, then goto exit */				send_cmd = CMD_FINISH;				rb_write(rb_disk2out, &send_cmd, 1);				goto done;				break;			case CMD_SEEKTO:				while (rb_read_space(rb_gui2disk) < sizeof(seek_t))					;				rb_read(rb_gui2disk, (char *)&seek, sizeof(seek_t));				if (fdec->file_lib != 0) {					file_decoder_seek(fdec, seek.seek_to_pos);					/* send a FLUSH command to output thread */					send_cmd = CMD_FLUSH;					rb_write(rb_disk2out, &send_cmd, 1);				} else {					/* send dummy STATUS to gui, to set pos slider to zero */					disk_thread_status.samples_left = 0;					disk_thread_status.sample_offset = 0;					send_cmd = CMD_STATUS;					rb_write(rb_disk2gui, &send_cmd, sizeof(send_cmd));					rb_write(rb_disk2gui, (char *)&disk_thread_status,							      sizeof(status_t));				}				break;			default:				fprintf(stderr, "disk thread: received unexpected command %d\n", recv_cmd);				break;			}		} else if (end_of_file)			goto sleep;		if (!info->is_streaming)			goto sleep;		n_space = rb_write_space(rb) / (2 * sample_size);		while (n_src < 0.95 * n_space) {						src_ratio = (double)info->out_SR / (double)info->in_SR;			n_src_prev = n_src;			want_read = floor((n_space - n_src) / src_ratio);			if (want_read > MAX_RATIO * info->rb_size)				want_read = MAX_RATIO * info->rb_size;						n_read = file_decoder_read(fdec, readbuf, want_read);			if (n_read < want_read)				end_of_file = 1;						if (info->is_mono) { /* convert to stereo interleaved */				for (i = 2*n_read - 1; i >= 0; i--) {					memcpy(readbuf + i * sample_size,					       readbuf + i/2 * sample_size,					       sample_size);				}			}						if (info->in_SR == info->out_SR) {				memcpy(framebuf + n_src_prev * 2*sample_size,				       readbuf, n_read * 2*sample_size);				n_src += n_read;			} else { /* do SRC */#ifdef HAVE_SRC								if ((info->in_SR_prev != info->in_SR) ||				    (src_type_prev != src_type)) { /* reinit SRC */					src_state = src_delete(src_state);					if ((src_state = src_new(src_type, 2, &src_error)) == NULL) {						fprintf(stderr, "disk thread: error: src_new() failed: "						       "%s.\n", src_strerror(src_error));						goto done;					}					info->in_SR_prev = info->in_SR;					src_type_prev = src_type;				}								src_data.input_frames = n_read;				src_data.data_in = readbuf;				src_data.src_ratio = src_ratio;				src_data.data_out = framebuf + n_src_prev * 2*sample_size;				src_data.output_frames = n_space - n_src_prev;				if ((src_error = src_process(src_state, &src_data))) {					fprintf(stderr, "disk thread: SRC error: %s\n",					       src_strerror(src_error));					goto done;				}				n_src += src_data.output_frames_gen;#endif /* HAVE_SRC */			}						if (end_of_file) {				file_decoder_close(fdec);				/* send request for a new filename */				send_cmd = CMD_FILEREQ;				rb_write(rb_disk2gui, &send_cmd, 1);				goto sleep;			}		}	flush:		rb_write(rb, framebuf, n_src * 2*sample_size);		/* update & send STATUS */		fdec->samples_left -= n_read;		sample_offset =	rb_read_space(rb) / (2 * sample_size);		disk_thread_status.samples_left = fdec->samples_left;		disk_thread_status.sample_offset = sample_offset / src_ratio;		if (disk_thread_status.samples_left < 0) {			disk_thread_status.samples_left = 0;		}		if (!rb_read_space(rb_gui2disk)) {			send_cmd = CMD_STATUS;			rb_write(rb_disk2gui, &send_cmd, sizeof(send_cmd));			rb_write(rb_disk2gui, (char *)&disk_thread_status,					      sizeof(status_t));		}		/* cleanup buffer counters */		n_src = 0;		n_src_prev = 0;		end_of_file = 0;			sleep:		{			/* suspend thread, wake up after 100 ms */#ifdef _WIN32			GTimeVal time;			GTimeVal * timeout = &time;			g_get_current_time(timeout);			g_time_val_add(timeout, 100000);#else			struct timeval now;			struct timezone tz;			struct timespec timeout;			gettimeofday(&now, &tz);			timeout.tv_nsec = now.tv_usec * 1000 + 100000000;			timeout.tv_sec = now.tv_sec;			while (timeout.tv_nsec > 1000000000) {				timeout.tv_nsec -= 1000000000;				timeout.tv_sec += 1;			}#endif /* _WIN32 */			AQUALUNG_COND_TIMEDWAIT(disk_thread_wake, disk_thread_lock, timeout)		}	} done:	free(readbuf);	free(framebuf);#ifdef HAVE_SRC	src_state = src_delete(src_state);#endif /* HAVE_SRC */	file_decoder_delete(fdec);	AQUALUNG_MUTEX_UNLOCK(disk_thread_lock)	return 0;}/* OSS output thread */#ifdef HAVE_OSSvoid *oss_thread(void * arg) {        u_int32_t i;        thread_info_t * info = (thread_info_t *)arg;	int bufsize = 1024;        int n_avail;	int ioctl_status;	char recv_cmd;	int fd_oss = info->fd_oss;	short * oss_short_buf;	struct timespec req_time;	struct timespec rem_time;	req_time.tv_sec = 0;        req_time.tv_nsec = 100000000;

⌨️ 快捷键说明

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