ecore_audio: drop support for CoreAudio on macOS

CoreAudio support was initially introduced by commit
62e29b39f4 as an experimental feature.

It played basic sounds, but suffered from drawbacks: it was controlling
the master channel, and therefore any sound played by ecore_audio would
shut down a previous sound (e.g. background music) for the time of the
sound being played. So that wasn't exactly great... Also, after some
time, some hangs have been reported when playing a sound on input. Most
of the time, it translated as a pause in the main loop (see T3797).
More recently (several months ago), ecore_audio with CoreAudio stopped
working during 1.19 development...

So... CoreAudio support on macOS has never been great. And now it's fully
broken. Instead of trying to revive the thing, let just use PulseAudio.
PulseAudio can be installed without any trouble on macOS thanks to
package managers such as Homebrew. Actually, the efl package provided by
Homebrew already provides PulseAudio as a dependency. And it actually
just works very fine. Dropping CoreAudio seems therefore a nice option:
removes unmaintained code, fixes bugs, and add features.
This commit is contained in:
Jean Guyomarc'h 2016-10-29 22:32:19 +02:00
parent 30d7410699
commit 403b0ecfa6
No known key found for this signature in database
GPG Key ID: 9BFD70B4662DC58C
8 changed files with 3 additions and 480 deletions

View File

