diff options
author | wm4 <wm4@nowhere> | 2013-11-12 23:42:04 +0100 |
---|---|---|
committer | wm4 <wm4@nowhere> | 2013-11-12 23:42:04 +0100 |
commit | e4bbb1d348dafbb32722f413648006a7bd9d0897 (patch) | |
tree | 7165ed9f86a77b751187600d0a9de8b35416f380 /audio/out | |
parent | e4f2fcc0ecd31322df65141edf0ddbff9c075f5d (diff) | |
parent | 22b3f522cacfbdba76d311c86efd6091512eb089 (diff) | |
download | mpv-e4bbb1d348dafbb32722f413648006a7bd9d0897.tar.bz2 mpv-e4bbb1d348dafbb32722f413648006a7bd9d0897.tar.xz |
Merge branch 'planar_audio'
Conflicts:
audio/out/ao_lavc.c
Diffstat (limited to 'audio/out')
-rw-r--r-- | audio/out/ao.c | 19 | ||||
-rw-r--r-- | audio/out/ao.h | 10 | ||||
-rw-r--r-- | audio/out/ao_alsa.c | 54 | ||||
-rw-r--r-- | audio/out/ao_coreaudio.c | 10 | ||||
-rw-r--r-- | audio/out/ao_dsound.c | 9 | ||||
-rw-r--r-- | audio/out/ao_jack.c | 320 | ||||
-rw-r--r-- | audio/out/ao_lavc.c | 22 | ||||
-rw-r--r-- | audio/out/ao_null.c | 34 | ||||
-rw-r--r-- | audio/out/ao_openal.c | 30 | ||||
-rw-r--r-- | audio/out/ao_oss.c | 18 | ||||
-rw-r--r-- | audio/out/ao_pcm.c | 10 | ||||
-rw-r--r-- | audio/out/ao_portaudio.c | 10 | ||||
-rw-r--r-- | audio/out/ao_pulse.c | 14 | ||||
-rw-r--r-- | audio/out/ao_rsound.c | 8 | ||||
-rw-r--r-- | audio/out/ao_sdl.c | 11 | ||||
-rw-r--r-- | audio/out/ao_sndio.c | 11 | ||||
-rw-r--r-- | audio/out/ao_wasapi.c | 14 |
17 files changed, 334 insertions, 270 deletions
diff --git a/audio/out/ao.c b/audio/out/ao.c index 55db34becb..50c95830c3 100644 --- a/audio/out/ao.c +++ b/audio/out/ao.c @@ -159,7 +159,10 @@ static struct ao *ao_create(bool probing, struct mpv_global *global, talloc_free(chmap); if (ao->driver->init(ao) < 0) goto error; - ao->bps = ao->channels.num * ao->samplerate * af_fmt2bits(ao->format) / 8; + ao->sstride = af_fmt2bits(ao->format) / 8; + if (!af_fmt_is_planar(ao->format)) + ao->sstride *= ao->channels.num; + ao->bps = ao->samplerate * ao->sstride; return ao; error: talloc_free(ao); @@ -206,9 +209,9 @@ void ao_uninit(struct ao *ao, bool cut_audio) talloc_free(ao); } -int ao_play(struct ao *ao, void *data, int len, int flags) +int ao_play(struct ao *ao, void **data, int samples, int flags) { - return ao->driver->play(ao, data, len, flags); + return ao->driver->play(ao, data, samples, flags); } int ao_control(struct ao *ao, enum aocontrol cmd, void *arg) @@ -254,10 +257,12 @@ int ao_play_silence(struct ao *ao, int samples) { if (samples <= 0 || AF_FORMAT_IS_SPECIAL(ao->format)) return 0; - int s = ao->channels.num * (af_fmt2bits(ao->format) / 8); - char *p = talloc_size(NULL, samples * s); - af_fill_silence(p, samples * s, ao->format); - int r = ao_play(ao, p, samples * s, 0); + char *p = talloc_size(NULL, samples * ao->sstride); + af_fill_silence(p, samples * ao->sstride, ao->format); + void *tmp[MP_NUM_CHANNELS]; + for (int n = 0; n < MP_NUM_CHANNELS; n++) + tmp[n] = p; + int r = ao_play(ao, tmp, samples, 0); talloc_free(p); return r; } diff --git a/audio/out/ao.h b/audio/out/ao.h index 159a6adc0f..dff9ad6a8b 100644 --- a/audio/out/ao.h +++ b/audio/out/ao.h @@ -56,7 +56,7 @@ struct ao_driver { void (*uninit)(struct ao *ao, bool cut_audio); void (*reset)(struct ao*ao); int (*get_space)(struct ao *ao); - int (*play)(struct ao *ao, void *data, int len, int flags); + int (*play)(struct ao *ao, void **data, int samples, int flags); float (*get_delay)(struct ao *ao); void (*pause)(struct ao *ao); void (*resume)(struct ao *ao); @@ -73,9 +73,11 @@ struct ao { struct mp_chmap channels; int format; int bps; // bytes per second + int sstride; // size of a sample on each plane + // (format_size*num_channels/num_planes) double pts; // some mplayer.c state (why is this here?) - struct bstr buffer; - int buffer_playable_size; // part of the part of the buffer the AO hasn't + struct mp_audio_buffer *buffer; // queued audio; passed to play() later + int buffer_playable_samples;// part of the part of the buffer the AO hasn't // accepted yet with play() bool probing; // if true, don't fail loudly on init bool untimed; @@ -95,7 +97,7 @@ struct ao *ao_init_best(struct mpv_global *global, struct encode_lavc_context *encode_lavc_ctx, int samplerate, int format, struct mp_chmap channels); void ao_uninit(struct ao *ao, bool cut_audio); -int ao_play(struct ao *ao, void *data, int len, int flags); +int ao_play(struct ao *ao, void **data, int samples, int flags); int ao_control(struct ao *ao, enum aocontrol cmd, void *arg); double ao_get_delay(struct ao *ao); int ao_get_space(struct ao *ao); diff --git a/audio/out/ao_alsa.c b/audio/out/ao_alsa.c index 5816ee5f5f..2ef35db6cf 100644 --- a/audio/out/ao_alsa.c +++ b/audio/out/ao_alsa.c @@ -52,12 +52,11 @@ struct priv { snd_pcm_t *alsa; snd_pcm_format_t alsa_fmt; - size_t bytes_per_sample; int can_pause; snd_pcm_sframes_t prepause_frames; float delay_before_pause; - int buffersize; - int outburst; + int buffersize; // in frames + int outburst; // in frames int cfg_block; char *cfg_device; @@ -251,6 +250,7 @@ static const int mp_to_alsa_format[][2] = { static int find_alsa_format(int af_format) { + af_format = af_fmt_from_planar(af_format); for (int n = 0; mp_to_alsa_format[n][0] != AF_FORMAT_UNKNOWN; n++) { if (mp_to_alsa_format[n][0] == af_format) return mp_to_alsa_format[n][1]; @@ -432,10 +432,6 @@ static int init(struct ao *ao) err = snd_pcm_hw_params_any(p->alsa, alsa_hwparams); CHECK_ALSA_ERROR("Unable to get initial parameters"); - err = snd_pcm_hw_params_set_access - (p->alsa, alsa_hwparams, SND_PCM_ACCESS_RW_INTERLEAVED); - CHECK_ALSA_ERROR("Unable to set access type"); - p->alsa_fmt = find_alsa_format(ao->format); if (p->alsa_fmt == SND_PCM_FORMAT_UNKNOWN) { p->alsa_fmt = SND_PCM_FORMAT_S16; @@ -458,6 +454,12 @@ static int init(struct ao *ao) err = snd_pcm_hw_params_set_format(p->alsa, alsa_hwparams, p->alsa_fmt); CHECK_ALSA_ERROR("Unable to set format"); + snd_pcm_access_t access = af_fmt_is_planar(ao->format) + ? SND_PCM_ACCESS_RW_NONINTERLEAVED + : SND_PCM_ACCESS_RW_INTERLEAVED; + err = snd_pcm_hw_params_set_access(p->alsa, alsa_hwparams, access); + CHECK_ALSA_ERROR("Unable to set access type"); + int num_channels = ao->channels.num; err = snd_pcm_hw_params_set_channels_near (p->alsa, alsa_hwparams, &num_channels); @@ -478,9 +480,6 @@ static int init(struct ao *ao) (p->alsa, alsa_hwparams, &ao->samplerate, NULL); CHECK_ALSA_ERROR("Unable to set samplerate-2"); - p->bytes_per_sample = af_fmt2bits(ao->format) / 8; - p->bytes_per_sample *= ao->channels.num; - err = snd_pcm_hw_params_set_buffer_time_near (p->alsa, alsa_hwparams, &(unsigned int){BUFFER_TIME}, NULL); CHECK_ALSA_ERROR("Unable to set buffer time near"); @@ -499,14 +498,14 @@ static int init(struct ao *ao) err = snd_pcm_hw_params_get_buffer_size(alsa_hwparams, &bufsize); CHECK_ALSA_ERROR("Unable to get buffersize"); - p->buffersize = bufsize * p->bytes_per_sample; - MP_VERBOSE(ao, "got buffersize=%i\n", p->buffersize); + p->buffersize = bufsize; + MP_VERBOSE(ao, "got buffersize=%i samples\n", p->buffersize); err = snd_pcm_hw_params_get_period_size(alsa_hwparams, &chunk_size, NULL); CHECK_ALSA_ERROR("Unable to get period size"); MP_VERBOSE(ao, "got period size %li\n", chunk_size); - p->outburst = chunk_size * p->bytes_per_sample; + p->outburst = chunk_size; /* setting software parameters */ err = snd_pcm_sw_params_current(p->alsa, alsa_swparams); @@ -537,8 +536,8 @@ static int init(struct ao *ao) p->can_pause = snd_pcm_hw_params_can_pause(alsa_hwparams); - MP_VERBOSE(ao, "opened: %d Hz/%d channels/%d bpf/%d bytes buffer/%s\n", - ao->samplerate, ao->channels.num, (int)p->bytes_per_sample, + MP_VERBOSE(ao, "opened: %d Hz/%d channels/%d bps/%d samples buffer/%s\n", + ao->samplerate, ao->channels.num, af_fmt2bits(ao->format), p->buffersize, snd_pcm_format_description(p->alsa_fmt)); return 0; @@ -634,32 +633,27 @@ static void reset(struct ao *ao) alsa_error: ; } -/* - plays 'len' bytes of 'data' - returns: number of bytes played - modified last at 29.06.02 by jp - thanxs for marius <marius@rospot.com> for giving us the light ;) - */ - -static int play(struct ao *ao, void *data, int len, int flags) +static int play(struct ao *ao, void **data, int samples, int flags) { struct priv *p = ao->priv; - int num_frames; snd_pcm_sframes_t res = 0; if (!(flags & AOPLAY_FINAL_CHUNK)) - len = len / p->outburst * p->outburst; - num_frames = len / p->bytes_per_sample; + samples = samples / p->outburst * p->outburst; if (!p->alsa) { MP_ERR(ao, "Device configuration error."); return -1; } - if (num_frames == 0) + if (samples == 0) return 0; do { - res = snd_pcm_writei(p->alsa, data, num_frames); + if (af_fmt_is_planar(ao->format)) { + res = snd_pcm_writen(p->alsa, data, samples); + } else { + res = snd_pcm_writei(p->alsa, data[0], samples); + } if (res == -EINTR) { /* nothing to do */ @@ -678,7 +672,7 @@ static int play(struct ao *ao, void *data, int len, int flags) } } while (res == 0); - return res < 0 ? -1 : res * p->bytes_per_sample; + return res < 0 ? -1 : res; alsa_error: return -1; @@ -696,7 +690,7 @@ static int get_space(struct ao *ao) err = snd_pcm_status(p->alsa, status); CHECK_ALSA_ERROR("cannot get pcm status"); - unsigned space = snd_pcm_status_get_avail(status) * p->bytes_per_sample; + unsigned space = snd_pcm_status_get_avail(status); if (space > p->buffersize) // Buffer underrun? space = p->buffersize; return space; diff --git a/audio/out/ao_coreaudio.c b/audio/out/ao_coreaudio.c index da526ada20..d61ce63d01 100644 --- a/audio/out/ao_coreaudio.c +++ b/audio/out/ao_coreaudio.c @@ -285,6 +285,8 @@ static int init(struct ao *ao) // Save selected device id p->device = selected_device; + ao->format = af_fmt_from_planar(ao->format); + bool supports_digital = false; /* Probe whether device support S/PDIF stream output if input is AC3 stream. */ if (AF_FORMAT_IS_AC3(ao->format)) { @@ -576,10 +578,12 @@ coreaudio_error: return CONTROL_ERROR; } -static int play(struct ao *ao, void *output_samples, int num_bytes, int flags) +static int play(struct ao *ao, void **data, int samples, int flags) { struct priv *p = ao->priv; struct priv_d *d = p->digital; + void *output_samples = data[0]; + int num_bytes = samples * ao->sstride; // Check whether we need to reset the digital output stream. if (p->is_digital && d->stream_asbd_changed) { @@ -597,7 +601,7 @@ static int play(struct ao *ao, void *output_samples, int num_bytes, int flags) int wrote = mp_ring_write(p->buffer, output_samples, num_bytes); audio_resume(ao); - return wrote; + return wrote / ao->sstride; } static void reset(struct ao *ao) @@ -610,7 +614,7 @@ static void reset(struct ao *ao) static int get_space(struct ao *ao) { struct priv *p = ao->priv; - return mp_ring_available(p->buffer); + return mp_ring_available(p->buffer) / ao->sstride; } static float get_delay(struct ao *ao) diff --git a/audio/out/ao_dsound.c b/audio/out/ao_dsound.c index 464947c0dc..f828a210dc 100644 --- a/audio/out/ao_dsound.c +++ b/audio/out/ao_dsound.c @@ -388,7 +388,7 @@ static int init(struct ao *ao) WAVEFORMATEXTENSIBLE wformat; DSBUFFERDESC dsbpridesc; DSBUFFERDESC dsbdesc; - int format = ao->format; + int format = af_fmt_from_planar(ao->format); int rate = ao->samplerate; if (AF_FORMAT_IS_AC3(format)) @@ -596,7 +596,7 @@ static int get_space(struct ao *ao) int space = check_free_buffer_size(ao); if (space < p->min_free_space) return 0; - return space - p->min_free_space; + return (space - p->min_free_space) / ao->sstride; } /** @@ -606,9 +606,10 @@ static int get_space(struct ao *ao) \param flags currently unused \return number of played bytes */ -static int play(struct ao *ao, void *data, int len, int flags) +static int play(struct ao *ao, void **data, int samples, int flags) { struct priv *p = ao->priv; + int len = samples * ao->sstride; int space = check_free_buffer_size(ao); if (space < len) @@ -616,7 +617,7 @@ static int play(struct ao *ao, void *data, int len, int flags) if (!(flags & AOPLAY_FINAL_CHUNK)) len = (len / p->outburst) * p->outburst; - return write_buffer(ao, data, len); + return write_buffer(ao, data[0], len) / ao->sstride; } /** diff --git a/audio/out/ao_jack.c b/audio/out/ao_jack.c index 20dd0d4aab..8a55a54239 100644 --- a/audio/out/ao_jack.c +++ b/audio/out/ao_jack.c @@ -4,6 +4,8 @@ * Copyleft 2001 by Felix Bünemann (atmosfear@users.sf.net) * and Reimar Döffinger (Reimar.Doeffinger@stud.uni-karlsruhe.de) * + * Copyleft 2013 by William Light <wrl@illest.net> for the mpv project + * * This file is part of MPlayer. * * MPlayer is free software; you can redistribute it and/or modify @@ -38,20 +40,19 @@ #include <jack/jack.h> -//! maximum number of channels supported, avoids lots of mallocs -#define MAX_CHANS MP_NUM_CHANNELS - //! size of one chunk, if this is too small MPlayer will start to "stutter" //! after a short time of playback -#define CHUNK_SIZE (24 * 1024) +#define CHUNK_SIZE (8 * 1024) //! number of "virtual" chunks the buffer consists of #define NUM_CHUNKS 8 +struct port_ring { + jack_port_t *port; + struct mp_ring *ring; +}; + struct priv { - jack_port_t * ports[MAX_CHANS]; - int num_ports; // Number of used ports == number of channels jack_client_t *client; - int outburst; float jack_latency; char *cfg_port; char *cfg_client_name; @@ -60,76 +61,49 @@ struct priv { int autostart; int stdlayout; volatile int paused; - volatile int underrun; // signals if an underrun occured + volatile int underrun; volatile float callback_interval; volatile float callback_time; - struct mp_ring *ring; // buffer for audio data -}; - -static void silence(float **bufs, int cnt, int num_bufs); -struct deinterleave { - float **bufs; - int num_bufs; - int cur_buf; - int pos; + int num_ports; + struct port_ring ports[MP_NUM_CHANNELS]; }; -static void deinterleave(void *info, void *src, int len) -{ - struct deinterleave *di = info; - float *s = src; - int i; - len /= sizeof(float); - for (i = 0; i < len; i++) { - di->bufs[di->cur_buf++][di->pos] = s[i]; - if (di->cur_buf >= di->num_bufs) { - di->cur_buf = 0; - di->pos++; - } - } -} - -/** - * \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(struct mp_ring *ring, float **bufs, int cnt, int num_bufs) -{ - struct deinterleave di = { - bufs, num_bufs, 0, 0 - }; - int buffered = mp_ring_buffered(ring); - if (cnt * sizeof(float) * num_bufs > buffered) { - silence(bufs, cnt, num_bufs); - cnt = buffered / sizeof(float) / num_bufs; - } - mp_ring_read_cb(ring, &di, cnt * num_bufs * sizeof(float), deinterleave); - return cnt; -} - -// end ring buffer stuff - /** * \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) +static void +silence(float *buf, jack_nframes_t nframes) { - int i; - for (i = 0; i < num_bufs; i++) - memset(bufs[i], 0, cnt * sizeof(float)); + memset(buf, 0, nframes * sizeof(*buf)); +} + +static int +process_port(struct ao *ao, struct port_ring *pr, jack_nframes_t nframes) +{ + struct priv *p = ao->priv; + int buffered; + float *buf; + + buf = jack_port_get_buffer(pr->port, nframes); + + if (p->paused || p->underrun) { + silence(buf, nframes); + return 0; + } + + buffered = mp_ring_buffered(pr->ring) / sizeof(float); + if (buffered < nframes) { + mp_ring_read(pr->ring, (void *) buf, buffered * sizeof(float)); + silence(&buf[buffered], nframes - buffered); + return 1; + } + + mp_ring_read(pr->ring, (void *) buf, nframes * sizeof(float)); + return 0; } /** @@ -140,18 +114,23 @@ static void silence(float **bufs, int cnt, int num_bufs) * * Write silence into buffers if paused or an underrun occured */ -static int outputaudio(jack_nframes_t nframes, void *arg) +static int +process(jack_nframes_t nframes, void *arg) { struct ao *ao = arg; struct priv *p = ao->priv; - float *bufs[MAX_CHANS]; - int i; - for (i = 0; i < p->num_ports; i++) - bufs[i] = jack_port_get_buffer(p->ports[i], nframes); - if (p->paused || p->underrun || !p->ring) - silence(bufs, nframes, p->num_ports); - else if (read_buffer(p->ring, bufs, nframes, p->num_ports) < nframes) + int i, underrun; + + underrun = 0; + + for (i = 0; i < p->num_ports; i++) { + if (process_port(ao, &p->ports[i], nframes)) + underrun = 1; + } + + if (underrun) p->underrun = 1; + if (p->estimate) { float now = mp_time_us() / 1000000.0; float diff = p->callback_time + p->callback_interval - now; @@ -161,117 +140,163 @@ static int outputaudio(jack_nframes_t nframes, void *arg) p->callback_time = now; p->callback_interval = (float)nframes / (float)ao->samplerate; } + return 0; } -static int init(struct ao *ao) +static int +connect_to_outports(struct ao *ao) { struct priv *p = ao->priv; + + char *port_name = (p->cfg_port && p->cfg_port[0]) ? p->cfg_port : NULL; const char **matching_ports = NULL; - char *port_name = p->cfg_port && p->cfg_port[0] ? p->cfg_port : NULL; - jack_options_t open_options = JackNullOption; int port_flags = JackPortIsInput; int i; + if (!port_name) + port_flags |= JackPortIsPhysical; + + matching_ports = jack_get_ports(p->client, port_name, NULL, port_flags); + + if (!matching_ports || !matching_ports[0]) { + MP_FATAL(ao, "no ports to connect to\n"); + goto err_get_ports; + } + + for (i = 0; i < p->num_ports && matching_ports[i]; i++) { + if (jack_connect(p->client, jack_port_name(p->ports[i].port), + matching_ports[i])) { + MP_FATAL(ao, "connecting failed\n"); + goto err_connect; + } + } + + free(matching_ports); + return 0; + +err_connect: + free(matching_ports); +err_get_ports: + return -1; +} + +static int +create_ports(struct ao *ao, int nports) +{ + struct priv *p = ao->priv; + struct port_ring *pr; + char pname[30]; + int i; + + for (i = 0; i < nports; i++) { + pr = &p->ports[i]; + + snprintf(pname, sizeof(pname), "out_%d", i); + pr->port = jack_port_register(p->client, pname, JACK_DEFAULT_AUDIO_TYPE, + JackPortIsOutput, 0); + + if (!pr->port) { + MP_FATAL(ao, "not enough ports available\n"); + goto err_port_register; + } + + pr->ring = mp_ring_new(p, NUM_CHUNKS * CHUNK_SIZE); + } + + p->num_ports = nports; + return 0; + +err_port_register: + return -1; +} + +static int init(struct ao *ao) +{ + struct priv *p = ao->priv; struct mp_chmap_sel sel = {0}; + jack_options_t open_options; - if (p->stdlayout == 0) { + ao->format = AF_FORMAT_FLOATP; + + switch (p->stdlayout) { + case 0: mp_chmap_sel_add_waveext(&sel); - } else if (p->stdlayout == 1) { + break; + + case 1: mp_chmap_sel_add_alsa_def(&sel); - } else { + break; + + default: mp_chmap_sel_add_any(&sel); } if (!ao_chmap_sel_adjust(ao, &sel, &ao->channels)) - goto err_out; + goto err_chmap; + open_options = JackNullOption; if (!p->autostart) open_options |= JackNoStartServer; + p->client = jack_client_open(p->cfg_client_name, open_options, NULL); if (!p->client) { MP_FATAL(ao, "cannot open server\n"); - goto err_out; - } - jack_set_process_callback(p->client, outputaudio, ao); - - // list matching ports if connections should be made - if (p->connect) { - if (!port_name) - port_flags |= JackPortIsPhysical; - matching_ports = jack_get_ports(p->client, port_name, NULL, port_flags); - if (!matching_ports || !matching_ports[0]) { - MP_FATAL(ao, "no physical ports available\n"); - goto err_out; - } - i = 1; - p->num_ports = ao->channels.num; - while (matching_ports[i]) - i++; - if (p->num_ports > i) - p->num_ports = i; + goto err_client_open; } - // create out output ports - for (i = 0; i < p->num_ports; i++) { - char pname[30]; - snprintf(pname, 30, "out_%d", i); - p->ports[i] = - jack_port_register(p->client, pname, JACK_DEFAULT_AUDIO_TYPE, - JackPortIsOutput, 0); - if (!p->ports[i]) { - MP_FATAL(ao, "not enough ports available\n"); - goto err_out; - } - } + if (create_ports(ao, ao->channels.num)) + goto err_create_ports; + + jack_set_process_callback(p->client, process, ao); + if (jack_activate(p->client)) { MP_FATAL(ao, "activate failed\n"); - goto err_out; - } - for (i = 0; i < p->num_ports; i++) { - if (jack_connect(p->client, jack_port_name(p->ports[i]), - matching_ports[i])) - { - MP_FATAL(ao, "connecting failed\n"); - goto err_out; - } + goto err_activate; } + ao->samplerate = jack_get_sample_rate(p->client); + + if (p->connect) + if (connect_to_outports(ao)) + goto err_connect; + jack_latency_range_t jack_latency_range; - jack_port_get_latency_range(p->ports[0], JackPlaybackLatency, + jack_port_get_latency_range(p->ports[0].port, JackPlaybackLatency, &jack_latency_range); p->jack_latency = (float)(jack_latency_range.max + jack_get_buffer_size(p->client)) / (float)ao->samplerate; p->callback_interval = 0; if (!ao_chmap_sel_get_def(ao, &sel, &ao->channels, p->num_ports)) - goto err_out; + goto err_chmap_sel_get_def; - ao->format = AF_FORMAT_FLOAT_NE; - int unitsize = ao->channels.num * sizeof(float); - p->outburst = (CHUNK_SIZE + unitsize - 1) / unitsize * unitsize; - p->ring = mp_ring_new(p, NUM_CHUNKS * p->outburst); - free(matching_ports); return 0; -err_out: - free(matching_ports); - if (p->client) - jack_client_close(p->client); +err_chmap_sel_get_def: +err_connect: + jack_deactivate(p->client); +err_activate: +err_create_ports: + jack_client_close(p->client); +err_client_open: +err_chmap: return -1; } static float get_delay(struct ao *ao) { struct priv *p = ao->priv; - int buffered = mp_ring_buffered(p->ring); // could be less + int buffered = mp_ring_buffered(p->ports[0].ring); // could be less float in_jack = p->jack_latency; + if (p->estimate && p->callback_interval > 0) { float elapsed = mp_time_us() / 1000000.0 - p->callback_time; in_jack += p->callback_interval - elapsed; if (in_jack < 0) in_jack = 0; } + return (float)buffered / (float)ao->bps + in_jack; } @@ -281,8 +306,12 @@ static float get_delay(struct ao *ao) static void reset(struct ao *ao) { struct priv *p = ao->priv; + int i; p->paused = 1; - mp_ring_reset(p->ring); + + for (i = 0; i < p->num_ports; i++) + mp_ring_reset(p->ports[i].ring); + p->paused = 0; } @@ -290,10 +319,10 @@ static void reset(struct ao *ao) static void uninit(struct ao *ao, bool immed) { struct priv *p = ao->priv; + if (!immed) mp_sleep_us(get_delay(ao) * 1000 * 1000); - // HACK, make sure jack doesn't loop-output dirty buffers - reset(ao); + mp_sleep_us(100 * 1000); jack_client_close(p->client); } @@ -319,19 +348,28 @@ static void audio_resume(struct ao *ao) static int get_space(struct ao *ao) { struct priv *p = ao->priv; - return mp_ring_available(p->ring); + return mp_ring_available(p->ports[0].ring) / ao->sstride; } /** * \brief write data into buffer and reset underrun flag */ -static int play(struct ao *ao, void *data, int len, int flags) +static int play(struct ao *ao, void **data, int samples, int flags) { struct priv *p = ao->priv; - if (!(flags & AOPLAY_FINAL_CHUNK)) - len -= len % p->outburst; + struct port_ring *pr; + int i, len, ret; + + len = samples * ao->sstride; + ret = 0; + + for (i = 0; i < p->num_ports; i++) { + pr = &p->ports[i]; + ret = mp_ring_write(pr->ring, data[i], len); + } + p->underrun = 0; - return mp_ring_write(p->ring, data, len); + return ret / ao->sstride; } #define OPT_BASE_STRUCT struct priv @@ -360,7 +398,7 @@ const struct ao_driver audio_out_jack = { OPT_FLAG("autostart", autostart, 0), OPT_FLAG("connect", connect, 0), OPT_CHOICE("std-channel-layout", stdlayout, 0, - ({"waveext", 0}, {"alsa", 1}, {"any", 2})), + ({"waveext", 0}, {"alsa", 1}, {"any", 2})), {0} }, }; diff --git a/audio/out/ao_lavc.c b/audio/out/ao_lavc.c index 153d5b92a0..c1fce6a715 100644 --- a/audio/out/ao_lavc.c +++ b/audio/out/ao_lavc.c @@ -103,6 +103,7 @@ static int init(struct ao *ao) ac->stream->codec->channel_layout = mp_chmap_to_lavc(&ao->channels); ac->stream->codec->sample_fmt = AV_SAMPLE_FMT_NONE; + ao->format = af_fmt_from_planar(ao->format); { // first check if the selected format is somewhere in the list of @@ -290,8 +291,6 @@ static void fill_with_padding(void *buf, int cnt, int sz, const void *padding) } // close audio device -static int encode(struct ao *ao, double apts, void *data); -static int play(struct ao *ao, void *data, int len, int flags); static void uninit(struct ao *ao, bool cut_audio) { struct encode_lavc_context *ectx = ao->encode_lavc_ctx; @@ -309,7 +308,7 @@ static int get_space(struct ao *ao) { struct priv *ac = ao->priv; - return ac->aframesize * ac->sample_size * ao->channels.num * ac->framecount; + return ac->aframesize * ac->framecount; } // must get exactly ac->aframesize amount of data @@ -438,10 +437,10 @@ static int encode(struct ao *ao, double apts, void *data) return packet.size; } -// plays 'len' bytes of 'data' +// plays 'samples' samples of 'ni_data[0]' // it should round it down to frame sizes -// return: number of bytes played -static int play(struct ao *ao, void *data, int len, int flags) +// return: number of samples played +static int play(struct ao *ao, void **ni_data, int samples, int flags) { struct priv *ac = ao->priv; struct encode_lavc_context *ectx = ao->encode_lavc_ctx; @@ -450,6 +449,8 @@ static int play(struct ao *ao, void *data, int len, int flags) double nextpts; double pts = ao->pts; double outpts; + void *data = ni_data[0]; + int len = samples * ao->sstride; int bytelen = len; len /= ac->sample_size * ao->channels.num; @@ -470,8 +471,9 @@ static int play(struct ao *ao, void *data, int len, int flags) extralen / ac->sample_size, ac->sample_size, ac->sample_padding); // No danger of recursion, because AOPLAY_FINAL_CHUNK not set - written = play(ao, paddingbuf, bytelen + extralen, 0); - if (written < bytelen) { + written = + play(ao, &paddingbuf, (bytelen + extralen) / ao->sstride, 0); + if (written * ao->sstride < bytelen) { MP_ERR(ao, "did not write enough data at the end\n"); } talloc_free(paddingbuf); @@ -485,7 +487,7 @@ static int play(struct ao *ao, void *data, int len, int flags) while (encode(ao, outpts, NULL) > 0) ; - return FFMIN(written, bytelen); + return (FFMIN(written, bytelen)) / ao->sstride; } if (pts == MP_NOPTS_VALUE) { @@ -576,7 +578,7 @@ static int play(struct ao *ao, void *data, int len, int flags) ectx->next_in_pts = nextpts; } - return bufpos * ac->sample_size * ao->channels.num; |