From: Ed W. <li...@wi...> - 2008-01-15 00:36:45
Attachments:
audio_jack_out.c
|
Hi folks I noticed that my patches for proper Jack output now date back to the beginning of 2005 and so with 2008 starting I thought it best to polish them up and release them at last... It's a complete new output layer from previous so I present it as a complete file rather than a patch. I looked over the new branch and can't see any new interfaces which would mean that this wouldn't work with current trunk either? It has been running here fine in various forms for several years. I also wrote the jack output layer for Mythtv (and mplayer although later it was replaced with a new output routine which in turn is the inspiration for this output code) I think it should fix all the complaints about the old code. - It writes to the buffer as fast as possible (person with the FLAC problems before please confirm it's now ok?). The old code strangely blocked until it could write all audio in a single chunk... - kind of a soft semaphore to prevent output when we are filling buffers while paused - arbitrary multichannel, although max channels fixed at compile time (not completely thought through the implications of mono, but chucked it back as non supported to see if xine can do something sensible...) - we only support floats so I added a basic 16 bit converter - I'm assuming that this can go once the new branch is stable though since xine seems to have acquired native support to change sample format? - Should be quite efficient and works in blocks where possible - Quite precise output pointer tracking which should lead to much more stable frame timing (should be sample accurate now) - Support for choosing output ports to bind to !! This is something important that I needed! - Some basic support for dying gracefully if Jack dies. Could probably do more here though Grateful if some jack users could test it and give a thumbs up so that this can be committed to replace the current code ASAP Note that I use this in a fairly extreme multichannel setup where the PC is the center of a lot of high power amplifiers which drive a reasonably high end audio system using correction filters from DRC. Pictures on the DuffRoomCorrection wiki if anyone cares.... http://www.duffroomcorrection.com Ed W |
From: <fla...@gm...> - 2008-01-15 01:15:05
|
Ed Wildgoose <li...@wi...> writes: > I noticed that my patches for proper Jack output now date back to the > beginning of 2005 and so with 2008 starting I thought it best to > polish them up and release them at last... Please look at the jack output plugin in 1.2-audio-out-conversion branch, which is totally renewed already. =2D-=20 Diego "Flameeyes" Petten=C3=B2 http://farragut.flameeyes.is-a-geek.org/ |
From: Ed W <li...@wi...> - 2008-01-16 19:28:29
|
Diego 'Flameeyes' Petten=C3=B2 wrote: > Ed Wildgoose <li...@wi...> writes: > > =20 >> I noticed that my patches for proper Jack output now date back to the >> beginning of 2005 and so with 2008 starting I thought it best to >> polish them up and release them at last... >> =20 > > Please look at the jack output plugin in 1.2-audio-out-conversion > branch, which is totally renewed already. > =20 Where am I looking? I see no changes at: http://hg.debian.org/hg/xine-lib/playgrounds/xine-lib-1.2-audio-out-conve= rsion?f=3Dd5149f2be821;file=3Dsrc/audio_out/audio_jack_out.c;style=3Dgitw= eb Confused? Ed W |
From: Ed W. <li...@wi...> - 2008-02-23 12:05:50
|
Ed W wrote: > Ed W wrote: >> Diego 'Flameeyes' Pettenò wrote: >>> Ed Wildgoose <li...@wi...> writes: >>> >>> >>>> I noticed that my patches for proper Jack output now date back to the >>>> beginning of 2005 and so with 2008 starting I thought it best to >>>> polish them up and release them at last... >>>> >>> >>> Please look at the jack output plugin in 1.2-audio-out-conversion >>> branch, which is totally renewed already. >>> >> >> Where am I looking? I see no changes at: >> >> http://hg.debian.org/hg/xine-lib/playgrounds/xine-lib-1.2-audio-out-conversion?f=d5149f2be821;file=src/audio_out/audio_jack_out.c;style=gitweb >> >> Confused? > > Bump? Anyone? > > Can't see that there is any new code in 1.2? > > Can someone please review my new Jack output layer and either commit > or offer feedback please > > Thanks > > Ed W Some months have gone by.... Any chance of ANYONE ever offering why this can't either be committed or how it needs to be reworked to be included? Diego, I just don't see any new Jack plugin in 1.2? In any case this is a fairly robust and debugged implementation which is in regular use by the writer. Grateful if you would consider including in 1.1 codebase - I offer to handle bug fixes and ongoing support for Jack... Ed W |
From: Ed W. <li...@wi...> - 2008-02-29 23:11:58
|
>>> Can someone please review my new Jack output layer and either commit >>> or offer feedback please >>> > > Seconding that. A month or two ago I checked out the above Hg url, but > it still stuttered. I'd love to see flac working properly through jack. > Can you please confirm that it's fixed with my updated driver? if not can you please send me an example file which doesn't work? My guess is that it was due to the old code blocking until enough space became available to write the whole chunk - if xine were feeding in the chunks larger than the soundcard buffers then it would block until the buffers were empty... Ed W |
From: Ed W. <li...@wi...> - 2008-03-08 19:42:30
Attachments:
audio_jack_out.c
|
John Anderson wrote: > > Where do I get the source for your updated driver? > Did you try following this thread back a few messages? Attached again anyway Ed |
From: John A. <ar...@se...> - 2008-03-19 13:18:11
|
On Sat, 2008-03-08 at 19:42 +0000, Ed Wildgoose wrote: > John Anderson wrote: > > > > Where do I get the source for your updated driver? > > > > Did you try following this thread back a few messages? I didn't. > Attached again anyway Thanks. Works perfectly. Yay! Now I can make music and listen to other music without doing the jack-and-apps-shutdown-dance. bye John |
From: Darren S. <li...@yo...> - 2008-03-19 15:35:58
|
I demand that Ed Wildgoose may or may not have written... > John Anderson wrote: >> Where do I get the source for your updated driver? > Did you try following this thread back a few messages? > Attached again anyway A patch with a suitable commit message would help. At worst, I'll put it in one of the patch queues (which one depends on whether your patch is targetted at 1.1 or 1.2). -- | Darren Salt | linux or ds at | nr. Ashington, | Toon | RISC OS, Linux | youmustbejoking,demon,co,uk | Northumberland | Army | + Use more efficient products. Use less. BE MORE ENERGY EFFICIENT. You will be given a post of trust and responsibility. |
From: Ed W <li...@wi...> - 2008-03-27 15:03:54
|
>> Attached again anyway >> > > A patch with a suitable commit message would help. At worst, I'll put it in > one of the patch queues (which one depends on whether your patch is targetted > at 1.1 or 1.2). > > Thanks for replying Can you put it into both patch queues. It's a complete replacement file so although I can put it in as a patch - basically it's a complete delete and replacement of a single file, so it will be more fragile as a patch than a single file? The make files stay the same - only the output plugin itself is changed As near as I can tell there were no significant useful changes in the 1.2 plugin so no reason not to zap both and replace them with this plugin. We seem to have a few people now tested it with good results on the mailing list (it's used here daily) Cheers Ed Wildgoose |
From: Darren S. <li...@yo...> - 2008-03-27 17:30:38
|
I demand that Ed W may or may not have written... >>> Attached again anyway >> A patch with a suitable commit message would help. At worst, I'll put it >> in one of the patch queues (which one depends on whether your patch is >> targetted at 1.1 or 1.2). > Thanks for replying > Can you put it into both patch queues. I could, but I don't see any point in doing so at present; so it's only in the 1.1 queue for now. I might add it to xine-lib-1.2 in Debian experimental, though. I've taken the opportunity to reformat the source and do one or two minor cleanups, possibly also fixing one bug (x = y < z, where (x = y) < z) was apparently intended; the last 'if' in jack_callback()). And if you can provide a better commit message than "Replacement JACK plugin", do so, else that's what will be used :-) > It's a complete replacement file so although I can put it in as a patch - > basically it's a complete delete and replacement of a single file, so it > will be more fragile as a patch than a single file? Unlikely, given the history of that file. [snip] -- | Darren Salt | linux or ds at | nr. Ashington, | Toon | RISC OS, Linux | youmustbejoking,demon,co,uk | Northumberland | Army | + Use more efficient products. Use less. BE MORE ENERGY EFFICIENT. Why are there no blue M&M's? |
From: Ed W <li...@wi...> - 2008-01-21 12:50:40
|
Ed W wrote: > Diego 'Flameeyes' Pettenò wrote: >> Ed Wildgoose <li...@wi...> writes: >> >> >>> I noticed that my patches for proper Jack output now date back to the >>> beginning of 2005 and so with 2008 starting I thought it best to >>> polish them up and release them at last... >>> >> >> Please look at the jack output plugin in 1.2-audio-out-conversion >> branch, which is totally renewed already. >> > > Where am I looking? I see no changes at: > > http://hg.debian.org/hg/xine-lib/playgrounds/xine-lib-1.2-audio-out-conversion?f=d5149f2be821;file=src/audio_out/audio_jack_out.c;style=gitweb > > Confused? Bump? Anyone? Can't see that there is any new code in 1.2? Can someone please review my new Jack output layer and either commit or offer feedback please Thanks Ed W |
From: John A. <ar...@se...> - 2008-02-26 14:12:28
|
On Sat, 2008-02-23 at 12:05 +0000, Ed Wildgoose wrote: > Ed W wrote: > > Ed W wrote: > > > Diego 'Flameeyes' Pettenò wrote: > > > > Ed Wildgoose <li...@wi...> writes: > > > > > > > > > > > > > I noticed that my patches for proper Jack output now date back to the > > > > > beginning of 2005 and so with 2008 starting I thought it best to > > > > > polish them up and release them at last... > > > > > > > > > > > > > Please look at the jack output plugin in 1.2-audio-out-conversion > > > > branch, which is totally renewed already. > > > > > > > > > > Where am I looking? I see no changes at: > > > > > > http://hg.debian.org/hg/xine-lib/playgrounds/xine-lib-1.2-audio-out-conversion?f=d5149f2be821;file=src/audio_out/audio_jack_out.c;style=gitweb > > > > > > Confused? > > > > Bump? Anyone? > > > > Can't see that there is any new code in 1.2? > > > > Can someone please review my new Jack output layer and either commit > > or offer feedback please Seconding that. A month or two ago I checked out the above Hg url, but it still stuttered. I'd love to see flac working properly through jack. bye John |
From: John A. <ar...@se...> - 2008-03-01 05:43:05
|
On Fri, 2008-02-29 at 23:11 +0000, Ed Wildgoose wrote: > > > > > Can someone please review my new Jack output layer and either commit > > > > or offer feedback please > > > > > > > > Seconding that. A month or two ago I checked out the above Hg url, but > > it still stuttered. I'd love to see flac working properly through jack. > > > > > Can you please confirm that it's fixed with my updated driver? if not > can you please send me an example file which doesn't work? > > My guess is that it was due to the old code blocking until enough > space became available to write the whole chunk - if xine were feeding > in the chunks larger than the soundcard buffers then it would block > until the buffers were empty... Where do I get the source for your updated driver? bye John |
From: tbrooke <tom...@gm...> - 2008-02-29 13:43:04
|
I'm newto linux What do I do? I suppose Iput this in a directroy and run make? I also have a multi channel system feeding audacious into Jack but I want to use Amarok -and maybe myhTV which both use xine. I also have been using drc with Inguz and the squeezebox. I plan to move drc to brutefir and jack so I can create a multi channel and multi driver setup. I was looking into setting up my sub when I found this post on google. I also want to convert my passivecrossoverstopassiveand I have been looking to go fromdrc to acourate but I didn't want to spend the money. It looks like I can do crossovers and correction filters with Jack. to get back on subject what do I do to compile this ? (I'm runnng Ubuntu) Tom Ed Wildgoose-2 wrote: > > Hi folks > > I noticed that my patches for proper Jack output now date back to the > beginning of 2005 and so with 2008 starting I thought it best to polish > them up and release them at last... > > It's a complete new output layer from previous so I present it as a > complete file rather than a patch. I looked over the new branch and > can't see any new interfaces which would mean that this wouldn't work > with current trunk either? > > It has been running here fine in various forms for several years. I > also wrote the jack output layer for Mythtv (and mplayer although later > it was replaced with a new output routine which in turn is the > inspiration for this output code) > > I think it should fix all the complaints about the old code. > > - It writes to the buffer as fast as possible (person with the FLAC > problems before please confirm it's now ok?). The old code strangely > blocked until it could write all audio in a single chunk... > - kind of a soft semaphore to prevent output when we are filling buffers > while paused > - arbitrary multichannel, although max channels fixed at compile time > (not completely thought through the implications of mono, but chucked it > back as non supported to see if xine can do something sensible...) > - we only support floats so I added a basic 16 bit converter - I'm > assuming that this can go once the new branch is stable though since > xine seems to have acquired native support to change sample format? > - Should be quite efficient and works in blocks where possible > - Quite precise output pointer tracking which should lead to much more > stable frame timing (should be sample accurate now) > - Support for choosing output ports to bind to !! This is something > important that I needed! > - Some basic support for dying gracefully if Jack dies. Could probably > do more here though > > Grateful if some jack users could test it and give a thumbs up so that > this can be committed to replace the current code ASAP > > Note that I use this in a fairly extreme multichannel setup where the PC > is the center of a lot of high power amplifiers which drive a reasonably > high end audio system using correction filters from DRC. Pictures on > the DuffRoomCorrection wiki if anyone cares.... > > http://www.duffroomcorrection.com > > Ed W > > > > #include <stdio.h> > #include <errno.h> > #include <string.h> > #include <stdlib.h> > #include <fcntl.h> > #include <math.h> > #include <unistd.h> > #include <inttypes.h> > > #include "xine_internal.h" > #include "xineutils.h" > #include "audio_out.h" > > #include <jack/jack.h> > > #define AO_OUT_JACK_IFACE_VERSION 8 > > #define GAP_TOLERANCE AO_MAX_GAP > //maximum number of channels supported, avoids lots of mallocs > #define MAX_CHANS 6 > > typedef struct jack_driver_s { > > ao_driver_t ao_driver; > xine_t *xine; > > int capabilities; > int mode; > int paused; > int underrun; > > int32_t output_sample_rate, input_sample_rate; > uint32_t num_channels; > uint32_t bits_per_sample; > uint32_t bytes_per_frame; > uint32_t bytes_in_buffer; /* number of bytes writen to audio > hardware */ > uint32_t fragment_size; > > jack_client_t *client; > jack_port_t *ports[MAX_CHANS]; > > //! buffer for audio data > unsigned char *buffer; > > //! buffer read position, may only be modified by playback thread or > while it is stopped > uint32_t read_pos; > //! buffer write position, may only be modified by MPlayer's thread > uint32_t write_pos; > > struct { > int volume; > int mute; > } mixer; > > } jack_driver_t; > > typedef struct { > audio_driver_class_t driver_class; > config_values_t *config; > xine_t *xine; > } jack_class_t; > > > /************************************************************** > * > * Simple ringbuffer implementation > * Lifted from mplayer ao_jack.c > * > **************************************************************/ > > > //! size of one chunk, if this is too small Xine will start to "stutter" > //! after a short time of playback > #define CHUNK_SIZE (16 * 1024) > //! number of "virtual" chunks the buffer consists of > #define NUM_CHUNKS 8 > // This type of ring buffer may never fill up completely, at least > // one byte must always be unused. > // For performance reasons (alignment etc.) one whole chunk always stays > // empty, not only one byte. > #define BUFFSIZE ((NUM_CHUNKS + 1) * CHUNK_SIZE) > > /** > * \brief get the number of free bytes in the buffer > * \return number of free bytes in buffer > * > * may only be called by Xine's thread > * return value may change between immediately following two calls, > * and the real number of free bytes might be larger! > */ > static int buf_free(jack_driver_t *this) { > int free = this->read_pos - this->write_pos - CHUNK_SIZE; > if (free < 0) free += BUFFSIZE; > return free; > } > > /** > * \brief get amount of data available in the buffer > * \return number of bytes available in buffer > * > * may only be called by the playback thread > * return value may change between immediately following two calls, > * and the real number of buffered bytes might be larger! > */ > static int buf_used(jack_driver_t *this) { > int used = this->write_pos - this->read_pos; > if (used < 0) used += BUFFSIZE; > return used; > } > > /** > * \brief insert len bytes into buffer > * \param data data to insert > * \param len length of data > * \return number of bytes inserted into buffer > * > * If there is not enough room, the buffer is filled up > * > * TODO: Xine should really pass data as float, perhaps in V1.2? > */ > static int write_buffer_32(jack_driver_t *this, unsigned char* data, int > len) { > int first_len = BUFFSIZE - this->write_pos; > int free = buf_free(this); > if (len > free) len = free; > if (first_len > len) first_len = len; > > // copy from current write_pos to end of buffer > memcpy (&(this->buffer[this->write_pos]), data, first_len); > if (len > first_len) { // we have to wrap around > // remaining part from beginning of buffer > memcpy (this->buffer, &data[first_len], len - first_len); > } > this->write_pos = (this->write_pos + len) % BUFFSIZE; > > return len; > } > static int write_buffer_16(jack_driver_t *this, unsigned char* data, int > len) { > int samples_free = buf_free(this) / (sizeof(float)); > int samples = len / 2; > if (samples > samples_free) samples = samples_free; > > // Rename some pointers so that the next bit of gymnastics is easier to > read > uint32_t write_pos = this->write_pos; > float *p_write; > int16_t *p_read = (int16_t *)data; > int i; > for (i = 0; i < samples; i++) { > // Read in 16bits, write out floats > p_write = (float*)(&(this->buffer[write_pos])); > *p_write = ((float)(p_read[i])) / 32767.0f; > write_pos = (write_pos + sizeof(float)) % BUFFSIZE; > } > this->write_pos = write_pos; > > return samples * 2; > } > > > > /** > * \brief read data from buffer and splitting it into channels > * \param bufs num_bufs float buffers, each will contain the data of one > channel > * \param cnt number of samples to read per channel > * \param num_bufs number of channels to split the data into > * \return number of samples read per channel, equals cnt unless there was > too > * little data in the buffer > * > * Assumes the data in the buffer is of type float, the number of bytes > * read is res * num_bufs * sizeof(float), where res is the return value. > * If there is not enough data in the buffer remaining parts will be > filled > * with silence. > */ > static int read_buffer(jack_driver_t *this, float **bufs, int cnt, int > num_bufs, float gain) { > int buffered = buf_used(this); > int i, j; > int orig_cnt = cnt; > if (cnt * sizeof(float) * num_bufs > buffered) > cnt = buffered / (sizeof(float) * num_bufs); > > uint32_t read_pos = this->read_pos; > unsigned char *buffer = this->buffer; > for (i = 0; i < cnt; i++) { > for (j = 0; j < num_bufs; j++) { > bufs[j][i] = *((float *)(&(buffer[read_pos]))) * gain; > read_pos = (read_pos + sizeof(float)) % BUFFSIZE; > } > } > this->read_pos = read_pos; > for (i = cnt; i < orig_cnt; i++) > for (j = 0; j < num_bufs; j++) > bufs[j][i] = 0; > > return cnt; > } > > /** > * \brief fill the buffers with silence > * \param bufs num_bufs float buffers, each will contain the data of one > channel > * \param cnt number of samples in each buffer > * \param num_bufs number of buffers > */ > static void silence(float **bufs, int cnt, int num_bufs) { > int i, j; > for (i = 0; i < cnt; i++) > for (j = 0; j < num_bufs; j++) > bufs[j][i] = 0; > } > > > /************************************************************** > * > * Jack interface functions > * > **************************************************************/ > > > /** > * \brief stop playing and empty buffers (for seeking/pause) > */ > static void jack_reset(jack_driver_t *this) { > this->paused = 1; > this->read_pos = this->write_pos = 0; > this->paused = 0; > } > > static int jack_callback(jack_nframes_t nframes, void *arg) > { > jack_driver_t *this = (jack_driver_t *)arg; > > if (!this->client) { > xprintf(this->xine, XINE_VERBOSITY_LOG, "jack_callback: called without > a client parameter? silently trying to continue...\n"); > return 0; > } > > float gain = 0; > if (!this->mixer.mute) { > gain = (float)this->mixer.volume / 100.0; > gain *= gain; // experiment with increasing volume range > } > > float *bufs[MAX_CHANS]; > int i; > for (i = 0; i < this->num_channels; i++) > bufs[i] = jack_port_get_buffer(this->ports[i], nframes); > > if (this->paused || this->underrun) { > silence(bufs, nframes, this->num_channels); > } else { > int frames_read=0; > if (frames_read=read_buffer(this, bufs, nframes, this->num_channels, > gain) < nframes) { > xprintf(this->xine, XINE_VERBOSITY_LOG, "jack_callback: underrun - > frames read: %d\n", frames_read); > this->underrun = 1; > } > } > > return 0; > } > > > static void jack_shutdown(void *arg) > { > jack_driver_t *this = (jack_driver_t *)arg; > this->client = NULL; > } > > /* > * Open the Jack audio device > * Return 1 on success, 0 on failure > * All error handling rests with the caller, we just try to open the > device here > */ > static int jack_open_device(ao_driver_t *this_gen, char *jack_device, > int32_t *poutput_sample_rate, int num_channels) > { > jack_driver_t *this = (jack_driver_t *) this_gen; > const char **matching_ports = NULL; > char *port_name = NULL; > jack_client_t *client = this->client; > > int port_flags = JackPortIsInput; > int i; > int num_ports; > > if (num_channels > MAX_CHANS) { > xprintf(this->xine, XINE_VERBOSITY_LOG, "jack_open_device: Invalid > number of channels: %i\n", num_channels); > goto err_out; > } > // Try to create a client called "xine" > if ((client = jack_client_new("xine")) == 0) { > // If that doesn't work it could be because running two copies of xine > - try using a unique name > char client_name[20]; > sprintf(client_name, "xine (%d)", (int)getpid()); > > if ((client = jack_client_new(client_name)) == 0) { > xprintf(this->xine, XINE_VERBOSITY_LOG, "\njack_open_device: Error: > Failed to connect to JACK server\n"); > xprintf(this->xine, XINE_VERBOSITY_LOG, "jack_open_device: (did you > start 'jackd' server?)\n"); > goto err_out; > } > } > > // Save the new client > this->client = client; > > jack_reset(this); > jack_set_process_callback(client, jack_callback, this); > > // list matching ports > if (!jack_device) > port_flags |= JackPortIsPhysical; > matching_ports = jack_get_ports(client, jack_device, NULL, port_flags); > for (num_ports = 0; matching_ports && matching_ports[num_ports]; > num_ports++) ; > if (!num_ports) { > xprintf(this->xine, XINE_VERBOSITY_LOG, "jack_open_device: no physical > ports available\n"); > goto err_out; > } > if (num_ports < num_channels) { > xprintf(this->xine, XINE_VERBOSITY_LOG, "jack_open_device: not enough > physical ports available\n"); > goto err_out; > } > > // create output ports > for (i = 0; i < num_channels; i++) { > char pname[50]; > snprintf(pname, 50, "out_%d", i); > this->ports[i] = jack_port_register(client, pname, > JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); > if (!this->ports[i]) { > xprintf(this->xine, XINE_VERBOSITY_LOG, "jack_open_device: could not > create output ports? Why not?\n"); > goto err_out; > } > } > if (jack_activate(client)) { > xprintf(this->xine, XINE_VERBOSITY_LOG, "jack_open_device: > jack_activate() failed\n"); > goto err_out; > } > for (i = 0; i < num_channels; i++) { > if (jack_connect(client, jack_port_name(this->ports[i]), > matching_ports[i])) { > xprintf(this->xine, XINE_VERBOSITY_LOG, "jack_open_device: > jack_connect() failed\n"); > goto err_out; > } > } > *poutput_sample_rate = jack_get_sample_rate(client); > > free(matching_ports); > return 1; > > err_out: > free(matching_ports); > if (client) { > jack_client_close(client); > this->client = NULL; > } > return 0; > } > > > /************************************************************** > * > * Xine interface functions > * > **************************************************************/ > > > /** > * close the device and reset the play position > */ > static void ao_jack_close(ao_driver_t *this_gen) > { > jack_driver_t *this = (jack_driver_t *) this_gen; > xprintf(this->xine, XINE_VERBOSITY_DEBUG, "ao_jack_close: closing\n"); > > jack_reset(this); > if (this->client) { > jack_client_close(this->client); > this->client = NULL; > } > } > > /* > * open the audio device for writing to > */ > static int ao_jack_open(ao_driver_t *this_gen, uint32_t bits, uint32_t > rate, int mode) > { > jack_driver_t *this = (jack_driver_t *) this_gen; > config_values_t *config = this->xine->config; > char *jack_device; > > jack_device = config->lookup_entry(config, > "audio.device.jack_device_name")->str_value; > > xprintf(this->xine, XINE_VERBOSITY_DEBUG, > "ao_jack_open: ao_open rate=%d, mode=%d, bits=%d dev=%s\n", rate, mode, > bits, jack_device); > > if ((bits != 16) && (bits != 32)) { > xprintf(this->xine, XINE_VERBOSITY_LOG, "ao_jack_open: bits=%u > expected 16 or 32bit only\n", bits); > return 0; > } > > if ( (mode & this->capabilities) == 0 ) { > xprintf (this->xine, XINE_VERBOSITY_LOG, "ao_jack_open: unsupported > mode %08x\n", mode); > return 0; > } > > // If device open already then either re-use it or close it > if (this->client) { > if ( (mode == this->mode) && (rate == this->input_sample_rate) ) { > xprintf (this->xine, XINE_VERBOSITY_DEBUG, "ao_jack_open: device > already open, reusing it\n"); > return this->output_sample_rate; > } > > ao_jack_close(this_gen); > } > > > this->mode = mode; > this->input_sample_rate = rate; > this->bits_per_sample = bits; > this->bytes_in_buffer = 0; > this->read_pos = this->write_pos = 0; > this->paused = 0; > this->underrun = 0; > > /* > * set number of channels / a52 passthrough > */ > switch (mode) { > case AO_CAP_MODE_MONO: > this->num_channels = 1; > break; > case AO_CAP_MODE_STEREO: > this->num_channels = 2; > break; > case AO_CAP_MODE_4CHANNEL: > this->num_channels = 4; > break; > case AO_CAP_MODE_4_1CHANNEL: > case AO_CAP_MODE_5CHANNEL: > case AO_CAP_MODE_5_1CHANNEL: > this->num_channels = 6; > break; > case AO_CAP_MODE_A52: > case AO_CAP_MODE_AC5: > /* FIXME: Is this correct...? */ > this->num_channels = 2; > xprintf(this->xine, XINE_VERBOSITY_DEBUG, "ao_jack_open: > AO_CAP_MODE_A52\n"); > break; > default: > xprintf (this->xine, XINE_VERBOSITY_LOG, > "ao_jack_open: JACK Driver does not support the requested > mode: 0x%X\n",mode); > return 0; > } > > xprintf(this->xine, XINE_VERBOSITY_LOG, "ao_jack_open: %d channels > output\n", this->num_channels); > this->bytes_per_frame=(this->bits_per_sample*this->num_channels)/8; > > /* > * open audio device > */ > if (! jack_open_device(this_gen, jack_device, > &(this->output_sample_rate), this->num_channels)) > return 0; > > if (this->input_sample_rate != this->output_sample_rate) { > xprintf (this->xine, XINE_VERBOSITY_DEBUG, > "ao_jack_open: audio rate : %d requested, %d provided by > device\n", > this->input_sample_rate, this->output_sample_rate); > } > > return this->output_sample_rate; > } > > > static int ao_jack_num_channels(ao_driver_t *this_gen) > { > jack_driver_t *this = (jack_driver_t *) this_gen; > return this->num_channels; > } > > static int ao_jack_bytes_per_frame(ao_driver_t *this_gen) > { > jack_driver_t *this = (jack_driver_t *) this_gen; > return this->bytes_per_frame; > } > > static int ao_jack_get_gap_tolerance (ao_driver_t *this_gen) > { > return GAP_TOLERANCE; > } > > /* > * Return the number of outstanding frames in all output buffers > * need to account for ring buffer plus Jack, plus soundcard > */ > static int ao_jack_delay(ao_driver_t *this_gen) > { > jack_driver_t *this = (jack_driver_t *) this_gen; > int frames_played = jack_frames_since_cycle_start(this->client); > > int delay = 0; > // Ring Buffer always stores floats > // TODO: Unsure if the delay should be fragment_size*2 or *3? > delay = buf_used(this) / (sizeof(float) * this->num_channels) + > this->fragment_size*3 - frames_played; > > return delay; > } > > /* Write audio samples > * num_frames is the number of audio frames present > * audio frames are equivalent one sample on each channel. > * I.E. Stereo 16 bits audio frames are 4 bytes. > * MUST SIMULATE BLOCKING WRITES > */ > static int ao_jack_write(ao_driver_t *this_gen, > int16_t* frame_buffer, uint32_t num_frames) > { > jack_driver_t *this = (jack_driver_t *) this_gen; > int written = 0; > int num_bytes = num_frames * this->bytes_per_frame; > > /* First try and write all the bytes in one go */ > this->underrun = 0; > // TODO: In the future Xine should pass only floats to us, so no > conversion needed > if (this->bits_per_sample == 16) > written = write_buffer_16(this, (char *)frame_buffer, num_bytes); > else if (this->bits_per_sample == 32) > written = write_buffer_32(this, (char *)frame_buffer, num_bytes); > > /* If this fails then need to spin and keep trying until everything > written */ > int spin_count = 0; > while ((written < num_bytes) && (spin_count < 40)) { > num_bytes -= written; > frame_buffer += written/2; > > /* Sleep to save CPU */ > int until_callback = this->fragment_size - > jack_frames_since_cycle_start(this->client); > if ((until_callback < 0) || (until_callback > this->fragment_size)) { > xprintf (this->xine, XINE_VERBOSITY_DEBUG, "ao_jack_write: Invalid > until_callback %d\n", until_callback); > until_callback = this->fragment_size; > } > > xine_usec_sleep(((until_callback+100)*1000.0*1000.0)/this->output_sample_rate); > > if (this->bits_per_sample == 16) > written = write_buffer_16(this, (char *)frame_buffer, num_bytes); > else if (this->bits_per_sample == 32) > written = write_buffer_32(this, (char *)frame_buffer, num_bytes); > > if (written == 0) > spin_count++; > else > spin_count=0; > > if (written == 0) > xprintf (this->xine, XINE_VERBOSITY_DEBUG, "ao_jack_write: unusual, > couldn't write anything\n"); > }; > > if (spin_count) > xprintf (this->xine, XINE_VERBOSITY_DEBUG, "Nonzero > spin_count...%d\n",spin_count); > > return spin_count ? 0 : 1; // return 1 on success, 0 if we got stuck for > some reason > } > > static uint32_t ao_jack_get_capabilities (ao_driver_t *this_gen) { > jack_driver_t *this = (jack_driver_t *) this_gen; > return this->capabilities; > } > > static void ao_jack_exit(ao_driver_t *this_gen) > { > jack_driver_t *this = (jack_driver_t *) this_gen; > > ao_jack_close(this_gen); > if (this->buffer) free(this->buffer); > free (this); > } > > static int ao_jack_get_property(ao_driver_t *this_gen, int property) { > jack_driver_t *this = (jack_driver_t *) this_gen; > > switch(property) { > case AO_PROP_PCM_VOL: > case AO_PROP_MIXER_VOL: > return this->mixer.volume; > break; > case AO_PROP_MUTE_VOL: > return this->mixer.mute; > break; > } > > return 0; > } > > static int ao_jack_set_property(ao_driver_t *this_gen, int property, int > value) { > jack_driver_t *this = (jack_driver_t *) this_gen; > > switch(property) { > case AO_PROP_PCM_VOL: > case AO_PROP_MIXER_VOL: > this->mixer.volume = value; > return value; > break; > case AO_PROP_MUTE_VOL: > this->mixer.mute = value; > return value; > break; > } > > return -1; > } > > static int ao_jack_ctrl(ao_driver_t *this_gen, int cmd, ...) { > jack_driver_t *this = (jack_driver_t *) this_gen; > > switch (cmd) { > > case AO_CTRL_PLAY_PAUSE: > this->paused = 1; > break; > > case AO_CTRL_PLAY_RESUME: > this->paused = 0; > break; > > case AO_CTRL_FLUSH_BUFFERS: > jack_reset(this); > break; > } > > return 0; > } > > static void jack_speaker_arrangement_cb (void *user_data, > xine_cfg_entry_t *entry); > > static ao_driver_t *open_jack_plugin (audio_driver_class_t *class_gen, > const void *data) > { > jack_class_t *class = (jack_class_t *) class_gen; > config_values_t *config = class->config; > jack_driver_t *this; > > jack_client_t *client; > uint32_t rate; > char *jack_device; > const char **matching_ports = NULL; > const char **port_names; > > /* for usability reasons, keep this in sync with audio_oss_out.c */ > static char *speaker_arrangement[] = {"Mono 1.0", "Stereo 2.0", > "Headphones 2.0", "Stereo 2.1", > "Surround 3.0", "Surround 4.0", "Surround 4.1", "Surround 5.0", > "Surround 5.1", "Surround 6.0", > "Surround 6.1", "Surround 7.1", "Pass Through", NULL}; > #define MONO 0 > #define STEREO 1 > #define HEADPHONES 2 > #define SURROUND21 3 > #define SURROUND3 4 > #define SURROUND4 5 > #define SURROUND41 6 > #define SURROUND5 7 > #define SURROUND51 8 > #define SURROUND6 9 > #define SURROUND61 10 > #define SURROUND71 11 > #define A52_PASSTHRU 12 > int speakers; > > // Try to create a client called "xine" > if ((client = jack_client_new("xine")) == 0) { > // If that doesn't work it could be because running two copies of xine > - try using a unique name > char name[20]; > sprintf(name, "xine (%d)", (int)getpid()); > > if ((client = jack_client_new(name)) == 0) { > xprintf(class->xine, XINE_VERBOSITY_LOG, "\nopen_jack_plugin: Error: > Failed to connect to JACK server\n"); > xprintf(class->xine, XINE_VERBOSITY_LOG, "open_jack_plugin: (did you > start 'jackd' server?)\n"); > return 0; > } > } > > this = (jack_driver_t *) xine_xmalloc (sizeof (jack_driver_t)); > > rate = jack_get_sample_rate(client); > xprintf(class->xine, XINE_VERBOSITY_DEBUG, "open_jack_plugin: JACK > sample rate is %u\n", rate); > > /* devname_val is offset used to select auto, /dev/dsp, or > /dev/sound/dsp */ > jack_device = config->register_string (config, > "audio.device.jack_device_name", > "", > _("JACK audio device name"), > _("Specifies the jack audio device name, " > "leave blank for the default physical output port."), > 10, NULL, NULL); > > this->capabilities = 0; > > > /* for usability reasons, keep this in sync with audio_alsa_out.c */ > speakers = config->register_enum(config, > "audio.output.speaker_arrangement", STEREO, > speaker_arrangement, > _("speaker arrangement"), > _("Select how your speakers are arranged, " > "this determines which speakers xine uses for sound output. " > "The individual values are:\n\n" > "Mono 1.0: You have only one speaker.\n" > "Stereo 2.0: You have two speakers for left and right channel.\n" > "Headphones 2.0: You use headphones.\n" > "Stereo 2.1: You have two speakers for left and right channel, and > one " > "subwoofer for the low frequencies.\n" > "Surround 3.0: You have three speakers for left, right and rear > channel.\n" > "Surround 4.0: You have four speakers for front left and right and > rear " > "left and right channels.\n" > "Surround 4.1: You have four speakers for front left and right and > rear " > "left and right channels, and one subwoofer for the low > frequencies.\n" > "Surround 5.0: You have five speakers for front left, center and > right and " > "rear left and right channels.\n" > "Surround 5.1: You have five speakers for front left, center and > right and " > "rear left and right channels, and one subwoofer for the low > frequencies.\n" > "Surround 6.0: You have six speakers for front left, center and right > and " > "rear left, center and right channels.\n" > "Surround 6.1: You have six speakers for front left, center and right > and " > "rear left, center and right channels, and one subwoofer for the low > frequencies.\n" > "Surround 7.1: You have seven speakers for front left, center and > right, " > "left and right and rear left and right channels, and one subwoofer > for the " > "low frequencies.\n" > "Pass Through: Your sound system will receive undecoded digital sound > from xine. " > "You need to connect a digital surround decoder capable of decoding > the " > "formats you want to play to your sound card's digital output."), > 0, jack_speaker_arrangement_cb, this); > > int port_flags = JackPortIsInput; > int num_ports; > // list matching ports > if (!jack_device) > port_flags |= JackPortIsPhysical; > // Find all the ports matching either the desired device regexp or > physical output ports > matching_ports = jack_get_ports(client, jack_device, NULL, port_flags); > // Count 'em > for (num_ports = 0; matching_ports && matching_ports[num_ports]; > num_ports++) ; > if (!num_ports) { > xprintf(this->xine, XINE_VERBOSITY_LOG, "open_jack_plugin: no physical > ports available\n"); > goto err_out; > } > > > // TODO: We deliberately don't offer mono, let Xine upsample instead? > // if (num_ports >= 1) { > // this->capabilities |= AO_CAP_MODE_MONO; > // xprintf(class->xine, XINE_VERBOSITY_DEBUG, "mono "); > // } > > if (num_ports >= 2) { > this->capabilities |= AO_CAP_MODE_STEREO; > xprintf(class->xine, XINE_VERBOSITY_DEBUG, "stereo "); > } > > if (num_ports >= 4) { > if ( speakers == SURROUND4 ) { > this->capabilities |= AO_CAP_MODE_4CHANNEL; > xprintf(class->xine, XINE_VERBOSITY_DEBUG, "4-channel "); > } else > xprintf(class->xine, XINE_VERBOSITY_DEBUG, "(4-channel not enabled > in xine config) " ); > } > > if (num_ports >= 5) { > if ( speakers == SURROUND5 ) { > this->capabilities |= AO_CAP_MODE_5CHANNEL; > xprintf(class->xine, XINE_VERBOSITY_DEBUG, "5-channel "); > } else > xprintf(class->xine, XINE_VERBOSITY_DEBUG, "(5-channel not enabled > in xine config) " ); > } > > if (num_ports >= 6) { > if ( speakers == SURROUND51 ) { > this->capabilities |= AO_CAP_MODE_5_1CHANNEL; > xprintf(class->xine, XINE_VERBOSITY_DEBUG, "5.1-channel "); > } else > xprintf(class->xine, XINE_VERBOSITY_DEBUG, "(5.1-channel not enabled > in xine config) " ); > } > > this->buffer = (unsigned char *) malloc(BUFFSIZE); > jack_reset(this); > > this->capabilities |= AO_CAP_MIXER_VOL; > this->capabilities |= AO_CAP_MUTE_VOL; > // TODO: Currently not respected by Xine, perhaps v1.2? > this->capabilities |= AO_CAP_FLOAT32; > > > this->mixer.mute = 0; > this->mixer.volume = 100; > > this->output_sample_rate = jack_get_sample_rate(client); > this->fragment_size = jack_get_buffer_size(client); > > // Close our JACK client > jack_client_close(client); > > this->xine = class->xine; > > this->ao_driver.get_capabilities = ao_jack_get_capabilities; > this->ao_driver.get_property = ao_jack_get_property; > this->ao_driver.set_property = ao_jack_set_property; > this->ao_driver.open = ao_jack_open; > this->ao_driver.num_channels = ao_jack_num_channels; > this->ao_driver.bytes_per_frame = ao_jack_bytes_per_frame; > this->ao_driver.delay = ao_jack_delay; > this->ao_driver.write = ao_jack_write; > this->ao_driver.close = ao_jack_close; > this->ao_driver.exit = ao_jack_exit; > this->ao_driver.get_gap_tolerance = ao_jack_get_gap_tolerance; > this->ao_driver.control = ao_jack_ctrl; > > return &this->ao_driver; > > err_out: > free(matching_ports); > if (client) > jack_client_close(client); > return 0; > } > > static void jack_speaker_arrangement_cb (void *user_data, > xine_cfg_entry_t *entry) { > jack_driver_t *this = (jack_driver_t *) user_data; > int32_t value = entry->num_value; > if (value == SURROUND4) { > this->capabilities |= AO_CAP_MODE_4CHANNEL; > } else { > this->capabilities &= ~AO_CAP_MODE_4CHANNEL; > } > if (value == SURROUND41) { > this->capabilities |= AO_CAP_MODE_4_1CHANNEL; > } else { > this->capabilities &= ~AO_CAP_MODE_4_1CHANNEL; > } > if (value == SURROUND5) { > this->capabilities |= AO_CAP_MODE_5CHANNEL; > } else { > this->capabilities &= ~AO_CAP_MODE_5CHANNEL; > } > if (value >= SURROUND51) { > this->capabilities |= AO_CAP_MODE_5_1CHANNEL; > } else { > this->capabilities &= ~AO_CAP_MODE_5_1CHANNEL; > } > } > > /* > * class functions > */ > > static char* get_identifier (audio_driver_class_t *this_gen) { > return "jack"; > } > > static char* get_description (audio_driver_class_t *this_gen) { > return _("xine output plugin for JACK Audio Connection Kit"); > } > > static void dispose_class (audio_driver_class_t *this_gen) { > > jack_class_t *this = (jack_class_t *) this_gen; > free (this); > } > > static void *init_class (xine_t *xine, void *data) { > > jack_class_t *this; > > this = (jack_class_t *) xine_xmalloc (sizeof (jack_class_t)); > > this->driver_class.open_plugin = open_jack_plugin; > this->driver_class.get_identifier = get_identifier; > this->driver_class.get_description = get_description; > this->driver_class.dispose = dispose_class; > > this->config = xine->config; > this->xine = xine; > > return this; > } > > static ao_info_t ao_info_jack = { > 6 > }; > > /* > * exported plugin catalog entry > */ > > const plugin_info_t xine_plugin_info[] EXPORTED = { > /* type, API, "name", version, special_info, init_function */ > { PLUGIN_AUDIO_OUT, AO_OUT_JACK_IFACE_VERSION, "jack", > XINE_VERSION_CODE /* XINE_VERSION_CODE */, &ao_info_jack, init_class }, > { PLUGIN_NONE, 0, "", 0, NULL, NULL } > }; > > > ------------------------------------------------------------------------- > Check out the new SourceForge.net Marketplace. > It's the best place to buy or sell services for > just about anything Open Source. > http://ad.doubleclick.net/clk;164216239;13503038;w?http://sf.net/marketplace > _______________________________________________ > xine-devel mailing list > xin...@li... > https://lists.sourceforge.net/lists/listinfo/xine-devel > > -- View this message in context: http://www.nabble.com/Updated-Jack-Output-plugin-tp14822217p15758843.html Sent from the xine-devel mailing list archive at Nabble.com. |
From: Ed W. <li...@wi...> - 2008-03-15 18:33:18
|
Hi > I suppose Iput this in a directroy and run make? > Yep, just overwrite the existing file with the same name. Dont' forget to make sure that you run configure with the appropriate options > I also have a multi channel system feeding audacious into Jack but I want to > use Amarok -and maybe myhTV which both use xine. I use mythtv + Xine with DSP crossovers and correction filters designed using DRC. A multichannel soundcard (RME 9632) is directly hooked up to a bunch of poweramps and everything is driven from the PC. Works really really nicely. I have 4x 15" subwoofers in an infinite baffle configuration (using the space under the floor as the speaker box) and this drives nicely down to single Hz levels (you can make the double glazing flex quite easily...) I'm really not quite sure why not only has this not been considered for inclusion, but the Xine maintainers are rather rudely refusing even to comment on it... I have simply patched my own code, but I think it's rather rude not to even respond to patches... > It looks like I can do > crossovers and correction filters with Jack. > You probably want to read the wiki at http://www.duffroomcorrection.com and hang out on the DRC list which really covers all systems Good luck Ed W |
From: Darren S. <li...@yo...> - 2008-03-15 19:30:32
|
I demand that Ed Wildgoose may or may not have written... [snip] > I'm really not quite sure why not only has this not been considered for > inclusion, but the Xine maintainers are rather rudely refusing even to > comment on it... Are you sure? I've been leaving commenting on it to others... [snip] -- | Darren Salt | linux or ds at | nr. Ashington, | Toon | RISC OS, Linux | youmustbejoking,demon,co,uk | Northumberland | Army | + Use more efficient products. Use less. BE MORE ENERGY EFFICIENT. If not controlled, work flows to the competent person until he is submerged. |