summaryrefslogtreecommitdiff
path: root/src/lib/ecore_audio
diff options
context:
space:
mode:
authorJean Guyomarc'h <jean@guyomarch.bzh>2016-10-29 22:32:19 +0200
committerJean Guyomarc'h <jean@guyomarch.bzh>2016-10-29 23:01:38 +0200
commit403b0ecfa66530e9cd598bd013aeda76df7ee98c (patch)
tree3e9416a93d989a315f621af74e456bcb4076a5d0 /src/lib/ecore_audio
parent30d7410699875cce2e255e3ebf862b3e7dbd641a (diff)
ecore_audio: drop support for CoreAudio on macOS
CoreAudio support was initially introduced by commit 62e29b39f4df40fd3c0a6b17f7a16f0f8fc1d0c9 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.
Diffstat (limited to 'src/lib/ecore_audio')
-rw-r--r--src/lib/ecore_audio/Ecore_Audio.h6
-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.c336
-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.eo11
-rw-r--r--src/lib/ecore_audio/ecore_audio_private.h7
6 files changed, 1 insertions, 418 deletions
diff --git a/src/lib/ecore_audio/Ecore_Audio.h b/src/lib/ecore_audio/Ecore_Audio.h
index 50e4b8347d..78dc346d73 100644
--- a/src/lib/ecore_audio/Ecore_Audio.h
+++ b/src/lib/ecore_audio/Ecore_Audio.h
@@ -44,7 +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_CORE_AUDIO EINA_DEPRECATED, /**< Use Core Audio module (Apple) - DEPRECATED */
48 ECORE_AUDIO_TYPE_CUSTOM, /**< Use custom module */ 48 ECORE_AUDIO_TYPE_CUSTOM, /**< Use custom module */
49 ECORE_AUDIO_MODULE_LAST, /**< Sentinel */ 49 ECORE_AUDIO_MODULE_LAST, /**< Sentinel */
50}; 50};
@@ -193,10 +193,6 @@ EAPI int ecore_audio_shutdown(void);
193 193
194#include <ecore_audio_obj_in_tone.h> 194#include <ecore_audio_obj_in_tone.h>
195 195
196#if HAVE_COREAUDIO
197# include <ecore_audio_obj_out_core_audio.h>
198#endif
199
200#if HAVE_PULSE 196#if HAVE_PULSE
201# include <ecore_audio_obj_out_pulse.h> 197# include <ecore_audio_obj_out_pulse.h>
202#endif 198#endif
diff --git a/src/lib/ecore_audio/ecore_audio_core_audio.c b/src/lib/ecore_audio/ecore_audio_core_audio.c
deleted file mode 100644
index 2141d9d330..0000000000
--- a/src/lib/ecore_audio/ecore_audio_core_audio.c
+++ /dev/null
@@ -1,44 +0,0 @@
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
deleted file mode 100644
index 21c21c1ddb..0000000000
--- a/src/lib/ecore_audio/ecore_audio_obj_out_core_audio.c
+++ /dev/null
@@ -1,336 +0,0 @@
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 * Helper API *
55 *============================================================================*/
56
57static Core_Audio_Helper *
58_core_audio_helper_new(void)
59{
60 return calloc(1, sizeof(Core_Audio_Helper));
61}
62
63static void
64_core_audio_helper_stop(Core_Audio_Helper *helper)
65{
66 EINA_SAFETY_ON_NULL_RETURN(helper);
67
68 OSStatus err;
69
70 if (!helper->is_playing) return;
71
72 /* Stop audio device */
73 err = AudioDeviceStop(helper->obj_id, helper->proc_id);
74 if (EINA_UNLIKELY(err != noErr))
75 ERR("Failed to stop audio device %i for proc id %p: '%s'",
76 helper->obj_id, helper->proc_id, APPLE_ERROR(err));
77
78 /* Remove proc ID */
79 err = AudioDeviceDestroyIOProcID(helper->obj_id, helper->proc_id);
80 if (EINA_UNLIKELY(err != noErr))
81 ERR("Failed to stop audio device %i for proc id %p: '%s'",
82 helper->obj_id, helper->proc_id, APPLE_ERROR(err));
83
84 helper->is_playing = EINA_FALSE;
85}
86
87static void
88_core_audio_helper_free(Core_Audio_Helper *helper)
89{
90 EINA_SAFETY_ON_NULL_RETURN(helper);
91
92 if (helper->is_playing)
93 _core_audio_helper_stop(helper);
94 free(helper);
95}
96
97
98/*============================================================================*
99 * Audio Object Properties *
100 *============================================================================*/
101
102static OSStatus
103_audio_object_id_get(AudioObjectID *obj_id)
104{
105 OSStatus err;
106 UInt32 size;
107 AudioObjectPropertyAddress prop = {
108 kAudioHardwarePropertyDefaultOutputDevice,
109 kAudioObjectPropertyScopePlayThrough,
110 kAudioObjectPropertyElementMaster
111 };
112
113 /* Default output device */
114 size = sizeof(AudioObjectID);
115 err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &prop, 0, NULL,
116 &size, obj_id);
117 return err;
118}
119
120static OSStatus
121_audio_device_stream_format_get(AudioObjectID obj_id,
122 AudioStreamBasicDescription *format)
123{
124 OSStatus err;
125 UInt32 size;
126 AudioObjectPropertyAddress prop = {
127 kAudioDevicePropertyStreamFormat,
128 kAudioObjectPropertyScopePlayThrough,
129 kAudioObjectPropertyElementMaster /* Channel number */
130 };
131
132 size = sizeof(AudioStreamBasicDescription);
133 err = AudioObjectGetPropertyData(obj_id, &prop, 0, NULL, &size, format);
134 return err;
135}
136
137static OSStatus
138_audio_device_stream_format_set(AudioObjectID obj_id,
139 AudioStreamBasicDescription *format)
140{
141 OSStatus err;
142 UInt32 size;
143 AudioObjectPropertyAddress prop = {
144 kAudioDevicePropertyStreamFormat,
145 kAudioObjectPropertyScopePlayThrough,
146 kAudioObjectPropertyElementMaster /* Channel number */
147 };
148
149 size = sizeof(AudioStreamBasicDescription);
150 err = AudioObjectSetPropertyData(obj_id, &prop, 0, NULL, size, format);
151 return err;
152}
153
154
155/*============================================================================*
156 * Audio Callback *
157 *============================================================================*/
158
159static OSStatus
160_audio_io_proc_cb(AudioObjectID obj_id EINA_UNUSED,
161 const AudioTimeStamp *in_now EINA_UNUSED,
162 const AudioBufferList *input_data EINA_UNUSED,
163 const AudioTimeStamp *input_time EINA_UNUSED,
164 AudioBufferList *output_data,
165 const AudioTimeStamp *in_output_time EINA_UNUSED,
166 void *data)
167{
168 Core_Audio_Helper *helper = data;
169 float *buf;
170 int size, bread, sample_count, k;
171
172 size = output_data->mBuffers[0].mDataByteSize;
173 buf = output_data->mBuffers[0].mData;
174 sample_count = size / sizeof(float);
175
176 if (helper->fake_stereo)
177 {
178 bread = ecore_audio_obj_in_read(helper->input, buf, size * 2);
179
180 for (k = bread - 1; k >= 0; --k)
181 {
182 buf[2 * k + 0] = buf[k];
183 buf[2 * k + 1] = buf[k];
184 }
185 bread /= 2;
186 }
187 else
188 {
189 bread = ecore_audio_obj_in_read(helper->input, buf, size * 4);
190 bread /= 4;
191 }
192
193 /* Done playing */
194 if (bread < sample_count)
195 {
196 INF("Done playing: %i < %i", bread, sample_count);
197 /* Auto-detached. Don't need to do more. */
198 }
199
200 return noErr;
201}
202
203
204/*============================================================================*
205 * Eo API *
206 *============================================================================*/
207
208EOLIAN static void
209_ecore_audio_out_core_audio_ecore_audio_volume_set(Eo *obj, void *sd EINA_UNUSED, double volume)
210{
211 // TODO Change volume of playing inputs
212 ecore_audio_obj_volume_set(efl_super(obj, MY_CLASS), volume);
213}
214
215EOLIAN static Eina_Bool
216_ecore_audio_out_core_audio_ecore_audio_out_input_attach(Eo *obj, void *sd EINA_UNUSED, Eo *input)
217{
218 Core_Audio_Helper *helper;
219 UInt32 channels;
220 OSStatus err;
221 Eina_Bool chk;
222
223 chk = ecore_audio_obj_out_input_attach(efl_super(obj, MY_CLASS), input);
224 if (EINA_UNLIKELY(!chk))
225 {
226 ERR("Failed to attach input (eo_do_super)");
227 goto return_failure;
228 }
229
230 helper = _core_audio_helper_new();
231 if (EINA_UNLIKELY(helper == NULL))
232 {
233 CRI("Failed to allocate memory");
234 goto detach;
235 }
236
237 /* Keep track of input source and output object */
238 helper->input = input;
239 helper->output = obj;
240
241 /* Default output device */
242 err = _audio_object_id_get(&(helper->obj_id));
243 if (EINA_UNLIKELY(err != noErr))
244 {
245 ERR("Failed to get object property: default output device: '%s'",
246 APPLE_ERROR(err));
247 goto free_helper;
248 }
249
250 /* Get data format description */
251 err = _audio_device_stream_format_get(helper->obj_id, &(helper->format));
252 if (EINA_UNLIKELY(err != noErr))
253 {
254 ERR("Failed to get property: stream format: '%s'", APPLE_ERROR(err));
255 goto free_helper;
256 }
257
258 /* Forward samplerate to CoreAudio */
259 helper->format.mSampleRate = ecore_audio_obj_in_samplerate_get(input);
260
261 /* Set channels. If only 1 channel, emulate stereo */
262 channels = ecore_audio_obj_in_channels_get(input);
263 if (channels == 1)
264 {
265 DBG("Fake stereo enabled for input %p", input);
266 helper->fake_stereo = EINA_TRUE;
267 channels = 2;
268 }
269 helper->format.mChannelsPerFrame = channels;
270
271 /* Set new format description */
272 err = _audio_device_stream_format_set(helper->obj_id, &(helper->format));
273 if (EINA_UNLIKELY(err != noErr))
274 {
275 ERR("Failed to set property: stream format: '%s'", APPLE_ERROR(err));
276 goto free_helper;
277 }
278
279 /* We want linear PCM */
280 if (helper->format.mFormatID != kAudioFormatLinearPCM)
281 {
282 ERR("Invalid format ID. Expected linear PCM: '%s'", APPLE_ERROR(err));
283 goto free_helper;
284 }
285
286 /* Create IO proc ID */
287 err = AudioDeviceCreateIOProcID(helper->obj_id, _audio_io_proc_cb,
288 helper, &(helper->proc_id));
289 if (err != noErr)
290 {
291 ERR("Failed to create IO proc ID. Error: '%s'", APPLE_ERROR(err));
292 goto free_helper;
293 }
294
295 /* Keep track of data for deallocation */
296 efl_key_data_set(input, "coreaudio_data", helper);
297
298 /* Start playing */
299 helper->is_playing = EINA_TRUE;
300 err = AudioDeviceStart(helper->obj_id, helper->proc_id);
301 if (err != noErr)
302 {
303 ERR("Failed to start proc ID %p for device id %i: '%s'",
304 helper->proc_id, helper->obj_id, APPLE_ERROR(err));
305 goto free_proc_id;
306 }
307
308 return EINA_TRUE;
309
310free_proc_id:
311 AudioDeviceDestroyIOProcID(helper->obj_id, helper->proc_id);
312free_helper:
313 free(helper);
314detach:
315 ecore_audio_obj_out_input_detach(efl_super(obj, MY_CLASS), input);
316return_failure:
317 return EINA_FALSE;
318}
319
320EOLIAN static Eina_Bool
321_ecore_audio_out_core_audio_ecore_audio_out_input_detach(Eo *obj, void *sd EINA_UNUSED, Eo *input)
322{
323 Core_Audio_Helper *data;
324 Eina_Bool ret;
325
326 DBG("Detach");
327 /* Free helper */
328 data = efl_key_data_get(input, "coreaudio_data");
329 _core_audio_helper_free(data);
330
331 ret = ecore_audio_obj_out_input_detach(efl_super(obj, MY_CLASS), input);
332
333 return ret;
334}
335
336#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
deleted file mode 100644
index 9b8eb7d8f8..0000000000
--- a/src/lib/ecore_audio/ecore_audio_obj_out_core_audio.h
+++ /dev/null
@@ -1,15 +0,0 @@
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
deleted file mode 100644
index f417a8b66c..0000000000
--- a/src/lib/ecore_audio/ecore_audio_out_core_audio.eo
+++ /dev/null
@@ -1,11 +0,0 @@
1class Ecore.Audio.Out.Core_Audio (Ecore.Audio.Out)
2{
3 [[Ecore audio output for Mac OSX Core Aduio.]]
4 data: null;
5 eo_prefix: ecore_audio_obj_out_core_audio;
6 implements {
7 Ecore.Audio.volume.set;
8 Ecore.Audio.Out.input_attach;
9 Ecore.Audio.Out.input_detach;
10 }
11}
diff --git a/src/lib/ecore_audio/ecore_audio_private.h b/src/lib/ecore_audio/ecore_audio_private.h
index 0bccb0ee68..03947b120f 100644
--- a/src/lib/ecore_audio/ecore_audio_private.h
+++ b/src/lib/ecore_audio/ecore_audio_private.h
@@ -231,13 +231,6 @@ void ecore_audio_sndfile_lib_unload(void);
231#endif /* HAVE_SNDFILE */ 231#endif /* HAVE_SNDFILE */
232 232
233////////////////////////////////////////////////////////////////////////// 233//////////////////////////////////////////////////////////////////////////
234#ifdef HAVE_COREAUDIO
235/* ecore_audio_core_audio */
236Ecore_Audio_Module *ecore_audio_core_audio_init(void);
237void ecore_audio_core_audio_shutdown(void);
238#endif /* HAVE_COREAUDIO */
239
240//////////////////////////////////////////////////////////////////////////
241Ecore_Audio_Module *ecore_audio_custom_init(void); 234Ecore_Audio_Module *ecore_audio_custom_init(void);
242void ecore_audio_custom_shutdown(void); 235void ecore_audio_custom_shutdown(void);
243 236