[vlc-devel] [RFC PATCH] coreaudio: replace atomic circular buffer by locked block FIFO
Thomas Guillem
thomas at gllm.fr
Mon Mar 12 19:30:01 CET 2018
Remove TPCircularBuffer.c and usage of multiple atomic variables that start to
make this code way too complicated. Replace it by a basic pthread_mutex and a
block FIFO.
RFC:
Theoretically, you should never block from the render callback. But pthread
mutexes on macOS/iOS are hybrid mutexes that will try to spinlock first, and
these locks are held for very fast operations (setting a pointer and a bool).
PS: I can't find anymore in the documentation the mention about forbiden usage
of blocking operations from audio callbacks (but I guess it's kind of
obvious?).
---
modules/audio_output/Makefile.am | 6 +-
modules/audio_output/TPCircularBuffer.c | 115 ------------------
modules/audio_output/TPCircularBuffer.h | 175 --------------------------
modules/audio_output/coreaudio_common.c | 209 ++++++++++++++------------------
modules/audio_output/coreaudio_common.h | 18 +--
5 files changed, 105 insertions(+), 418 deletions(-)
delete mode 100644 modules/audio_output/TPCircularBuffer.c
delete mode 100644 modules/audio_output/TPCircularBuffer.h
diff --git a/modules/audio_output/Makefile.am b/modules/audio_output/Makefile.am
index d7766af7e9..48c19d79ea 100644
--- a/modules/audio_output/Makefile.am
+++ b/modules/audio_output/Makefile.am
@@ -101,16 +101,14 @@ aout_LTLIBRARIES += libwaveout_plugin.la
endif
libauhal_plugin_la_SOURCES = audio_output/auhal.c \
- audio_output/coreaudio_common.c audio_output/coreaudio_common.h \
- audio_output/TPCircularBuffer.h audio_output/TPCircularBuffer.c
+ audio_output/coreaudio_common.c audio_output/coreaudio_common.h
libauhal_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(aoutdir)' \
-Wl,-framework,CoreAudio,-framework,AudioUnit,-framework,AudioToolbox,-framework,CoreServices
if HAVE_OSX
aout_LTLIBRARIES += libauhal_plugin.la
endif
libaudiounit_ios_plugin_la_SOURCES = audio_output/audiounit_ios.m \
- audio_output/coreaudio_common.c audio_output/coreaudio_common.h \
- audio_output/TPCircularBuffer.h audio_output/TPCircularBuffer.c
+ audio_output/coreaudio_common.c audio_output/coreaudio_common.h
libaudiounit_ios_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(aoutdir)' \
-Wl,-framework,CoreAudio,-framework,AudioUnit,-framework,AudioToolbox,-framework,CoreServices,-framework,UIKit,-framework,AVFoundation
if HAVE_IOS
diff --git a/modules/audio_output/TPCircularBuffer.c b/modules/audio_output/TPCircularBuffer.c
deleted file mode 100644
index 1f7f05fa8c..0000000000
--- a/modules/audio_output/TPCircularBuffer.c
+++ /dev/null
@@ -1,115 +0,0 @@
-//
-// TPCircularBuffer.c
-// Circular/Ring buffer implementation
-//
-// Created by Michael Tyson on 10/12/2011.
-// Copyright 2011-2012 A Tasty Pixel. All rights reserved.
-
-
-#include "audio_output/TPCircularBuffer.h"
-#include <mach/mach.h>
-#include <stdio.h>
-
-#define reportResult(result,operation) (_reportResult((result),(operation),strrchr(__FILE__, '/')+1,__LINE__))
-static inline bool _reportResult(kern_return_t result, const char *operation, const char* file, int line) {
- if ( result != ERR_SUCCESS ) {
- printf("%s:%d: %s: %s\n", file, line, operation, mach_error_string(result));
- return false;
- }
- return true;
-}
-
-bool TPCircularBufferInit(TPCircularBuffer *buffer, int length) {
-
- // Keep trying until we get our buffer, needed to handle race conditions
- int retries = 3;
- while ( true ) {
-
- buffer->length = round_page(length); // We need whole page sizes
-
- // Temporarily allocate twice the length, so we have the contiguous address space to
- // support a second instance of the buffer directly after
- vm_address_t bufferAddress;
- kern_return_t result = vm_allocate(mach_task_self(),
- &bufferAddress,
- buffer->length * 2,
- VM_FLAGS_ANYWHERE); // allocate anywhere it'll fit
- if ( result != ERR_SUCCESS ) {
- if ( retries-- == 0 ) {
- reportResult(result, "Buffer allocation");
- return false;
- }
- // Try again if we fail
- continue;
- }
-
- // Now replace the second half of the allocation with a virtual copy of the first half. Deallocate the second half...
- result = vm_deallocate(mach_task_self(),
- bufferAddress + buffer->length,
- buffer->length);
- if ( result != ERR_SUCCESS ) {
- if ( retries-- == 0 ) {
- reportResult(result, "Buffer deallocation");
- return false;
- }
- // If this fails somehow, deallocate the whole region and try again
- vm_deallocate(mach_task_self(), bufferAddress, buffer->length);
- continue;
- }
-
- // Re-map the buffer to the address space immediately after the buffer
- vm_address_t virtualAddress = bufferAddress + buffer->length;
- vm_prot_t cur_prot, max_prot;
- result = vm_remap(mach_task_self(),
- &virtualAddress, // mirror target
- buffer->length, // size of mirror
- 0, // auto alignment
- 0, // force remapping to virtualAddress
- mach_task_self(), // same task
- bufferAddress, // mirror source
- 0, // MAP READ-WRITE, NOT COPY
- &cur_prot, // unused protection struct
- &max_prot, // unused protection struct
- VM_INHERIT_DEFAULT);
- if ( result != ERR_SUCCESS ) {
- if ( retries-- == 0 ) {
- reportResult(result, "Remap buffer memory");
- return false;
- }
- // If this remap failed, we hit a race condition, so deallocate and try again
- vm_deallocate(mach_task_self(), bufferAddress, buffer->length);
- continue;
- }
-
- if ( virtualAddress != bufferAddress+buffer->length ) {
- // If the memory is not contiguous, clean up both allocated buffers and try again
- if ( retries-- == 0 ) {
- printf("Couldn't map buffer memory to end of buffer\n");
- return false;
- }
-
- vm_deallocate(mach_task_self(), virtualAddress, buffer->length);
- vm_deallocate(mach_task_self(), bufferAddress, buffer->length);
- continue;
- }
-
- buffer->buffer = (void*)bufferAddress;
- buffer->fillCount = 0;
- buffer->head = buffer->tail = 0;
-
- return true;
- }
- return false;
-}
-
-void TPCircularBufferCleanup(TPCircularBuffer *buffer) {
- vm_deallocate(mach_task_self(), (vm_address_t)buffer->buffer, buffer->length * 2);
- memset(buffer, 0, sizeof(TPCircularBuffer));
-}
-
-void TPCircularBufferClear(TPCircularBuffer *buffer) {
- int32_t fillCount;
- if ( TPCircularBufferTail(buffer, &fillCount) ) {
- TPCircularBufferConsume(buffer, fillCount);
- }
-}
diff --git a/modules/audio_output/TPCircularBuffer.h b/modules/audio_output/TPCircularBuffer.h
deleted file mode 100644
index b4932edeb2..0000000000
--- a/modules/audio_output/TPCircularBuffer.h
+++ /dev/null
@@ -1,175 +0,0 @@
-//
-// TPCircularBuffer.h
-// Circular/Ring buffer implementation
-//
-// https://github.com/michaeltyson/TPCircularBuffer
-//
-// Created by Michael Tyson on 10/12/2011.
-// Copyright 2011-2012 A Tasty Pixel. All rights reserved.
-//
-//
-// This implementation makes use of a virtual memory mapping technique that inserts a virtual copy
-// of the buffer memory directly after the buffer's end, negating the need for any buffer wrap-around
-// logic. Clients can simply use the returned memory address as if it were contiguous space.
-//
-// The implementation is thread-safe in the case of a single producer and single consumer.
-//
-// Virtual memory technique originally proposed by Philip Howard (http://vrb.slashusr.org/), and
-// adapted to Darwin by Kurt Revis (http://www.snoize.com,
-// http://www.snoize.com/Code/PlayBufferedSoundFile.tar.gz)
-//
-
-#ifndef TPCircularBuffer_h
-#define TPCircularBuffer_h
-
-#include <libkern/OSAtomic.h>
-#include <string.h>
-#include <assert.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct {
- void *buffer;
- int32_t length;
- int32_t tail;
- int32_t head;
- volatile int32_t fillCount;
-} TPCircularBuffer;
-
-/*!
- * Initialise buffer
- *
- * Note that the length is advisory only: Because of the way the
- * memory mirroring technique works, the true buffer length will
- * be multiples of the device page size (e.g. 4096 bytes)
- *
- * @param buffer Circular buffer
- * @param length Length of buffer
- */
-bool TPCircularBufferInit(TPCircularBuffer *buffer, int32_t length);
-
-/*!
- * Cleanup buffer
- *
- * Releases buffer resources.
- */
-void TPCircularBufferCleanup(TPCircularBuffer *buffer);
-
-/*!
- * Clear buffer
- *
- * Resets buffer to original, empty state.
- *
- * This is safe for use by consumer while producer is accessing
- * buffer.
- */
-void TPCircularBufferClear(TPCircularBuffer *buffer);
-
-// Reading (consuming)
-
-/*!
- * Access end of buffer
- *
- * This gives you a pointer to the end of the buffer, ready
- * for reading, and the number of available bytes to read.
- *
- * @param buffer Circular buffer
- * @param availableBytes On output, the number of bytes ready for reading
- * @return Pointer to the first bytes ready for reading, or NULL if buffer is empty
- */
-static __inline__ __attribute__((always_inline)) void* TPCircularBufferTail(TPCircularBuffer *buffer, int32_t* availableBytes) {
- *availableBytes = buffer->fillCount;
- if ( *availableBytes == 0 ) return NULL;
- return (void*)((char*)buffer->buffer + buffer->tail);
-}
-
-/*!
- * Consume bytes in buffer
- *
- * This frees up the just-read bytes, ready for writing again.
- *
- * @param buffer Circular buffer
- * @param amount Number of bytes to consume
- */
-static __inline__ __attribute__((always_inline)) void TPCircularBufferConsume(TPCircularBuffer *buffer, int32_t amount) {
- buffer->tail = (buffer->tail + amount) % buffer->length;
- OSAtomicAdd32Barrier(-amount, &buffer->fillCount);
- assert(buffer->fillCount >= 0);
-}
-
-/*!
- * Version of TPCircularBufferConsume without the memory barrier, for more optimal use in single-threaded contexts
- */
-static __inline__ __attribute__((always_inline)) void TPCircularBufferConsumeNoBarrier(TPCircularBuffer *buffer, int32_t amount) {
- buffer->tail = (buffer->tail + amount) % buffer->length;
- buffer->fillCount -= amount;
- assert(buffer->fillCount >= 0);
-}
-
-/*!
- * Access front of buffer
- *
- * This gives you a pointer to the front of the buffer, ready
- * for writing, and the number of available bytes to write.
- *
- * @param buffer Circular buffer
- * @param availableBytes On output, the number of bytes ready for writing
- * @return Pointer to the first bytes ready for writing, or NULL if buffer is full
- */
-static __inline__ __attribute__((always_inline)) void* TPCircularBufferHead(TPCircularBuffer *buffer, int32_t* availableBytes) {
- *availableBytes = (buffer->length - buffer->fillCount);
- if ( *availableBytes == 0 ) return NULL;
- return (void*)((char*)buffer->buffer + buffer->head);
-}
-
-// Writing (producing)
-
-/*!
- * Produce bytes in buffer
- *
- * This marks the given section of the buffer ready for reading.
- *
- * @param buffer Circular buffer
- * @param amount Number of bytes to produce
- */
-static __inline__ __attribute__((always_inline)) void TPCircularBufferProduce(TPCircularBuffer *buffer, int amount) {
- buffer->head = (buffer->head + amount) % buffer->length;
- OSAtomicAdd32Barrier(amount, &buffer->fillCount);
- assert(buffer->fillCount <= buffer->length);
-}
-
-/*!
- * Version of TPCircularBufferProduce without the memory barrier, for more optimal use in single-threaded contexts
- */
-static __inline__ __attribute__((always_inline)) void TPCircularBufferProduceNoBarrier(TPCircularBuffer *buffer, int amount) {
- buffer->head = (buffer->head + amount) % buffer->length;
- buffer->fillCount += amount;
- assert(buffer->fillCount <= buffer->length);
-}
-
-/*!
- * Helper routine to copy bytes to buffer
- *
- * This copies the given bytes to the buffer, and marks them ready for writing.
- *
- * @param buffer Circular buffer
- * @param src Source buffer
- * @param len Number of bytes in source buffer
- * @return true if bytes copied, false if there was insufficient space
- */
-static __inline__ __attribute__((always_inline)) bool TPCircularBufferProduceBytes(TPCircularBuffer *buffer, const void* src, int32_t len) {
- int32_t space;
- void *ptr = TPCircularBufferHead(buffer, &space);
- if ( space < len ) return false;
- memcpy(ptr, src, len);
- TPCircularBufferProduce(buffer, len);
- return true;
-}
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/modules/audio_output/coreaudio_common.c b/modules/audio_output/coreaudio_common.c
index 0413dea570..e1fa48f667 100644
--- a/modules/audio_output/coreaudio_common.c
+++ b/modules/audio_output/coreaudio_common.c
@@ -42,16 +42,28 @@ FramesToUs(struct aout_sys_common *p_sys, uint64_t i_nb_frames)
return i_nb_frames * CLOCK_FREQ / p_sys->i_rate;
}
+static void
+ca_ClearOutBuffers(audio_output_t *p_aout)
+{
+ struct aout_sys_common *p_sys = (struct aout_sys_common *) p_aout->sys;
+
+ block_ChainRelease(p_sys->p_out_chain);
+ p_sys->p_out_chain = NULL;
+ p_sys->pp_out_last = &p_sys->p_out_chain;
+
+ p_sys->i_out_size = 0;
+ p_sys->b_do_flush = false;
+}
+
void
ca_Open(audio_output_t *p_aout)
{
struct aout_sys_common *p_sys = (struct aout_sys_common *) p_aout->sys;
- atomic_init(&p_sys->i_underrun_size, 0);
- atomic_init(&p_sys->b_paused, false);
- atomic_init(&p_sys->b_do_flush, false);
- vlc_sem_init(&p_sys->flush_sem, 0);
+ p_sys->p_out_chain = NULL;
+
vlc_mutex_init(&p_sys->lock);
+ vlc_cond_init(&p_sys->wait);
p_aout->play = ca_Play;
p_aout->pause = ca_Pause;
@@ -64,8 +76,8 @@ ca_Close(audio_output_t *p_aout)
{
struct aout_sys_common *p_sys = (struct aout_sys_common *) p_aout->sys;
- vlc_sem_destroy(&p_sys->flush_sem);
vlc_mutex_destroy(&p_sys->lock);
+ vlc_cond_destroy(&p_sys->wait);
}
/* Called from render callbacks. No lock, wait, and IO here */
@@ -74,41 +86,54 @@ ca_Render(audio_output_t *p_aout, uint8_t *p_output, size_t i_requested)
{
struct aout_sys_common *p_sys = (struct aout_sys_common *) p_aout->sys;
- bool expected = true;
- if (atomic_compare_exchange_weak(&p_sys->b_do_flush, &expected, false))
- {
- TPCircularBufferClear(&p_sys->circular_buffer);
- /* Signal that the renderer is flushed */
- vlc_sem_post(&p_sys->flush_sem);
- }
+ vlc_mutex_lock(&p_sys->lock);
+ if (p_sys->b_do_flush)
+ ca_ClearOutBuffers(p_aout);
- if (atomic_load_explicit(&p_sys->b_paused, memory_order_relaxed))
+ if (p_sys->b_paused)
{
memset(p_output, 0, i_requested);
+ vlc_mutex_unlock(&p_sys->lock);
return;
}
- /* Pull audio from buffer */
- int32_t i_available;
- void *p_data = TPCircularBufferTail(&p_sys->circular_buffer,
- &i_available);
- if (i_available < 0)
- i_available = 0;
-
- size_t i_tocopy = __MIN(i_requested, (size_t) i_available);
-
- if (i_tocopy > 0)
+ size_t i_copied = 0;
+ block_t *p_block = p_sys->p_out_chain;
+ while (p_block != NULL && i_requested != 0)
{
- memcpy(p_output, p_data, i_tocopy);
- TPCircularBufferConsume(&p_sys->circular_buffer, i_tocopy);
+ size_t i_tocopy = __MIN(i_requested, p_block->i_buffer);
+ memcpy(&p_output[i_copied], p_block->p_buffer, i_tocopy);
+ i_requested -= i_tocopy;
+ i_copied += i_tocopy;
+ if (i_tocopy == p_block->i_buffer)
+ {
+ block_t *p_release = p_block;
+ p_block = p_block->p_next;
+ block_Release(p_release);
+ }
+ else
+ {
+ assert(i_requested == 0);
+
+ p_block->p_buffer += i_tocopy;
+ p_block->i_buffer -= i_tocopy;
+ }
}
+ p_sys->p_out_chain = p_block;
+ if (!p_sys->p_out_chain)
+ p_sys->pp_out_last = &p_sys->p_out_chain;
+ p_sys->i_out_size -= i_copied;
/* Pad with 0 */
- if (i_requested > i_tocopy)
+ if (i_requested > 0)
{
- atomic_fetch_add(&p_sys->i_underrun_size, i_requested - i_tocopy);
- memset(&p_output[i_tocopy], 0, i_requested - i_tocopy);
+ assert(p_sys->i_out_size == 0);
+ p_sys->i_underrun_size += i_requested;
+ memset(&p_output[i_copied], 0, i_requested);
}
+
+ vlc_mutex_unlock(&p_sys->lock);
+ vlc_cond_signal(&p_sys->wait);
}
int
@@ -116,12 +141,12 @@ ca_TimeGet(audio_output_t *p_aout, mtime_t *delay)
{
struct aout_sys_common *p_sys = (struct aout_sys_common *) p_aout->sys;
- int32_t i_bytes;
- TPCircularBufferTail(&p_sys->circular_buffer, &i_bytes);
+ vlc_mutex_lock(&p_sys->lock);
- int64_t i_frames = BytesToFrames(p_sys, i_bytes);
+ int64_t i_frames = BytesToFrames(p_sys, p_sys->i_out_size);
*delay = FramesToUs(p_sys, i_frames) + p_sys->i_dev_latency_us;
+ vlc_mutex_unlock(&p_sys->lock);
return 0;
}
@@ -130,47 +155,17 @@ ca_Flush(audio_output_t *p_aout, bool wait)
{
struct aout_sys_common *p_sys = (struct aout_sys_common *) p_aout->sys;
- if (wait)
+ vlc_mutex_lock(&p_sys->lock);
+ if (!wait)
{
- int32_t i_bytes;
-
- while (TPCircularBufferTail(&p_sys->circular_buffer, &i_bytes) != NULL)
- {
- if (atomic_load(&p_sys->b_paused))
- {
- TPCircularBufferClear(&p_sys->circular_buffer);
- return;
- }
-
- /* Calculate the duration of the circular buffer, in order to wait
- * for the render thread to play it all */
- const mtime_t i_frame_us =
- FramesToUs(p_sys, BytesToFrames(p_sys, i_bytes)) + 10000;
-
- msleep(i_frame_us / 2);
- }
+ assert(!&p_sys->b_do_flush);
+ p_sys->b_do_flush = true;
}
- else
- {
- /* Request the renderer to flush, and wait for an ACK.
- * b_do_flush and b_paused need to be locked together in order to not
- * get stuck here when b_paused is being set after reading. This can
- * happen when setAliveState() is called from any thread through an
- * interrupt notification */
-
- vlc_mutex_lock(&p_sys->lock);
- assert(!atomic_load(&p_sys->b_do_flush));
- if (atomic_load(&p_sys->b_paused))
- {
- vlc_mutex_unlock(&p_sys->lock);
- TPCircularBufferClear(&p_sys->circular_buffer);
- return;
- }
- atomic_store_explicit(&p_sys->b_do_flush, true, memory_order_release);
- vlc_mutex_unlock(&p_sys->lock);
- vlc_sem_wait(&p_sys->flush_sem);
- }
+ while (p_sys->i_out_size > 0)
+ vlc_cond_wait(&p_sys->wait, &p_sys->lock);
+
+ vlc_mutex_unlock(&p_sys->lock);
}
void
@@ -179,7 +174,9 @@ ca_Pause(audio_output_t * p_aout, bool pause, mtime_t date)
struct aout_sys_common *p_sys = (struct aout_sys_common *) p_aout->sys;
VLC_UNUSED(date);
- atomic_store_explicit(&p_sys->b_paused, pause, memory_order_relaxed);
+ vlc_mutex_lock(&p_sys->lock);
+ p_sys->b_paused = pause;
+ vlc_mutex_unlock(&p_sys->lock);
}
void
@@ -193,43 +190,23 @@ ca_Play(audio_output_t * p_aout, block_t * p_block)
p_sys->chans_to_reorder, p_sys->chan_table,
VLC_CODEC_FL32);
- /* move data to buffer */
- while (!TPCircularBufferProduceBytes(&p_sys->circular_buffer,
- p_block->p_buffer, p_block->i_buffer))
- {
- if (atomic_load_explicit(&p_sys->b_paused, memory_order_relaxed))
- {
- msg_Warn(p_aout, "dropping block because the circular buffer is "
- "full and paused");
- break;
- }
+ vlc_mutex_lock(&p_sys->lock);
- /* Try to play what we can */
- int32_t i_avalaible_bytes;
- TPCircularBufferHead(&p_sys->circular_buffer, &i_avalaible_bytes);
- assert(i_avalaible_bytes >= 0);
- if (unlikely((size_t) i_avalaible_bytes >= p_block->i_buffer))
- continue;
-
- bool ret =
- TPCircularBufferProduceBytes(&p_sys->circular_buffer,
- p_block->p_buffer, i_avalaible_bytes);
- VLC_UNUSED(ret);
- assert(ret == true);
- p_block->p_buffer += i_avalaible_bytes;
- p_block->i_buffer -= i_avalaible_bytes;
-
- /* Wait for the render buffer to play the remaining data */
- const mtime_t i_frame_us =
- FramesToUs(p_sys, BytesToFrames(p_sys, p_block->i_buffer));
- msleep(i_frame_us / 2);
+ if (likely(p_block->i_buffer <= p_sys->i_out_max_size))
+ {
+ while (p_sys->i_out_max_size - p_sys->i_out_size < p_block->i_buffer)
+ vlc_cond_wait(&p_sys->wait, &p_sys->lock);
}
- unsigned i_underrun_size = atomic_exchange(&p_sys->i_underrun_size, 0);
+ block_ChainLastAppend(&p_sys->pp_out_last, p_block);
+ p_sys->i_out_size += p_block->i_buffer;
+
+ size_t i_underrun_size = p_sys->i_underrun_size;
+ p_sys->i_underrun_size = 0;
+ vlc_mutex_unlock(&p_sys->lock);
+
if (i_underrun_size > 0)
msg_Warn(p_aout, "underrun of %u bytes", i_underrun_size);
-
- block_Release(p_block);
}
int
@@ -238,8 +215,9 @@ ca_Initialize(audio_output_t *p_aout, const audio_sample_format_t *fmt,
{
struct aout_sys_common *p_sys = (struct aout_sys_common *) p_aout->sys;
- atomic_store(&p_sys->i_underrun_size, 0);
- atomic_store(&p_sys->b_paused, false);
+ p_sys->i_underrun_size = 0;
+ p_sys->b_paused = false;
+
p_sys->i_rate = fmt->i_rate;
p_sys->i_bytes_per_frame = fmt->i_bytes_per_frame;
p_sys->i_frame_length = fmt->i_frame_length;
@@ -272,8 +250,9 @@ ca_Initialize(audio_output_t *p_aout, const audio_sample_format_t *fmt,
i_audiobuffer_size = i_audiobuffer_size * AOUT_MAX_ADVANCE_TIME
/ CLOCK_FREQ;
}
- if (!TPCircularBufferInit(&p_sys->circular_buffer, i_audiobuffer_size))
- return VLC_EGENERIC;
+
+ p_sys->i_out_max_size = i_audiobuffer_size;
+ ca_ClearOutBuffers(p_aout);
return VLC_SUCCESS;
}
@@ -282,8 +261,8 @@ void
ca_Uninitialize(audio_output_t *p_aout)
{
struct aout_sys_common *p_sys = (struct aout_sys_common *) p_aout->sys;
- /* clean-up circular buffer */
- TPCircularBufferCleanup(&p_sys->circular_buffer);
+ ca_ClearOutBuffers(p_aout);
+ p_sys->i_out_max_size = 0;
}
void
@@ -292,16 +271,14 @@ ca_SetAliveState(audio_output_t *p_aout, bool alive)
struct aout_sys_common *p_sys = (struct aout_sys_common *) p_aout->sys;
vlc_mutex_lock(&p_sys->lock);
- atomic_store(&p_sys->b_paused, !alive);
+ p_sys->b_paused = !alive;
+
+ if (!alive && p_sys->b_do_flush)
+ ca_ClearOutBuffers(p_aout);
- bool expected = true;
- if (!alive && atomic_compare_exchange_strong(&p_sys->b_do_flush, &expected, false))
- {
- TPCircularBufferClear(&p_sys->circular_buffer);
- /* Signal that the renderer is flushed */
- vlc_sem_post(&p_sys->flush_sem);
- }
vlc_mutex_unlock(&p_sys->lock);
+
+ vlc_cond_signal(&p_sys->wait);
}
AudioUnit
diff --git a/modules/audio_output/coreaudio_common.h b/modules/audio_output/coreaudio_common.h
index 4fb4e5fb64..79e8945240 100644
--- a/modules/audio_output/coreaudio_common.h
+++ b/modules/audio_output/coreaudio_common.h
@@ -27,13 +27,11 @@
#endif
#import <vlc_common.h>
-#import <stdatomic.h>
#import <vlc_aout.h>
#import <vlc_threads.h>
#import <AudioUnit/AudioUnit.h>
#import <AudioToolbox/AudioToolbox.h>
-#import "TPCircularBuffer.h"
#define STREAM_FORMAT_MSG(pre, sfm) \
pre "[%f][%4.4s][%u][%u][%u][%u][%u][%u]", \
@@ -50,13 +48,17 @@ struct aout_sys_common
/* The following is owned by common.c (initialized from ca_Init, cleaned
* from ca_Clean) */
- /* circular buffer to swap the audio data */
- TPCircularBuffer circular_buffer;
- atomic_uint i_underrun_size;
- atomic_bool b_paused;
- atomic_bool b_do_flush;
- vlc_sem_t flush_sem;
+ size_t i_underrun_size;
+ bool b_paused;
+ bool b_do_flush;
+
+ size_t i_out_max_size;
+ size_t i_out_size;
+ block_t *p_out_chain;
+ block_t **pp_out_last;
+
vlc_mutex_t lock;
+ vlc_cond_t wait;
int i_rate;
unsigned int i_bytes_per_frame;
unsigned int i_frame_length;
--
2.11.0
More information about the vlc-devel
mailing list