]> git.sesse.net Git - vlc/blobdiff - modules/audio_output/auhal.c
skins2: reuse graphics from generic bitmap cache (radialslider)
[vlc] / modules / audio_output / auhal.c
index 353096d7f067d913d1bc19b7c8f317a9246aef39..b520dc61b273a7cad70e7a5e8aaf811607b607a3 100644 (file)
@@ -6,6 +6,7 @@
  *
  * 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
@@ -56,7 +57,8 @@
 
 #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
@@ -64,6 +66,9 @@
 #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
  *****************************************************************************
@@ -100,12 +105,12 @@ struct aout_sys_t
     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
@@ -161,6 +166,7 @@ vlc_module_begin ()
     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 ()
 
@@ -176,6 +182,7 @@ static int Open(vlc_object_t *obj)
         return VLC_ENOMEM;
 
     vlc_mutex_init(&sys->lock);
+    vlc_cond_init(&sys->cond);
 
     aout->sys = sys;
     aout->start = Start;
@@ -192,6 +199,8 @@ static int Open(vlc_object_t *obj)
     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;
 }
 
@@ -200,6 +209,8 @@ static void Close(vlc_object_t *obj)
     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);
@@ -207,6 +218,7 @@ static void Close(vlc_object_t *obj)
     }
 
     vlc_mutex_destroy(&sys->lock);
+    vlc_cond_destroy(&sys->cond);
 
     free(sys);
 }
@@ -221,6 +233,8 @@ static int Start(audio_output_t *p_aout, audio_sample_format_t *restrict fmt)
      * 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;
@@ -231,12 +245,10 @@ static int Start(audio_output_t *p_aout, audio_sample_format_t *restrict fmt)
     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 */
@@ -254,10 +266,19 @@ static int Start(audio_output_t *p_aout, audio_sample_format_t *restrict fmt)
     }
 
     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) {
@@ -289,7 +310,7 @@ static int Start(audio_output_t *p_aout, audio_sample_format_t *restrict fmt)
     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;
@@ -625,11 +646,10 @@ static int StartAnalog(audio_output_t *p_aout, audio_sample_format_t *fmt)
     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;
@@ -849,6 +869,9 @@ static int StartSPDIF (audio_output_t * p_aout, audio_sample_format_t *fmt)
         return false;
     }
 
+    /* setup circular buffer */
+    TPCircularBufferInit(&p_sys->circular_buffer, 200 * AOUT_SPDIF_SIZE);
+
     return true;
 }
 
@@ -928,8 +951,7 @@ static void Stop(audio_output_t *p_aout)
             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);
@@ -992,12 +1014,13 @@ static void RebuildDeviceList(audio_output_t * p_aout)
             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;
     }
 
@@ -1017,7 +1040,7 @@ static void RebuildDeviceList(audio_output_t * p_aout)
     /* 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;
     }
 
@@ -1026,7 +1049,7 @@ static void RebuildDeviceList(audio_output_t * p_aout)
     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;
@@ -1181,14 +1204,12 @@ static void Play (audio_output_t * p_aout, block_t * p_block)
                                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);
@@ -1214,33 +1235,40 @@ static void Pause (audio_output_t *p_aout, bool pause, mtime_t date)
 
 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;
 }
 
 /*****************************************************************************
@@ -1258,6 +1286,7 @@ static OSStatus RenderCallbackAnalog(vlc_object_t *p_obj,
     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;
@@ -1265,6 +1294,7 @@ static OSStatus RenderCallbackAnalog(vlc_object_t *p_obj,
     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);
@@ -1277,12 +1307,11 @@ static OSStatus RenderCallbackAnalog(vlc_object_t *p_obj,
     } 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;
 }
 
@@ -1301,16 +1330,18 @@ static OSStatus RenderCallbackSPDIF (AudioDeviceID inDevice,
     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) {
@@ -1319,11 +1350,11 @@ static OSStatus RenderCallbackSPDIF (AudioDeviceID inDevice,
     } 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;
 }
 
@@ -1367,6 +1398,7 @@ static OSStatus HardwareListener(AudioObjectID inObjectID,  UInt32 inNumberAddre
 #endif
 
     RebuildDeviceList(p_aout);
+    aout_RestartRequest(p_aout, AOUT_RESTART_OUTPUT);
 
     return err;
 }