ecore_audio: integrate Apple's CoreAudio to play sounds on OS X.
Summary: Ecore_Audio now supports Apple's CoreAudio to play sounds read by libsndfile. edje_multisense integrates this new feature to enable PLAY_SAMPLE on OS X. Test Plan: Compiles, links and installs fine on OS X. Run terminology and elementary_test to hear sound played on user input. Reviewers: raster, naguirre, cedric Reviewed By: cedric Subscribers: plamot, cedric Differential Revision: https://phab.enlightenment.org/D2295 Signed-off-by: Cedric BAIL <cedric@osg.samsung.com>
This commit is contained in:
parent
a53c52dee0
commit
62e29b39f4
70
configure.ac
70
configure.ac
|
@ -3208,6 +3208,54 @@ 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
|
||||
|
||||
|
@ -3234,6 +3282,7 @@ 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
|
||||
|
||||
|
@ -3250,6 +3299,7 @@ EFL_ADD_FEATURE([ECORE_AUDIO], [sndfile])
|
|||
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
|
||||
|
||||
|
@ -4117,7 +4167,7 @@ EFL_LIB_START([Edje])
|
|||
### Additional options to configure
|
||||
|
||||
### Default values
|
||||
want_multisense="${want_pulseaudio}"
|
||||
|
||||
AC_ARG_ENABLE([multisense],
|
||||
[AS_HELP_STRING([--enable-multisense],[Enable multisense support. @<:@default=enabled@:>@])],
|
||||
[
|
||||
|
@ -4128,7 +4178,13 @@ AC_ARG_ENABLE([multisense],
|
|||
CFOPT_WARNING="xyes"
|
||||
fi
|
||||
],
|
||||
[want_multisense="${want_pulseaudio}"])
|
||||
[
|
||||
if test "x${want_pulseaudio}" = "xyes" -o "x${want_coreaudio}" = "xyes"; then
|
||||
want_multisense="yes"
|
||||
else
|
||||
want_multisense="no"
|
||||
fi
|
||||
])
|
||||
|
||||
# TODO: should we keep or remove these?
|
||||
want_edje_program_cache="no"
|
||||
|
@ -4960,11 +5016,12 @@ if test -n "$CFOPT_WARNING"; then
|
|||
echo "Reconsider disabling audio."
|
||||
echo "_____________________________________________________________________"
|
||||
fi
|
||||
if test "x${want_pulseaudio}" = "xno"; then
|
||||
if test "x${have_darwin}" = "xno" -a "x${want_pulseaudio}" = "xno"; then
|
||||
echo "_____________________________________________________________________"
|
||||
echo "The only audio output method supported by Ecore right now is via"
|
||||
echo "Pulseaudio. You have disabled that and likely have broken a whole"
|
||||
echo "bunch of things in the process. Reconsider your configure options."
|
||||
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"
|
||||
echo "broken a whole bunch of things in the process. Reconsider your"
|
||||
echo "configure options."
|
||||
echo "_____________________________________________________________________"
|
||||
fi
|
||||
if test "x${want_xinput2}" = "xno"; then
|
||||
|
@ -5143,3 +5200,4 @@ if test "x${efl_deprecated_option}" = "xyes"; then
|
|||
echo ""
|
||||
echo "#-------------------------------------------------------------------#"
|
||||
fi
|
||||
|
||||
|
|
|
@ -8,9 +8,17 @@ ecore_audio_eolian_files = \
|
|||
lib/ecore_audio/ecore_audio_out.eo \
|
||||
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_in_tone.eo
|
||||
|
||||
|
||||
if HAVE_ECORE_AUDIO_PULSE
|
||||
ecore_audio_eolian_files += lib/ecore_audio/ecore_audio_out_pulse.eo
|
||||
endif
|
||||
|
||||
if HAVE_ECORE_AUDIO_CORE_AUDIO
|
||||
ecore_audio_eolian_files += lib/ecore_audio/ecore_audio_out_core_audio.eo
|
||||
endif
|
||||
|
||||
ecore_audio_eolian_c = $(ecore_audio_eolian_files:%.eo=%.eo.c)
|
||||
ecore_audio_eolian_h = $(ecore_audio_eolian_files:%.eo=%.eo.h)
|
||||
|
||||
|
@ -74,6 +82,15 @@ 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
|
||||
|
||||
endif
|
||||
|
||||
if HAVE_ELUA
|
||||
|
|
|
@ -44,6 +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_CUSTOM, /**< Use custom module */
|
||||
ECORE_AUDIO_MODULE_LAST, /**< Sentinel */
|
||||
};
|
||||
|
@ -211,7 +212,13 @@ EAPI int ecore_audio_shutdown(void);
|
|||
|
||||
#include <ecore_audio_obj_in_tone.h>
|
||||
|
||||
#include <ecore_audio_obj_out_pulse.h>
|
||||
#if HAVE_COREAUDIO
|
||||
# include <ecore_audio_obj_out_core_audio.h>
|
||||
#endif
|
||||
|
||||
#if HAVE_PULSE
|
||||
# include <ecore_audio_obj_out_pulse.h>
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @}
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
#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 */
|
||||
|
|
@ -0,0 +1,358 @@
|
|||
#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"
|
||||
|
||||
/*
|
||||
* Unused structure. Only here because of Eolian.
|
||||
* XXX Maybe it is possible to get rid of it.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
void *this_data_is_here_to_silent_warnings;
|
||||
} Ecore_Audio_Out_Core_Audio_Data;
|
||||
|
||||
|
||||
/*============================================================================*
|
||||
* 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)
|
||||
{
|
||||
eo_do(helper->input, bread = ecore_audio_obj_in_read(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
|
||||
{
|
||||
eo_do(helper->input, bread = ecore_audio_obj_in_read(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_eo_base_constructor(Eo *obj, Ecore_Audio_Out_Core_Audio_Data *sd EINA_UNUSED)
|
||||
{
|
||||
eo_do_super(obj, MY_CLASS, eo_constructor());
|
||||
}
|
||||
|
||||
EOLIAN static void
|
||||
_ecore_audio_out_core_audio_eo_base_destructor(Eo *obj, Ecore_Audio_Out_Core_Audio_Data *sd EINA_UNUSED)
|
||||
{
|
||||
eo_do_super(obj, MY_CLASS, eo_destructor());
|
||||
}
|
||||
|
||||
EOLIAN static void
|
||||
_ecore_audio_out_core_audio_ecore_audio_volume_set(Eo *obj, Ecore_Audio_Out_Core_Audio_Data *sd EINA_UNUSED, double volume)
|
||||
{
|
||||
// TODO Change volume of playing inputs
|
||||
eo_do_super(obj, MY_CLASS, ecore_audio_obj_volume_set(volume));
|
||||
}
|
||||
|
||||
EOLIAN static Eina_Bool
|
||||
_ecore_audio_out_core_audio_ecore_audio_out_input_attach(Eo *obj, Ecore_Audio_Out_Core_Audio_Data *sd EINA_UNUSED, Eo *input)
|
||||
{
|
||||
Core_Audio_Helper *helper;
|
||||
UInt32 channels;
|
||||
OSStatus err;
|
||||
Eina_Bool chk;
|
||||
|
||||
eo_do_super(obj, MY_CLASS, chk = ecore_audio_obj_out_input_attach(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 */
|
||||
eo_do(input, helper->format.mSampleRate = ecore_audio_obj_in_samplerate_get());
|
||||
|
||||
/* Set channels. If only 1 channel, emulate stereo */
|
||||
eo_do(input, channels = ecore_audio_obj_in_channels_get());
|
||||
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 */
|
||||
eo_do(input, eo_key_data_set("coreaudio_data", helper, NULL));
|
||||
|
||||
/* 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:
|
||||
eo_do_super(obj, MY_CLASS, ecore_audio_obj_out_input_detach(input));
|
||||
return_failure:
|
||||
return EINA_FALSE;
|
||||
}
|
||||
|
||||
EOLIAN static Eina_Bool
|
||||
_ecore_audio_out_core_audio_ecore_audio_out_input_detach(Eo *obj, Ecore_Audio_Out_Core_Audio_Data *sd EINA_UNUSED, Eo *input)
|
||||
{
|
||||
Core_Audio_Helper *data;
|
||||
Eina_Bool ret;
|
||||
|
||||
DBG("Detach");
|
||||
/* Free helper */
|
||||
eo_do(input, data = eo_key_data_get("coreaudio_data"));
|
||||
_core_audio_helper_free(data);
|
||||
|
||||
eo_do_super(obj, MY_CLASS, ret = ecore_audio_obj_out_input_detach(input));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#include "ecore_audio_out_core_audio.eo.c"
|
|
@ -0,0 +1,15 @@
|
|||
#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_ */
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
class Ecore_Audio_Out_Core_Audio (Ecore_Audio_Out)
|
||||
{
|
||||
eo_prefix: ecore_audio_obj_out_core_audio;
|
||||
implements {
|
||||
Eo.Base.constructor;
|
||||
Eo.Base.destructor;
|
||||
Ecore_Audio.volume.set;
|
||||
Ecore_Audio_Out.input_attach;
|
||||
Ecore_Audio_Out.input_detach;
|
||||
}
|
||||
}
|
||||
|
|
@ -169,6 +169,12 @@ Ecore_Audio_Module *ecore_audio_sndfile_init(void);
|
|||
void ecore_audio_sndfile_shutdown(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_tone_init(void);
|
||||
void ecore_audio_tone_shutdown(void);
|
||||
|
||||
|
|
|
@ -204,13 +204,21 @@ _edje_multisense_internal_sound_sample_play(Edje *ed, const char *sample_name, c
|
|||
eo_event_callback_add(ECORE_AUDIO_IN_EVENT_IN_STOPPED, _play_finished, NULL));
|
||||
if (!out)
|
||||
{
|
||||
#if HAVE_COREAUDIO
|
||||
out = eo_add(ECORE_AUDIO_OUT_CORE_AUDIO_CLASS, NULL);
|
||||
#elif HAVE_PULSE
|
||||
out = eo_add(ECORE_AUDIO_OUT_PULSE_CLASS, NULL,
|
||||
eo_event_callback_add(ECORE_AUDIO_OUT_PULSE_EVENT_CONTEXT_FAIL, _out_fail, NULL));
|
||||
#endif
|
||||
if (out) outs++;
|
||||
}
|
||||
if (!out)
|
||||
{
|
||||
#if HAVE_COREAUDIO
|
||||
ERR("Could not create multisense audio out (CoreAudio)");
|
||||
#elif HAVE_PULSE
|
||||
ERR("Could not create multisense audio out (pulse)");
|
||||
#endif
|
||||
eo_del(in);
|
||||
return EINA_FALSE;
|
||||
}
|
||||
|
@ -269,8 +277,12 @@ _edje_multisense_internal_sound_tone_play(Edje *ed, const char *tone_name, const
|
|||
|
||||
if (!out)
|
||||
{
|
||||
#if HAVE_COREAUDIO
|
||||
out = eo_add(ECORE_AUDIO_OUT_CORE_AUDIO_CLASS, NULL);
|
||||
#elif HAVE_PULSE
|
||||
out = eo_add(ECORE_AUDIO_OUT_PULSE_CLASS, NULL,
|
||||
eo_event_callback_add(ECORE_AUDIO_OUT_PULSE_EVENT_CONTEXT_FAIL, _out_fail, NULL));
|
||||
#endif
|
||||
if (out) outs++;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue