From cf6f5debd57c2cba3ad63a8d697d656b54cb94da Mon Sep 17 00:00:00 2001 From: Darren Salt Date: Thu, 12 Jun 2008 20:55:44 +0100 Subject: Fix up reporting of supported formats by the ALSA & OSS output plugins. Adjust translations for the spacing changes etc. which this introduces. --- src/audio_out/audio_alsa_out.c | 44 ++++++++++++++++++++++++------------------ src/audio_out/audio_oss_out.c | 33 ++++++++++++++++--------------- src/xine-utils/utils.c | 8 ++++++++ src/xine-utils/xineutils.h | 7 +++++++ 4 files changed, 57 insertions(+), 35 deletions(-) (limited to 'src') diff --git a/src/audio_out/audio_alsa_out.c b/src/audio_out/audio_alsa_out.c index e68d80a71..470cd953a 100644 --- a/src/audio_out/audio_alsa_out.c +++ b/src/audio_out/audio_alsa_out.c @@ -1497,70 +1497,73 @@ static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, const void *da "formats you want to play to your sound card's digital output."), 0, alsa_speaker_arrangement_cb, this); - xprintf(class->xine, XINE_VERBOSITY_LOG, _("audio_alsa_out : supported modes are ")); + char *logmsg = strdup (_("audio_alsa_out : supported modes are")); + if (!(snd_pcm_hw_params_test_format(this->audio_fd, params, SND_PCM_FORMAT_U8))) { this->capabilities |= AO_CAP_8BITS; - xprintf(class->xine, XINE_VERBOSITY_LOG, _("8bit ")); + xine_strcat_realloc (&logmsg, _(" 8bit")); } /* ALSA automatically appends _LE or _BE depending on the CPU */ if (!(snd_pcm_hw_params_test_format(this->audio_fd, params, SND_PCM_FORMAT_S16))) { this->capabilities |= AO_CAP_16BITS; - xprintf(class->xine, XINE_VERBOSITY_LOG, _("16bit ")); + xine_strcat_realloc (&logmsg, _(" 16bit")); } if (!(snd_pcm_hw_params_test_format(this->audio_fd, params, SND_PCM_FORMAT_S24))) { this->capabilities |= AO_CAP_24BITS; - xprintf(class->xine, XINE_VERBOSITY_LOG, _("24bit ")); + xine_strcat_realloc (&logmsg, _(" 24bit")); } if (!(snd_pcm_hw_params_test_format(this->audio_fd, params, SND_PCM_FORMAT_FLOAT))) { this->capabilities |= AO_CAP_FLOAT32; - xprintf(class->xine, XINE_VERBOSITY_LOG, _("32bit ")); + xine_strcat_realloc (&logmsg, _(" 32bit")); } if (0 == (this->capabilities & (AO_CAP_FLOAT32 | AO_CAP_24BITS | AO_CAP_16BITS | AO_CAP_8BITS))) { - xprintf (this->class->xine, XINE_VERBOSITY_DEBUG, - "\naudio_alsa_out: no supported PCM format found\n"); + xprintf(class->xine, XINE_VERBOSITY_LOG, "%s\n", logmsg); + free (logmsg); + xprintf (class->xine, XINE_VERBOSITY_DEBUG, + "audio_alsa_out: no supported PCM format found\n"); snd_pcm_close(this->audio_fd); free(this); return NULL; } if (!(snd_pcm_hw_params_test_channels(this->audio_fd, params, 1))) { this->capabilities |= AO_CAP_MODE_MONO; - xprintf(class->xine, XINE_VERBOSITY_LOG, _("mono ")); + xine_strcat_realloc (&logmsg, _(" mono")); } if (!(snd_pcm_hw_params_test_channels(this->audio_fd, params, 2))) { this->capabilities |= AO_CAP_MODE_STEREO; - xprintf(class->xine, XINE_VERBOSITY_LOG, _("stereo ")); + xine_strcat_realloc (&logmsg, _(" stereo")); } if (!(snd_pcm_hw_params_test_channels(this->audio_fd, params, 4)) && ( speakers == SURROUND4 )) { this->capabilities |= AO_CAP_MODE_4CHANNEL; - xprintf(class->xine, XINE_VERBOSITY_LOG, _("4-channel ")); + xine_strcat_realloc (&logmsg, _(" 4-channel")); } else - xprintf(class->xine, XINE_VERBOSITY_LOG, _("(4-channel not enabled in xine config) ")); + xine_strcat_realloc (&logmsg, _(" (4-channel not enabled in xine config)")); if (!(snd_pcm_hw_params_test_channels(this->audio_fd, params, 6)) && ( speakers == SURROUND41 )) { this->capabilities |= AO_CAP_MODE_4_1CHANNEL; - xprintf(class->xine, XINE_VERBOSITY_LOG, _("4.1-channel ")); + xine_strcat_realloc (&logmsg, _(" 4.1-channel")); } else - xprintf(class->xine, XINE_VERBOSITY_LOG, _("(4.1-channel not enabled in xine config) ")); + xine_strcat_realloc (&logmsg, _(" (4.1-channel not enabled in xine config)")); if (!(snd_pcm_hw_params_test_channels(this->audio_fd, params, 6)) && ( speakers == SURROUND5 )) { this->capabilities |= AO_CAP_MODE_5CHANNEL; - xprintf(class->xine, XINE_VERBOSITY_LOG, _("5-channel ")); + xine_strcat_realloc (&logmsg, _(" 5-channel")); } else - xprintf(class->xine, XINE_VERBOSITY_LOG, _("(5-channel not enabled in xine config) ")); + xine_strcat_realloc (&logmsg, _(" (5-channel not enabled in xine config)")); if (!(snd_pcm_hw_params_test_channels(this->audio_fd, params, 6)) && ( speakers >= SURROUND51 )) { this->capabilities |= AO_CAP_MODE_5_1CHANNEL; - xprintf(class->xine, XINE_VERBOSITY_LOG, _("5.1-channel ")); + xine_strcat_realloc (&logmsg, _(" 5.1-channel")); } else - xprintf(class->xine, XINE_VERBOSITY_LOG, _("(5.1-channel not enabled in xine config) ")); + xine_strcat_realloc (&logmsg, _(" (5.1-channel not enabled in xine config)")); this->has_pause_resume = 0; /* This is checked at open time instead */ this->is_paused = 0; @@ -1583,10 +1586,13 @@ static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, const void *da if ( speakers == A52_PASSTHRU ) { this->capabilities |= AO_CAP_MODE_A52; this->capabilities |= AO_CAP_MODE_AC5; - xprintf(class->xine, XINE_VERBOSITY_LOG, _("a/52 and DTS pass-through\n")); + xine_strcat_realloc (&logmsg, _(" a/52 and DTS pass-through")); } else - xprintf(class->xine, XINE_VERBOSITY_LOG, _("(a/52 and DTS pass-through not enabled in xine config)\n")); + xine_strcat_realloc (&logmsg, _(" (a/52 and DTS pass-through not enabled in xine config)")); + + xprintf(class->xine, XINE_VERBOSITY_LOG, "%s\n", logmsg); + free (logmsg); /* printf("audio_alsa_out: capabilities 0x%X\n",this->capabilities); */ diff --git a/src/audio_out/audio_oss_out.c b/src/audio_out/audio_oss_out.c index df29a43ea..2ae116970 100644 --- a/src/audio_out/audio_oss_out.c +++ b/src/audio_out/audio_oss_out.c @@ -877,10 +877,7 @@ static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, const void *da if (this->sync_method == OSS_SYNC_PROBEBUFFER) { char *buf; int c; - - xprintf(class->xine, XINE_VERBOSITY_LOG, - _("audio_oss_out: Audio driver realtime sync disabled...\n" - "audio_oss_out: ...probing output buffer size: ")); + this->buffer_size = 0; if( (buf=calloc(1, 1024)) != NULL ) { @@ -894,7 +891,8 @@ static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, const void *da } close(audio_fd); xprintf(class->xine, XINE_VERBOSITY_LOG, - _("%d bytes\naudio_oss_out: ...there may be audio/video synchronization issues\n"), this->buffer_size); + _("audio_oss_out: Audio driver realtime sync disabled...\n" + "audio_oss_out: ...probing output buffer size: %d bytes\naudio_oss_out: ...there may be audio/video synchronization issues\n"), this->buffer_size); audio_fd=open(this->audio_dev, O_WRONLY|O_NONBLOCK); @@ -957,48 +955,48 @@ static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, const void *da 0, oss_speaker_arrangement_cb, this); - xprintf(class->xine, XINE_VERBOSITY_DEBUG, "audio_oss_out: supported modes are "); + char *logmsg = strdup (_("audio_oss_out: supported modes are")); num_channels = 1; status = ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &num_channels); if ( (status != -1) && (num_channels==1) ) { this->capabilities |= AO_CAP_MODE_MONO; - xprintf(class->xine, XINE_VERBOSITY_DEBUG, "mono "); + xine_strcat_realloc (&logmsg, _(" mono")); } num_channels = 2; status = ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &num_channels); if ( (status != -1) && (num_channels==2) ) { this->capabilities |= AO_CAP_MODE_STEREO; - xprintf(class->xine, XINE_VERBOSITY_DEBUG, "stereo "); + xine_strcat_realloc (&logmsg, _(" stereo")); } num_channels = 4; status = ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &num_channels); if ( (status != -1) && (num_channels==4) ) { if ( speakers == SURROUND4 ) { this->capabilities |= AO_CAP_MODE_4CHANNEL; - xprintf(class->xine, XINE_VERBOSITY_DEBUG, "4-channel "); + xine_strcat_realloc (&logmsg, _(" 4-channel")); } else - xprintf(class->xine, XINE_VERBOSITY_DEBUG, "(4-channel not enabled in xine config) " ); + xine_strcat_realloc (&logmsg, _(" (4-channel not enabled in xine config)")); } num_channels = 5; status = ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &num_channels); if ( (status != -1) && (num_channels==5) ) { if ( speakers == SURROUND5 ) { this->capabilities |= AO_CAP_MODE_5CHANNEL; - xprintf(class->xine, XINE_VERBOSITY_DEBUG, "5-channel "); + xine_strcat_realloc (&logmsg, _(" 5-channel")); } else - xprintf(class->xine, XINE_VERBOSITY_DEBUG, "(5-channel not enabled in xine config) " ); + xine_strcat_realloc (&logmsg, _(" (5-channel not enabled in xine config)")); } num_channels = 6; status = ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &num_channels); if ( (status != -1) && (num_channels==6) ) { if ( speakers == SURROUND51 ) { this->capabilities |= AO_CAP_MODE_5_1CHANNEL; - xprintf(class->xine, XINE_VERBOSITY_DEBUG, "5.1-channel "); + xine_strcat_realloc (&logmsg, _(" 5.1-channel")); } else - xprintf(class->xine, XINE_VERBOSITY_DEBUG, "(5.1-channel not enabled in xine config) " ); + xine_strcat_realloc (&logmsg, _(" (5.1-channel not enabled in xine config)")); } ioctl(audio_fd,SNDCTL_DSP_GETFMTS,&caps); @@ -1008,10 +1006,13 @@ static ao_driver_t *open_plugin (audio_driver_class_t *class_gen, const void *da if ( speakers == A52_PASSTHRU ) { this->capabilities |= AO_CAP_MODE_A52; this->capabilities |= AO_CAP_MODE_AC5; - xprintf(class->xine, XINE_VERBOSITY_DEBUG, "a/52-pass-through "); + xine_strcat_realloc (&logmsg, _(" a/52 pass-through")); } else - xprintf(class->xine, XINE_VERBOSITY_DEBUG, "(a/52-pass-through not enabled in xine config)"); + xine_strcat_realloc (&logmsg, _(" (a/52 pass-through not enabled in xine config)")); + + xprintf(class->xine, XINE_VERBOSITY_DEBUG, "%s\n", logmsg); + free (logmsg); /* * mixer initialisation. diff --git a/src/xine-utils/utils.c b/src/xine-utils/utils.c index 9f5d122cb..f533d69e5 100644 --- a/src/xine-utils/utils.c +++ b/src/xine-utils/utils.c @@ -692,3 +692,11 @@ int xine_monotonic_clock(struct timeval *tv, struct timezone *tz) #endif } + +char *xine_strcat_realloc (char **dest, char *append) +{ + char *newstr = realloc (*dest, (*dest ? strlen (*dest) : 0) + strlen (append) + 1); + if (newstr) + strcat (*dest = newstr, append); + return newstr; +} diff --git a/src/xine-utils/xineutils.h b/src/xine-utils/xineutils.h index 3d630b066..2d6425b00 100644 --- a/src/xine-utils/xineutils.h +++ b/src/xine-utils/xineutils.h @@ -969,6 +969,13 @@ const char *xine_guess_spu_encoding(void) XINE_PROTECTED; */ int xine_monotonic_clock(struct timeval *tv, struct timezone *tz) XINE_PROTECTED; +/** + * append to a string, reallocating + * normally, updates & returns *dest + * on error, *dest is unchanged & NULL is returned. + */ +char *xine_strcat_realloc (char **dest, char *append) XINE_PROTECTED; + /* don't harm following code */ #ifdef extern # undef extern -- cgit v1.2.3 From c933983028f45ef90684a1794e2625ba5e5b6861 Mon Sep 17 00:00:00 2001 From: Darren Salt Date: Sat, 14 Jun 2008 16:29:03 +0100 Subject: Extra MIME types for Quicktime/ISO media. --- src/demuxers/demux_qt.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/demuxers/demux_qt.c b/src/demuxers/demux_qt.c index e51344798..1fa9b4327 100644 --- a/src/demuxers/demux_qt.c +++ b/src/demuxers/demux_qt.c @@ -3095,7 +3095,9 @@ static const char *get_mimetypes (demux_class_t *this_gen) { return "video/quicktime: mov,qt: Quicktime animation;" "video/x-quicktime: mov,qt: Quicktime animation;" "audio/x-m4a: m4a,m4b: MPEG-4 audio;" - "application/x-quicktimeplayer: qtl: Quicktime list;"; + "application/x-quicktimeplayer: qtl: Quicktime list;" + "video/mp4: mp4,mpg4: MPEG-4 video;" + "audio/mp4: mp4,mpg4: MPEG-4 audio;"; } static void class_dispose (demux_class_t *this_gen) { -- cgit v1.2.3 From e2af4baad07a84b3d139f532c059fec856f379ab Mon Sep 17 00:00:00 2001 From: Ed Wildgoose Date: Sat, 14 Jun 2008 16:29:28 +0100 Subject: Replacement JACK plugin --- src/audio_out/audio_jack_out.c | 1141 +++++++++++++++++++++++++++++----------- 1 file changed, 826 insertions(+), 315 deletions(-) (limited to 'src') diff --git a/src/audio_out/audio_jack_out.c b/src/audio_out/audio_jack_out.c index 070b96df8..8a77ab018 100644 --- a/src/audio_out/audio_jack_out.c +++ b/src/audio_out/audio_jack_out.c @@ -17,431 +17,942 @@ #define AO_OUT_JACK_IFACE_VERSION 8 #define GAP_TOLERANCE AO_MAX_GAP -#define BUFSIZE 81920 +/* maximum number of channels supported, avoids lots of mallocs */ +#define MAX_CHANS 6 -typedef struct jack_driver_s { +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; - ao_driver_t ao_driver; - xine_t *xine; +} jack_driver_t; - int capabilities; +typedef struct +{ + audio_driver_class_t driver_class; + config_values_t *config; + xine_t *xine; +} jack_class_t; - int32_t sample_rate; - uint32_t num_channels; - uint32_t bits_per_sample; - uint32_t bytes_per_frame; - jack_client_t *client; - jack_port_t *port_1; - jack_port_t *port_2; - float buf_1[BUFSIZE]; - float buf_2[BUFSIZE]; - uint32_t buf_read; - uint32_t buf_write; +/************************************************************** + * + * 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; +} - uint32_t volume; - uint32_t mute; +/** + * \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; +} -} jack_driver_t; +/** + * \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; +} -typedef struct { - audio_driver_class_t driver_class; - config_values_t *config; - xine_t *xine; -} jack_class_t; -static int jack_process(jack_nframes_t nframes, void *arg) +/** + * \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) { - jack_driver_t *this = (jack_driver_t *)arg; - uint32_t local_buf_read = this->buf_read; - uint32_t local_buf_write = this->buf_write; - uint32_t src_channel, target_channel; - uint32_t frame; - float *buf, *out; - float gain = 0; - - if (!this->client) return 0; - - if (!this->mute) { - gain = (float)this->volume / 100.0; + 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; - for (target_channel = 0; target_channel < 2; ++target_channel) { - - if (target_channel < this->num_channels) src_channel = target_channel; - else src_channel = 0; + return cnt; +} - jack_port_t *port = (target_channel ? this->port_2 : this->port_1); - if (!port) continue; +/** + * \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; +} - buf = (src_channel ? this->buf_2 : this->buf_1); - out = (float *)jack_port_get_buffer(port, nframes); - local_buf_read = this->buf_read; - frame = 0; +/************************************************************** + * + * Jack interface functions + * +**************************************************************/ - while (frame < nframes && local_buf_read != local_buf_write) { - // local_buf_write doesn't change during this process, - // so we can safely defer updating buf_read until after +/** + * \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; +} - out[frame++] = buf[local_buf_read] * gain; - if (++local_buf_read == BUFSIZE) local_buf_read = 0; - } +static int jack_callback (jack_nframes_t nframes, void *arg) +{ + jack_driver_t *this = (jack_driver_t *) arg; - if (frame < nframes) { -// printf("jack_process: underrun: %u required, %u available\n", -// nframes, frame); - while (frame < nframes) { - out[frame++] = 0.0f; - } - } + 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 = read_buffer (this, bufs, nframes, this->num_channels, gain); + if (frames_read < nframes) { + xprintf (this->xine, XINE_VERBOSITY_LOG, + "jack_callback: underrun - frames read: %d\n", frames_read); + this->underrun = 1; } + } - this->buf_read = local_buf_read; + return 0; +} -// printf("jack_process: buf_read %u, buf_write %u\n", this->buf_read, this->buf_write); +static void jack_shutdown (void *arg) +{ + jack_driver_t *this = (jack_driver_t *) arg; + this->client = NULL; +} - return 0; +/* + * 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; } - -static void jack_shutdown(void *arg) + +/************************************************************** + * + * 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 *)arg; - this->client = 0; + 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) +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; + jack_driver_t *this = (jack_driver_t *) this_gen; + config_values_t *config = this->xine->config; + char *jack_device; - if (bits != 16) { - fprintf(stderr, "ao_jack_open: bits=%u expected %u\n", bits, 16); - return 0; - } + jack_device = + config->lookup_entry (config, "audio.device.jack_device_name")->str_value; - rate = jack_get_sample_rate(this->client); - fprintf(stderr, "ao_jack_open: JACK sample rate is %u\n", rate); + 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); - switch (mode) { - case AO_CAP_MODE_MONO: - this->num_channels = 1; - break; - case AO_CAP_MODE_STEREO: - this->num_channels = 2; - break; + 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; } - this->buf_read = this->buf_write = 0; - this->sample_rate = rate; - this->bits_per_sample = bits; - this->capabilities = AO_CAP_16BITS | AO_CAP_MODE_MONO | \ - AO_CAP_MODE_STEREO | AO_CAP_MIXER_VOL | AO_CAP_MUTE_VOL; - this->bytes_per_frame = this->num_channels * (bits / 8); + 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; - fprintf(stderr, "ao_jack_open: bits=%d rate=%d, mode=%d OK\n", bits, rate, mode); + /* + * open audio device + */ + if (!jack_open_device (this_gen, jack_device, &(this->output_sample_rate), + this->num_channels)) + return 0; - return rate; + 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) +static int ao_jack_num_channels (ao_driver_t *this_gen) { - jack_driver_t *this = (jack_driver_t *) this_gen; - return this->num_channels; + 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) +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; + 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 GAP_TOLERANCE; } -static int last_write_space = 0; - -static int ao_jack_write(ao_driver_t *this_gen, int16_t *data, - uint32_t num_frames) +/* + * 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; - uint32_t frame, channel; - - uint32_t local_buf_read = this->buf_read; - uint32_t local_buf_write = this->buf_write; - uint32_t space = (local_buf_read + BUFSIZE - local_buf_write - 1) % BUFSIZE; - uint32_t first_frame = 0; - - int c = 0; - while (space < num_frames) { - if (++c == 10) return 0; - usleep(10000); - local_buf_read = this->buf_read; - space = (local_buf_read + BUFSIZE - local_buf_write - 1) % BUFSIZE; - } - -// if (space < num_frames) return 0; - -// printf("ao_jack_write: %u frames on %u channels, space is %u\n", num_frames, this->num_channels, space); - last_write_space = space; - - for (frame = first_frame; frame < num_frames; ++frame) { - for (channel = 0; channel < this->num_channels; ++channel) { - float *buf = (channel ? this->buf_2 : this->buf_1); - int16_t sample = data[frame * this->num_channels + channel]; - buf[local_buf_write] = ((float)sample) / 32767.0f; -// printf("%6f ", buf[local_buf_write]); -// if (++c == 8) { printf("\n"); c = 0; } - } - if (++local_buf_write == BUFSIZE) local_buf_write = 0; - } - - this->buf_write = local_buf_write; + jack_driver_t *this = (jack_driver_t *) this_gen; + int frames_played = jack_frames_since_cycle_start (this->client); -// printf("ao_jack_write: buf_read %u, buf_write %u\n", this->buf_read, this->buf_write); + 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 1; + return delay; } -static int ao_jack_delay (ao_driver_t *this_gen) + /* 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; - - uint32_t local_buf_read = this->buf_read; - uint32_t local_buf_write = this->buf_write; + 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); - int delay = 0; + 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 (local_buf_write > local_buf_read) { - delay = local_buf_write - local_buf_read; - } else { - delay = ((local_buf_write + BUFSIZE - local_buf_read) % BUFSIZE); - } + if (written == 0) + spin_count++; + else + spin_count = 0; - return delay;// - jack_get_buffer_size(this->client); -} + if (written == 0) + xprintf (this->xine, XINE_VERBOSITY_DEBUG, + "ao_jack_write: unusual, couldn't write anything\n"); + }; -static void ao_jack_close(ao_driver_t *this_gen) -{ - // nothing -} + if (spin_count) + xprintf (this->xine, XINE_VERBOSITY_DEBUG, + "Nonzero spin_count...%d\n", spin_count); -static uint32_t ao_jack_get_capabilities (ao_driver_t *this_gen) { - jack_driver_t *this = (jack_driver_t *) this_gen; - return this->capabilities; + return spin_count ? 0 : 1; /* return 1 on success, 0 if we got stuck for some reason */ } -static void ao_jack_exit(ao_driver_t *this_gen) +static uint32_t ao_jack_get_capabilities (ao_driver_t *this_gen) { - jack_driver_t *this = (jack_driver_t *) this_gen; - jack_client_t *client = this->client; - ao_jack_close(this_gen); - this->client = 0; - if (client) jack_client_close(client); - free (this); + jack_driver_t *this = (jack_driver_t *) this_gen; + return this->capabilities; } -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: -// printf("ao_jack_get_property(AO_PROP_MIXER_VOL): %u\n", this->volume); - return this->volume; - break; - case AO_PROP_MUTE_VOL: -// printf("ao_jack_get_property(AO_PROP_MUTE_VOL): %u\n", this->mute); - return this->mute; - break; - } +static void ao_jack_exit (ao_driver_t *this_gen) +{ + jack_driver_t *this = (jack_driver_t *) this_gen; - return 0; + ao_jack_close (this_gen); + if (this->buffer) + free (this->buffer); + free (this); } -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: -// printf("ao_jack_set_property(AO_PROP_MIXER_VOL): %u\n", value); - this->volume = value; - break; - case AO_PROP_MUTE_VOL: -// printf("ao_jack_get_property(AO_PROP_MUTE_VOL): %u\n", value); - this->mute = value; - break; - } +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; +} - return ~value; +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; +static int ao_jack_ctrl (ao_driver_t *this_gen, int cmd, ...) +{ + jack_driver_t *this = (jack_driver_t *) this_gen; - switch (cmd) { + switch (cmd) { - case AO_CTRL_PLAY_PAUSE: - break; + case AO_CTRL_PLAY_PAUSE: + this->paused = 1; + break; - case AO_CTRL_PLAY_RESUME: - break; + case AO_CTRL_PLAY_RESUME: + this->paused = 0; + break; - case AO_CTRL_FLUSH_BUFFERS: -// fprintf(stderr, "ao_jack_ctrl(AO_CTRL_FLUSH_BUFFERS)\n"); - this->buf_write = this->buf_read = 0; - break; - } + case AO_CTRL_FLUSH_BUFFERS: + jack_reset (this); + break; + } - return 0; + 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; - jack_driver_t *this; - jack_client_t *client; - uint32_t rate; - const char **port_names; - int i; - - if ((client = jack_client_new("xine")) == 0) { - - char name[20]; - sprintf(name, "xine (%d)", (int)getpid()); - - if ((client = jack_client_new(name)) == 0) { - fprintf(stderr, "\nopen_jack_plugin: Error: Failed to connect to JACK server\n"); - fprintf(stderr, "open_jack_plugin: (did you start 'jackd' server?)\n"); - return 0; - } - } - - this = calloc(1, sizeof (jack_driver_t)); - - this->client = client; - - jack_set_process_callback(client, jack_process, this); - jack_on_shutdown(client, jack_shutdown, this); - - rate = jack_get_sample_rate(client); - fprintf(stderr, "open_jack_plugin: JACK sample rate is %u\n", rate); - - // We support up to 2-channel output - - for (i = 0; i < 2; ++i) { - jack_port_t *port = jack_port_register - (client, (i ? "out_r" : "out_l"), - JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); - if (!port) { - fprintf(stderr, "ao_jack_open: failed to register port %u\n", i); - } - if (i) this->port_2 = port; - else this->port_1 = port; - } - - this->buf_read = this->buf_write = 0; - this->volume = 100; - this->mute = 0; - - if (jack_activate(client)) { - fprintf(stderr, "ao_jack_open: failed to activate JACK client\n"); - return 0; - } - - if ((port_names = jack_get_ports(client, NULL, NULL, - JackPortIsPhysical | JackPortIsInput)) != NULL) { - if (port_names[0]) { - jack_connect(client, jack_port_name(this->port_1), port_names[0]); - } - if (port_names[1] && this->port_2) { - jack_connect(client, jack_port_name(this->port_2), port_names[1]); - } - free(port_names); + 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 = calloc(1, 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; +} - this->sample_rate = rate; - - this->xine = class->xine; - this->capabilities = AO_CAP_FLOAT32 | AO_CAP_MODE_MONO | - AO_CAP_MODE_STEREO | AO_CAP_MIXER_VOL | AO_CAP_MUTE_VOL; - - 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; - - fprintf(stderr, "jack open_jack_plugin returning %p\n", (void *)(&this->ao_driver)); - return &this->ao_driver; +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_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 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 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 = calloc(1, sizeof (jack_class_t)); +static void *init_class (xine_t *xine, void *data) +{ + jack_class_t *this; - 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 = calloc(1, sizeof (jack_class_t)); - this->config = xine->config; - this->xine = xine; + 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; - fprintf(stderr, "jack init_class returning %p\n", (void *)this); + this->config = xine->config; + this->xine = xine; - return this; + return this; } -static ao_info_t ao_info_jack = { - 6 -}; +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 } + /* type, API, "name", version, special_info, init_function */ + { PLUGIN_AUDIO_OUT, AO_OUT_JACK_IFACE_VERSION, "jack", XINE_VERSION_CODE, + &ao_info_jack, init_class }, + { PLUGIN_NONE, 0, "", 0, NULL, NULL } }; - -- cgit v1.2.3 From 1dde20995e9c585955bf22c8e7240514bb989ac5 Mon Sep 17 00:00:00 2001 From: Darren Salt Date: Sun, 15 Jun 2008 00:09:29 +0100 Subject: Backed out changeset a1dad259c8f8. In 1.1.x, deprecated functions must remain. --- src/input/net_buf_ctrl.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'src') diff --git a/src/input/net_buf_ctrl.c b/src/input/net_buf_ctrl.c index df7dbadce..624af4081 100644 --- a/src/input/net_buf_ctrl.c +++ b/src/input/net_buf_ctrl.c @@ -113,6 +113,10 @@ static void nbc_set_speed_normal (nbc_t *this) { stream->xine->clock->set_option (stream->xine->clock, CLOCK_SCR_ADJUSTABLE, 1); } +void nbc_check_buffers (nbc_t *this) { + /* Deprecated */ +} + static void display_stats (nbc_t *this) { const char *buffering[2] = {" ", "buf"}; const char *enabled[2] = {"off", "on "}; @@ -560,3 +564,22 @@ void nbc_close (nbc_t *this) { free (this); xprintf(xine, XINE_VERBOSITY_DEBUG, "\nnet_buf_ctrl: nbc_close: done\n"); } + + +void nbc_set_high_water_mark(nbc_t *this, int value) { +/* + Deprecated + this->high_water_mark = value; +*/ + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, + "\nnet_buf_ctrl: this method is deprecated, please fix the input plugin\n"); +} + +void nbc_set_low_water_mark(nbc_t *this, int value) { +/* + Deprecated + this->low_water_mark = value; +*/ + xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, + "\nnet_buf_ctrl: this method is deprecated, please fix the input plugin\n"); +} -- cgit v1.2.3 From 53926f54e4dcf163afd397ed937c8b542535ee0b Mon Sep 17 00:00:00 2001 From: Darren Salt Date: Sun, 15 Jun 2008 00:14:40 +0100 Subject: Remove nbc_check_buffers calls; mark it & the low-water mark fns as deprecated. --- src/input/input_dvb.c | 3 --- src/input/input_pnm.c | 2 -- src/input/input_rtsp.c | 2 -- src/input/net_buf_ctrl.h | 6 +++--- 4 files changed, 3 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/input/input_dvb.c b/src/input/input_dvb.c index 795b843c5..957a7beb9 100644 --- a/src/input/input_dvb.c +++ b/src/input/input_dvb.c @@ -2505,9 +2505,6 @@ static off_t dvb_plugin_read (input_plugin_t *this_gen, "input_dvb: reading %" PRIdMAX " bytes...\n", (intmax_t)len); #endif -#ifndef DVB_NO_BUFFERING - nbc_check_buffers (this->nbc); -#endif /* protect against channel changes */ have_mutex = pthread_mutex_lock(&this->channel_change_mutex); total=0; diff --git a/src/input/input_pnm.c b/src/input/input_pnm.c index 680c5b1e8..f4bfa1395 100644 --- a/src/input/input_pnm.c +++ b/src/input/input_pnm.c @@ -82,8 +82,6 @@ static off_t pnm_plugin_read (input_plugin_t *this_gen, lprintf ("pnm_plugin_read: %"PRId64" bytes ...\n", len); - nbc_check_buffers (this->nbc); - n = pnm_read (this->pnm, buf, len); this->curpos += n; diff --git a/src/input/input_rtsp.c b/src/input/input_rtsp.c index 2895edf5d..42d24ed3a 100644 --- a/src/input/input_rtsp.c +++ b/src/input/input_rtsp.c @@ -83,8 +83,6 @@ static off_t rtsp_plugin_read (input_plugin_t *this_gen, lprintf ("rtsp_plugin_read: %"PRId64" bytes ...\n", len); - nbc_check_buffers (this->nbc); - n = rtsp_session_read (this->rtsp, buf, len); this->curpos += n; diff --git a/src/input/net_buf_ctrl.h b/src/input/net_buf_ctrl.h index 79f698008..9229144f8 100644 --- a/src/input/net_buf_ctrl.h +++ b/src/input/net_buf_ctrl.h @@ -29,12 +29,12 @@ typedef struct nbc_s nbc_t; nbc_t *nbc_init (xine_stream_t *xine); -void nbc_check_buffers (nbc_t *this); +void nbc_check_buffers (nbc_t *this) XINE_DEPRECATED; void nbc_close (nbc_t *this); -void nbc_set_high_water_mark(nbc_t *this, int value); +void nbc_set_high_water_mark(nbc_t *this, int value) XINE_DEPRECATED; -void nbc_set_low_water_mark(nbc_t *this, int value); +void nbc_set_low_water_mark(nbc_t *this, int value) XINE_DEPRECATED; #endif -- cgit v1.2.3 From bc589d30c18a0517804c1306869e77f67d0da3ec Mon Sep 17 00:00:00 2001 From: Darren Salt Date: Sun, 15 Jun 2008 02:32:33 +0100 Subject: Move the declaration of xine_strcat_realloc. --- src/xine-utils/xineutils.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/xine-utils/xineutils.h b/src/xine-utils/xineutils.h index 2d6425b00..5476ef2ce 100644 --- a/src/xine-utils/xineutils.h +++ b/src/xine-utils/xineutils.h @@ -676,6 +676,13 @@ void xine_strdupa(char *dest, char *src) XINE_PROTECTED XINE_DEPRECATED; #define xine_strsep(STRINGP, DELIM) strsep((STRINGP), (DELIM)) #define xine_setenv(NAME, VAL, XX) setenv((NAME), (VAL), (XX)) +/** + * append to a string, reallocating + * normally, updates & returns *dest + * on error, *dest is unchanged & NULL is returned. + */ +char *xine_strcat_realloc (char **dest, char *append) XINE_PROTECTED; + /* * Color Conversion Utility Functions * The following data structures and functions facilitate the conversion @@ -969,13 +976,6 @@ const char *xine_guess_spu_encoding(void) XINE_PROTECTED; */ int xine_monotonic_clock(struct timeval *tv, struct timezone *tz) XINE_PROTECTED; -/** - * append to a string, reallocating - * normally, updates & returns *dest - * on error, *dest is unchanged & NULL is returned. - */ -char *xine_strcat_realloc (char **dest, char *append) XINE_PROTECTED; - /* don't harm following code */ #ifdef extern # undef extern -- cgit v1.2.3