diff options
Diffstat (limited to 'audio')
-rw-r--r-- | audio/decode/ad_spdif.c | 14 | ||||
-rw-r--r-- | audio/filter/af_rubberband.c | 2 | ||||
-rw-r--r-- | audio/format.c | 38 | ||||
-rw-r--r-- | audio/format.h | 3 | ||||
-rw-r--r-- | audio/out/ao_alsa.c | 29 | ||||
-rw-r--r-- | audio/out/ao_audiounit.m | 2 | ||||
-rw-r--r-- | audio/out/ao_jack.c | 3 | ||||
-rw-r--r-- | audio/out/ao_openal.c | 14 | ||||
-rw-r--r-- | audio/out/ao_opensles.c | 98 | ||||
-rw-r--r-- | audio/out/ao_pulse.c | 6 |
10 files changed, 107 insertions, 102 deletions
diff --git a/audio/decode/ad_spdif.c b/audio/decode/ad_spdif.c index 0706b11614..ef34042990 100644 --- a/audio/decode/ad_spdif.c +++ b/audio/decode/ad_spdif.c @@ -208,13 +208,21 @@ static int init_filter(struct mp_filter *da, AVPacket *pkt) break; case AV_CODEC_ID_DTS: { bool is_hd = profile == FF_PROFILE_DTS_HD_HRA || - profile == FF_PROFILE_DTS_HD_MA || + profile == FF_PROFILE_DTS_HD_MA || profile == FF_PROFILE_UNKNOWN; + + // Apparently, DTS-HD over SPDIF is specified to be 7.1 (8 channels) + // for DTS-HD MA, and stereo (2 channels) for DTS-HD HRA. The bit + // streaming rate as well as the signaled channel count are defined + // based on this value. + int dts_hd_spdif_channel_count = profile == FF_PROFILE_DTS_HD_HRA ? + 2 : 8; if (spdif_ctx->use_dts_hd && is_hd) { - av_dict_set(&format_opts, "dtshd_rate", "768000", 0); // 4*192000 + av_dict_set_int(&format_opts, "dtshd_rate", + dts_hd_spdif_channel_count * 96000, 0); sample_format = AF_FORMAT_S_DTSHD; samplerate = 192000; - num_channels = 2*4; + num_channels = dts_hd_spdif_channel_count; } else { sample_format = AF_FORMAT_S_DTS; samplerate = 48000; diff --git a/audio/filter/af_rubberband.c b/audio/filter/af_rubberband.c index 6c8c773e62..c7b6317c13 100644 --- a/audio/filter/af_rubberband.c +++ b/audio/filter/af_rubberband.c @@ -167,6 +167,7 @@ static void process(struct mp_filter *f) if (eof) { mp_pin_in_write(f->ppins[1], MP_EOF_FRAME); rubberband_reset(p->rubber); + p->rubber_delay = 0; TA_FREEP(&p->pending); p->sent_final = false; return; @@ -263,6 +264,7 @@ static void reset(struct mp_filter *f) if (p->rubber) rubberband_reset(p->rubber); + p->rubber_delay = 0; p->sent_final = false; TA_FREEP(&p->pending); } diff --git a/audio/format.c b/audio/format.c index 8a13698ff7..f56546a207 100644 --- a/audio/format.c +++ b/audio/format.c @@ -55,12 +55,6 @@ bool af_fmt_is_int(int format) return format && !af_fmt_is_spdif(format) && !af_fmt_is_float(format); } -// false for interleaved and AF_FORMAT_UNKNOWN -bool af_fmt_is_planar(int format) -{ - return format && af_fmt_to_planar(format) == format; -} - bool af_fmt_is_spdif(int format) { return af_format_sample_alignment(format) > 1; @@ -79,23 +73,30 @@ static const int planar_formats[][2] = { {AF_FORMAT_DOUBLEP, AF_FORMAT_DOUBLE}, }; +bool af_fmt_is_planar(int format) +{ + for (int n = 0; n < MP_ARRAY_SIZE(planar_formats); n++) { + if (planar_formats[n][0] == format) + return true; + } + return false; +} + // Return the planar format corresponding to the given format. -// If the format is already planar, return it. -// Return 0 if there's no equivalent. +// If the format is already planar or if there's no equivalent, +// return it. int af_fmt_to_planar(int format) { for (int n = 0; n < MP_ARRAY_SIZE(planar_formats); n++) { if (planar_formats[n][1] == format) return planar_formats[n][0]; - if (planar_formats[n][0] == format) - return format; } - return 0; + return format; } // Return the interleaved format corresponding to the given format. -// If the format is already interleaved, return it. -// Always succeeds if format is actually planar; otherwise return 0. +// If the format is already interleaved or if there's no equivalent, +// return it. int af_fmt_from_planar(int format) { for (int n = 0; n < MP_ARRAY_SIZE(planar_formats); n++) { @@ -134,17 +135,6 @@ const char *af_fmt_to_str(int format) return "??"; } -int af_fmt_seconds_to_bytes(int format, float seconds, int channels, int samplerate) -{ - assert(!af_fmt_is_planar(format)); - int bps = af_fmt_to_bytes(format); - int framelen = channels * bps; - int bytes = seconds * bps * samplerate; - if (bytes % framelen) - bytes += framelen - (bytes % framelen); - return bytes; -} - void af_fill_silence(void *dst, size_t bytes, int format) { memset(dst, af_fmt_is_unsigned(format) ? 0x80 : 0, bytes); diff --git a/audio/format.h b/audio/format.h index 0afc6567c9..24e1c5404f 100644 --- a/audio/format.h +++ b/audio/format.h @@ -64,9 +64,6 @@ bool af_fmt_is_pcm(int format); int af_fmt_to_planar(int format); int af_fmt_from_planar(int format); -// Amount of bytes that contain audio of the given duration, aligned to frames. -int af_fmt_seconds_to_bytes(int format, float seconds, int channels, int samplerate); - void af_fill_silence(void *dst, size_t bytes, int format); void af_get_best_sample_formats(int src_format, int *out_formats); diff --git a/audio/out/ao_alsa.c b/audio/out/ao_alsa.c index d8a1ec5cae..df78a67178 100644 --- a/audio/out/ao_alsa.c +++ b/audio/out/ao_alsa.c @@ -939,17 +939,32 @@ static void drain(struct ao *ao) static int get_space(struct ao *ao) { struct priv *p = ao->priv; - snd_pcm_status_t *status; - int err; - snd_pcm_status_alloca(&status); + // in case of pausing or the device still being configured, + // just return our buffer size. + if (p->paused || snd_pcm_state(p->alsa) == SND_PCM_STATE_SETUP) + return p->buffersize; + + snd_pcm_sframes_t space = snd_pcm_avail(p->alsa); + if (space < 0) { + if (space == -EPIPE) { + MP_WARN(ao, "ALSA XRUN hit, attempting to recover...\n"); + int err = snd_pcm_prepare(p->alsa); + CHECK_ALSA_ERROR("Unable to recover from under/overrun!"); + return p->buffersize; + } + + MP_ERR(ao, "Error received from snd_pcm_avail " + "(%ld, %s with ALSA state %s)!\n", + space, snd_strerror(space), + snd_pcm_state_name(snd_pcm_state(p->alsa))); - err = snd_pcm_status(p->alsa, status); - if (!check_device_present(ao, err)) + // request a reload of the AO if device is not present, + // then error out. + check_device_present(ao, space); goto alsa_error; - CHECK_ALSA_ERROR("cannot get pcm status"); + } - unsigned space = snd_pcm_status_get_avail(status); if (space > p->buffersize) // Buffer underrun? space = p->buffersize; return space / p->outburst * p->outburst; diff --git a/audio/out/ao_audiounit.m b/audio/out/ao_audiounit.m index fb18f1eb14..70a80f29f6 100644 --- a/audio/out/ao_audiounit.m +++ b/audio/out/ao_audiounit.m @@ -192,7 +192,7 @@ const struct ao_driver audio_out_audiounit = { .name = "audiounit", .uninit = uninit, .init = init, - .pause = stop, + .reset = stop, .resume = start, .priv_size = sizeof(struct priv), }; diff --git a/audio/out/ao_jack.c b/audio/out/ao_jack.c index b5413f77cf..0d5a2da207 100644 --- a/audio/out/ao_jack.c +++ b/audio/out/ao_jack.c @@ -143,7 +143,8 @@ connect_to_outports(struct ao *ao) if (!port_name) port_flags |= JackPortIsPhysical; - matching_ports = jack_get_ports(p->client, port_name, NULL, port_flags); + const char *port_type = JACK_DEFAULT_AUDIO_TYPE; // exclude MIDI ports + matching_ports = jack_get_ports(p->client, port_name, port_type, port_flags); if (!matching_ports || !matching_ports[0]) { MP_FATAL(ao, "no ports to connect to\n"); diff --git a/audio/out/ao_openal.c b/audio/out/ao_openal.c index c1f405bf12..53571b6d6e 100644 --- a/audio/out/ao_openal.c +++ b/audio/out/ao_openal.c @@ -24,19 +24,6 @@ #include <stdlib.h> #include <stdio.h> #include <inttypes.h> - -#ifdef __APPLE__ -#ifndef AL_FORMAT_MONO_FLOAT32 -#define AL_FORMAT_MONO_FLOAT32 0x10010 -#endif -#ifndef AL_FORMAT_STEREO_FLOAT32 -#define AL_FORMAT_STEREO_FLOAT32 0x10011 -#endif -#ifndef AL_FORMAT_MONO_DOUBLE_EXT -#define AL_FORMAT_MONO_DOUBLE_EXT 0x10012 -#endif -#include <OpenAL/MacOSX_OALExtensions.h> -#else #ifdef OPENAL_AL_H #include <OpenAL/alc.h> #include <OpenAL/al.h> @@ -46,7 +33,6 @@ #include <AL/al.h> #include <AL/alext.h> #endif -#endif // __APPLE__ #include "common/msg.h" diff --git a/audio/out/ao_opensles.c b/audio/out/ao_opensles.c index ea48de892e..8c24320406 100644 --- a/audio/out/ao_opensles.c +++ b/audio/out/ao_opensles.c @@ -35,18 +35,13 @@ struct priv { SLBufferQueueItf buffer_queue; SLEngineItf engine; SLPlayItf play; - char *buf; - size_t buffer_size; + void *buf; + int bytes_per_enqueue; pthread_mutex_t buffer_lock; double audio_latency; - int cfg_frames_per_buffer; -}; - -static const int fmtmap[][2] = { - { AF_FORMAT_U8, SL_PCMSAMPLEFORMAT_FIXED_8 }, - { AF_FORMAT_S16, SL_PCMSAMPLEFORMAT_FIXED_16 }, - { 0 } + int frames_per_enqueue; + int buffer_size_in_ms; }; #define DESTROY(thing) \ @@ -71,7 +66,6 @@ static void uninit(struct ao *ao) free(p->buf); p->buf = NULL; - p->buffer_size = 0; } #undef DESTROY @@ -81,26 +75,22 @@ static void buffer_callback(SLBufferQueueItf buffer_queue, void *context) struct ao *ao = context; struct priv *p = ao->priv; SLresult res; - void *data[1]; double delay; pthread_mutex_lock(&p->buffer_lock); - data[0] = p->buf; - delay = 2 * p->buffer_size / (double)ao->bps; + delay = 2 * p->frames_per_enqueue / (double)ao->samplerate; delay += p->audio_latency; - ao_read_data(ao, data, p->buffer_size / ao->sstride, + ao_read_data(ao, &p->buf, p->frames_per_enqueue, mp_time_us() + 1000000LL * delay); - res = (*buffer_queue)->Enqueue(buffer_queue, p->buf, p->buffer_size); + res = (*buffer_queue)->Enqueue(buffer_queue, p->buf, p->bytes_per_enqueue); if (res != SL_RESULT_SUCCESS) MP_ERR(ao, "Failed to Enqueue: %d\n", res); pthread_mutex_unlock(&p->buffer_lock); } -#define DEFAULT_BUFFER_SIZE_MS 250 - #define CHK(stmt) \ { \ SLresult res = stmt; \ @@ -115,7 +105,7 @@ static int init(struct ao *ao) struct priv *p = ao->priv; SLDataLocator_BufferQueue locator_buffer_queue; SLDataLocator_OutputMix locator_output_mix; - SLDataFormat_PCM pcm; + SLAndroidDataFormat_PCM_EX pcm; SLDataSource audio_source; SLDataSink audio_sink; @@ -129,43 +119,55 @@ static int init(struct ao *ao) CHK((*p->output_mix)->Realize(p->output_mix, SL_BOOLEAN_FALSE)); locator_buffer_queue.locatorType = SL_DATALOCATOR_BUFFERQUEUE; - locator_buffer_queue.numBuffers = 1; - - pcm.formatType = SL_DATAFORMAT_PCM; - pcm.numChannels = 2; - - int compatible_formats[AF_FORMAT_COUNT + 1]; - af_get_best_sample_formats(ao->format, compatible_formats); - pcm.bitsPerSample = 0; - for (int i = 0; compatible_formats[i] && !pcm.bitsPerSample; ++i) - for (int j = 0; fmtmap[j][0]; ++j) - if (compatible_formats[i] == fmtmap[j][0]) { - ao->format = fmtmap[j][0]; - pcm.bitsPerSample = fmtmap[j][1]; - break; - } - if (!pcm.bitsPerSample) { - MP_ERR(ao, "Cannot find compatible audio format\n"); - goto error; + locator_buffer_queue.numBuffers = 8; + + if (af_fmt_is_int(ao->format)) { + // Be future-proof + if (af_fmt_to_bytes(ao->format) > 2) + ao->format = AF_FORMAT_S32; + else + ao->format = af_fmt_from_planar(ao->format); + pcm.formatType = SL_DATAFORMAT_PCM; + } else { + ao->format = AF_FORMAT_FLOAT; + pcm.formatType = SL_ANDROID_DATAFORMAT_PCM_EX; + pcm.representation = SL_ANDROID_PCM_REPRESENTATION_FLOAT; } - pcm.containerSize = 8 * af_fmt_to_bytes(ao->format); + pcm.numChannels = ao->channels.num; + pcm.containerSize = pcm.bitsPerSample = 8 * af_fmt_to_bytes(ao->format); pcm.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT; pcm.endianness = SL_BYTEORDER_LITTLEENDIAN; + pcm.sampleRate = ao->samplerate * 1000; + + if (p->buffer_size_in_ms) { + ao->device_buffer = ao->samplerate * p->buffer_size_in_ms / 1000; + // As the purpose of buffer_size_in_ms is to request a specific + // soft buffer size: + ao->def_buffer = 0; + } - // samplesPerSec is misnamed, actually it's samples per ms - pcm.samplesPerSec = ao->samplerate * 1000; + // But it does not make sense if it is smaller than the enqueue size: + if (p->frames_per_enqueue) { + ao->device_buffer = MPMAX(ao->device_buffer, p->frames_per_enqueue); + } else { + if (ao->device_buffer) { + p->frames_per_enqueue = ao->device_buffer; + } else if (ao->def_buffer) { + p->frames_per_enqueue = ao->def_buffer * ao->samplerate; + } else { + MP_ERR(ao, "Enqueue size is not set and can neither be derived\n"); + goto error; + } + } - if (p->cfg_frames_per_buffer) - ao->device_buffer = p->cfg_frames_per_buffer; - else - ao->device_buffer = ao->samplerate * DEFAULT_BUFFER_SIZE_MS / 1000; - p->buffer_size = ao->device_buffer * ao->channels.num * + p->bytes_per_enqueue = p->frames_per_enqueue * ao->channels.num * af_fmt_to_bytes(ao->format); - p->buf = calloc(1, p->buffer_size); + p->buf = calloc(1, p->bytes_per_enqueue); if (!p->buf) { MP_ERR(ao, "Failed to allocate device buffer\n"); goto error; } + int r = pthread_mutex_init(&p->buffer_lock, NULL); if (r) { MP_ERR(ao, "Failed to initialize the mutex: %d\n", r); @@ -248,8 +250,12 @@ const struct ao_driver audio_out_opensles = { .resume = resume, .priv_size = sizeof(struct priv), + .priv_defaults = &(const struct priv) { + .buffer_size_in_ms = 250, + }, .options = (const struct m_option[]) { - OPT_INTRANGE("frames-per-buffer", cfg_frames_per_buffer, 0, 1, 96000), + OPT_INTRANGE("frames-per-enqueue", frames_per_enqueue, 0, 1, 96000), + OPT_INTRANGE("buffer-size-in-ms", buffer_size_in_ms, 0, 0, 500), {0} }, .options_prefix = "opensles", diff --git a/audio/out/ao_pulse.c b/audio/out/ao_pulse.c index ed45ba6549..e288841788 100644 --- a/audio/out/ao_pulse.c +++ b/audio/out/ao_pulse.c @@ -454,11 +454,11 @@ static int init(struct ao *ao) pa_stream_set_write_callback(priv->stream, stream_request_cb, ao); pa_stream_set_latency_update_callback(priv->stream, stream_latency_update_cb, ao); - int buf_size = af_fmt_seconds_to_bytes(ao->format, priv->cfg_buffer / 1000.0, - ao->channels.num, ao->samplerate); + uint32_t buf_size = ao->samplerate * (priv->cfg_buffer / 1000.0) * + af_fmt_to_bytes(ao->format) * ao->channels.num; pa_buffer_attr bufattr = { .maxlength = -1, - .tlength = buf_size > 0 ? buf_size : (uint32_t)-1, + .tlength = buf_size > 0 ? buf_size : -1, .prebuf = -1, .minreq = -1, .fragsize = -1, |