summaryrefslogtreecommitdiffstats
path: root/audio
diff options
context:
space:
mode:
Diffstat (limited to 'audio')
-rw-r--r--audio/audio_buffer.c136
-rw-r--r--audio/audio_buffer.h12
-rw-r--r--audio/out/push.c89
3 files changed, 112 insertions, 125 deletions
diff --git a/audio/audio_buffer.c b/audio/audio_buffer.c
index a443a2185a..b54f1f41b8 100644
--- a/audio/audio_buffer.c
+++ b/audio/audio_buffer.c
@@ -21,141 +21,137 @@
#include "common/common.h"
+#include "chmap.h"
#include "audio_buffer.h"
-#include "audio.h"
#include "format.h"
struct mp_audio_buffer {
- struct mp_audio *buffer;
+ int format;
+ struct mp_chmap channels;
+ int srate;
+ int sstride;
+ int num_planes;
+ uint8_t *data[MP_NUM_CHANNELS];
+ int allocated;
+ int num_samples;
};
struct mp_audio_buffer *mp_audio_buffer_create(void *talloc_ctx)
{
- struct mp_audio_buffer *ab = talloc(talloc_ctx, struct mp_audio_buffer);
- *ab = (struct mp_audio_buffer) {
- .buffer = talloc_zero(ab, struct mp_audio),
- };
- return ab;
+ return talloc_zero(talloc_ctx, struct mp_audio_buffer);
}
// Reinitialize the buffer, set a new format, drop old data.
// The audio data in fmt is not used, only the format.
-void mp_audio_buffer_reinit(struct mp_audio_buffer *ab, struct mp_audio *fmt)
-{
- mp_audio_copy_config(ab->buffer, fmt);
- mp_audio_realloc(ab->buffer, 1);
- ab->buffer->samples = 0;
-}
-
void mp_audio_buffer_reinit_fmt(struct mp_audio_buffer *ab, int format,
const struct mp_chmap *channels, int srate)
{
- struct mp_audio mpa = {0};
- mp_audio_set_format(&mpa, format);
- mp_audio_set_channels(&mpa, channels);
- mpa.rate = srate;
- mp_audio_buffer_reinit(ab, &mpa);
-}
-
-void mp_audio_buffer_get_format(struct mp_audio_buffer *ab,
- struct mp_audio *out_fmt)
-{
- *out_fmt = (struct mp_audio){0};
- mp_audio_copy_config(out_fmt, ab->buffer);
+ for (int n = 0; n < MP_NUM_CHANNELS; n++)
+ TA_FREEP(&ab->data[n]);
+ ab->format = format;
+ ab->channels = *channels;
+ ab->srate = srate;
+ ab->allocated = 0;
+ ab->num_samples = 0;
+ ab->sstride = af_fmt_to_bytes(ab->format);
+ ab->num_planes = 1;
+ if (af_fmt_is_planar(ab->format)) {
+ ab->num_planes = ab->channels.num;
+ } else {
+ ab->sstride *= ab->channels.num;
+ }
}
// Make the total size of the internal buffer at least this number of samples.
void mp_audio_buffer_preallocate_min(struct mp_audio_buffer *ab, int samples)
{
- mp_audio_realloc_min(ab->buffer, samples);
+ if (samples > ab->allocated) {
+ for (int n = 0; n < ab->num_planes; n++) {
+ ab->data[n] = talloc_realloc(ab, ab->data[n], char,
+ ab->sstride * samples);
+ }
+ ab->allocated = samples;
+ }
}
// Get number of samples that can be written without forcing a resize of the
// internal buffer.
int mp_audio_buffer_get_write_available(struct mp_audio_buffer *ab)
{
- return mp_audio_get_allocated_size(ab->buffer) - ab->buffer->samples;
-}
-
-// Get a pointer to the end of the buffer (where writing would append). If the
-// internal buffer is too small for the given number of samples, it's resized.
-// After writing to the buffer, mp_audio_buffer_finish_write() has to be used
-// to make the written data part of the readable buffer.
-void mp_audio_buffer_get_write_buffer(struct mp_audio_buffer *ab, int samples,
- struct mp_audio *out_buffer)
-{
- assert(samples >= 0);
- mp_audio_realloc_min(ab->buffer, ab->buffer->samples + samples);
- *out_buffer = *ab->buffer;
- out_buffer->samples = ab->buffer->samples + samples;
- mp_audio_skip_samples(out_buffer, ab->buffer->samples);
+ return ab->allocated - ab->num_samples;
}
-void mp_audio_buffer_finish_write(struct mp_audio_buffer *ab, int samples)
+// All integer parameters are in samples.
+// dst and src can overlap.
+static void copy_planes(struct mp_audio_buffer *ab,
+ uint8_t **dst, int dst_offset,
+ uint8_t **src, int src_offset, int length)
{
- assert(samples >= 0 && samples <= mp_audio_buffer_get_write_available(ab));
- ab->buffer->samples += samples;
+ for (int n = 0; n < ab->num_planes; n++) {
+ memmove((char *)dst[n] + dst_offset * ab->sstride,
+ (char *)src[n] + src_offset * ab->sstride,
+ length * ab->sstride);
+ }
}
// Append data to the end of the buffer.
// If the buffer is not large enough, it is transparently resized.
-// For now always copies the data.
-void mp_audio_buffer_append(struct mp_audio_buffer *ab, struct mp_audio *mpa)
+void mp_audio_buffer_append(struct mp_audio_buffer *ab, void **ptr, int samples)
{
- int offset = ab->buffer->samples;
- ab->buffer->samples += mpa->samples;
- mp_audio_realloc_min(ab->buffer, ab->buffer->samples);
- mp_audio_copy(ab->buffer, offset, mpa, 0, mpa->samples);
+ mp_audio_buffer_preallocate_min(ab, ab->num_samples + samples);
+ copy_planes(ab, ab->data, ab->num_samples, (uint8_t **)ptr, 0, samples);
+ ab->num_samples += samples;
}
// Prepend silence to the start of the buffer.
void mp_audio_buffer_prepend_silence(struct mp_audio_buffer *ab, int samples)
{
assert(samples >= 0);
- int oldlen = ab->buffer->samples;
- ab->buffer->samples += samples;
- mp_audio_realloc_min(ab->buffer, ab->buffer->samples);
- mp_audio_copy(ab->buffer, samples, ab->buffer, 0, oldlen);
- mp_audio_fill_silence(ab->buffer, 0, samples);
+ mp_audio_buffer_preallocate_min(ab, ab->num_samples + samples);
+ copy_planes(ab, ab->data, samples, ab->data, 0, ab->num_samples);
+ ab->num_samples += samples;
+ for (int n = 0; n < ab->num_planes; n++)
+ af_fill_silence(ab->data[n], samples * ab->sstride, ab->format);
}
void mp_audio_buffer_duplicate(struct mp_audio_buffer *ab, int samples)
{
- assert(samples >= 0 && samples <= ab->buffer->samples);
- int oldlen = ab->buffer->samples;
- ab->buffer->samples += samples;
- mp_audio_realloc_min(ab->buffer, ab->buffer->samples);
- mp_audio_copy(ab->buffer, oldlen, ab->buffer, oldlen - samples, samples);
+ assert(samples >= 0 && samples <= ab->num_samples);
+ mp_audio_buffer_preallocate_min(ab, ab->num_samples + samples);
+ copy_planes(ab, ab->data, ab->num_samples,
+ ab->data, ab->num_samples - samples, samples);
+ ab->num_samples += samples;
}
// Get the start of the current readable buffer.
-void mp_audio_buffer_peek(struct mp_audio_buffer *ab, struct mp_audio *out_mpa)
+void mp_audio_buffer_peek(struct mp_audio_buffer *ab, uint8_t ***ptr,
+ int *samples)
{
- *out_mpa = *ab->buffer;
+ *ptr = ab->data;
+ *samples = ab->num_samples;
}
// Skip leading samples. (Used with mp_audio_buffer_peek() to read data.)
void mp_audio_buffer_skip(struct mp_audio_buffer *ab, int samples)
{
- assert(samples >= 0 && samples <= ab->buffer->samples);
- mp_audio_copy(ab->buffer, 0, ab->buffer, samples,
- ab->buffer->samples - samples);
- ab->buffer->samples -= samples;
+ assert(samples >= 0 && samples <= ab->num_samples);
+ copy_planes(ab, ab->data, 0, ab->data, samples, ab->num_samples - samples);
+ ab->num_samples -= samples;
}
void mp_audio_buffer_clear(struct mp_audio_buffer *ab)
{
- ab->buffer->samples = 0;
+ ab->num_samples = 0;
}
// Return number of buffered audio samples
int mp_audio_buffer_samples(struct mp_audio_buffer *ab)
{
- return ab->buffer->samples;
+ return ab->num_samples;
}
// Return amount of buffered audio in seconds.
double mp_audio_buffer_seconds(struct mp_audio_buffer *ab)
{
- return ab->buffer->samples / (double)ab->buffer->rate;
+ return ab->num_samples / (double)ab->srate;
}
diff --git a/audio/audio_buffer.h b/audio/audio_buffer.h
index 212d187572..0d7b66a527 100644
--- a/audio/audio_buffer.h
+++ b/audio/audio_buffer.h
@@ -19,24 +19,18 @@
#define MP_AUDIO_BUFFER_H
struct mp_audio_buffer;
-struct mp_audio;
struct mp_chmap;
struct mp_audio_buffer *mp_audio_buffer_create(void *talloc_ctx);
-void mp_audio_buffer_reinit(struct mp_audio_buffer *ab, struct mp_audio *fmt);
void mp_audio_buffer_reinit_fmt(struct mp_audio_buffer *ab, int format,
const struct mp_chmap *channels, int srate);
-void mp_audio_buffer_get_format(struct mp_audio_buffer *ab,
- struct mp_audio *out_fmt);
void mp_audio_buffer_preallocate_min(struct mp_audio_buffer *ab, int samples);
int mp_audio_buffer_get_write_available(struct mp_audio_buffer *ab);
-void mp_audio_buffer_get_write_buffer(struct mp_audio_buffer *ab, int minsamples,
- struct mp_audio *out_buffer);
-void mp_audio_buffer_finish_write(struct mp_audio_buffer *ab, int samples);
-void mp_audio_buffer_append(struct mp_audio_buffer *ab, struct mp_audio *mpa);
+void mp_audio_buffer_append(struct mp_audio_buffer *ab, void **ptr, int samples);
void mp_audio_buffer_prepend_silence(struct mp_audio_buffer *ab, int samples);
void mp_audio_buffer_duplicate(struct mp_audio_buffer *ab, int samples);
-void mp_audio_buffer_peek(struct mp_audio_buffer *ab, struct mp_audio *out_mpa);
+void mp_audio_buffer_peek(struct mp_audio_buffer *ab, uint8_t ***ptr,
+ int *samples);
void mp_audio_buffer_skip(struct mp_audio_buffer *ab, int samples);
void mp_audio_buffer_clear(struct mp_audio_buffer *ab);
int mp_audio_buffer_samples(struct mp_audio_buffer *ab);
diff --git a/audio/out/push.c b/audio/out/push.c
index c4083923fd..8546ec816d 100644
--- a/audio/out/push.c
+++ b/audio/out/push.c
@@ -37,7 +37,6 @@
#include "osdep/timer.h"
#include "osdep/atomic.h"
-#include "audio/audio.h"
#include "audio/audio_buffer.h"
struct ao_push_state {
@@ -49,7 +48,8 @@ struct ao_push_state {
struct mp_audio_buffer *buffer;
- struct mp_audio *silence;
+ uint8_t *silence[MP_NUM_CHANNELS];
+ int silence_samples;
bool terminate;
bool wait_on_ao;
@@ -237,12 +237,7 @@ static int play(struct ao *ao, void **data, int samples, int flags)
flags = flags & ~AOPLAY_FINAL_CHUNK;
bool is_final = flags & AOPLAY_FINAL_CHUNK;
- struct mp_audio audio;
- mp_audio_buffer_get_format(p->buffer, &audio);
- for (int n = 0; n < ao->num_planes; n++)
- audio.planes[n] = data[n];
- audio.samples = write_samples;
- mp_audio_buffer_append(p->buffer, &audio);
+ mp_audio_buffer_append(p->buffer, data, samples);
bool got_data = write_samples > 0 || p->paused || p->final_chunk != is_final;
@@ -260,22 +255,26 @@ static int play(struct ao *ao, void **data, int samples, int flags)
return write_samples;
}
-static void ao_get_silence(struct ao *ao, struct mp_audio *data, int size)
+static bool realloc_silence(struct ao *ao, int samples)
{
struct ao_push_state *p = ao->api_priv;
- if (!p->silence) {
- p->silence = talloc_zero(p, struct mp_audio);
- mp_audio_set_format(p->silence, ao->format);
- mp_audio_set_channels(p->silence, &ao->channels);
- p->silence->rate = ao->samplerate;
- }
- if (p->silence->samples < size) {
- mp_audio_realloc_min(p->silence, size);
- p->silence->samples = size;
- mp_audio_fill_silence(p->silence, 0, size);
+
+ if (samples <= 0 || !af_fmt_is_pcm(ao->format))
+ return false;
+
+ if (samples > p->silence_samples) {
+ talloc_free(p->silence[0]);
+
+ int bytes = af_fmt_to_bytes(ao->format) * samples * ao->channels.num;
+ p->silence[0] = talloc_size(p, bytes);
+ for (int n = 1; n < MP_NUM_CHANNELS; n++)
+ p->silence[n] = p->silence[0];
+ p->silence_samples = samples;
+
+ af_fill_silence(p->silence[0], bytes, ao->format);
}
- *data = *p->silence;
- data->samples = size;
+
+ return true;
}
// called locked
@@ -287,39 +286,41 @@ static void ao_play_data(struct ao *ao)
space = MPMAX(space, 0);
if (space % ao->period_size)
MP_ERR(ao, "Audio device reports unaligned available buffer size.\n");
- struct mp_audio data;
+ uint8_t **planes;
+ int samples;
if (play_silence) {
- ao_get_silence(ao, &data, space);
+ planes = p->silence;
+ samples = realloc_silence(ao, space) ? space : 0;
} else {
- mp_audio_buffer_peek(p->buffer, &data);
+ mp_audio_buffer_peek(p->buffer, &planes, &samples);
}
- int max = data.samples;
- if (data.samples > space)
- data.samples = space;
+ int max = samples;
+ if (samples > space)
+ samples = space;
int flags = 0;
- if (p->final_chunk && data.samples == max) {
+ if (p->final_chunk && samples == max) {
flags |= AOPLAY_FINAL_CHUNK;
} else {
- data.samples = data.samples / ao->period_size * ao->period_size;
+ samples = samples / ao->period_size * ao->period_size;
}
MP_STATS(ao, "start ao fill");
int r = 0;
- if (data.samples)
- r = ao->driver->play(ao, data.planes, data.samples, flags);
+ if (samples)
+ r = ao->driver->play(ao, (void **)planes, samples, flags);
MP_STATS(ao, "end ao fill");
- if (r > data.samples) {
+ if (r > samples) {
MP_ERR(ao, "Audio device returned non-sense value.\n");
- r = data.samples;
+ r = samples;
} else if (r < 0) {
MP_ERR(ao, "Error writing audio to device.\n");
- } else if (r != data.samples) {
+ } else if (r != samples) {
MP_ERR(ao, "Audio device returned broken buffer state (sent %d samples, "
- "got %d samples, %d period%s)!\n", data.samples, r,
+ "got %d samples, %d period%s)!\n", samples, r,
ao->period_size, flags & AOPLAY_FINAL_CHUNK ? " final" : "");
}
r = MPMAX(r, 0);
// Probably can't copy the rest of the buffer due to period alignment.
- bool stuck_eof = r <= 0 && space >= max && data.samples > 0;
+ bool stuck_eof = r <= 0 && space >= max && samples > 0;
if ((flags & AOPLAY_FINAL_CHUNK) && stuck_eof) {
MP_ERR(ao, "Audio output driver seems to ignore AOPLAY_FINAL_CHUNK.\n");
r = max;
@@ -491,17 +492,13 @@ const struct ao_driver ao_api_push = {
int ao_play_silence(struct ao *ao, int samples)
{
assert(ao->api == &ao_api_push);
- if (samples <= 0 || !af_fmt_is_pcm(ao->format) || !ao->driver->play)
+
+ struct ao_push_state *p = ao->api_priv;
+
+ if (!realloc_silence(ao, samples) || !ao->driver->play)
return 0;
- int bytes = af_fmt_to_bytes(ao->format) * samples * ao->channels.num;
- char *p = talloc_size(NULL, bytes);
- af_fill_silence(p, bytes, ao->format);
- void *tmp[MP_NUM_CHANNELS];
- for (int n = 0; n < MP_NUM_CHANNELS; n++)
- tmp[n] = p;
- int r = ao->driver->play(ao, tmp, samples, 0);
- talloc_free(p);
- return r;
+
+ return ao->driver->play(ao, (void **)p->silence, samples, 0);
}
#ifndef __MINGW32__