@ -3904,55 +3904,6 @@ AC_ARG_ENABLE([pulseaudio],
],
[want_pulseaudio="yes"])
if test "x${have_darwin}" = "xyes"; then
want_pulseaudio="no"
want_alsa="no"
want_coreaudio="yes"
else
want_coreaudio="no"
fi
# CoreAudio flags
if test "x${want_coreaudio}" = "xyes"; then
coreaudio_ldflags=""
have_coreaudio="no"
LIBS_save="$LIBS"
LIBS="$LIBS -framework CoreAudio"
AC_LINK_IFELSE(
[AC_LANG_PROGRAM(
[[
#include <CoreAudio/CoreAudio.h>
]],
[[
UInt32 size;
AudioDeviceID dev_id;
AudioObjectPropertyAddress prop = {
kAudioHardwarePropertyDefaultOutputDevice,
kAudioObjectPropertyScopeGlobal,
kAudioObjectPropertyElementMaster
};
size = sizeof(AudioDeviceID);
AudioObjectGetPropertyData(kAudioObjectSystemObject, &prop, 0, NULL,
&size, &dev_id);
]])],
[
have_coreaudio="yes"
coreaudio_ldflags="-framework CoreAudio"
],
[have_coreaudio="no"])
LIBS="$LIBS_save"
AC_MSG_CHECKING([whether Apple CoreAudio framework is supported])
AC_MSG_RESULT([${have_coreaudio}])
fi
AC_SUBST(coreaudio_ldflags)
if test "x${have_coreaudio}" = "xyes"; then
AC_DEFINE([HAVE_COREAUDIO], [1], [CoreAudio support enabled])
else
AC_DEFINE([HAVE_COREAUDIO], [0], [CoreAudio support disabled])
fi
### Default values
### Checks for programs
@ -3992,7 +3943,6 @@ EFL_EVAL_PKGS([ECORE_AUDIO])
EFL_ADD_FEATURE([ECORE_AUDIO], [alsa])
EFL_ADD_FEATURE([ECORE_AUDIO], [pulseaudio])
EFL_ADD_FEATURE([ECORE_AUDIO], [sndfile])
EFL_ADD_FEATURE([ECORE_AUDIO], [coreaudio])
### Checks for header files
@ -4009,7 +3959,6 @@ EFL_ADD_FEATURE([ECORE_AUDIO], [coreaudio])
EFL_LIB_END_OPTIONAL([Ecore_Audio])
AM_CONDITIONAL([HAVE_ECORE_AUDIO_PULSE], [test "x${want_pulseaudio}" = "xyes"])
AM_CONDITIONAL([HAVE_ECORE_AUDIO_SNDFILE], [test "x${want_sndfile}" = "xyes"])
AM_CONDITIONAL([HAVE_ECORE_AUDIO_CORE_AUDIO], [test "x${want_coreaudio}" = "xyes"])
#### End of Ecore_Audio
@ -4913,7 +4862,7 @@ AC_ARG_ENABLE([multisense],
fi
],
[
if test "x${want_pulseaudio}" = "xyes" -o "x${want_coreaudio}" = "xyes"; then
if test "x${want_pulseaudio}" = "xyes"; then
want_multisense="yes"
else
want_multisense="no"
@ -6242,7 +6191,7 @@ if test -n "$CFOPT_WARNING"; then
echo "Reconsider disabling audio."
echo "_____________________________________________________________________"
fi
if test "x${have_darwin}" = "xno" -a "x${want_pulseaudio}" = "xno"; then
if test "x${want_pulseaudio}" = "xno"; then
echo "_____________________________________________________________________"
echo "The only audio output method supported by Ecore right now on your"
echo "system is via Pulseaudio. You have disabled that and likely have"

View File

@ -9,7 +9,6 @@ ecore_audio_eolian_files = \
lib/ecore_audio/ecore_audio_in_sndfile.eo \
lib/ecore_audio/ecore_audio_out_sndfile.eo \
lib/ecore_audio/ecore_audio_out_pulse.eo \
lib/ecore_audio/ecore_audio_out_core_audio.eo \
lib/ecore_audio/ecore_audio_in_tone.eo
@ -72,14 +71,6 @@ lib/ecore_audio/ecore_audio_obj_out_sndfile.c \
lib/ecore_audio/ecore_audio_sndfile_vio.c
endif
if HAVE_ECORE_AUDIO_CORE_AUDIO
dist_installed_ecoreaudiomainheaders_DATA += \
lib/ecore_audio/ecore_audio_obj_out_core_audio.h
lib_ecore_audio_libecore_audio_la_SOURCES += \
lib/ecore_audio/ecore_audio_obj_out_core_audio.c
lib_ecore_audio_libecore_audio_la_LDFLAGS += @coreaudio_ldflags@
endif
if HAVE_ELUA

View File

@ -44,7 +44,7 @@ enum _Ecore_Audio_Type {
ECORE_AUDIO_TYPE_ALSA, /**< Use ALSA module*/
ECORE_AUDIO_TYPE_SNDFILE, /**< Use libsndfile module */
ECORE_AUDIO_TYPE_TONE, /**< Use tone module */
ECORE_AUDIO_TYPE_CORE_AUDIO, /**< Use Core Audio module (Apple) */
ECORE_AUDIO_TYPE_CORE_AUDIO EINA_DEPRECATED, /**< Use Core Audio module (Apple) - DEPRECATED */
ECORE_AUDIO_TYPE_CUSTOM, /**< Use custom module */
ECORE_AUDIO_MODULE_LAST, /**< Sentinel */
};
@ -193,10 +193,6 @@ EAPI int ecore_audio_shutdown(void);
#include <ecore_audio_obj_in_tone.h>
#if HAVE_COREAUDIO
# include <ecore_audio_obj_out_core_audio.h>
#endif
#if HAVE_PULSE
# include <ecore_audio_obj_out_pulse.h>
#endif

View File

@ -1,44 +0,0 @@
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifdef HAVE_COREAUDIO
#include "Ecore.h"
#include "ecore_private.h"
#include "Ecore_Audio.h"
#include "ecore_audio_private.h"
static Ecore_Audio_Module *_module = NULL;
EAPI Ecore_Audio_Module *
ecore_audio_core_audio_init(void)
{
/* Don't call this twice */
if (_module != NULL) return _module;
_module = calloc(1, sizeof(Ecore_Audio_Module));
if (EINA_UNLIKELY(_module == NULL))
{
CRI("Failed to allocate Ecore_Audio_Module");
goto ret_null;
}
ECORE_MAGIC_SET(_module, ECORE_MAGIC_AUDIO_MODULE);
_module->type = ECORE_AUDIO_TYPE_CORE_AUDIO;
_module->name = "CoreAudio";
return _module;
ret_null:
return NULL;
}
EAPI void
ecore_audio_nssound_shutdown(void)
{
free(_module);
_module = NULL;
}
#endif /* HAVE_COREAUDIO */

View File

@ -1,336 +0,0 @@
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <Eo.h>
#include "ecore_audio_private.h"
#include <CoreAudio/CoreAudio.h>
/* Notes:
*
* A lot of source code on the internet dealing with CoreAudio is deprecated.
* sndfile-play (bundled with libsndfile) is no exception and uses an almost
* 10 years old API. Nethertheless, sndfile-play has been heavily used to
* create the CoreAudio module.
*
* Documentation is almost non-existant, but here is the technical note from
* Apple explaining how CoreAudio objects should be manipulated:
* https://developer.apple.com/library/mac/technotes/tn2223/_index.html
*/
#include "ecore_audio_obj_out_core_audio.h"
typedef struct
{
Eo *input;
Eo *output;
AudioDeviceIOProcID proc_id;
AudioStreamBasicDescription format;
AudioObjectID obj_id;
UInt32 buf_size;
Eina_Bool is_playing;
Eina_Bool fake_stereo;
} Core_Audio_Helper;
/* Apple's error codes are tricky: they are stored as 32 bits integers.
* However, they are supposed to be represented as 4-bytes strings.
* There is no equivalent of strerror() (of what I know).
*
* Ref: http://vgable.com/blog/2008/04/23/printing-a-fourcharcode/
*
* In case of error, take a look at CoreAudio/AudioHardwareBase.h where
* the error codes are explained.
*/
#define APPLE_ERROR(err_) \
(char[5]){((err_) >> 24) & 0xff, ((err_) >> 16) & 0xff, ((err_) >> 8) & 0xff, (err_) & 0xff, 0}
#define MY_CLASS ECORE_AUDIO_OUT_CORE_AUDIO_CLASS
#define MY_CLASS_NAME "Ecore_Audio_Out_Core_Audio"
/*============================================================================*
* Helper API *
*============================================================================*/
static Core_Audio_Helper *
_core_audio_helper_new(void)
{
return calloc(1, sizeof(Core_Audio_Helper));
}
static void
_core_audio_helper_stop(Core_Audio_Helper *helper)
{
EINA_SAFETY_ON_NULL_RETURN(helper);
OSStatus err;
if (!helper->is_playing) return;
/* Stop audio device */
err = AudioDeviceStop(helper->obj_id, helper->proc_id);
if (EINA_UNLIKELY(err != noErr))
ERR("Failed to stop audio device %i for proc id %p: '%s'",
helper->obj_id, helper->proc_id, APPLE_ERROR(err));
/* Remove proc ID */
err = AudioDeviceDestroyIOProcID(helper->obj_id, helper->proc_id);
if (EINA_UNLIKELY(err != noErr))
ERR("Failed to stop audio device %i for proc id %p: '%s'",
helper->obj_id, helper->proc_id, APPLE_ERROR(err));
helper->is_playing = EINA_FALSE;
}
static void
_core_audio_helper_free(Core_Audio_Helper *helper)
{
EINA_SAFETY_ON_NULL_RETURN(helper);
if (helper->is_playing)
_core_audio_helper_stop(helper);
free(helper);
}
/*============================================================================*
* Audio Object Properties *
*============================================================================*/
static OSStatus
_audio_object_id_get(AudioObjectID *obj_id)
{
OSStatus err;
UInt32 size;
AudioObjectPropertyAddress prop = {
kAudioHardwarePropertyDefaultOutputDevice,
kAudioObjectPropertyScopePlayThrough,
kAudioObjectPropertyElementMaster
};
/* Default output device */
size = sizeof(AudioObjectID);
err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &prop, 0, NULL,
&size, obj_id);
return err;
}
static OSStatus
_audio_device_stream_format_get(AudioObjectID obj_id,
AudioStreamBasicDescription *format)
{
OSStatus err;
UInt32 size;
AudioObjectPropertyAddress prop = {
kAudioDevicePropertyStreamFormat,
kAudioObjectPropertyScopePlayThrough,
kAudioObjectPropertyElementMaster /* Channel number */
};
size = sizeof(AudioStreamBasicDescription);
err = AudioObjectGetPropertyData(obj_id, &prop, 0, NULL, &size, format);
return err;
}
static OSStatus
_audio_device_stream_format_set(AudioObjectID obj_id,
AudioStreamBasicDescription *format)
{
OSStatus err;
UInt32 size;
AudioObjectPropertyAddress prop = {
kAudioDevicePropertyStreamFormat,
kAudioObjectPropertyScopePlayThrough,
kAudioObjectPropertyElementMaster /* Channel number */
};
size = sizeof(AudioStreamBasicDescription);
err = AudioObjectSetPropertyData(obj_id, &prop, 0, NULL, size, format);
return err;
}
/*============================================================================*
* Audio Callback *
*============================================================================*/
static OSStatus
_audio_io_proc_cb(AudioObjectID obj_id EINA_UNUSED,
const AudioTimeStamp *in_now EINA_UNUSED,
const AudioBufferList *input_data EINA_UNUSED,
const AudioTimeStamp *input_time EINA_UNUSED,
AudioBufferList *output_data,
const AudioTimeStamp *in_output_time EINA_UNUSED,
void *data)
{
Core_Audio_Helper *helper = data;
float *buf;
int size, bread, sample_count, k;
size = output_data->mBuffers[0].mDataByteSize;
buf = output_data->mBuffers[0].mData;
sample_count = size / sizeof(float);
if (helper->fake_stereo)
{
bread = ecore_audio_obj_in_read(helper->input, buf, size * 2);
for (k = bread - 1; k >= 0; --k)
{
buf[2 * k + 0] = buf[k];
buf[2 * k + 1] = buf[k];
}
bread /= 2;
}
else
{
bread = ecore_audio_obj_in_read(helper->input, buf, size * 4);
bread /= 4;
}
/* Done playing */
if (bread < sample_count)
{
INF("Done playing: %i < %i", bread, sample_count);
/* Auto-detached. Don't need to do more. */
}
return noErr;
}
/*============================================================================*
* Eo API *
*============================================================================*/
EOLIAN static void
_ecore_audio_out_core_audio_ecore_audio_volume_set(Eo *obj, void *sd EINA_UNUSED, double volume)
{
// TODO Change volume of playing inputs
ecore_audio_obj_volume_set(efl_super(obj, MY_CLASS), volume);
}
EOLIAN static Eina_Bool
_ecore_audio_out_core_audio_ecore_audio_out_input_attach(Eo *obj, void *sd EINA_UNUSED, Eo *input)
{
Core_Audio_Helper *helper;
UInt32 channels;
OSStatus err;
Eina_Bool chk;
chk = ecore_audio_obj_out_input_attach(efl_super(obj, MY_CLASS), input);
if (EINA_UNLIKELY(!chk))
{
ERR("Failed to attach input (eo_do_super)");
goto return_failure;
}
helper = _core_audio_helper_new();
if (EINA_UNLIKELY(helper == NULL))
{
CRI("Failed to allocate memory");
goto detach;
}
/* Keep track of input source and output object */
helper->input = input;
helper->output = obj;
/* Default output device */
err = _audio_object_id_get(&(helper->obj_id));
if (EINA_UNLIKELY(err != noErr))
{
ERR("Failed to get object property: default output device: '%s'",
APPLE_ERROR(err));
goto free_helper;
}
/* Get data format description */
err = _audio_device_stream_format_get(helper->obj_id, &(helper->format));
if (EINA_UNLIKELY(err != noErr))
{
ERR("Failed to get property: stream format: '%s'", APPLE_ERROR(err));
goto free_helper;
}
/* Forward samplerate to CoreAudio */
helper->format.mSampleRate = ecore_audio_obj_in_samplerate_get(input);
/* Set channels. If only 1 channel, emulate stereo */
channels = ecore_audio_obj_in_channels_get(input);
if (channels == 1)
{
DBG("Fake stereo enabled for input %p", input);
helper->fake_stereo = EINA_TRUE;
channels = 2;
}
helper->format.mChannelsPerFrame = channels;
/* Set new format description */
err = _audio_device_stream_format_set(helper->obj_id, &(helper->format));
if (EINA_UNLIKELY(err != noErr))
{
ERR("Failed to set property: stream format: '%s'", APPLE_ERROR(err));
goto free_helper;
}
/* We want linear PCM */
if (helper->format.mFormatID != kAudioFormatLinearPCM)
{
ERR("Invalid format ID. Expected linear PCM: '%s'", APPLE_ERROR(err));
goto free_helper;
}
/* Create IO proc ID */
err = AudioDeviceCreateIOProcID(helper->obj_id, _audio_io_proc_cb,
helper, &(helper->proc_id));
if (err != noErr)
{
ERR("Failed to create IO proc ID. Error: '%s'", APPLE_ERROR(err));
goto free_helper;
}
/* Keep track of data for deallocation */
efl_key_data_set(input, "coreaudio_data", helper);
/* Start playing */
helper->is_playing = EINA_TRUE;
err = AudioDeviceStart(helper->obj_id, helper->proc_id);
if (err != noErr)
{
ERR("Failed to start proc ID %p for device id %i: '%s'",
helper->proc_id, helper->obj_id, APPLE_ERROR(err));
goto free_proc_id;
}
return EINA_TRUE;
free_proc_id:
AudioDeviceDestroyIOProcID(helper->obj_id, helper->proc_id);
free_helper:
free(helper);
detach:
ecore_audio_obj_out_input_detach(efl_super(obj, MY_CLASS), input);
return_failure:
return EINA_FALSE;
}
EOLIAN static Eina_Bool
_ecore_audio_out_core_audio_ecore_audio_out_input_detach(Eo *obj, void *sd EINA_UNUSED, Eo *input)
{
Core_Audio_Helper *data;
Eina_Bool ret;
DBG("Detach");
/* Free helper */
data = efl_key_data_get(input, "coreaudio_data");
_core_audio_helper_free(data);
ret = ecore_audio_obj_out_input_detach(efl_super(obj, MY_CLASS), input);
return ret;
}
#include "ecore_audio_out_core_audio.eo.c"

