aplay.c

来自「alsa-utils-1.0.14编译声卡驱动所需要的一些文件源码」· C语言 代码 · 共 2,374 行 · 第 1/5 页

C
2,374
字号
	if (buffer_time > 0) {		err = snd_pcm_hw_params_set_buffer_time_near(handle, params,							     &buffer_time, 0);	} else {		err = snd_pcm_hw_params_set_buffer_size_near(handle, params,							     &buffer_frames);	}	assert(err >= 0);	err = snd_pcm_hw_params(handle, params);	if (err < 0) {		error(_("Unable to install hw params:"));		snd_pcm_hw_params_dump(params, log);		exit(EXIT_FAILURE);	}	snd_pcm_hw_params_get_period_size(params, &chunk_size, 0);	snd_pcm_hw_params_get_buffer_size(params, &buffer_size);	if (chunk_size == buffer_size) {		error(_("Can't use period equal to buffer size (%lu == %lu)"),		      chunk_size, buffer_size);		exit(EXIT_FAILURE);	}	snd_pcm_sw_params_current(handle, swparams);	err = snd_pcm_sw_params_get_xfer_align(swparams, &xfer_align);	if (err < 0) {		error(_("Unable to obtain xfer align\n"));		exit(EXIT_FAILURE);	}	if (sleep_min)		xfer_align = 1;	err = snd_pcm_sw_params_set_sleep_min(handle, swparams,					      sleep_min);	assert(err >= 0);	if (avail_min < 0)		n = chunk_size;	else		n = (double) rate * avail_min / 1000000;	err = snd_pcm_sw_params_set_avail_min(handle, swparams, n);	/* round up to closest transfer boundary */	n = (buffer_size / xfer_align) * xfer_align;	if (start_delay <= 0) {		start_threshold = n + (double) rate * start_delay / 1000000;	} else		start_threshold = (double) rate * start_delay / 1000000;	if (start_threshold < 1)		start_threshold = 1;	if (start_threshold > n)		start_threshold = n;	err = snd_pcm_sw_params_set_start_threshold(handle, swparams, start_threshold);	assert(err >= 0);	if (stop_delay <= 0) 		stop_threshold = buffer_size + (double) rate * stop_delay / 1000000;	else		stop_threshold = (double) rate * stop_delay / 1000000;	err = snd_pcm_sw_params_set_stop_threshold(handle, swparams, stop_threshold);	assert(err >= 0);	err = snd_pcm_sw_params_set_xfer_align(handle, swparams, xfer_align);	assert(err >= 0);	if (snd_pcm_sw_params(handle, swparams) < 0) {		error(_("unable to install sw params:"));		snd_pcm_sw_params_dump(swparams, log);		exit(EXIT_FAILURE);	}	if (verbose)		snd_pcm_dump(handle, log);	bits_per_sample = snd_pcm_format_physical_width(hwparams.format);	bits_per_frame = bits_per_sample * hwparams.channels;	chunk_bytes = chunk_size * bits_per_frame / 8;	audiobuf = realloc(audiobuf, chunk_bytes);	if (audiobuf == NULL) {		error(_("not enough memory"));		exit(EXIT_FAILURE);	}	// fprintf(stderr, "real chunk_size = %i, frags = %i, total = %i\n", chunk_size, setup.buf.block.frags, setup.buf.block.frags * chunk_size);}#ifndef timersub#define	timersub(a, b, result) \do { \	(result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \	(result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \	if ((result)->tv_usec < 0) { \		--(result)->tv_sec; \		(result)->tv_usec += 1000000; \	} \} while (0)#endif/* I/O error handler */static void xrun(void){	snd_pcm_status_t *status;	int res;		snd_pcm_status_alloca(&status);	if ((res = snd_pcm_status(handle, status))<0) {		error(_("status error: %s"), snd_strerror(res));		exit(EXIT_FAILURE);	}	if (snd_pcm_status_get_state(status) == SND_PCM_STATE_XRUN) {		struct timeval now, diff, tstamp;		gettimeofday(&now, 0);		snd_pcm_status_get_trigger_tstamp(status, &tstamp);		timersub(&now, &tstamp, &diff);		fprintf(stderr, _("%s!!! (at least %.3f ms long)\n"),			stream == SND_PCM_STREAM_PLAYBACK ? _("underrun") : _("overrun"),			diff.tv_sec * 1000 + diff.tv_usec / 1000.0);		if (verbose) {			fprintf(stderr, _("Status:\n"));			snd_pcm_status_dump(status, log);		}		if ((res = snd_pcm_prepare(handle))<0) {			error(_("xrun: prepare error: %s"), snd_strerror(res));			exit(EXIT_FAILURE);		}		return;		/* ok, data should be accepted again */	} if (snd_pcm_status_get_state(status) == SND_PCM_STATE_DRAINING) {		if (verbose) {			fprintf(stderr, _("Status(DRAINING):\n"));			snd_pcm_status_dump(status, log);		}		if (stream == SND_PCM_STREAM_CAPTURE) {			fprintf(stderr, _("capture stream format change? attempting recover...\n"));			if ((res = snd_pcm_prepare(handle))<0) {				error(_("xrun(DRAINING): prepare error: %s"), snd_strerror(res));				exit(EXIT_FAILURE);			}			return;		}	}	if (verbose) {		fprintf(stderr, _("Status(R/W):\n"));		snd_pcm_status_dump(status, log);	}	error(_("read/write error, state = %s"), snd_pcm_state_name(snd_pcm_status_get_state(status)));	exit(EXIT_FAILURE);}/* I/O suspend handler */static void suspend(void){	int res;	if (!quiet_mode)		fprintf(stderr, _("Suspended. Trying resume. ")); fflush(stderr);	while ((res = snd_pcm_resume(handle)) == -EAGAIN)		sleep(1);	/* wait until suspend flag is released */	if (res < 0) {		if (!quiet_mode)			fprintf(stderr, _("Failed. Restarting stream. ")); fflush(stderr);		if ((res = snd_pcm_prepare(handle)) < 0) {			error(_("suspend: prepare error: %s"), snd_strerror(res));			exit(EXIT_FAILURE);		}	}	if (!quiet_mode)		fprintf(stderr, _("Done.\n"));}/* peak handler */static void compute_max_peak(u_char *data, size_t count){	signed int val, max, max_peak = 0, perc;	static	int	run = 0;	size_t ocount = count;	int	format_little_endian = snd_pcm_format_little_endian(hwparams.format);		switch (bits_per_sample) {	case 8: {		signed char *valp = (signed char *)data;		signed char mask = snd_pcm_format_silence(hwparams.format);		while (count-- > 0) {			val = *valp++ ^ mask;			val = abs(val);			if (max_peak < val)				max_peak = val;		}		break;	}	case 16: {		signed short *valp = (signed short *)data;		signed short mask = snd_pcm_format_silence_16(hwparams.format);		signed short sval;		count /= 2;		while (count-- > 0) {			if (format_little_endian)				sval = __le16_to_cpu(*valp);			else	sval = __be16_to_cpu(*valp);			sval = abs(sval) ^ mask;			if (max_peak < sval)				max_peak = sval;			valp++;		}		break;	}	case 24: {		unsigned char *valp = data;		signed int mask = snd_pcm_format_silence_32(hwparams.format);		count /= 3;		while (count-- > 0) {			if (format_little_endian) {				val = valp[0] | (valp[1]<<8) | (valp[2]<<16);			} else {				val = (valp[0]<<16) | (valp[1]<<8) | valp[2];			}			/* Correct signed bit in 32-bit value */			if (val & (1<<(bits_per_sample-1))) {				val |= 0xff<<24;	/* Negate upper bits too */			}			val = abs(val) ^ mask;			if (max_peak < val)				max_peak = val;			valp += 3;		}		break;	}	case 32: {		signed int *valp = (signed int *)data;		signed int mask = snd_pcm_format_silence_32(hwparams.format);		count /= 4;		while (count-- > 0) {			if (format_little_endian)				val = __le32_to_cpu(*valp);			else	val = __be32_to_cpu(*valp);			val = abs(val) ^ mask;			if (max_peak < val)				max_peak = val;			valp++;		}		break;	}	default:		if (run == 0) {			fprintf(stderr, _("Unsupported bit size %d.\n"), bits_per_sample);			run = 1;		}		return;	}	max = 1 << (bits_per_sample-1);	if (max <= 0)		max = 0x7fffffff;	if (bits_per_sample > 16)		perc = max_peak / (max / 100);	else		perc = max_peak * 100 / max;	if(verbose<=2) {		static int maxperc=0;		static time_t t=0;		const time_t tt=time(NULL);		if(tt>t) {			t=tt;			maxperc=0;		}		if(perc>maxperc)			maxperc=perc;		putchar('\r');		for (val = 0; val <= perc / 2 && val < 50; val++)			putchar('#');		for (; val < maxperc / 2 && val < 50; val++)			putchar(' ');		putchar('+');		for (++val; val < 50; val++)			putchar(' ');		printf("| %02i%%", maxperc);		if (perc>99)			printf(_(" !clip  "));		fflush(stdout);	}	else if(verbose==3) {		printf(_("Max peak (%li samples): 0x%08x "), (long)ocount, max_peak);		for (val = 0; val < 20; val++)			if (val <= perc / 5)				putchar('#');			else				putchar(' ');		printf(" %i%%\n", perc);		fflush(stdout);	}}/* *  write function */static ssize_t pcm_write(u_char *data, size_t count){	ssize_t r;	ssize_t result = 0;	if (sleep_min == 0 &&	    count < chunk_size) {		snd_pcm_format_set_silence(hwparams.format, data + count * bits_per_frame / 8, (chunk_size - count) * hwparams.channels);		count = chunk_size;	}	while (count > 0) {		r = writei_func(handle, data, count);		if (r == -EAGAIN || (r >= 0 && (size_t)r < count)) {			snd_pcm_wait(handle, 1000);		} else if (r == -EPIPE) {			xrun();		} else if (r == -ESTRPIPE) {			suspend();		} else if (r < 0) {			error(_("write error: %s"), snd_strerror(r));			exit(EXIT_FAILURE);		}		if (r > 0) {			if (verbose > 1)				compute_max_peak(data, r * hwparams.channels);			result += r;			count -= r;			data += r * bits_per_frame / 8;		}	}	return result;}static ssize_t pcm_writev(u_char **data, unsigned int channels, size_t count){	ssize_t r;	size_t result = 0;	if (sleep_min == 0 &&	    count != chunk_size) {		unsigned int channel;		size_t offset = count;		size_t remaining = chunk_size - count;		for (channel = 0; channel < channels; channel++)			snd_pcm_format_set_silence(hwparams.format, data[channel] + offset * bits_per_sample / 8, remaining);		count = chunk_size;	}	while (count > 0) {		unsigned int channel;		void *bufs[channels];		size_t offset = result;		for (channel = 0; channel < channels; channel++)			bufs[channel] = data[channel] + offset * bits_per_sample / 8;		r = writen_func(handle, bufs, count);		if (r == -EAGAIN || (r >= 0 && (size_t)r < count)) {			snd_pcm_wait(handle, 1000);		} else if (r == -EPIPE) {			xrun();		} else if (r == -ESTRPIPE) {			suspend();		} else if (r < 0) {			error(_("writev error: %s"), snd_strerror(r));			exit(EXIT_FAILURE);		}		if (r > 0) {			if (verbose > 1) {				for (channel = 0; channel < channels; channel++)					compute_max_peak(data[channel], r);			}			result += r;			count -= r;		}	}	return result;}/* *  read function */static ssize_t pcm_read(u_char *data, size_t rcount){	ssize_t r;	size_t result = 0;	size_t count = rcount;	if (sleep_min == 0 &&	    count != chunk_size) {		count = chunk_size;	}	while (count > 0) {		r = readi_func(handle, data, count);		if (r == -EAGAIN || (r >= 0 && (size_t)r < count)) {			snd_pcm_wait(handle, 1000);		} else if (r == -EPIPE) {			xrun();		} else if (r == -ESTRPIPE) {			suspend();		} else if (r < 0) {			error(_("read error: %s"), snd_strerror(r));			exit(EXIT_FAILURE);		}		if (r > 0) {			if (verbose > 1)				compute_max_peak(data, r * hwparams.channels);			result += r;			count -= r;			data += r * bits_per_frame / 8;		}	}	return rcount;}static ssize_t pcm_readv(u_char **data, unsigned int channels, size_t rcount){	ssize_t r;	size_t result = 0;	size_t count = rcount;	if (sleep_min == 0 &&	    count != chunk_size) {		count = chunk_size;	}	while (count > 0) {		unsigned int channel;		void *bufs[channels];		size_t offset = result;		for (channel = 0; channel < channels; channel++)			bufs[channel] = data[channel] + offset * bits_per_sample / 8;		r = readn_func(handle, bufs, count);		if (r == -EAGAIN || (r >= 0 && (size_t)r < count)) {			snd_pcm_wait(handle, 1000);		} else if (r == -EPIPE) {			xrun();		} else if (r == -ESTRPIPE) {			suspend();		} else if (r < 0) {			error(_("readv error: %s"), snd_strerror(r));			exit(EXIT_FAILURE);		}		if (r > 0) {			if (verbose > 1) {				for (channel = 0; channel < channels; channel++)					compute_max_peak(data[channel], r);			}			result += r;			count -= r;		}	}	return rcount;}/* *  ok, let's play a .voc file */static ssize_t voc_pcm_write(u_char *data, size_t count){	ssize_t result = count, r;	size_t size;	while (count > 0) {		size = count;		if (size > chunk_bytes - buffer_pos)			size = chunk_bytes - buffer_pos;		memcpy(audiobuf + buffer_pos, data, size);		data += size;		count -= size;		buffer_pos += size;		if ((size_t)buffer_pos == chunk_bytes) {			if ((size_t)(r = pcm_write(audiobuf, chunk_size)) != chunk_size)				return r;			buffer_pos = 0;		}	}	return result;}

⌨️ 快捷键说明

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