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

📄 aplay.c

📁 ALSA驱动的一些调试测试工具
💻 C
📖 第 1 页 / 共 5 页
字号:
		err = snd_pcm_hw_params_get_buffer_time_max(params,							    &buffer_time, 0);		assert(err >= 0);		if (buffer_time > 500000)			buffer_time = 500000;	}	if (period_time == 0 && period_frames == 0) {		if (buffer_time > 0)			period_time = buffer_time / 4;		else			period_frames = buffer_frames / 4;	}	if (period_time > 0)		err = snd_pcm_hw_params_set_period_time_near(handle, params,							     &period_time, 0);	else		err = snd_pcm_hw_params_set_period_size_near(handle, params,							     &period_frames, 0);	assert(err >= 0);	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);	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;	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);	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);	/* stereo VU-meter isn't always available... */	if (vumeter == VUMETER_STEREO) {		if (hwparams.channels != 2 || !interleaved || verbose > 2)			vumeter = VUMETER_MONO;	}	/* show mmap buffer arragment */	if (mmap_flag && verbose) {		const snd_pcm_channel_area_t *areas;		snd_pcm_uframes_t offset;		int i;		err = snd_pcm_mmap_begin(handle, &areas, &offset, &chunk_size);		if (err < 0) {			error("snd_pcm_mmap_begin problem: %s", snd_strerror(err));			exit(EXIT_FAILURE);		}		for (i = 0; i < hwparams.channels; i++)			fprintf(stderr, "mmap_area[%i] = %p,%u,%u (%u)\n", i, areas[i].addr, areas[i].first, areas[i].step, snd_pcm_format_physical_width(hwparams.format));		/* not required, but for sure */		snd_pcm_mmap_commit(handle, offset, 0);	}	buffer_frames = buffer_size;	/* for position test */}#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"));}static void print_vu_meter_mono(int perc, int maxperc){	const int bar_length = 50;	char line[80];	int val;	for (val = 0; val <= perc * bar_length / 100 && val < bar_length; val++)		line[val] = '#';	for (; val <= maxperc * bar_length / 100 && val < bar_length; val++)		line[val] = ' ';	line[val] = '+';	for (++val; val <= bar_length; val++)		line[val] = ' ';	if (maxperc > 99)		sprintf(line + val, "| MAX");	else		sprintf(line + val, "| %02i%%", maxperc);	fputs(line, stdout);	if (perc > 100)		printf(_(" !clip  "));}static void print_vu_meter_stereo(int *perc, int *maxperc){	const int bar_length = 35;	char line[80];	int c;	memset(line, ' ', sizeof(line) - 1);	line[bar_length + 3] = '|';	for (c = 0; c < 2; c++) {		int p = perc[c] * bar_length / 100;		char tmp[4];		if (p > bar_length)			p = bar_length;		if (c)			memset(line + bar_length + 6 + 1, '#', p);		else			memset(line + bar_length - p - 1, '#', p);		p = maxperc[c] * bar_length / 100;		if (p > bar_length)			p = bar_length;		if (c)			line[bar_length + 6 + 1 + p] = '+';		else			line[bar_length - p - 1] = '+';		if (maxperc[c] > 99)			sprintf(tmp, "MAX");		else			sprintf(tmp, "%02d%%", maxperc[c]);		if (c)			memcpy(line + bar_length + 3 + 1, tmp, 3);		else			memcpy(line + bar_length, tmp, 3);	}	line[bar_length * 2 + 6 + 2] = 0;	fputs(line, stdout);}static void print_vu_meter(signed int *perc, signed int *maxperc){	if (vumeter == VUMETER_STEREO)		print_vu_meter_stereo(perc, maxperc);	else		print_vu_meter_mono(*perc, *maxperc);}/* peak handler */static void compute_max_peak(u_char *data, size_t count){	signed int val, max, perc[2], max_peak[2];	static	int	run = 0;	size_t ocount = count;	int	format_little_endian = snd_pcm_format_little_endian(hwparams.format);		int ichans, c;	if (vumeter == VUMETER_STEREO)		ichans = 2;	else		ichans = 1;	memset(max_peak, 0, sizeof(max_peak));	switch (bits_per_sample) {	case 8: {		signed char *valp = (signed char *)data;		signed char mask = snd_pcm_format_silence(hwparams.format);		c = 0;		while (count-- > 0) {			val = *valp++ ^ mask;			val = abs(val);			if (max_peak[c] < val)				max_peak[c] = val;			if (vumeter == VUMETER_STEREO)				c = !c;		}		break;	}	case 16: {		signed short *valp = (signed short *)data;		signed short mask = snd_pcm_format_silence_16(hwparams.format);		signed short sval;		count /= 2;		c = 0;		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[c] < sval)				max_peak[c] = sval;			valp++;			if (vumeter == VUMETER_STEREO)				c = !c;		}		break;	}	case 24: {		unsigned char *valp = data;		signed int mask = snd_pcm_format_silence_32(hwparams.format);		count /= 3;		c = 0;		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[c] < val)				max_peak[c] = val;			valp += 3;			if (vumeter == VUMETER_STEREO)				c = !c;		}		break;	}	case 32: {		signed int *valp = (signed int *)data;		signed int mask = snd_pcm_format_silence_32(hwparams.format);		count /= 4;		c = 0;		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[c] < val)				max_peak[c] = val;			valp++;			if (vumeter == VUMETER_STEREO)				c = !c;		}		break;	}	default:		if (run == 0) {			fprintf(stderr, _("Unsupported bit size %d.\n"), (int)bits_per_sample);			run = 1;		}		return;	}	max = 1 << (bits_per_sample-1);	if (max <= 0)		max = 0x7fffffff;	for (c = 0; c < ichans; c++) {		if (bits_per_sample > 16)			perc[c] = max_peak[c] / (max / 100);		else			perc[c] = max_peak[c] * 100 / max;	}	if (interleaved && verbose <= 2) {		static int maxperc[2];		static time_t t=0;		const time_t tt=time(NULL);		if(tt>t) {			t=tt;			maxperc[0] = 0;			maxperc[1] = 0;		}		for (c = 0; c < ichans; c++)			if (perc[c] > maxperc[c])				maxperc[c] = perc[c];		putchar('\r');		print_vu_meter(perc, maxperc);		fflush(stdout);	}	else if(verbose==3) {		printf(_("Max peak (%li samples): 0x%08x "), (long)ocount, max_peak[0]);		for (val = 0; val < 20; val++)			if (val <= perc[0] / 5)				putchar('#');			else				putchar(' ');		printf(" %i%%\n", perc[0]);		fflush(stdout);	}}static void do_test_position(void){	static int counter = 0;	snd_pcm_sframes_t avail, delay;	int err;	err = snd_pcm_avail_delay(handle, &avail, &delay);	if (err < 0)		return;	if (avail > 4 * (snd_pcm_sframes_t)buffer_frames ||	    avail < -4 * (snd_pcm_sframes_t)buffer_frames ||	    delay > 4 * (snd_pcm_sframes_t)buffer_frames ||	    delay < -4 * (snd_pcm_sframes_t)buffer_frames) {	  fprintf(stderr, "Suspicious buffer position (%i total): avail = %li, delay = %li, buffer = %li\n", ++counter, (long)avail, (long)delay, (long)buffer_frames);	} else if (verbose) {	  fprintf(stderr, "Buffer position: %li/%li (%li)\n", (long)avail, (long)delay, (long)buffer_frames);	}}/* *  write function */static ssize_t pcm_write(u_char *data, size_t count){	ssize_t r;	ssize_t result = 0;	if (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) {		if (test_position)			do_test_position();		r = writei_func(handle, data, count);		if (test_position)			do_test_position();		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 (vumeter)				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 (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;		if (test_position)			do_test_position();		r = writen_func(handle, bufs, count);		if (test_position)			do_test_position();		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);

⌨️ 快捷键说明

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