*
* 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
#define AOUT_VAR_SPDIF_FLAG 0xf00000
-#define kBufferLength 2048 * 8 * 8 * 4
+#define AUDIO_BUFFER_SIZE_IN_SECONDS (AOUT_MAX_ADVANCE_TIME / CLOCK_FREQ)
+
#define AOUT_VOLUME_DEFAULT 256
#define AOUT_VOLUME_MAX 512
#define VOLUME_TEXT N_("Audio volume")
#define VOLUME_LONGTEXT VOLUME_TEXT
+#define DEVICE_TEXT N_("Last audio device")
+#define DEVICE_LONGTEXT DEVICE_TEXT
+
/*****************************************************************************
* aout_sys_t: private audio output method descriptor
*****************************************************************************
bool b_got_first_sample; /* did the aout core provide something to render? */
int i_rate; /* media sample rate */
- mtime_t i_played_length; /* how much did we play already */
- mtime_t i_last_sample_time; /* last sample time played by the AudioUnit */
+ int i_bytes_per_sample;
struct audio_device_t *devices;
vlc_mutex_t lock;
+ vlc_cond_t cond;
};
struct audio_device_t
add_integer("auhal-volume", AOUT_VOLUME_DEFAULT,
VOLUME_TEXT, VOLUME_LONGTEXT, true)
change_integer_range(0, AOUT_VOLUME_MAX)
+ add_string("auhal-audio-device", "", DEVICE_TEXT, DEVICE_LONGTEXT, true)
add_obsolete_integer("macosx-audio-device") /* since 2.1.0 */
vlc_module_end ()
return VLC_ENOMEM;
vlc_mutex_init(&sys->lock);
+ vlc_cond_init(&sys->cond);
aout->sys = sys;
aout->start = Start;
aout_VolumeReport(aout, var_InheritInteger(aout, "auhal-volume") / (float)AOUT_VOLUME_DEFAULT);
MuteSet(aout, var_InheritBool(aout, "mute"));
+ SwitchAudioDevice(aout, config_GetPsz(aout, "auhal-audio-device"));
+
return VLC_SUCCESS;
}
audio_output_t *aout = (audio_output_t *)obj;
aout_sys_t *sys = aout->sys;
+ config_PutPsz(aout, "auhal-audio-device", aout_DeviceGet(aout));
+
for (struct audio_device_t * device = sys->devices, *next; device != NULL; device = next) {
next = device->next;
free(device->name);
}
vlc_mutex_destroy(&sys->lock);
+ vlc_cond_destroy(&sys->cond);
free(sys);
}
* property size */
int b_alive = false;
+ bool b_start_digital = false;
+
p_sys = p_aout->sys;
p_sys->b_digital = false;
p_sys->au_component = NULL;
p_sys->i_stream_index = -1;
p_sys->b_revert = false;
p_sys->b_changed_mixing = false;
+ p_sys->i_bytes_per_sample = 0;
aout_FormatPrint(p_aout, "VLC is looking for:", fmt);
- if (p_sys->b_selected_dev_is_digital)
- msg_Dbg(p_aout, "audio device supports digital output");
-
msg_Dbg(p_aout, "attempting to use device %i", p_sys->i_selected_dev);
/* Check if the desired device is alive and usable */
}
if (!b_alive) {
- msg_Warn(p_aout, "selected audio device is not alive, switching to default device");
+ msg_Warn(p_aout, "selected audio device is not alive, switching to default device with id %i", p_sys->i_default_dev);
p_sys->i_selected_dev = p_sys->i_default_dev;
+ p_sys->b_selected_dev_is_digital = false;
}
+ // recheck if device still supports digital
+ b_start_digital = p_sys->b_selected_dev_is_digital;
+ if(!AudioDeviceSupportsDigital(p_aout, p_sys->i_selected_dev))
+ b_start_digital = false;
+
+ if (b_start_digital)
+ msg_Dbg(p_aout, "Use audio device for digital output");
+
/* add a callback to see if the device dies later on */
err = AudioObjectAddPropertyListener(p_sys->i_selected_dev, &audioDeviceAliveAddress, HardwareListener, (void *)p_aout);
if (err != noErr) {
bool b_success = false;
/* Check for Digital mode or Analog output mode */
- if (AOUT_FMT_SPDIF (fmt) && p_sys->b_selected_dev_is_digital) {
+ if (AOUT_FMT_SPDIF (fmt) && b_start_digital) {
if (StartSPDIF (p_aout, fmt)) {
msg_Dbg(p_aout, "digital output successfully opened");
b_success = true;
p_sys->clock_diff += mdate();
/* setup circular buffer */
- TPCircularBufferInit(&p_sys->circular_buffer, kBufferLength);
+ TPCircularBufferInit(&p_sys->circular_buffer, AUDIO_BUFFER_SIZE_IN_SECONDS *
+ fmt->i_rate * fmt->i_bytes_per_frame);
p_sys->b_got_first_sample = false;
- p_sys->i_played_length = 0;
- p_sys->i_last_sample_time = 0;
/* Set volume for output unit */
float volume = var_InheritInteger(p_aout, "auhal-volume") / (float)AOUT_VOLUME_DEFAULT;
return false;
}
+ /* setup circular buffer */
+ TPCircularBufferInit(&p_sys->circular_buffer, 200 * AOUT_SPDIF_SIZE);
+
return true;
}
msg_Err(p_aout, "Could not release hogmode: [%4.4s]", (char *)&err);
}
- p_sys->i_played_length = 0;
- p_sys->i_last_sample_time = 0;
+ p_sys->i_bytes_per_sample = 0;
/* clean-up circular buffer */
TPCircularBufferCleanup(&p_sys->circular_buffer);
free(device);
}
}
+ p_sys->devices = NULL;
/* Get number of devices */
AudioObjectPropertyAddress audioDevicesAddress = { kAudioHardwarePropertyDevices, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
err = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, &audioDevicesAddress, 0, NULL, &propertySize);
if (err != noErr) {
- msg_Err(p_aout, "Could not get number of devices: [%s]", (char *)&err);
+ msg_Err(p_aout, "Could not get number of devices: [%4.4s]", (char *)&err);
return;
}
/* Populate DeviceID array */
err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &audioDevicesAddress, 0, NULL, &propertySize, deviceIDs);
if (err != noErr) {
- msg_Err(p_aout, "could not get the device IDs: [%s]", (char *)&err);
+ msg_Err(p_aout, "could not get the device IDs: [%4.4s]", (char *)&err);
return;
}
propertySize = sizeof(AudioObjectID);
err= AudioObjectGetPropertyData(kAudioObjectSystemObject, &defaultDeviceAddress, 0, NULL, &propertySize, &defaultDeviceID);
if (err != noErr) {
- msg_Err(p_aout, "could not get default audio device: [%s]", (char *)&err);
+ msg_Err(p_aout, "could not get default audio device: [%4.4s]", (char *)&err);
return;
}
p_sys->i_default_dev = defaultDeviceID;
VLC_CODEC_FL32);
}
- /* keep track of the played data */
- p_aout->sys->i_played_length += p_block->i_length;
-
/* move data to buffer */
- if (unlikely(TPCircularBufferProduceBytes(&p_sys->circular_buffer, p_block->p_buffer, p_block->i_buffer) == 0)) {
- msg_Warn(p_aout, "Audio buffer was dropped");
- }
+ if (unlikely(!TPCircularBufferProduceBytes(&p_sys->circular_buffer, p_block->p_buffer, p_block->i_buffer)))
+ msg_Warn(p_aout, "dropped buffer");
+ 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 Flush(audio_output_t *p_aout, bool wait)
{
- struct aout_sys_t * p_sys = p_aout->sys;
- VLC_UNUSED(wait);
+ struct aout_sys_t *p_sys = p_aout->sys;
- p_sys->b_got_first_sample = false;
+ if (wait) {
+ int32_t availableBytes;
+ vlc_mutex_lock(&p_sys->lock);
+ TPCircularBufferTail(&p_sys->circular_buffer, &availableBytes);
+ while (availableBytes > 0) {
+ vlc_cond_wait(&p_sys->cond, &p_sys->lock);
+ TPCircularBufferTail(&p_sys->circular_buffer, &availableBytes);
+ }
+ vlc_mutex_unlock(&p_sys->lock);
- /* flush circular buffer */
- AudioOutputUnitStop(p_aout->sys->au_unit);
- TPCircularBufferClear(&p_aout->sys->circular_buffer);
+ } else {
+ p_sys->b_got_first_sample = false;
- p_sys->i_played_length = 0;
- p_sys->i_last_sample_time = 0;
+ /* flush circular buffer */
+ AudioOutputUnitStop(p_aout->sys->au_unit);
+ TPCircularBufferClear(&p_aout->sys->circular_buffer);
+ }
}
static int TimeGet(audio_output_t *p_aout, mtime_t *delay)
{
struct aout_sys_t * p_sys = p_aout->sys;
- vlc_mutex_lock(&p_sys->lock);
- mtime_t i_pos = p_sys->i_last_sample_time * CLOCK_FREQ / p_sys->i_rate;
- vlc_mutex_unlock(&p_sys->lock);
-
- if (i_pos > 0) {
- *delay = p_aout->sys->i_played_length - i_pos;
- return 0;
- }
- else
+ 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;
}
/*****************************************************************************
VLC_UNUSED(ioActionFlags);
VLC_UNUSED(inTimeStamp);
VLC_UNUSED(inBusNumber);
+ VLC_UNUSED(inNumberFrames);
audio_output_t * p_aout = (audio_output_t *)p_obj;
struct aout_sys_t * p_sys = p_aout->sys;
int bytesToCopy = 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);
} else {
memcpy(targetBuffer, buffer, __MIN(bytesToCopy, availableBytes));
TPCircularBufferConsume(&p_sys->circular_buffer, __MIN(bytesToCopy, availableBytes));
- VLC_UNUSED(inNumberFrames);
- vlc_mutex_lock(&p_sys->lock);
- p_sys->i_last_sample_time = inTimeStamp->mSampleTime;
- vlc_mutex_unlock(&p_sys->lock);
}
+ vlc_cond_signal(&p_sys->cond);
+ vlc_mutex_unlock(&p_sys->lock);
+
return noErr;
}
VLC_UNUSED(inDevice);
VLC_UNUSED(inInputData);
VLC_UNUSED(inInputTime);
+ VLC_UNUSED(inOutputTime);
audio_output_t * p_aout = (audio_output_t *)threadGlobals;
struct aout_sys_t * p_sys = p_aout->sys;
int bytesToCopy = outOutputData->mBuffers[p_sys->i_stream_index].mDataByteSize;
- Float32 *targetBuffer = (Float32*)outOutputData->mBuffers[p_sys->i_stream_index].mData;
+ char *targetBuffer = outOutputData->mBuffers[p_sys->i_stream_index].mData;
+ vlc_mutex_lock(&p_sys->lock);
/* Pull audio from buffer */
int32_t availableBytes;
- Float32 *buffer = TPCircularBufferTail(&p_sys->circular_buffer, &availableBytes);
+ char *buffer = TPCircularBufferTail(&p_sys->circular_buffer, &availableBytes);
/* check if we have enough data */
if (!availableBytes) {
} else {
memcpy(targetBuffer, buffer, __MIN(bytesToCopy, availableBytes));
TPCircularBufferConsume(&p_sys->circular_buffer, __MIN(bytesToCopy, availableBytes));
- vlc_mutex_lock(&p_sys->lock);
- p_sys->i_last_sample_time = inOutputTime->mSampleTime;
- vlc_mutex_unlock(&p_sys->lock);
}
+ vlc_cond_signal(&p_sys->cond);
+ vlc_mutex_unlock(&p_sys->lock);
+
return noErr;
}
#endif
RebuildDeviceList(p_aout);
+ aout_RestartRequest(p_aout, AOUT_RESTART_OUTPUT);
return err;
}