[vlc-commits] auhal/audiounit_ios: factor common code
Thomas Guillem
git at videolan.org
Fri Feb 24 11:41:12 CET 2017
vlc | branch: master | Thomas Guillem <thomas at gllm.fr> | Thu Feb 23 17:09:55 2017 +0100| [d3a9c12e58aa37231762cc8d9edaae546d1bcdf2] | committer: Thomas Guillem
auhal/audiounit_ios: factor common code
coreaudio_common.c/.h contains the common code for auhal.c and audiounit_ios.m.
TODO: factor StartAnalog.
> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=d3a9c12e58aa37231762cc8d9edaae546d1bcdf2
---
modules/audio_output/Makefile.am | 10 +-
modules/audio_output/audiounit_ios.m | 146 ++---------------
modules/audio_output/auhal.c | 274 +++++++-------------------------
modules/audio_output/coreaudio_common.c | 183 +++++++++++++++++++++
modules/audio_output/coreaudio_common.h | 73 +++++++++
5 files changed, 337 insertions(+), 349 deletions(-)
diff --git a/modules/audio_output/Makefile.am b/modules/audio_output/Makefile.am
index f8c247b..ad98f12 100644
--- a/modules/audio_output/Makefile.am
+++ b/modules/audio_output/Makefile.am
@@ -102,14 +102,18 @@ 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
-libauhal_plugin_la_LDFLAGS = $(AM_LDFLAGS) -Wl,-framework,CoreAudio,-framework,AudioUnit,-framework,AudioToolbox,-framework,CoreServices -rpath '$(aoutdir)'
+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/TPCircularBuffer.h audio_output/TPCircularBuffer.c
-libaudiounit_ios_plugin_la_LDFLAGS = $(AM_LDFLAGS) -Wl,-framework,CoreAudio,-framework,AudioUnit,-framework,AudioToolbox,-framework,CoreServices,-framework,UIKit,-framework,AVFoundation -rpath '$(aoutdir)'
+ audio_output/coreaudio_common.c audio_output/coreaudio_common.h \
+ audio_output/TPCircularBuffer.h audio_output/TPCircularBuffer.c
+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
aout_LTLIBRARIES += libaudiounit_ios_plugin.la
endif
diff --git a/modules/audio_output/audiounit_ios.m b/modules/audio_output/audiounit_ios.m
index 359700e..5f22f2c 100644
--- a/modules/audio_output/audiounit_ios.m
+++ b/modules/audio_output/audiounit_ios.m
@@ -22,13 +22,9 @@
#pragma mark includes
-#ifdef HAVE_CONFIG_H
-# import "config.h"
-#endif
+#import "coreaudio_common.h"
-#import <vlc_common.h>
#import <vlc_plugin.h>
-#import <vlc_aout.h>
#import <AudioUnit/AudioUnit.h>
#import <CoreAudio/CoreAudioTypes.h>
@@ -37,8 +33,6 @@
#import <AudioToolbox/AudioToolbox.h>
#import <mach/mach_time.h>
-#import "TPCircularBuffer.h"
-
#pragma mark -
#pragma mark local prototypes & module descriptor
@@ -55,17 +49,8 @@ vlc_module_begin ()
vlc_module_end ()
#pragma mark -
-
-#pragma mark -
#pragma mark private declarations
-#define STREAM_FORMAT_MSG(pre, sfm) \
- pre "[%f][%4.4s][%u][%u][%u][%u][%u][%u]", \
- sfm.mSampleRate, (char *)&sfm.mFormatID, \
- (unsigned int)sfm.mFormatFlags, (unsigned int)sfm.mBytesPerPacket, \
- (unsigned int)sfm.mFramesPerPacket, (unsigned int)sfm.mBytesPerFrame, \
- (unsigned int)sfm.mChannelsPerFrame, (unsigned int)sfm.mBitsPerChannel
-
#define AUDIO_BUFFER_SIZE_IN_SECONDS (AOUT_MAX_ADVANCE_TIME / CLOCK_FREQ)
/*****************************************************************************
@@ -76,48 +61,20 @@ vlc_module_end ()
*****************************************************************************/
struct aout_sys_t
{
- TPCircularBuffer circular_buffer; /* circular buffer to swap the audio data */
-
- /* AUHAL specific */
- AudioUnit au_unit; /* The AudioUnit we use */
-
- int i_rate; /* media sample rate */
- int i_bytes_per_sample;
+ struct aout_sys_common c;
- bool b_paused;
-
- vlc_mutex_t lock;
- vlc_cond_t cond;
+ /* The AudioUnit we use */
+ AudioUnit au_unit;
};
#pragma mark -
#pragma mark actual playback
-static void Play (audio_output_t * p_aout, block_t * p_block)
-{
- struct aout_sys_t *p_sys = p_aout->sys;
-
- if (p_block->i_nb_samples > 0) {
- /* move data to buffer */
- if (unlikely(!TPCircularBufferProduceBytes(&p_sys->circular_buffer, p_block->p_buffer, p_block->i_buffer)))
- msg_Warn(p_aout, "Audio buffer was dropped");
-
- if (!p_sys->i_bytes_per_sample)
- p_sys->i_bytes_per_sample = p_block->i_buffer / p_block->i_nb_samples;
- }
-
- block_Release(p_block);
-}
-
static void Pause (audio_output_t *p_aout, bool pause, mtime_t date)
{
struct aout_sys_t * p_sys = p_aout->sys;
VLC_UNUSED(date);
- vlc_mutex_lock(&p_sys->lock);
- p_sys->b_paused = pause;
- vlc_mutex_unlock(&p_sys->lock);
-
/* we need to start / stop the audio unit here because otherwise
* the OS won't believe us that we stopped the audio output
* so in case of an interruption, our unit would be permanently
@@ -148,43 +105,6 @@ static int MuteSet(audio_output_t *p_aout, bool mute)
return VLC_SUCCESS;
}
-static void Flush(audio_output_t *p_aout, bool wait)
-{
- struct aout_sys_t *p_sys = p_aout->sys;
-
- int32_t availableBytes;
- vlc_mutex_lock(&p_sys->lock);
- TPCircularBufferTail(&p_sys->circular_buffer, &availableBytes);
-
- if (wait) {
- while (availableBytes > 0) {
- vlc_cond_wait(&p_sys->cond, &p_sys->lock);
- TPCircularBufferTail(&p_sys->circular_buffer, &availableBytes);
- }
- } else {
- /* flush circular buffer if data is left */
- if (availableBytes > 0)
- TPCircularBufferClear(&p_aout->sys->circular_buffer);
- }
-
- vlc_mutex_unlock(&p_sys->lock);
-}
-
-static int TimeGet(audio_output_t *p_aout, mtime_t *delay)
-{
- struct aout_sys_t * p_sys = p_aout->sys;
-
- if (!p_sys->i_bytes_per_sample)
- return -1;
-
- int32_t availableBytes;
- TPCircularBufferTail(&p_sys->circular_buffer, &availableBytes);
-
- *delay = (availableBytes / p_sys->i_bytes_per_sample) * CLOCK_FREQ / p_sys->i_rate;
-
- return 0;
-}
-
/*****************************************************************************
* RenderCallback: This function is called everytime the AudioUnit wants
* us to provide some more audio data.
@@ -202,35 +122,8 @@ static OSStatus RenderCallback(void *p_data,
VLC_UNUSED(inBusNumber);
VLC_UNUSED(inNumberFrames);
- audio_output_t * p_aout = p_data;
- struct aout_sys_t * p_sys = p_aout->sys;
-
- int bytesRequested = ioData->mBuffers[0].mDataByteSize;
- Float32 *targetBuffer = (Float32*)ioData->mBuffers[0].mData;
-
- vlc_mutex_lock(&p_sys->lock);
- /* Pull audio from buffer */
- int32_t availableBytes;
- Float32 *buffer = TPCircularBufferTail(&p_sys->circular_buffer, &availableBytes);
- if (unlikely(bytesRequested == 0)) /* cannot be negative */
- return noErr;
-
- /* check if we have enough data */
- if (!availableBytes || p_sys->b_paused) {
- /* return an empty buffer so silence is played until we have data */
- memset(targetBuffer, 0, bytesRequested);
- } else {
- int32_t bytesToCopy = __MIN(bytesRequested, availableBytes);
-
- if (likely(bytesToCopy > 0)) {
- memcpy(targetBuffer, buffer, bytesToCopy);
- TPCircularBufferConsume(&p_sys->circular_buffer, bytesToCopy);
- ioData->mBuffers[0].mDataByteSize = bytesToCopy;
- }
- }
-
- vlc_cond_signal(&p_sys->cond);
- vlc_mutex_unlock(&p_sys->lock);
+ ca_Render(p_data, ioData->mBuffers[0].mData,
+ ioData->mBuffers[0].mDataByteSize);
return noErr;
}
@@ -290,7 +183,6 @@ static int StartAnalog(audio_output_t *p_aout, audio_sample_format_t *fmt)
streamDescription.mBytesPerFrame = streamDescription.mBitsPerChannel * streamDescription.mChannelsPerFrame / 8;
streamDescription.mBytesPerPacket = streamDescription.mBytesPerFrame * streamDescription.mFramesPerPacket;
i_param_size = sizeof(streamDescription);
- p_sys->i_rate = fmt->i_rate;
/* Set the desired format */
i_param_size = sizeof(AudioStreamBasicDescription);
@@ -340,8 +232,13 @@ static int StartAnalog(audio_output_t *p_aout, audio_sample_format_t *fmt)
goto error;
}
- /* setup circular buffer */
- TPCircularBufferInit(&p_sys->circular_buffer, AUDIO_BUFFER_SIZE_IN_SECONDS * fmt->i_rate * fmt->i_bytes_per_frame);
+ int ret = ca_Init(p_aout, fmt, AUDIO_BUFFER_SIZE_IN_SECONDS * fmt->i_rate *
+ fmt->i_bytes_per_frame);
+ if (ret != VLC_SUCCESS)
+ {
+ AudioUnitUninitialize(p_sys->au_unit);
+ goto error;
+ }
/* start audio session so playback continues if mute switch is on */
AVAudioSession *instance = [AVAudioSession sharedInstance];
@@ -381,12 +278,10 @@ static void Stop(audio_output_t *p_aout)
if (status != noErr)
msg_Warn(p_aout, "failed to dispose Audio Component instance (%i)", (int)status);
}
- p_sys->i_bytes_per_sample = 0;
[[AVAudioSession sharedInstance] setActive:NO withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:nil];
- /* clean-up circular buffer */
- TPCircularBufferCleanup(&p_sys->circular_buffer);
+ ca_Clean(p_aout);
}
static int Start(audio_output_t *p_aout, audio_sample_format_t *restrict fmt)
@@ -398,16 +293,12 @@ static int Start(audio_output_t *p_aout, audio_sample_format_t *restrict fmt)
p_sys = p_aout->sys;
p_sys->au_unit = NULL;
- p_sys->i_bytes_per_sample = 0;
aout_FormatPrint(p_aout, "VLC is looking for:", fmt);
if (StartAnalog(p_aout, fmt) == VLC_SUCCESS) {
msg_Dbg(p_aout, "analog AudioUnit output successfully opened");
- p_aout->play = Play;
- p_aout->flush = Flush;
p_aout->mute_set = MuteSet;
- p_aout->time_get = TimeGet;
p_aout->pause = Pause;
return VLC_SUCCESS;
@@ -423,24 +314,17 @@ static void Close(vlc_object_t *obj)
audio_output_t *aout = (audio_output_t *)obj;
aout_sys_t *sys = aout->sys;
- vlc_mutex_destroy(&sys->lock);
- vlc_cond_destroy(&sys->cond);
-
free(sys);
}
static int Open(vlc_object_t *obj)
{
audio_output_t *aout = (audio_output_t *)obj;
- aout_sys_t *sys = malloc(sizeof (*sys));
+ aout_sys_t *sys = calloc(1, sizeof (*sys));
if (unlikely(sys == NULL))
return VLC_ENOMEM;
- vlc_mutex_init(&sys->lock);
- vlc_cond_init(&sys->cond);
- sys->b_paused = false;
-
aout->sys = sys;
aout->start = Start;
aout->stop = Stop;
diff --git a/modules/audio_output/auhal.c b/modules/audio_output/auhal.c
index 088e727..a960680 100644
--- a/modules/audio_output/auhal.c
+++ b/modules/audio_output/auhal.c
@@ -24,23 +24,16 @@
#pragma mark includes
-#ifdef HAVE_CONFIG_H
-# import "config.h"
-#endif
+#import "coreaudio_common.h"
-#import <vlc_atomic.h>
-#import <vlc_common.h>
#import <vlc_plugin.h>
#import <vlc_dialog.h> // vlc_dialog_display_error
-#import <vlc_aout.h> // aout_*
#import <AudioUnit/AudioUnit.h> // AudioUnit
#import <CoreAudio/CoreAudio.h> // AudioDeviceID
#import <AudioToolbox/AudioFormat.h> // AudioFormatGetProperty
#import <CoreServices/CoreServices.h>
-#import "TPCircularBuffer.h"
-
#pragma mark -
#pragma mark local prototypes & module descriptor
@@ -74,13 +67,6 @@ vlc_module_end ()
#pragma mark -
#pragma mark private declarations
-#define STREAM_FORMAT_MSG(pre, sfm) \
- pre "[%f][%4.4s][%u][%u][%u][%u][%u][%u]", \
- sfm.mSampleRate, (char *)&sfm.mFormatID, \
- (unsigned int)sfm.mFormatFlags, (unsigned int)sfm.mBytesPerPacket, \
- (unsigned int)sfm.mFramesPerPacket, (unsigned int)sfm.mBytesPerFrame, \
- (unsigned int)sfm.mChannelsPerFrame, (unsigned int)sfm.mBitsPerChannel
-
#define AOUT_VAR_SPDIF_FLAG 0xf00000
#define AUDIO_BUFFER_SIZE_IN_SECONDS ((AOUT_MAX_ADVANCE_TIME + CLOCK_FREQ) / CLOCK_FREQ)
@@ -93,6 +79,8 @@ vlc_module_end ()
*****************************************************************************/
struct aout_sys_t
{
+ struct aout_sys_common c;
+
/* DeviceID of the selected device */
AudioObjectID i_selected_dev;
/* DeviceID of device which will be selected on start */
@@ -106,13 +94,6 @@ struct aout_sys_t
/* Are we running in digital mode? */
bool b_digital;
- uint8_t chans_to_reorder;
- uint8_t chan_table[AOUT_CHAN_MAX];
-
- /* circular buffer to swap the audio data */
- TPCircularBuffer circular_buffer;
- atomic_uint i_underrun_size;
-
/* AUHAL specific */
AudioUnit au_unit;
@@ -130,11 +111,6 @@ struct aout_sys_t
/* Whether we need to set the mixing mode back */
bool b_changed_mixing;
- /* media sample rate */
- int i_rate;
- unsigned int i_bytes_per_frame;
- unsigned int i_frame_length;
-
CFArrayRef device_list;
/* protects access to device_list */
vlc_mutex_t device_list_lock;
@@ -150,9 +126,6 @@ struct aout_sys_t
atomic_bool b_paused;
bool b_ignore_streams_changed_callback;
-
- /* The time the device needs to process the data. In samples. */
- UInt32 i_device_latency;
};
#pragma mark -
@@ -940,52 +913,6 @@ MuteSet(audio_output_t * p_aout, bool mute)
#pragma mark -
#pragma mark actual playback
-static inline uint64_t
-BytesToFrames(aout_sys_t *p_sys, size_t i_bytes)
-{
- return i_bytes * p_sys->i_frame_length / p_sys->i_bytes_per_frame;
-}
-
-static inline mtime_t
-FramesToUs(aout_sys_t *p_sys, uint64_t i_nb_frames)
-{
- return i_nb_frames * CLOCK_FREQ / p_sys->i_rate;
-}
-
-/* Called from AudioUnit render callbacks. No lock, wait, and IO here */
-static void
-CopyOutput(audio_output_t *p_aout, uint8_t *p_output, size_t i_requested)
-{
- aout_sys_t *p_sys = p_aout->sys;
-
- /* Pull audio from buffer */
- if (!atomic_load(&p_sys->b_paused))
- {
- 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)
- {
- memcpy(p_output, p_data, i_tocopy);
- TPCircularBufferConsume(&p_sys->circular_buffer, i_tocopy);
- }
-
- /* Pad with 0 */
- if (i_requested > i_tocopy)
- {
- atomic_fetch_add(&p_sys->i_underrun_size, i_requested - i_tocopy);
- memset(&p_output[i_tocopy], 0, i_requested - i_tocopy);
- }
- }
- else
- memset(p_output, 0, i_requested);
-}
-
/*****************************************************************************
* RenderCallbackAnalog: This function is called everytime the AudioUnit wants
* us to provide some more audio data.
@@ -1003,8 +930,15 @@ RenderCallbackAnalog(void *p_data, AudioUnitRenderActionFlags *ioActionFlags,
VLC_UNUSED(inBusNumber);
VLC_UNUSED(inNumberFrames);
- CopyOutput(p_data, ioData->mBuffers[0].mData,
- ioData->mBuffers[0].mDataByteSize);
+ audio_output_t * p_aout = p_data;
+ aout_sys_t *p_sys = p_aout->sys;
+ uint8_t *p_output = ioData->mBuffers[0].mData;
+ size_t i_size = ioData->mBuffers[0].mDataByteSize;
+
+ if (!atomic_load(&p_sys->b_paused))
+ ca_Render(p_aout, p_output, i_size);
+ else
+ memset(p_output, 0, i_size);
return noErr;
}
@@ -1027,25 +961,19 @@ RenderCallbackSPDIF(AudioDeviceID inDevice, const AudioTimeStamp * inNow,
audio_output_t * p_aout = p_data;
aout_sys_t *p_sys = p_aout->sys;
- CopyOutput(p_aout, outOutputData->mBuffers[p_sys->i_stream_index].mData,
- outOutputData->mBuffers[p_sys->i_stream_index].mDataByteSize);
+ uint8_t *p_output = outOutputData->mBuffers[p_sys->i_stream_index].mData;
+ size_t i_size = outOutputData->mBuffers[p_sys->i_stream_index].mDataByteSize;
+
+ if (!atomic_load(&p_sys->b_paused))
+ ca_Render(p_data, p_output, i_size);
+ else
+ memset(p_output, 0, i_size);
return noErr;
}
-static int
-TimeGet(audio_output_t *p_aout, mtime_t *delay)
-{
- struct aout_sys_t * p_sys = p_aout->sys;
-
- int32_t i_bytes;
- TPCircularBufferTail(&p_sys->circular_buffer, &i_bytes);
-
- int64_t i_frames = BytesToFrames(p_sys, i_bytes) + p_sys->i_device_latency;
- *delay = FramesToUs(p_sys, i_frames);
-
- return 0;
-}
+#pragma mark -
+#pragma mark initialization
static void
Pause(audio_output_t *p_aout, bool pause, mtime_t date)
@@ -1056,89 +984,6 @@ Pause(audio_output_t *p_aout, bool pause, mtime_t date)
atomic_store(&p_sys->b_paused, pause);
}
-static void
-Flush(audio_output_t *p_aout, bool wait)
-{
- struct aout_sys_t *p_sys = p_aout->sys;
-
- if (wait)
- {
- int32_t i_bytes;
-
- while (TPCircularBufferTail(&p_sys->circular_buffer, &i_bytes) != NULL)
- {
- /* 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;
-
- /* Don't sleep less than 10ms */
- msleep(__MAX(i_frame_us, 10000));
- }
- }
- else
- {
- /* flush circular buffer if data is left */
- TPCircularBufferClear(&p_aout->sys->circular_buffer);
- }
-}
-
-static void
-Play(audio_output_t * p_aout, block_t * p_block)
-{
- struct aout_sys_t *p_sys = p_aout->sys;
-
- if (p_block->i_nb_samples > 0)
- {
- /* Do the channel reordering */
- if (p_sys->chans_to_reorder && !p_sys->b_digital)
- {
- aout_ChannelReorder(p_block->p_buffer,
- p_block->i_buffer,
- 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 (unlikely(p_block->i_buffer >
- (uint32_t) p_sys->circular_buffer.length))
- {
- msg_Err(p_aout, "the block is too big for the circular buffer");
- assert(false);
- break;
- }
-
- /* Wait for the render buffer to play the remaining data */
- int32_t i_avalaible_bytes;
- TPCircularBufferTail(&p_sys->circular_buffer, &i_avalaible_bytes);
- assert(i_avalaible_bytes >= 0);
- if (unlikely((size_t) i_avalaible_bytes >= p_block->i_buffer))
- continue;
- int32_t i_waiting_bytes = p_block->i_buffer - i_avalaible_bytes;
-
- const mtime_t i_frame_us =
- FramesToUs(p_sys, BytesToFrames(p_sys, i_waiting_bytes));
-
- /* Don't sleep less than 10ms */
- msleep(__MAX(i_frame_us, 10000));
- }
- }
-
- unsigned i_underrun_size = atomic_exchange(&p_sys->i_underrun_size, 0);
- if (i_underrun_size > 0)
- msg_Warn(p_aout, "underrun of %u bytes", i_underrun_size);
-
- block_Release(p_block);
-}
-
-#pragma mark -
-#pragma mark initialization
-
/*
* StartAnalog: open and setup a HAL AudioUnit to do PCM audio output
*/
@@ -1153,7 +998,7 @@ StartAnalog(audio_output_t *p_aout, audio_sample_format_t *fmt)
AudioStreamBasicDescription DeviceFormat;
AudioChannelLayout *layout;
AURenderCallbackStruct input;
- p_aout->sys->chans_to_reorder = 0;
+ p_sys->c.chans_to_reorder = 0;
SInt32 currentMinorSystemVersion;
if (Gestalt(gestaltSystemVersionMinor, ¤tMinorSystemVersion) != noErr)
@@ -1410,11 +1255,11 @@ StartAnalog(audio_output_t *p_aout, audio_sample_format_t *fmt)
chans_out[4] = AOUT_CHAN_CENTER;
chans_out[5] = AOUT_CHAN_LFE;
- p_aout->sys->chans_to_reorder =
+ p_sys->c.chans_to_reorder =
aout_CheckChannelReorder(NULL, chans_out,
fmt->i_physical_channels,
- p_aout->sys->chan_table);
- if (p_aout->sys->chans_to_reorder)
+ p_sys->c.chan_table);
+ if (p_sys->c.chans_to_reorder)
msg_Dbg(p_aout, "channel reordering needed for 5.1 output");
}
else
@@ -1430,11 +1275,11 @@ StartAnalog(audio_output_t *p_aout, audio_sample_format_t *fmt)
chans_out[4] = AOUT_CHAN_CENTER;
chans_out[5] = AOUT_CHAN_REARCENTER;
- p_aout->sys->chans_to_reorder =
+ p_sys->c.chans_to_reorder =
aout_CheckChannelReorder(NULL, chans_out,
fmt->i_physical_channels,
- p_aout->sys->chan_table);
- if (p_aout->sys->chans_to_reorder)
+ p_sys->c.chan_table);
+ if (p_sys->c.chans_to_reorder)
msg_Dbg(p_aout, "channel reordering needed for 6.0 output");
}
break;
@@ -1450,11 +1295,11 @@ StartAnalog(audio_output_t *p_aout, audio_sample_format_t *fmt)
chans_out[5] = AOUT_CHAN_REARRIGHT;
chans_out[6] = AOUT_CHAN_REARCENTER;
- p_aout->sys->chans_to_reorder =
+ p_sys->c.chans_to_reorder =
aout_CheckChannelReorder(NULL, chans_out,
fmt->i_physical_channels,
- p_aout->sys->chan_table);
- if (p_aout->sys->chans_to_reorder)
+ p_sys->c.chan_table);
+ if (p_sys->c.chans_to_reorder)
msg_Dbg(p_aout, "channel reordering needed for 6.1 output");
break;
@@ -1497,11 +1342,11 @@ StartAnalog(audio_output_t *p_aout, audio_sample_format_t *fmt)
chans_out[7] = AOUT_CHAN_REARRIGHT;
}
#endif
- p_aout->sys->chans_to_reorder =
+ p_sys->c.chans_to_reorder =
aout_CheckChannelReorder(NULL, chans_out,
fmt->i_physical_channels,
- p_aout->sys->chan_table);
- if (p_aout->sys->chans_to_reorder)
+ p_sys->c.chan_table);
+ if (p_sys->c.chans_to_reorder)
msg_Dbg(p_aout, "channel reordering needed for 7.1 / 8.0 output");
break;
case 9:
@@ -1525,11 +1370,11 @@ StartAnalog(audio_output_t *p_aout, audio_sample_format_t *fmt)
chans_out[7] = AOUT_CHAN_REARRIGHT;
chans_out[8] = AOUT_CHAN_LFE;
- p_aout->sys->chans_to_reorder =
+ p_sys->c.chans_to_reorder =
aout_CheckChannelReorder(NULL, chans_out,
fmt->i_physical_channels,
- p_aout->sys->chan_table);
- if (p_aout->sys->chans_to_reorder)
+ p_sys->c.chan_table);
+ if (p_sys->c.chans_to_reorder)
msg_Dbg(p_aout, "channel reordering needed for 8.1 output");
#endif
break;
@@ -1603,9 +1448,13 @@ StartAnalog(audio_output_t *p_aout, audio_sample_format_t *fmt)
goto error;
}
- /* setup circular buffer */
- TPCircularBufferInit(&p_sys->circular_buffer, AUDIO_BUFFER_SIZE_IN_SECONDS *
- fmt->i_rate * fmt->i_bytes_per_frame);
+ int ret = ca_Init(p_aout, fmt, AUDIO_BUFFER_SIZE_IN_SECONDS * fmt->i_rate *
+ fmt->i_bytes_per_frame);
+ if (ret != VLC_SUCCESS)
+ {
+ AudioUnitUninitialize(p_sys->au_unit);
+ goto error;
+ }
err = AudioOutputUnitStart(p_sys->au_unit);
if (err != noErr)
@@ -1849,6 +1698,13 @@ StartSPDIF(audio_output_t * p_aout, audio_sample_format_t *fmt)
return VLC_EGENERIC;
}
+ ret = ca_Init(p_aout, fmt, 200 * AOUT_SPDIF_SIZE);
+ if (ret != VLC_SUCCESS)
+ {
+ AudioDeviceDestroyIOProcID(p_sys->i_selected_dev, p_sys->i_procID);
+ return VLC_EGENERIC;
+ }
+
/* Start device */
err = AudioDeviceStart(p_sys->i_selected_dev, p_sys->i_procID);
if (err != noErr)
@@ -1864,9 +1720,6 @@ StartSPDIF(audio_output_t * p_aout, audio_sample_format_t *fmt)
return VLC_EGENERIC;
}
- /* setup circular buffer */
- TPCircularBufferInit(&p_sys->circular_buffer, 200 * AOUT_SPDIF_SIZE);
-
return VLC_SUCCESS;
}
@@ -1954,10 +1807,9 @@ Stop(audio_output_t *p_aout)
kAudioDevicePropertyDeviceIsAlive,
kAudioObjectPropertyScopeGlobal);
- p_sys->b_digital = false;
+ ca_Clean(p_aout);
- /* clean-up circular buffer */
- TPCircularBufferCleanup(&p_sys->circular_buffer);
+ p_sys->b_digital = false;
}
static int
@@ -1982,7 +1834,7 @@ Start(audio_output_t *p_aout, audio_sample_format_t *restrict fmt)
p_sys->b_revert = false;
p_sys->b_changed_mixing = false;
p_sys->b_paused = false;
- p_sys->i_device_latency = 0;
+ p_sys->c.i_device_latency = 0;
vlc_mutex_lock(&p_sys->selected_device_lock);
p_sys->i_selected_dev = p_sys->i_new_selected_dev;
@@ -2085,17 +1937,17 @@ Start(audio_output_t *p_aout, audio_sample_format_t *restrict fmt)
}
/* get device latency */
- AO_GET1PROP(p_sys->i_selected_dev, UInt32, &p_sys->i_device_latency,
+ AO_GET1PROP(p_sys->i_selected_dev, UInt32, &p_sys->c.i_device_latency,
kAudioDevicePropertyLatency, kAudioObjectPropertyScopeOutput);
- float f_latency_in_sec = (float)p_sys->i_device_latency / (float)fmt->i_rate;
+ float f_latency_in_sec = (float)p_sys->c.i_device_latency / (float)fmt->i_rate;
msg_Dbg(p_aout, "Current device has a latency of %u frames (%f sec)",
- p_sys->i_device_latency, f_latency_in_sec);
+ p_sys->c.i_device_latency, f_latency_in_sec);
/* Ignore long Airplay latency as this is not correctly working yet */
if (f_latency_in_sec > 0.5f)
{
msg_Info(p_aout, "Ignore high latency as it causes problems currently.");
- p_sys->i_device_latency = 0;
+ p_sys->c.i_device_latency = 0;
}
bool b_success = false;
@@ -2120,13 +1972,6 @@ Start(audio_output_t *p_aout, audio_sample_format_t *restrict fmt)
if (b_success)
{
- 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;
-
- p_aout->play = Play;
- p_aout->flush = Flush;
- p_aout->time_get = TimeGet;
p_aout->pause = Pause;
return VLC_SUCCESS;
}
@@ -2197,7 +2042,7 @@ static void Close(vlc_object_t *obj)
static int Open(vlc_object_t *obj)
{
audio_output_t *p_aout = (audio_output_t *)obj;
- aout_sys_t *p_sys = malloc(sizeof (*p_sys));
+ aout_sys_t *p_sys = calloc(1, sizeof (*p_sys));
if (unlikely(p_sys == NULL))
return VLC_ENOMEM;
@@ -2208,7 +2053,6 @@ static int Open(vlc_object_t *obj)
p_sys->b_selected_dev_is_default = false;
memset(&p_sys->sfmt_revert, 0, sizeof(p_sys->sfmt_revert));
p_sys->i_stream_id = 0;
- atomic_init(&p_sys->i_underrun_size, 0);
atomic_init(&p_sys->b_paused, false);
p_aout->sys = p_sys;
diff --git a/modules/audio_output/coreaudio_common.c b/modules/audio_output/coreaudio_common.c
new file mode 100644
index 0000000..f7f7fcc
--- /dev/null
+++ b/modules/audio_output/coreaudio_common.c
@@ -0,0 +1,183 @@
+/*****************************************************************************
+ * coreaudio_common.c: Common AudioUnit code for iOS and macOS
+ *****************************************************************************
+ * Copyright (C) 2005 - 2017 VLC authors and VideoLAN
+ *
+ * Authors: Derk-Jan Hartman <hartman at videolan dot org>
+ * Felix Paul Kühne <fkuehne at videolan dot org>
+ * David Fuhrmann <david dot fuhrmann at googlemail dot com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#import "coreaudio_common.h"
+
+static inline uint64_t
+BytesToFrames(struct aout_sys_common *p_sys, size_t i_bytes)
+{
+ return i_bytes * p_sys->i_frame_length / p_sys->i_bytes_per_frame;
+}
+
+static inline mtime_t
+FramesToUs(struct aout_sys_common *p_sys, uint64_t i_nb_frames)
+{
+ return i_nb_frames * CLOCK_FREQ / p_sys->i_rate;
+}
+
+/* Called from render callbacks. No lock, wait, and IO here */
+void
+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;
+
+ /* 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)
+ {
+ memcpy(p_output, p_data, i_tocopy);
+ TPCircularBufferConsume(&p_sys->circular_buffer, i_tocopy);
+ }
+
+ /* Pad with 0 */
+ if (i_requested > i_tocopy)
+ {
+ atomic_fetch_add(&p_sys->i_underrun_size, i_requested - i_tocopy);
+ memset(&p_output[i_tocopy], 0, i_requested - i_tocopy);
+ }
+}
+
+int
+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);
+
+ int64_t i_frames = BytesToFrames(p_sys, i_bytes) + p_sys->i_device_latency;
+ *delay = FramesToUs(p_sys, i_frames);
+
+ return 0;
+}
+
+void
+ca_Flush(audio_output_t *p_aout, bool wait)
+{
+ struct aout_sys_common *p_sys = (struct aout_sys_common *) p_aout->sys;
+
+ if (wait)
+ {
+ int32_t i_bytes;
+
+ while (TPCircularBufferTail(&p_sys->circular_buffer, &i_bytes) != NULL)
+ {
+ /* 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;
+
+ /* Don't sleep less than 10ms */
+ msleep(__MAX(i_frame_us, 10000));
+ }
+ }
+ else
+ {
+ /* flush circular buffer if data is left */
+ TPCircularBufferClear(&p_sys->circular_buffer);
+ }
+}
+
+void
+ca_Play(audio_output_t * p_aout, block_t * p_block)
+{
+ struct aout_sys_common *p_sys = (struct aout_sys_common *) p_aout->sys;
+
+ /* Do the channel reordering */
+ if (p_sys->chans_to_reorder)
+ aout_ChannelReorder(p_block->p_buffer, p_block->i_buffer,
+ 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 (unlikely(p_block->i_buffer >
+ (uint32_t) p_sys->circular_buffer.length))
+ {
+ msg_Err(p_aout, "the block is too big for the circular buffer");
+ assert(false);
+ break;
+ }
+
+ /* Wait for the render buffer to play the remaining data */
+ int32_t i_avalaible_bytes;
+ TPCircularBufferTail(&p_sys->circular_buffer, &i_avalaible_bytes);
+ assert(i_avalaible_bytes >= 0);
+ if (unlikely((size_t) i_avalaible_bytes >= p_block->i_buffer))
+ continue;
+ int32_t i_waiting_bytes = p_block->i_buffer - i_avalaible_bytes;
+
+ const mtime_t i_frame_us =
+ FramesToUs(p_sys, BytesToFrames(p_sys, i_waiting_bytes));
+
+ /* Don't sleep less than 10ms */
+ msleep(__MAX(i_frame_us, 10000));
+ }
+
+ unsigned i_underrun_size = atomic_exchange(&p_sys->i_underrun_size, 0);
+ if (i_underrun_size > 0)
+ msg_Warn(p_aout, "underrun of %u bytes", i_underrun_size);
+
+ block_Release(p_block);
+}
+
+int
+ca_Init(audio_output_t *p_aout, const audio_sample_format_t *fmt,
+ size_t i_audio_buffer_size)
+{
+ struct aout_sys_common *p_sys = (struct aout_sys_common *) p_aout->sys;
+
+ /* setup circular buffer */
+ if (!TPCircularBufferInit(&p_sys->circular_buffer, i_audio_buffer_size))
+ return VLC_EGENERIC;
+
+ atomic_init(&p_sys->i_underrun_size, 0);
+
+ 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;
+
+ p_aout->play = ca_Play;
+ p_aout->flush = ca_Flush;
+ p_aout->time_get = ca_TimeGet;
+ return VLC_SUCCESS;
+}
+
+void
+ca_Clean(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);
+}
diff --git a/modules/audio_output/coreaudio_common.h b/modules/audio_output/coreaudio_common.h
new file mode 100644
index 0000000..7403a30
--- /dev/null
+++ b/modules/audio_output/coreaudio_common.h
@@ -0,0 +1,73 @@
+/*****************************************************************************
+ * coreaudio_common.h: Common AudioUnit code for iOS and macOS
+ *****************************************************************************
+ * Copyright (C) 2005 - 2017 VLC authors and VideoLAN
+ *
+ * Authors: Derk-Jan Hartman <hartman at videolan dot org>
+ * Felix Paul Kühne <fkuehne at videolan dot org>
+ * David Fuhrmann <david dot fuhrmann at googlemail dot com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# import "config.h"
+#endif
+
+#import <vlc_common.h>
+#import <vlc_atomic.h>
+#import <vlc_aout.h>
+
+#import "TPCircularBuffer.h"
+
+#define STREAM_FORMAT_MSG(pre, sfm) \
+ pre "[%f][%4.4s][%u][%u][%u][%u][%u][%u]", \
+ sfm.mSampleRate, (char *)&sfm.mFormatID, \
+ (unsigned int)sfm.mFormatFlags, (unsigned int)sfm.mBytesPerPacket, \
+ (unsigned int)sfm.mFramesPerPacket, (unsigned int)sfm.mBytesPerFrame, \
+ (unsigned int)sfm.mChannelsPerFrame, (unsigned int)sfm.mBitsPerChannel
+
+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;
+ int i_rate;
+ unsigned int i_bytes_per_frame;
+ unsigned int i_frame_length;
+
+ /* The following need to set by the caller */
+
+ uint8_t chans_to_reorder;
+ uint8_t chan_table[AOUT_CHAN_MAX];
+ /* The time the device needs to process the data. In samples. */
+ uint32_t i_device_latency;
+};
+
+void ca_Render(audio_output_t *p_aout, uint8_t *p_output, size_t i_requested);
+
+int ca_TimeGet(audio_output_t *p_aout, mtime_t *delay);
+
+void ca_Flush(audio_output_t *p_aout, bool wait);
+
+void ca_Play(audio_output_t * p_aout, block_t * p_block);
+
+int ca_Init(audio_output_t *p_aout, const audio_sample_format_t *fmt,
+ size_t i_audio_buffer_size);
+
+void ca_Clean(audio_output_t *p_aout);
More information about the vlc-commits
mailing list