View File

@ -1,15 +0,0 @@
#ifndef _ECORE_AUDIO_OBJ_OUT_CORE_AUDIO_H_
#define _ECORE_AUDIO_OBJ_OUT_CORE_AUDIO_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "ecore_audio_out_core_audio.eo.h"
#ifdef __cplusplus
}
#endif
#endif /* ! _ECORE_AUDIO_OBJ_OUT_CORE_AUDIO_H_ */

View File

@ -1,11 +0,0 @@
class Ecore.Audio.Out.Core_Audio (Ecore.Audio.Out)
{
[[Ecore audio output for Mac OSX Core Aduio.]]
data: null;
eo_prefix: ecore_audio_obj_out_core_audio;
implements {
Ecore.Audio.volume.set;
Ecore.Audio.Out.input_attach;
Ecore.Audio.Out.input_detach;
}
}

View File

@ -230,13 +230,6 @@ Eina_Bool ecore_audio_sndfile_lib_load(void);
void ecore_audio_sndfile_lib_unload(void);
#endif /* HAVE_SNDFILE */
//////////////////////////////////////////////////////////////////////////
#ifdef HAVE_COREAUDIO
/* ecore_audio_core_audio */
Ecore_Audio_Module *ecore_audio_core_audio_init(void);
void ecore_audio_core_audio_shutdown(void);
#endif /* HAVE_COREAUDIO */
//////////////////////////////////////////////////////////////////////////
Ecore_Audio_Module *ecore_audio_custom_init(void);
void ecore_audio_custom_shutdown(void);