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

📄 audio_jack.c

📁 mpg123 是 MPEG 1.0/2.0/2.5 的实时播放软件
💻 C
字号:
/*	audio_jack.c: audio output via JACK	copyright 2006 by the mpg123 project - free software under the terms of the LGPL 2.1	see COPYING and AUTHORS files in distribution or http://mpg123.de	initially written by Nicholas J. Humfrey*/#include <stdlib.h>#include <stdio.h>#include <math.h>#include <jack/jack.h>#include <jack/ringbuffer.h>#include "config.h"#include "mpg123.h"#include "debug.h"#define MAX_CHANNELS	(2)typedef struct {	int channels;	jack_port_t *ports[MAX_CHANNELS];	jack_ringbuffer_t * rb[MAX_CHANNELS];	size_t rb_size;	jack_client_t *client;	jack_default_audio_sample_t *tmp_buffer;} jack_handle_t, *jack_handle_ptr;static jack_handle_t* alloc_jack_handle(){	jack_handle_t *handle=NULL;	handle = malloc(sizeof(jack_handle_t));	if (!handle) {		error("audio_open(): Failed to allocate memory for our handle.");		return NULL;	}	/* Initialise the handle, and store for later*/	handle->rb[0] = NULL;	handle->rb[1] = NULL;	handle->ports[0] = NULL;	handle->ports[1] = NULL;	handle->client = NULL;	handle->tmp_buffer = NULL;	handle->rb_size = 0;		return handle;}static void free_jack_handle( jack_handle_t* handle ){	int i;		for(i=0; i<MAX_CHANNELS; i++) {		/* Close the port for channel*/		if ( handle->ports[i] )			jack_port_unregister( handle->client, handle->ports[i] );		/* Free up the ring buffer for channel*/		if ( handle->rb[i] )			jack_ringbuffer_free( handle->rb[i] );	}	if (handle->client)		jack_client_close(handle->client);			if (handle->tmp_buffer)		free(handle->tmp_buffer);	free(handle);}static intprocess_callback( jack_nframes_t nframes, void *arg ){	jack_handle_t* handle = (jack_handle_t*)arg;    size_t to_read = sizeof (jack_default_audio_sample_t) * nframes;	unsigned int c;	    /* copy data to ringbuffer; one per channel*/    for (c=0; c < handle->channels; c++)    {			char *buf = (char*)jack_port_get_buffer(handle->ports[c], nframes);		size_t len = jack_ringbuffer_read(handle->rb[c], buf, to_read);				/* If we don't have enough audio, fill it up with silence*/		/* (this is to deal with pausing etc.)*/		if (to_read > len)			bzero( buf+len, to_read - len );				/*if (len < to_read)*/		/*	fprintf(stderr, "failed to read from ring buffer %d\n",c);*/    }	/* Success*/	return 0;}static voidshutdown_callback( void *arg ){//	jack_handle_t* handle = (jack_handle_t*)arg;	fprintf(stderr, "shutdown_callback()\n");}/* crude way of automatically connecting up jack ports *//* 0 on error */int autoconnect_jack_ports( jack_handle_t* handle ){	const char **all_ports;	unsigned int ch=0;	int err,i;	/* Get a list of all the jack ports*/	all_ports = jack_get_ports (handle->client, NULL, NULL, JackPortIsInput);	if (!all_ports) {		error("connect_jack_ports(): jack_get_ports() returned NULL.");		return 0;	}		/* Step through each port name*/	for (i = 0; all_ports[i]; ++i) {		const char* in = jack_port_name( handle->ports[ch] );		const char* out = all_ports[i];				fprintf(stderr, "Connecting %s to %s\n", in, out);				if ((err = jack_connect(handle->client, in, out)) != 0) {			error1("connect_jack_ports(): failed to jack_connect() ports: %d",err);			return 0;		}			/* Found enough ports ?*/		if (++ch >= handle->channels) break;	}		free( all_ports );	return 1;}int connect_jack_ports( jack_handle_t* handle, const char *dev ) {	if (dev==NULL || strcmp(dev, "auto")==0) {		return autoconnect_jack_ports( handle );	} else if (strcmp(dev, "none")==0) {		fprintf(stderr, "Not connecting up jack ports as requested.\n");	} else {		fprintf(stderr, "Sorry I don't know how to connect up ports yet.\n");	}	return 1;}int audio_open(struct audio_info_struct *ai){	char client_name[255];	jack_handle_t *handle=NULL;	unsigned int i;	if(!ai) return -1;	/* Return if already open*/	if (ai->handle) {		fprintf(stderr, "audio_open(): error, already open\n");		return -1;	}	/* For some reason we get called with format=-1 initially*/	/* Just prentend that it didn't happen*/	if (ai->format==-1) {		return 0;	}		/* Create some storage for ourselves*/	if((handle = alloc_jack_handle()) == NULL) return -1;	ai->handle = (void*)handle;	/* Register with Jack*/	snprintf(client_name, 255, "mpg123-%d", getpid());	if ((handle->client = jack_client_new(client_name)) == 0) {		error("JACK server not running?");		audio_close(ai);		return -1;	}	printf("Registering as JACK client %s.\n", client_name);	/* Check the sample rate is correct*/	if (jack_get_sample_rate( handle->client ) != (jack_nframes_t)ai->rate) {		error("JACK Sample Rate is different to sample rate of file.");		audio_close(ai);		return -1;	}		/* Register ports with Jack*/	handle->channels = ai->channels;	if (handle->channels == 1) {		if (!(handle->ports[0] = jack_port_register(handle->client, "mono", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0)))		{			error("Cannot register JACK output port 'mono'.");			audio_close(ai);			return -1;		}	} else if (handle->channels == 2) {		if (!(handle->ports[0] = jack_port_register(handle->client, "left", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0)))		{			error("Cannot register JACK output port 'left'.");			audio_close(ai);			return -1;		}		if (!(handle->ports[1] = jack_port_register(handle->client, "right", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0)))		{			error("Cannot register JACK output port 'right'.");			audio_close(ai);			return -1;		}	} else {		error1("audio_open(): invalid number of channels (%d).", handle->channels);		audio_close(ai);		return -1;	}	/* Create the ring buffers (one seconds audio)*/    handle->rb_size = jack_get_sample_rate(handle->client) * sizeof(jack_default_audio_sample_t);    for(i=0;i<handle->channels;i++){        handle->rb[i]=jack_ringbuffer_create(handle->rb_size);    }	/* Set the callbacks*/	jack_set_process_callback(handle->client, process_callback, (void*)handle);	jack_on_shutdown(handle->client, shutdown_callback, (void*)handle);		/* Activate client*/	if (jack_activate(handle->client)) {		fprintf(stderr, "audio_open(): Can't activate client\n");	}	/* Connect up the portsm, return */	if(!connect_jack_ports( handle, ai->device ))	{		/* deregistering of ports will not work but should just fail, then, and let the rest clean up */		audio_close(ai);		return -1;	}	return 0;}/* Jack is in fact 32-bit floats only */int audio_get_formats(struct audio_info_struct *ai){	return AUDIO_FORMAT_SIGNED_16;}int audio_play_samples(struct audio_info_struct *ai, unsigned char *buf, int len){	int c,n = 0;	short* src = (short*)buf;	jack_handle_t *handle = (jack_handle_t*)ai->handle;	jack_nframes_t samples = len / 2 / handle->channels;	size_t tmp_size = samples * sizeof( jack_default_audio_sample_t );			/* Sanity check that ring buffer is at least twice the size of the audio we just got*/	if (handle->rb_size/2 < len) {		error("audio_play_samples(): ring buffer is less than twice the size of audio given.");		return -1;	}			/* Wait until there is space in the ring buffer*/	while (jack_ringbuffer_write_space( handle->rb[0] ) < tmp_size) {		/* Sleep for a quarter of the ring buffer size (1/4 second)*/		usleep(250000);	}			/* Ensure the temporary buffer is big enough*/	handle->tmp_buffer = (jack_default_audio_sample_t*)realloc( handle->tmp_buffer, tmp_size);	if (!handle->tmp_buffer) {		error("audio_play_samples(): failed to realloc temporary buffer.");		return -1;	}			for(c=0; c<handle->channels; c++) {			/* Convert samples from short to flat and put in temporary buffer*/		for(n=0; n<samples; n++) {			handle->tmp_buffer[n] = src[(n*handle->channels)+c] / 32768.0f;		}				/* Copy temporary buffer into ring buffer*/		size_t len = jack_ringbuffer_write(handle->rb[c], (char*)handle->tmp_buffer, tmp_size);		if (len < tmp_size)        {			error("audio_play_samples(): failed to write to ring ruffer.");			return -1;		}	}			return len;}int audio_close(struct audio_info_struct *ai){	jack_handle_t *handle = (jack_handle_t*)ai->handle;		/*fprintf(stderr, "audio_close().\n");*/	/* Close and shutdown*/	if (handle) {		free_jack_handle( handle );		ai->handle = NULL;    }    	return 0;}void audio_queueflush(struct audio_info_struct *ai){	jack_handle_t *handle = (jack_handle_t*)ai->handle;	int c;	fprintf(stderr, "audio_queueflush().\n");	/* Reset the ring buffers*/	for(c=0; c<handle->channels; c++) {		jack_ringbuffer_reset(handle->rb[c]);	}}

⌨️ 快捷键说明

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