summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJean Guyomarc'h <jean.guyomarch@gmail.com>2015-04-15 16:53:39 +0200
committerCedric BAIL <cedric@osg.samsung.com>2015-05-07 09:53:07 +0200
commit62e29b39f4df40fd3c0a6b17f7a16f0f8fc1d0c9 (patch)
treeef94069e64c3d00e792a55fc4bc9147b054cffa1
parenta53c52dee0a3906d1ed3628396929127bcb665ea (diff)
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>
Diffstat (limited to '')
-rw-r--r--configure.ac70
-rw-r--r--src/Makefile_Ecore_Audio.am21
-rw-r--r--src/lib/ecore_audio/Ecore_Audio.h9
-rw-r--r--src/lib/ecore_audio/ecore_audio_core_audio.c44
-rw-r--r--src/lib/ecore_audio/ecore_audio_obj_out_core_audio.c358
-rw-r--r--src/lib/ecore_audio/ecore_audio_obj_out_core_audio.h15
-rw-r--r--src/lib/ecore_audio/ecore_audio_out_core_audio.eo12
-rw-r--r--src/lib/ecore_audio/ecore_audio_private.h6
-rw-r--r--src/lib/edje/edje_multisense.c12
9 files changed, 538 insertions, 9 deletions
diff --git a/configure.ac b/configure.ac
index 45fa102ffe..9eed98ce9b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -3208,6 +3208,54 @@ AC_ARG_ENABLE([pulseaudio],
3208 ], 3208 ],
3209 [want_pulseaudio="yes"]) 3209 [want_pulseaudio="yes"])
3210 3210
3211if test "x${have_darwin}" = "xyes"; then
3212 want_pulseaudio="no"
3213 want_alsa="no"
3214 want_coreaudio="yes"
3215else
3216 want_coreaudio="no"
3217fi
3218
3219
3220# CoreAudio flags
3221if test "x${want_coreaudio}" = "xyes"; then
3222 coreaudio_ldflags=""
3223 have_coreaudio="no"
3224 LIBS_save="$LIBS"
3225 LIBS="$LIBS -framework CoreAudio"
3226 AC_LINK_IFELSE(
3227 [AC_LANG_PROGRAM(
3228 [[
3229#include <CoreAudio/CoreAudio.h>
3230 ]],
3231 [[
3232UInt32 size;
3233AudioDeviceID dev_id;
3234AudioObjectPropertyAddress prop = {
3235 kAudioHardwarePropertyDefaultOutputDevice,
3236 kAudioObjectPropertyScopeGlobal,
3237 kAudioObjectPropertyElementMaster
3238};
3239size = sizeof(AudioDeviceID);
3240AudioObjectGetPropertyData(kAudioObjectSystemObject, &prop, 0, NULL,
3241 &size, &dev_id);
3242 ]])],
3243 [
3244 have_coreaudio="yes"
3245 coreaudio_ldflags="-framework CoreAudio"
3246 ],
3247 [have_coreaudio="no"])
3248 LIBS="$LIBS_save"
3249 AC_MSG_CHECKING([whether Apple CoreAudio framework is supported])
3250 AC_MSG_RESULT([${have_coreaudio}])
3251fi
3252AC_SUBST(coreaudio_ldflags)
3253if test "x${have_coreaudio}" = "xyes"; then
3254 AC_DEFINE([HAVE_COREAUDIO], [1], [CoreAudio support enabled])
3255else
3256 AC_DEFINE([HAVE_COREAUDIO], [0], [CoreAudio support disabled])
3257fi
3258
3211 3259
3212### Default values 3260### Default values
3213 3261
@@ -3234,6 +3282,7 @@ EFL_EVAL_PKGS([ECORE_AUDIO])
3234EFL_ADD_FEATURE([ECORE_AUDIO], [alsa]) 3282EFL_ADD_FEATURE([ECORE_AUDIO], [alsa])
3235EFL_ADD_FEATURE([ECORE_AUDIO], [pulseaudio]) 3283EFL_ADD_FEATURE([ECORE_AUDIO], [pulseaudio])
3236EFL_ADD_FEATURE([ECORE_AUDIO], [sndfile]) 3284EFL_ADD_FEATURE([ECORE_AUDIO], [sndfile])
3285EFL_ADD_FEATURE([ECORE_AUDIO], [coreaudio])
3237 3286
3238### Checks for header files 3287### Checks for header files
3239 3288
@@ -3250,6 +3299,7 @@ EFL_ADD_FEATURE([ECORE_AUDIO], [sndfile])
3250EFL_LIB_END_OPTIONAL([Ecore_Audio]) 3299EFL_LIB_END_OPTIONAL([Ecore_Audio])
3251AM_CONDITIONAL([HAVE_ECORE_AUDIO_PULSE], [test "x${want_pulseaudio}" = "xyes"]) 3300AM_CONDITIONAL([HAVE_ECORE_AUDIO_PULSE], [test "x${want_pulseaudio}" = "xyes"])
3252AM_CONDITIONAL([HAVE_ECORE_AUDIO_SNDFILE], [test "x${want_sndfile}" = "xyes"]) 3301AM_CONDITIONAL([HAVE_ECORE_AUDIO_SNDFILE], [test "x${want_sndfile}" = "xyes"])
3302AM_CONDITIONAL([HAVE_ECORE_AUDIO_CORE_AUDIO], [test "x${want_coreaudio}" = "xyes"])
3253 3303
3254#### End of Ecore_Audio 3304#### End of Ecore_Audio
3255 3305
@@ -4117,7 +4167,7 @@ EFL_LIB_START([Edje])
4117### Additional options to configure 4167### Additional options to configure
4118 4168
4119### Default values 4169### Default values
4120want_multisense="${want_pulseaudio}" 4170
4121AC_ARG_ENABLE([multisense], 4171AC_ARG_ENABLE([multisense],
4122 [AS_HELP_STRING([--enable-multisense],[Enable multisense support. @<:@default=enabled@:>@])], 4172 [AS_HELP_STRING([--enable-multisense],[Enable multisense support. @<:@default=enabled@:>@])],
4123 [ 4173 [
@@ -4128,7 +4178,13 @@ AC_ARG_ENABLE([multisense],
4128 CFOPT_WARNING="xyes" 4178 CFOPT_WARNING="xyes"
4129 fi 4179 fi
4130 ], 4180 ],
4131 [want_multisense="${want_pulseaudio}"]) 4181 [
4182 if test "x${want_pulseaudio}" = "xyes" -o "x${want_coreaudio}" = "xyes"; then
4183 want_multisense="yes"
4184 else
4185 want_multisense="no"
4186 fi
4187 ])
4132 4188
4133# TODO: should we keep or remove these? 4189# TODO: should we keep or remove these?
4134want_edje_program_cache="no" 4190want_edje_program_cache="no"
@@ -4960,11 +5016,12 @@ if test -n "$CFOPT_WARNING"; then
4960 echo "Reconsider disabling audio." 5016 echo "Reconsider disabling audio."
4961 echo "_____________________________________________________________________" 5017 echo "_____________________________________________________________________"
4962 fi 5018 fi
4963 if test "x${want_pulseaudio}" = "xno"; then 5019 if test "x${have_darwin}" = "xno" -a "x${want_pulseaudio}" = "xno"; then
4964 echo "_____________________________________________________________________" 5020 echo "_____________________________________________________________________"
4965 echo "The only audio output method supported by Ecore right now is via" 5021 echo "The only audio output method supported by Ecore right now on your"
4966 echo "Pulseaudio. You have disabled that and likely have broken a whole" 5022 echo "system is via Pulseaudio. You have disabled that and likely have"
4967 echo "bunch of things in the process. Reconsider your configure options." 5023 echo "broken a whole bunch of things in the process. Reconsider your"
5024 echo "configure options."
4968 echo "_____________________________________________________________________" 5025 echo "_____________________________________________________________________"
4969 fi 5026 fi
4970 if test "x${want_xinput2}" = "xno"; then 5027 if test "x${want_xinput2}" = "xno"; then
@@ -5143,3 +5200,4 @@ if test "x${efl_deprecated_option}" = "xyes"; then
5143 echo "" 5200 echo ""
5144 echo "#-------------------------------------------------------------------#" 5201 echo "#-------------------------------------------------------------------#"
5145fi 5202fi
5203
diff --git a/src/Makefile_Ecore_Audio.am b/src/Makefile_Ecore_Audio.am
index e87ffb408a..8881f19401 100644
--- a/src/Makefile_Ecore_Audio.am
+++ b/src/Makefile_Ecore_Audio.am
@@ -8,9 +8,17 @@ ecore_audio_eolian_files = \
8 lib/ecore_audio/ecore_audio_out.eo \ 8 lib/ecore_audio/ecore_audio_out.eo \
9 lib/ecore_audio/ecore_audio_in_sndfile.eo \ 9 lib/ecore_audio/ecore_audio_in_sndfile.eo \
10 lib/ecore_audio/ecore_audio_out_sndfile.eo \ 10 lib/ecore_audio/ecore_audio_out_sndfile.eo \
11 lib/ecore_audio/ecore_audio_out_pulse.eo \
12 lib/ecore_audio/ecore_audio_in_tone.eo 11 lib/ecore_audio/ecore_audio_in_tone.eo
13 12
13
14if HAVE_ECORE_AUDIO_PULSE
15ecore_audio_eolian_files += lib/ecore_audio/ecore_audio_out_pulse.eo
16endif
17
18if HAVE_ECORE_AUDIO_CORE_AUDIO
19ecore_audio_eolian_files += lib/ecore_audio/ecore_audio_out_core_audio.eo
20endif
21
14ecore_audio_eolian_c = $(ecore_audio_eolian_files:%.eo=%.eo.c) 22ecore_audio_eolian_c = $(ecore_audio_eolian_files:%.eo=%.eo.c)
15ecore_audio_eolian_h = $(ecore_audio_eolian_files:%.eo=%.eo.h) 23ecore_audio_eolian_h = $(ecore_audio_eolian_files:%.eo=%.eo.h)
16 24
@@ -40,7 +48,7 @@ lib/ecore_audio/ecore_audio_obj_in_tone.h \
40lib/ecore_audio/ecore_audio_protected.h 48lib/ecore_audio/ecore_audio_protected.h
41 49
42nodist_installed_ecoreaudiomainheaders_DATA = $(ecore_audio_eolian_h) 50nodist_installed_ecoreaudiomainheaders_DATA = $(ecore_audio_eolian_h)
43 51
44lib_ecore_audio_libecore_audio_la_SOURCES = \ 52lib_ecore_audio_libecore_audio_la_SOURCES = \
45lib/ecore_audio/ecore_audio.c \ 53lib/ecore_audio/ecore_audio.c \
46lib/ecore_audio/ecore_audio_obj.c \ 54lib/ecore_audio/ecore_audio_obj.c \
@@ -74,6 +82,15 @@ lib/ecore_audio/ecore_audio_obj_out_sndfile.c \
74lib/ecore_audio/ecore_audio_sndfile_vio.c 82lib/ecore_audio/ecore_audio_sndfile_vio.c
75endif 83endif
76 84
85if HAVE_ECORE_AUDIO_CORE_AUDIO
86dist_installed_ecoreaudiomainheaders_DATA += \
87lib/ecore_audio/ecore_audio_obj_out_core_audio.h
88lib_ecore_audio_libecore_audio_la_SOURCES += \
89lib/ecore_audio/ecore_audio_obj_out_core_audio.c
90lib_ecore_audio_libecore_audio_la_LDFLAGS += @coreaudio_ldflags@
91
92endif
93
77endif 94endif
78 95
79if HAVE_ELUA 96if HAVE_ELUA
diff --git a/src/lib/ecore_audio/Ecore_Audio.h b/src/lib/ecore_audio/Ecore_Audio.h
index 0835d6d99d..edb9b49ea7 100644
--- a/src/lib/ecore_audio/Ecore_Audio.h
+++ b/src/lib/ecore_audio/Ecore_Audio.h
@@ -44,6 +44,7 @@ enum _Ecore_Audio_Type {
44 ECORE_AUDIO_TYPE_ALSA, /**< Use ALSA module*/ 44 ECORE_AUDIO_TYPE_ALSA, /**< Use ALSA module*/
45 ECORE_AUDIO_TYPE_SNDFILE, /**< Use libsndfile module */ 45 ECORE_AUDIO_TYPE_SNDFILE, /**< Use libsndfile module */
46 ECORE_AUDIO_TYPE_TONE, /**< Use tone module */ 46 ECORE_AUDIO_TYPE_TONE, /**< Use tone module */
47 ECORE_AUDIO_TYPE_CORE_AUDIO, /**< Use Core Audio module (Apple) */
47 ECORE_AUDIO_TYPE_CUSTOM, /**< Use custom module */ 48 ECORE_AUDIO_TYPE_CUSTOM, /**< Use custom module */
48 ECORE_AUDIO_MODULE_LAST, /**< Sentinel */ 49 ECORE_AUDIO_MODULE_LAST, /**< Sentinel */
49}; 50};
@@ -211,7 +212,13 @@ EAPI int ecore_audio_shutdown(void);
211 212
212#include <ecore_audio_obj_in_tone.h> 213#include <ecore_audio_obj_in_tone.h>
213 214
214#include <ecore_audio_obj_out_pulse.h> 215#if HAVE_COREAUDIO
216# include <ecore_audio_obj_out_core_audio.h>
217#endif
218
219#if HAVE_PULSE
220# include <ecore_audio_obj_out_pulse.h>
221#endif
215 222
216/** 223/**
217 * @} 224 * @}
diff --git a/src/lib/ecore_audio/ecore_audio_core_audio.c b/src/lib/ecore_audio/ecore_audio_core_audio.c
new file mode 100644
index 0000000000..2141d9d330
--- /dev/null
+++ b/src/lib/ecore_audio/ecore_audio_core_audio.c
@@ -0,0 +1,44 @@
1#ifdef HAVE_CONFIG_H
2#include <config.h>
3#endif
4
5#ifdef HAVE_COREAUDIO
6#include "Ecore.h"
7#include "ecore_private.h"
8#include "Ecore_Audio.h"
9#include "ecore_audio_private.h"
10
11static Ecore_Audio_Module *_module = NULL;
12
13EAPI Ecore_Audio_Module *
14ecore_audio_core_audio_init(void)
15{
16 /* Don't call this twice */
17 if (_module != NULL) return _module;
18
19 _module = calloc(1, sizeof(Ecore_Audio_Module));
20 if (EINA_UNLIKELY(_module == NULL))
21 {
22 CRI("Failed to allocate Ecore_Audio_Module");
23 goto ret_null;
24 }
25
26 ECORE_MAGIC_SET(_module, ECORE_MAGIC_AUDIO_MODULE);
27 _module->type = ECORE_AUDIO_TYPE_CORE_AUDIO;
28 _module->name = "CoreAudio";
29
30 return _module;
31
32ret_null:
33 return NULL;
34}
35
36EAPI void
37ecore_audio_nssound_shutdown(void)
38{
39 free(_module);
40 _module = NULL;
41}
42
43#endif /* HAVE_COREAUDIO */
44
diff --git a/src/lib/ecore_audio/ecore_audio_obj_out_core_audio.c b/src/lib/ecore_audio/ecore_audio_obj_out_core_audio.c
new file mode 100644
index 0000000000..d358ec036d
--- /dev/null
+++ b/src/lib/ecore_audio/ecore_audio_obj_out_core_audio.c
@@ -0,0 +1,358 @@
1#ifdef HAVE_CONFIG_H
2#include <config.h>
3#endif
4
5#include <Eo.h>
6#include "ecore_audio_private.h"
7
8#include <CoreAudio/CoreAudio.h>
9
10/* Notes:
11 *
12 * A lot of source code on the internet dealing with CoreAudio is deprecated.
13 * sndfile-play (bundled with libsndfile) is no exception and uses an almost
14 * 10 years old API. Nethertheless, sndfile-play has been heavily used to
15 * create the CoreAudio module.
16 *
17 * Documentation is almost non-existant, but here is the technical note from
18 * Apple explaining how CoreAudio objects should be manipulated:
19 * https://developer.apple.com/library/mac/technotes/tn2223/_index.html
20 */
21
22#include "ecore_audio_obj_out_core_audio.h"
23
24typedef struct
25{
26 Eo *input;
27 Eo *output;
28 AudioDeviceIOProcID proc_id;
29 AudioStreamBasicDescription format;
30 AudioObjectID obj_id;
31 UInt32 buf_size;
32
33 Eina_Bool is_playing;
34 Eina_Bool fake_stereo;
35} Core_Audio_Helper;
36
37
38/* Apple's error codes are tricky: they are stored as 32 bits integers.
39 * However, they are supposed to be represented as 4-bytes strings.
40 * There is no equivalent of strerror() (of what I know).
41 *
42 * Ref: http://vgable.com/blog/2008/04/23/printing-a-fourcharcode/
43 *
44 * In case of error, take a look at CoreAudio/AudioHardwareBase.h where
45 * the error codes are explained.
46 */
47#define APPLE_ERROR(err_) \
48 (char[5]){((err_) >> 24) & 0xff, ((err_) >> 16) & 0xff, ((err_) >> 8) & 0xff, (err_) & 0xff, 0}
49
50#define MY_CLASS ECORE_AUDIO_OUT_CORE_AUDIO_CLASS
51#define MY_CLASS_NAME "Ecore_Audio_Out_Core_Audio"
52
53/*
54 * Unused structure. Only here because of Eolian.
55 * XXX Maybe it is possible to get rid of it.
56 */
57typedef struct
58{
59 void *this_data_is_here_to_silent_warnings;
60} Ecore_Audio_Out_Core_Audio_Data;
61
62
63/*============================================================================*
64 * Helper API *
65 *============================================================================*/
66
67static Core_Audio_Helper *
68_core_audio_helper_new(void)
69{
70 return calloc(1, sizeof(Core_Audio_Helper));
71}
72
73static void
74_core_audio_helper_stop(Core_Audio_Helper *helper)
75{
76 EINA_SAFETY_ON_NULL_RETURN(helper);
77
78 OSStatus err;
79
80 if (!helper->is_playing) return;
81
82 /* Stop audio device */
83 err = AudioDeviceStop(helper->obj_id, helper->proc_id);
84 if (EINA_UNLIKELY(err != noErr))
85 ERR("Failed to stop audio device %i for proc id %p: '%s'",
86 helper->obj_id, helper->proc_id, APPLE_ERROR(err));
87
88 /* Remove proc ID */
89 err = AudioDeviceDestroyIOProcID(helper->obj_id, helper->proc_id);
90 if (EINA_UNLIKELY(err != noErr))
91 ERR("Failed to stop audio device %i for proc id %p: '%s'",
92 helper->obj_id, helper->proc_id, APPLE_ERROR(err));
93
94 helper->is_playing = EINA_FALSE;
95}
96
97static void
98_core_audio_helper_free(Core_Audio_Helper *helper)
99{
100 EINA_SAFETY_ON_NULL_RETURN(helper);
101
102 if (helper->is_playing)
103 _core_audio_helper_stop(helper);
104 free(helper);
105}
106
107
108/*============================================================================*
109 * Audio Object Properties *
110 *============================================================================*/
111
112static OSStatus
113_audio_object_id_get(AudioObjectID *obj_id)
114{
115 OSStatus err;
116 UInt32 size;
117 AudioObjectPropertyAddress prop = {
118 kAudioHardwarePropertyDefaultOutputDevice,
119 kAudioObjectPropertyScopePlayThrough,
120 kAudioObjectPropertyElementMaster
121 };
122
123 /* Default output device */
124 size = sizeof(AudioObjectID);
125 err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &prop, 0, NULL,
126 &size, obj_id);
127 return err;
128}
129
130static OSStatus
131_audio_device_stream_format_get(AudioObjectID obj_id,
132 AudioStreamBasicDescription *format)
133{
134 OSStatus err;
135 UInt32 size;
136 AudioObjectPropertyAddress prop = {
137 kAudioDevicePropertyStreamFormat,
138 kAudioObjectPropertyScopePlayThrough,
139 kAudioObjectPropertyElementMaster /* Channel number */
140 };
141
142 size = sizeof(AudioStreamBasicDescription);
143 err = AudioObjectGetPropertyData(obj_id, &prop, 0, NULL, &size, format);
144 return err;
145}
146
147static OSStatus
148_audio_device_stream_format_set(AudioObjectID obj_id,
149 AudioStreamBasicDescription *format)
150{
151 OSStatus err;
152 UInt32 size;
153 AudioObjectPropertyAddress prop = {
154 kAudioDevicePropertyStreamFormat,
155 kAudioObjectPropertyScopePlayThrough,
156 kAudioObjectPropertyElementMaster /* Channel number */
157 };
158
159 size = sizeof(AudioStreamBasicDescription);
160 err = AudioObjectSetPropertyData(obj_id, &prop, 0, NULL, size, format);
161 return err;
162}
163
164
165/*============================================================================*
166 * Audio Callback *
167 *============================================================================*/
168
169static OSStatus
170_audio_io_proc_cb(AudioObjectID obj_id EINA_UNUSED,
171 const AudioTimeStamp *in_now EINA_UNUSED,
172 const AudioBufferList *input_data EINA_UNUSED,
173 const AudioTimeStamp *input_time EINA_UNUSED,
174 AudioBufferList *output_data,
175 const AudioTimeStamp *in_output_time EINA_UNUSED,
176 void *data)
177{
178 Core_Audio_Helper *helper = data;
179 float *buf;
180 int size, bread, sample_count, k;
181
182 size = output_data->mBuffers[0].mDataByteSize;
183 buf = output_data->mBuffers[0].mData;
184 sample_count = size / sizeof(float);
185
186 if (helper->fake_stereo)
187 {
188 eo_do(helper->input, bread = ecore_audio_obj_in_read(buf, size * 2));
189
190 for (k = bread - 1; k >= 0; --k)
191 {
192 buf[2 * k + 0] = buf[k];
193 buf[2 * k + 1] = buf[k];
194 }
195 bread /= 2;
196 }
197 else
198 {
199 eo_do(helper->input, bread = ecore_audio_obj_in_read(buf, size * 4));
200 bread /= 4;
201 }
202
203 /* Done playing */
204 if (bread < sample_count)
205 {
206 INF("Done playing: %i < %i", bread, sample_count);
207 /* Auto-detached. Don't need to do more. */
208 }
209
210 return noErr;
211}
212
213
214/*============================================================================*
215 * Eo API *
216 *============================================================================*/
217
218EOLIAN static void
219_ecore_audio_out_core_audio_eo_base_constructor(Eo *obj, Ecore_Audio_Out_Core_Audio_Data *sd EINA_UNUSED)
220{
221 eo_do_super(obj, MY_CLASS, eo_constructor());
222}
223
224EOLIAN static void
225_ecore_audio_out_core_audio_eo_base_destructor(Eo *obj, Ecore_Audio_Out_Core_Audio_Data *sd EINA_UNUSED)
226{
227 eo_do_super(obj, MY_CLASS, eo_destructor());
228}
229
230EOLIAN static void
231_ecore_audio_out_core_audio_ecore_audio_volume_set(Eo *obj, Ecore_Audio_Out_Core_Audio_Data *sd EINA_UNUSED, double volume)
232{
233 // TODO Change volume of playing inputs
234 eo_do_super(obj, MY_CLASS, ecore_audio_obj_volume_set(volume));
235}
236
237EOLIAN static Eina_Bool
238_ecore_audio_out_core_audio_ecore_audio_out_input_attach(Eo *obj, Ecore_Audio_Out_Core_Audio_Data *sd EINA_UNUSED, Eo *input)
239{
240 Core_Audio_Helper *helper;
241 UInt32 channels;
242 OSStatus err;
243 Eina_Bool chk;
244
245 eo_do_super(obj, MY_CLASS, chk = ecore_audio_obj_out_input_attach(input));
246 if (EINA_UNLIKELY(!chk))
247 {
248 ERR("Failed to attach input (eo_do_super)");
249 goto return_failure;
250 }
251
252 helper = _core_audio_helper_new();
253 if (EINA_UNLIKELY(helper == NULL))
254 {
255 CRI("Failed to allocate memory");
256 goto detach;
257 }
258
259 /* Keep track of input source and output object */
260 helper->input = input;
261 helper->output = obj;
262
263 /* Default output device */
264 err = _audio_object_id_get(&(helper->obj_id));
265 if (EINA_UNLIKELY(err != noErr))
266 {
267 ERR("Failed to get object property: default output device: '%s'",
268 APPLE_ERROR(err));
269 goto free_helper;
270 }
271
272 /* Get data format description */
273 err = _audio_device_stream_format_get(helper->obj_id, &(helper->format));
274 if (EINA_UNLIKELY(err != noErr))
275 {
276 ERR("Failed to get property: stream format: '%s'", APPLE_ERROR(err));
277 goto free_helper;
278 }
279
280 /* Forward samplerate to CoreAudio */
281 eo_do(input, helper->format.mSampleRate = ecore_audio_obj_in_samplerate_get());
282
283 /* Set channels. If only 1 channel, emulate stereo */
284 eo_do(input, channels = ecore_audio_obj_in_channels_get());
285 if (channels == 1)
286 {
287 DBG("Fake stereo enabled for input %p", input);
288 helper->fake_stereo = EINA_TRUE;
289 channels = 2;
290 }
291 helper->format.mChannelsPerFrame = channels;
292
293 /* Set new format description */
294 err = _audio_device_stream_format_set(helper->obj_id, &(helper->format));
295 if (EINA_UNLIKELY(err != noErr))
296 {
297 ERR("Failed to set property: stream format: '%s'", APPLE_ERROR(err));
298 goto free_helper;
299 }
300
301 /* We want linear PCM */
302 if (helper->format.mFormatID != kAudioFormatLinearPCM)
303 {
304 ERR("Invalid format ID. Expected linear PCM: '%s'", APPLE_ERROR(err));
305 goto free_helper;
306 }
307
308 /* Create IO proc ID */
309 err = AudioDeviceCreateIOProcID(helper->obj_id, _audio_io_proc_cb,
310 helper, &(helper->proc_id));
311 if (err != noErr)
312 {
313 ERR("Failed to create IO proc ID. Error: '%s'", APPLE_ERROR(err));
314 goto free_helper;
315 }
316
317 /* Keep track of data for deallocation */
318 eo_do(input, eo_key_data_set("coreaudio_data", helper, NULL));
319
320 /* Start playing */
321 helper->is_playing = EINA_TRUE;
322 err = AudioDeviceStart(helper->obj_id, helper->proc_id);
323 if (err != noErr)
324 {
325 ERR("Failed to start proc ID %p for device id %i: '%s'",
326 helper->proc_id, helper->obj_id, APPLE_ERROR(err));
327 goto free_proc_id;
328 }
329
330 return EINA_TRUE;
331
332free_proc_id:
333 AudioDeviceDestroyIOProcID(helper->obj_id, helper->proc_id);
334free_helper:
335 free(helper);
336detach:
337 eo_do_super(obj, MY_CLASS, ecore_audio_obj_out_input_detach(input));
338return_failure:
339 return EINA_FALSE;
340}
341
342EOLIAN static Eina_Bool
343_ecore_audio_out_core_audio_ecore_audio_out_input_detach(Eo *obj, Ecore_Audio_Out_Core_Audio_Data *sd EINA_UNUSED, Eo *input)
344{
345 Core_Audio_Helper *data;
346 Eina_Bool ret;
347
348 DBG("Detach");
349 /* Free helper */
350 eo_do(input, data = eo_key_data_get("coreaudio_data"));
351 _core_audio_helper_free(data);
352
353 eo_do_super(obj, MY_CLASS, ret = ecore_audio_obj_out_input_detach(input));
354
355 return ret;
356}
357
358#include "ecore_audio_out_core_audio.eo.c"
diff --git a/src/lib/ecore_audio/ecore_audio_obj_out_core_audio.h b/src/lib/ecore_audio/ecore_audio_obj_out_core_audio.h
new file mode 100644
index 0000000000..9b8eb7d8f8
--- /dev/null
+++ b/src/lib/ecore_audio/ecore_audio_obj_out_core_audio.h
@@ -0,0 +1,15 @@
1#ifndef _ECORE_AUDIO_OBJ_OUT_CORE_AUDIO_H_
2#define _ECORE_AUDIO_OBJ_OUT_CORE_AUDIO_H_
3
4#ifdef __cplusplus
5extern "C" {
6#endif
7
8#include "ecore_audio_out_core_audio.eo.h"
9
10#ifdef __cplusplus
11}
12#endif
13
14#endif /* ! _ECORE_AUDIO_OBJ_OUT_CORE_AUDIO_H_ */
15
diff --git a/src/lib/ecore_audio/ecore_audio_out_core_audio.eo b/src/lib/ecore_audio/ecore_audio_out_core_audio.eo
new file mode 100644
index 0000000000..6176ce73a9
--- /dev/null
+++ b/src/lib/ecore_audio/ecore_audio_out_core_audio.eo
@@ -0,0 +1,12 @@
1class Ecore_Audio_Out_Core_Audio (Ecore_Audio_Out)
2{
3 eo_prefix: ecore_audio_obj_out_core_audio;
4 implements {
5 Eo.Base.constructor;
6 Eo.Base.destructor;
7 Ecore_Audio.volume.set;
8 Ecore_Audio_Out.input_attach;
9 Ecore_Audio_Out.input_detach;
10 }
11}
12
diff --git a/src/lib/ecore_audio/ecore_audio_private.h b/src/lib/ecore_audio/ecore_audio_private.h
index 36a06f5f4c..13a7b6ae4c 100644
--- a/src/lib/ecore_audio/ecore_audio_private.h
+++ b/src/lib/ecore_audio/ecore_audio_private.h
@@ -169,6 +169,12 @@ Ecore_Audio_Module *ecore_audio_sndfile_init(void);
169void ecore_audio_sndfile_shutdown(void); 169void ecore_audio_sndfile_shutdown(void);
170#endif /* HAVE_SNDFILE */ 170#endif /* HAVE_SNDFILE */
171 171
172#ifdef HAVE_COREAUDIO
173/* ecore_audio_core_audio */
174Ecore_Audio_Module *ecore_audio_core_audio_init(void);
175void ecore_audio_core_audio_shutdown(void);
176#endif /* HAVE_COREAUDIO */
177
172Ecore_Audio_Module *ecore_audio_tone_init(void); 178Ecore_Audio_Module *ecore_audio_tone_init(void);
173void ecore_audio_tone_shutdown(void); 179void ecore_audio_tone_shutdown(void);
174 180
diff --git a/src/lib/edje/edje_multisense.c b/src/lib/edje/edje_multisense.c
index da24e0cf4a..913c1f9a89 100644
--- a/src/lib/edje/edje_multisense.c
+++ b/src/lib/edje/edje_multisense.c
@@ -204,13 +204,21 @@ _edje_multisense_internal_sound_sample_play(Edje *ed, const char *sample_name, c
204 eo_event_callback_add(ECORE_AUDIO_IN_EVENT_IN_STOPPED, _play_finished, NULL)); 204 eo_event_callback_add(ECORE_AUDIO_IN_EVENT_IN_STOPPED, _play_finished, NULL));
205 if (!out) 205 if (!out)
206 { 206 {
207#if HAVE_COREAUDIO
208 out = eo_add(ECORE_AUDIO_OUT_CORE_AUDIO_CLASS, NULL);
209#elif HAVE_PULSE
207 out = eo_add(ECORE_AUDIO_OUT_PULSE_CLASS, NULL, 210 out = eo_add(ECORE_AUDIO_OUT_PULSE_CLASS, NULL,
208 eo_event_callback_add(ECORE_AUDIO_OUT_PULSE_EVENT_CONTEXT_FAIL, _out_fail, NULL)); 211 eo_event_callback_add(ECORE_AUDIO_OUT_PULSE_EVENT_CONTEXT_FAIL, _out_fail, NULL));
212#endif
209 if (out) outs++; 213 if (out) outs++;
210 } 214 }
211 if (!out) 215 if (!out)
212 { 216 {
217#if HAVE_COREAUDIO
218 ERR("Could not create multisense audio out (CoreAudio)");
219#elif HAVE_PULSE
213 ERR("Could not create multisense audio out (pulse)"); 220 ERR("Could not create multisense audio out (pulse)");
221#endif
214 eo_del(in); 222 eo_del(in);
215 return EINA_FALSE; 223 return EINA_FALSE;
216 } 224 }
@@ -269,8 +277,12 @@ _edje_multisense_internal_sound_tone_play(Edje *ed, const char *tone_name, const
269 277
270 if (!out) 278 if (!out)
271 { 279 {
280#if HAVE_COREAUDIO
281 out = eo_add(ECORE_AUDIO_OUT_CORE_AUDIO_CLASS, NULL);
282#elif HAVE_PULSE
272 out = eo_add(ECORE_AUDIO_OUT_PULSE_CLASS, NULL, 283 out = eo_add(ECORE_AUDIO_OUT_PULSE_CLASS, NULL,
273 eo_event_callback_add(ECORE_AUDIO_OUT_PULSE_EVENT_CONTEXT_FAIL, _out_fail, NULL)); 284 eo_event_callback_add(ECORE_AUDIO_OUT_PULSE_EVENT_CONTEXT_FAIL, _out_fail, NULL));
285#endif
274 if (out) outs++; 286 if (out) outs++;
275 } 287 }
276 288