blob: 4695291621a3c9f4fff66f983d2900a13f9aada9 [file] [log] [blame]
bellard1d14ffa2005-10-30 18:58:22 +00001/*
2 * QEMU OS X CoreAudio audio driver
3 *
4 * Copyright (c) 2005 Mike Kronenberg
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24
Peter Maydell6086a562016-01-18 17:33:52 +000025#include "qemu/osdep.h"
bellard1d14ffa2005-10-30 18:58:22 +000026#include <CoreAudio/CoreAudio.h>
bellard1d14ffa2005-10-30 18:58:22 +000027#include <pthread.h> /* pthread_X */
28
Akihiko Odakieb1a35e2021-06-23 05:17:40 +090029#include "qemu/main-loop.h"
Markus Armbruster0b8fa322019-05-23 16:35:07 +020030#include "qemu/module.h"
pbrook749bc4b2007-11-17 17:35:54 +000031#include "audio.h"
bellard1d14ffa2005-10-30 18:58:22 +000032
33#define AUDIO_CAP "coreaudio"
34#include "audio_int.h"
35
bellard1d14ffa2005-10-30 18:58:22 +000036typedef struct coreaudioVoiceOut {
37 HWVoiceOut hw;
Akihiko Odakieb1a35e2021-06-23 05:17:40 +090038 pthread_mutex_t buf_mutex;
bellard1d14ffa2005-10-30 18:58:22 +000039 AudioDeviceID outputDeviceID;
Akihiko Odaki7d6948c2021-03-12 00:15:11 +090040 int frameSizeSetting;
41 uint32_t bufferCount;
bellard5e941d42005-11-20 16:24:09 +000042 UInt32 audioDevicePropertyBufferFrameSize;
Peter Maydell2f79a182015-11-28 21:55:24 +000043 AudioDeviceIOProcID ioprocid;
Akihiko Odaki3ba6e3f2021-03-12 00:15:12 +090044 bool enabled;
bellard1d14ffa2005-10-30 18:58:22 +000045} coreaudioVoiceOut;
46
Philippe Mathieu-Daudé9f56bd62022-01-09 14:30:03 +010047#if !defined(MAC_OS_VERSION_12_0) \
48 || (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_VERSION_12_0)
49#define kAudioObjectPropertyElementMain kAudioObjectPropertyElementMaster
50#endif
51
Akihiko Odaki3ba6e3f2021-03-12 00:15:12 +090052static const AudioObjectPropertyAddress voice_addr = {
53 kAudioHardwarePropertyDefaultOutputDevice,
54 kAudioObjectPropertyScopeGlobal,
Philippe Mathieu-Daudé9f56bd62022-01-09 14:30:03 +010055 kAudioObjectPropertyElementMain
Akihiko Odaki3ba6e3f2021-03-12 00:15:12 +090056};
57
Peter Maydell624d1fc2015-11-28 21:55:21 +000058static OSStatus coreaudio_get_voice(AudioDeviceID *id)
59{
60 UInt32 size = sizeof(*id);
Peter Maydell624d1fc2015-11-28 21:55:21 +000061
62 return AudioObjectGetPropertyData(kAudioObjectSystemObject,
Akihiko Odaki3ba6e3f2021-03-12 00:15:12 +090063 &voice_addr,
Peter Maydell624d1fc2015-11-28 21:55:21 +000064 0,
65 NULL,
66 &size,
67 id);
68}
Peter Maydell2d99f622015-11-28 21:55:23 +000069
70static OSStatus coreaudio_get_framesizerange(AudioDeviceID id,
71 AudioValueRange *framerange)
72{
73 UInt32 size = sizeof(*framerange);
74 AudioObjectPropertyAddress addr = {
75 kAudioDevicePropertyBufferFrameSizeRange,
76 kAudioDevicePropertyScopeOutput,
Philippe Mathieu-Daudé9f56bd62022-01-09 14:30:03 +010077 kAudioObjectPropertyElementMain
Peter Maydell2d99f622015-11-28 21:55:23 +000078 };
79
80 return AudioObjectGetPropertyData(id,
81 &addr,
82 0,
83 NULL,
84 &size,
85 framerange);
86}
87
88static OSStatus coreaudio_get_framesize(AudioDeviceID id, UInt32 *framesize)
89{
90 UInt32 size = sizeof(*framesize);
91 AudioObjectPropertyAddress addr = {
92 kAudioDevicePropertyBufferFrameSize,
93 kAudioDevicePropertyScopeOutput,
Philippe Mathieu-Daudé9f56bd62022-01-09 14:30:03 +010094 kAudioObjectPropertyElementMain
Peter Maydell2d99f622015-11-28 21:55:23 +000095 };
96
97 return AudioObjectGetPropertyData(id,
98 &addr,
99 0,
100 NULL,
101 &size,
102 framesize);
103}
104
105static OSStatus coreaudio_set_framesize(AudioDeviceID id, UInt32 *framesize)
106{
107 UInt32 size = sizeof(*framesize);
108 AudioObjectPropertyAddress addr = {
109 kAudioDevicePropertyBufferFrameSize,
110 kAudioDevicePropertyScopeOutput,
Philippe Mathieu-Daudé9f56bd62022-01-09 14:30:03 +0100111 kAudioObjectPropertyElementMain
Peter Maydell2d99f622015-11-28 21:55:23 +0000112 };
113
114 return AudioObjectSetPropertyData(id,
115 &addr,
116 0,
117 NULL,
118 size,
119 framesize);
120}
121
Peter Maydell2d99f622015-11-28 21:55:23 +0000122static OSStatus coreaudio_set_streamformat(AudioDeviceID id,
123 AudioStreamBasicDescription *d)
124{
125 UInt32 size = sizeof(*d);
126 AudioObjectPropertyAddress addr = {
127 kAudioDevicePropertyStreamFormat,
128 kAudioDevicePropertyScopeOutput,
Philippe Mathieu-Daudé9f56bd62022-01-09 14:30:03 +0100129 kAudioObjectPropertyElementMain
Peter Maydell2d99f622015-11-28 21:55:23 +0000130 };
131
132 return AudioObjectSetPropertyData(id,
133 &addr,
134 0,
135 NULL,
136 size,
137 d);
138}
139
140static OSStatus coreaudio_get_isrunning(AudioDeviceID id, UInt32 *result)
141{
142 UInt32 size = sizeof(*result);
143 AudioObjectPropertyAddress addr = {
144 kAudioDevicePropertyDeviceIsRunning,
145 kAudioDevicePropertyScopeOutput,
Philippe Mathieu-Daudé9f56bd62022-01-09 14:30:03 +0100146 kAudioObjectPropertyElementMain
Peter Maydell2d99f622015-11-28 21:55:23 +0000147 };
148
149 return AudioObjectGetPropertyData(id,
150 &addr,
151 0,
152 NULL,
153 &size,
154 result);
155}
Peter Maydell95a860f2015-11-28 21:55:22 +0000156
bellard1d14ffa2005-10-30 18:58:22 +0000157static void coreaudio_logstatus (OSStatus status)
158{
Alexandre Raymondd9cbb0f2011-05-27 13:22:28 -0400159 const char *str = "BUG";
bellard1d14ffa2005-10-30 18:58:22 +0000160
Zhang Han3c8de962021-01-15 09:24:26 +0800161 switch (status) {
bellard1d14ffa2005-10-30 18:58:22 +0000162 case kAudioHardwareNoError:
163 str = "kAudioHardwareNoError";
164 break;
165
166 case kAudioHardwareNotRunningError:
167 str = "kAudioHardwareNotRunningError";
168 break;
169
170 case kAudioHardwareUnspecifiedError:
171 str = "kAudioHardwareUnspecifiedError";
172 break;
173
174 case kAudioHardwareUnknownPropertyError:
175 str = "kAudioHardwareUnknownPropertyError";
176 break;
177
178 case kAudioHardwareBadPropertySizeError:
179 str = "kAudioHardwareBadPropertySizeError";
180 break;
181
182 case kAudioHardwareIllegalOperationError:
183 str = "kAudioHardwareIllegalOperationError";
184 break;
185
186 case kAudioHardwareBadDeviceError:
187 str = "kAudioHardwareBadDeviceError";
188 break;
189
190 case kAudioHardwareBadStreamError:
191 str = "kAudioHardwareBadStreamError";
192 break;
193
194 case kAudioHardwareUnsupportedOperationError:
195 str = "kAudioHardwareUnsupportedOperationError";
196 break;
197
198 case kAudioDeviceUnsupportedFormatError:
199 str = "kAudioDeviceUnsupportedFormatError";
200 break;
201
202 case kAudioDevicePermissionsError:
203 str = "kAudioDevicePermissionsError";
204 break;
205
206 default:
Andreas Färber744d3642011-06-23 16:24:45 +0200207 AUD_log (AUDIO_CAP, "Reason: status code %" PRId32 "\n", (int32_t)status);
bellard1d14ffa2005-10-30 18:58:22 +0000208 return;
209 }
210
211 AUD_log (AUDIO_CAP, "Reason: %s\n", str);
212}
213
Marc-André Lureau9edc6312022-02-20 20:39:25 +0400214static void G_GNUC_PRINTF (2, 3) coreaudio_logerr (
bellard1d14ffa2005-10-30 18:58:22 +0000215 OSStatus status,
216 const char *fmt,
217 ...
218 )
219{
220 va_list ap;
221
222 va_start (ap, fmt);
223 AUD_log (AUDIO_CAP, fmt, ap);
224 va_end (ap);
225
226 coreaudio_logstatus (status);
227}
228
Marc-André Lureau9edc6312022-02-20 20:39:25 +0400229static void G_GNUC_PRINTF (3, 4) coreaudio_logerr2 (
bellard1d14ffa2005-10-30 18:58:22 +0000230 OSStatus status,
231 const char *typ,
232 const char *fmt,
233 ...
234 )
235{
236 va_list ap;
237
bellardc0fe3822005-11-05 18:55:28 +0000238 AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ);
bellard1d14ffa2005-10-30 18:58:22 +0000239
240 va_start (ap, fmt);
241 AUD_vlog (AUDIO_CAP, fmt, ap);
242 va_end (ap);
243
244 coreaudio_logstatus (status);
245}
246
Akihiko Odaki7d6948c2021-03-12 00:15:11 +0900247#define coreaudio_playback_logerr(status, ...) \
248 coreaudio_logerr2(status, "playback", __VA_ARGS__)
249
Akihiko Odakieb1a35e2021-06-23 05:17:40 +0900250static int coreaudio_buf_lock (coreaudioVoiceOut *core, const char *fn_name)
bellard1d14ffa2005-10-30 18:58:22 +0000251{
252 int err;
253
Akihiko Odakieb1a35e2021-06-23 05:17:40 +0900254 err = pthread_mutex_lock (&core->buf_mutex);
bellard1d14ffa2005-10-30 18:58:22 +0000255 if (err) {
bellardc0fe3822005-11-05 18:55:28 +0000256 dolog ("Could not lock voice for %s\nReason: %s\n",
bellard1d14ffa2005-10-30 18:58:22 +0000257 fn_name, strerror (err));
258 return -1;
259 }
260 return 0;
261}
262
Akihiko Odakieb1a35e2021-06-23 05:17:40 +0900263static int coreaudio_buf_unlock (coreaudioVoiceOut *core, const char *fn_name)
bellard1d14ffa2005-10-30 18:58:22 +0000264{
265 int err;
266
Akihiko Odakieb1a35e2021-06-23 05:17:40 +0900267 err = pthread_mutex_unlock (&core->buf_mutex);
bellard1d14ffa2005-10-30 18:58:22 +0000268 if (err) {
bellardc0fe3822005-11-05 18:55:28 +0000269 dolog ("Could not unlock voice for %s\nReason: %s\n",
bellard1d14ffa2005-10-30 18:58:22 +0000270 fn_name, strerror (err));
271 return -1;
272 }
273 return 0;
274}
275
Kővágó, Zoltán2ceb8242019-09-19 23:24:11 +0200276#define COREAUDIO_WRAPPER_FUNC(name, ret_type, args_decl, args) \
277 static ret_type glue(coreaudio_, name)args_decl \
278 { \
279 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw; \
280 ret_type ret; \
281 \
Akihiko Odakieb1a35e2021-06-23 05:17:40 +0900282 if (coreaudio_buf_lock(core, "coreaudio_" #name)) { \
Kővágó, Zoltán2ceb8242019-09-19 23:24:11 +0200283 return 0; \
284 } \
285 \
286 ret = glue(audio_generic_, name)args; \
287 \
Akihiko Odakieb1a35e2021-06-23 05:17:40 +0900288 coreaudio_buf_unlock(core, "coreaudio_" #name); \
Kővágó, Zoltán2ceb8242019-09-19 23:24:11 +0200289 return ret; \
bellard1d14ffa2005-10-30 18:58:22 +0000290 }
Volker Rümelin98334382022-03-01 20:13:06 +0100291COREAUDIO_WRAPPER_FUNC(buffer_get_free, size_t, (HWVoiceOut *hw), (hw))
Kővágó, Zoltán2ceb8242019-09-19 23:24:11 +0200292COREAUDIO_WRAPPER_FUNC(get_buffer_out, void *, (HWVoiceOut *hw, size_t *size),
293 (hw, size))
Volker Rümelinfdc8c5f2020-01-23 08:49:39 +0100294COREAUDIO_WRAPPER_FUNC(put_buffer_out, size_t,
Kővágó, Zoltán2ceb8242019-09-19 23:24:11 +0200295 (HWVoiceOut *hw, void *buf, size_t size),
296 (hw, buf, size))
297COREAUDIO_WRAPPER_FUNC(write, size_t, (HWVoiceOut *hw, void *buf, size_t size),
298 (hw, buf, size))
299#undef COREAUDIO_WRAPPER_FUNC
bellard1d14ffa2005-10-30 18:58:22 +0000300
Akihiko Odakieb1a35e2021-06-23 05:17:40 +0900301/*
302 * callback to feed audiooutput buffer. called without iothread lock.
303 * allowed to lock "buf_mutex", but disallowed to have any other locks.
304 */
bellard1d14ffa2005-10-30 18:58:22 +0000305static OSStatus audioDeviceIOProc(
306 AudioDeviceID inDevice,
Zhang Handcf10e42021-01-15 09:24:27 +0800307 const AudioTimeStamp *inNow,
308 const AudioBufferList *inInputData,
309 const AudioTimeStamp *inInputTime,
310 AudioBufferList *outOutputData,
311 const AudioTimeStamp *inOutputTime,
312 void *hwptr)
bellard1d14ffa2005-10-30 18:58:22 +0000313{
Kővágó, Zoltán2ceb8242019-09-19 23:24:11 +0200314 UInt32 frameCount, pending_frames;
315 void *out = outOutputData->mBuffers[0].mData;
bellard1d14ffa2005-10-30 18:58:22 +0000316 HWVoiceOut *hw = hwptr;
317 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hwptr;
Kővágó, Zoltán2ceb8242019-09-19 23:24:11 +0200318 size_t len;
bellard1d14ffa2005-10-30 18:58:22 +0000319
Akihiko Odakieb1a35e2021-06-23 05:17:40 +0900320 if (coreaudio_buf_lock (core, "audioDeviceIOProc")) {
bellard1d14ffa2005-10-30 18:58:22 +0000321 inInputTime = 0;
322 return 0;
323 }
324
Akihiko Odaki3ba6e3f2021-03-12 00:15:12 +0900325 if (inDevice != core->outputDeviceID) {
Akihiko Odakieb1a35e2021-06-23 05:17:40 +0900326 coreaudio_buf_unlock (core, "audioDeviceIOProc(old device)");
Akihiko Odaki3ba6e3f2021-03-12 00:15:12 +0900327 return 0;
328 }
329
bellard5e941d42005-11-20 16:24:09 +0000330 frameCount = core->audioDevicePropertyBufferFrameSize;
Kővágó, Zoltán2b9cce82019-10-13 21:58:02 +0200331 pending_frames = hw->pending_emul / hw->info.bytes_per_frame;
bellard1d14ffa2005-10-30 18:58:22 +0000332
333 /* if there are not enough samples, set signal and return */
Kővágó, Zoltán2ceb8242019-09-19 23:24:11 +0200334 if (pending_frames < frameCount) {
bellard1d14ffa2005-10-30 18:58:22 +0000335 inInputTime = 0;
Akihiko Odakieb1a35e2021-06-23 05:17:40 +0900336 coreaudio_buf_unlock (core, "audioDeviceIOProc(empty)");
bellard1d14ffa2005-10-30 18:58:22 +0000337 return 0;
338 }
339
Kővágó, Zoltán2b9cce82019-10-13 21:58:02 +0200340 len = frameCount * hw->info.bytes_per_frame;
Kővágó, Zoltán2ceb8242019-09-19 23:24:11 +0200341 while (len) {
Volker Rümelin18404ff2022-03-01 20:12:57 +0100342 size_t write_len, start;
343
344 start = audio_ring_posb(hw->pos_emul, hw->pending_emul, hw->size_emul);
345 assert(start < hw->size_emul);
bellard1d14ffa2005-10-30 18:58:22 +0000346
Kővágó, Zoltán2ceb8242019-09-19 23:24:11 +0200347 write_len = MIN(MIN(hw->pending_emul, len),
348 hw->size_emul - start);
349
350 memcpy(out, hw->buf_emul + start, write_len);
351 hw->pending_emul -= write_len;
352 len -= write_len;
353 out += write_len;
bellard1d14ffa2005-10-30 18:58:22 +0000354 }
355
Akihiko Odakieb1a35e2021-06-23 05:17:40 +0900356 coreaudio_buf_unlock (core, "audioDeviceIOProc");
bellard1d14ffa2005-10-30 18:58:22 +0000357 return 0;
358}
359
Akihiko Odaki7d6948c2021-03-12 00:15:11 +0900360static OSStatus init_out_device(coreaudioVoiceOut *core)
bellard1d14ffa2005-10-30 18:58:22 +0000361{
362 OSStatus status;
bellard5e941d42005-11-20 16:24:09 +0000363 AudioValueRange frameRange;
bellard1d14ffa2005-10-30 18:58:22 +0000364
Akihiko Odaki986bdbc2021-06-16 23:17:21 +0900365 AudioStreamBasicDescription streamBasicDescription = {
366 .mBitsPerChannel = core->hw.info.bits,
367 .mBytesPerFrame = core->hw.info.bytes_per_frame,
368 .mBytesPerPacket = core->hw.info.bytes_per_frame,
369 .mChannelsPerFrame = core->hw.info.nchannels,
370 .mFormatFlags = kLinearPCMFormatFlagIsFloat,
371 .mFormatID = kAudioFormatLinearPCM,
372 .mFramesPerPacket = 1,
373 .mSampleRate = core->hw.info.freq
374 };
375
Peter Maydell88a0f832015-11-28 21:55:20 +0000376 status = coreaudio_get_voice(&core->outputDeviceID);
bellard1d14ffa2005-10-30 18:58:22 +0000377 if (status != kAudioHardwareNoError) {
Akihiko Odaki7d6948c2021-03-12 00:15:11 +0900378 coreaudio_playback_logerr (status,
379 "Could not get default output Device\n");
380 return status;
bellard1d14ffa2005-10-30 18:58:22 +0000381 }
382 if (core->outputDeviceID == kAudioDeviceUnknown) {
Akihiko Odaki7d6948c2021-03-12 00:15:11 +0900383 dolog ("Could not initialize playback - Unknown Audiodevice\n");
384 return status;
bellard1d14ffa2005-10-30 18:58:22 +0000385 }
386
bellard5e941d42005-11-20 16:24:09 +0000387 /* get minimum and maximum buffer frame sizes */
Peter Maydell95a860f2015-11-28 21:55:22 +0000388 status = coreaudio_get_framesizerange(core->outputDeviceID,
389 &frameRange);
Akihiko Odaki3ba6e3f2021-03-12 00:15:12 +0900390 if (status == kAudioHardwareBadObjectError) {
391 return 0;
392 }
bellard5e941d42005-11-20 16:24:09 +0000393 if (status != kAudioHardwareNoError) {
Akihiko Odaki7d6948c2021-03-12 00:15:11 +0900394 coreaudio_playback_logerr (status,
395 "Could not get device buffer frame range\n");
396 return status;
bellard5e941d42005-11-20 16:24:09 +0000397 }
398
Akihiko Odaki7d6948c2021-03-12 00:15:11 +0900399 if (frameRange.mMinimum > core->frameSizeSetting) {
bellard5e941d42005-11-20 16:24:09 +0000400 core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMinimum;
401 dolog ("warning: Upsizing Buffer Frames to %f\n", frameRange.mMinimum);
Akihiko Odaki7d6948c2021-03-12 00:15:11 +0900402 } else if (frameRange.mMaximum < core->frameSizeSetting) {
bellard5e941d42005-11-20 16:24:09 +0000403 core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMaximum;
404 dolog ("warning: Downsizing Buffer Frames to %f\n", frameRange.mMaximum);
Zhang Han6c6886b2021-01-15 09:24:25 +0800405 } else {
Akihiko Odaki7d6948c2021-03-12 00:15:11 +0900406 core->audioDevicePropertyBufferFrameSize = core->frameSizeSetting;
bellard5e941d42005-11-20 16:24:09 +0000407 }
408
409 /* set Buffer Frame Size */
Peter Maydell95a860f2015-11-28 21:55:22 +0000410 status = coreaudio_set_framesize(core->outputDeviceID,
411 &core->audioDevicePropertyBufferFrameSize);
Akihiko Odaki3ba6e3f2021-03-12 00:15:12 +0900412 if (status == kAudioHardwareBadObjectError) {
413 return 0;
414 }
bellard1d14ffa2005-10-30 18:58:22 +0000415 if (status != kAudioHardwareNoError) {
Akihiko Odaki7d6948c2021-03-12 00:15:11 +0900416 coreaudio_playback_logerr (status,
417 "Could not set device buffer frame size %" PRIu32 "\n",
418 (uint32_t)core->audioDevicePropertyBufferFrameSize);
419 return status;
bellard1d14ffa2005-10-30 18:58:22 +0000420 }
421
bellard5e941d42005-11-20 16:24:09 +0000422 /* get Buffer Frame Size */
Peter Maydell95a860f2015-11-28 21:55:22 +0000423 status = coreaudio_get_framesize(core->outputDeviceID,
424 &core->audioDevicePropertyBufferFrameSize);
Akihiko Odaki3ba6e3f2021-03-12 00:15:12 +0900425 if (status == kAudioHardwareBadObjectError) {
426 return 0;
427 }
bellard1d14ffa2005-10-30 18:58:22 +0000428 if (status != kAudioHardwareNoError) {
Akihiko Odaki7d6948c2021-03-12 00:15:11 +0900429 coreaudio_playback_logerr (status,
430 "Could not get device buffer frame size\n");
431 return status;
bellard1d14ffa2005-10-30 18:58:22 +0000432 }
Akihiko Odaki7d6948c2021-03-12 00:15:11 +0900433 core->hw.samples = core->bufferCount * core->audioDevicePropertyBufferFrameSize;
bellard1d14ffa2005-10-30 18:58:22 +0000434
bellard1d14ffa2005-10-30 18:58:22 +0000435 /* set Samplerate */
Peter Maydell95a860f2015-11-28 21:55:22 +0000436 status = coreaudio_set_streamformat(core->outputDeviceID,
Akihiko Odaki986bdbc2021-06-16 23:17:21 +0900437 &streamBasicDescription);
Akihiko Odaki3ba6e3f2021-03-12 00:15:12 +0900438 if (status == kAudioHardwareBadObjectError) {
439 return 0;
440 }
bellard1d14ffa2005-10-30 18:58:22 +0000441 if (status != kAudioHardwareNoError) {
Akihiko Odaki7d6948c2021-03-12 00:15:11 +0900442 coreaudio_playback_logerr (status,
443 "Could not set samplerate %lf\n",
Akihiko Odaki986bdbc2021-06-16 23:17:21 +0900444 streamBasicDescription.mSampleRate);
bellard1d14ffa2005-10-30 18:58:22 +0000445 core->outputDeviceID = kAudioDeviceUnknown;
Akihiko Odaki7d6948c2021-03-12 00:15:11 +0900446 return status;
bellard1d14ffa2005-10-30 18:58:22 +0000447 }
448
Akihiko Odakieb1a35e2021-06-23 05:17:40 +0900449 /*
450 * set Callback.
451 *
452 * On macOS 11.3.1, Core Audio calls AudioDeviceIOProc after calling an
453 * internal function named HALB_Mutex::Lock(), which locks a mutex in
454 * HALB_IOThread::Entry(void*). HALB_Mutex::Lock() is also called in
455 * AudioObjectGetPropertyData, which is called by coreaudio driver.
456 * Therefore, the specified callback must be designed to avoid a deadlock
457 * with the callers of AudioObjectGetPropertyData.
458 */
Peter Maydell2f79a182015-11-28 21:55:24 +0000459 core->ioprocid = NULL;
460 status = AudioDeviceCreateIOProcID(core->outputDeviceID,
461 audioDeviceIOProc,
Akihiko Odaki7d6948c2021-03-12 00:15:11 +0900462 &core->hw,
Peter Maydell2f79a182015-11-28 21:55:24 +0000463 &core->ioprocid);
Akihiko Odaki3ba6e3f2021-03-12 00:15:12 +0900464 if (status == kAudioHardwareBadDeviceError) {
465 return 0;
466 }
Peter Maydell2f79a182015-11-28 21:55:24 +0000467 if (status != kAudioHardwareNoError || core->ioprocid == NULL) {
Akihiko Odaki7d6948c2021-03-12 00:15:11 +0900468 coreaudio_playback_logerr (status, "Could not set IOProc\n");
bellard1d14ffa2005-10-30 18:58:22 +0000469 core->outputDeviceID = kAudioDeviceUnknown;
Akihiko Odaki7d6948c2021-03-12 00:15:11 +0900470 return status;
bellard1d14ffa2005-10-30 18:58:22 +0000471 }
472
bellard1d14ffa2005-10-30 18:58:22 +0000473 return 0;
474}
475
Akihiko Odaki7d6948c2021-03-12 00:15:11 +0900476static void fini_out_device(coreaudioVoiceOut *core)
bellard1d14ffa2005-10-30 18:58:22 +0000477{
478 OSStatus status;
Akihiko Odaki3ba6e3f2021-03-12 00:15:12 +0900479 UInt32 isrunning;
bellard1d14ffa2005-10-30 18:58:22 +0000480
Volker Rümelinceb11652020-12-13 14:05:27 +0100481 /* stop playback */
Akihiko Odaki3ba6e3f2021-03-12 00:15:12 +0900482 status = coreaudio_get_isrunning(core->outputDeviceID, &isrunning);
483 if (status != kAudioHardwareBadObjectError) {
bellard5e941d42005-11-20 16:24:09 +0000484 if (status != kAudioHardwareNoError) {
Akihiko Odaki3ba6e3f2021-03-12 00:15:12 +0900485 coreaudio_logerr(status,
486 "Could not determine whether Device is playing\n");
487 }
488
489 if (isrunning) {
490 status = AudioDeviceStop(core->outputDeviceID, core->ioprocid);
491 if (status != kAudioHardwareBadDeviceError && status != kAudioHardwareNoError) {
492 coreaudio_logerr(status, "Could not stop playback\n");
493 }
bellard5e941d42005-11-20 16:24:09 +0000494 }
bellard1d14ffa2005-10-30 18:58:22 +0000495 }
Volker Rümelinceb11652020-12-13 14:05:27 +0100496
497 /* remove callback */
498 status = AudioDeviceDestroyIOProcID(core->outputDeviceID,
499 core->ioprocid);
Akihiko Odaki3ba6e3f2021-03-12 00:15:12 +0900500 if (status != kAudioHardwareBadDeviceError && status != kAudioHardwareNoError) {
Volker Rümelinceb11652020-12-13 14:05:27 +0100501 coreaudio_logerr(status, "Could not remove IOProc\n");
502 }
bellard1d14ffa2005-10-30 18:58:22 +0000503 core->outputDeviceID = kAudioDeviceUnknown;
Akihiko Odaki7d6948c2021-03-12 00:15:11 +0900504}
505
Akihiko Odaki3ba6e3f2021-03-12 00:15:12 +0900506static void update_device_playback_state(coreaudioVoiceOut *core)
507{
508 OSStatus status;
509 UInt32 isrunning;
510
511 status = coreaudio_get_isrunning(core->outputDeviceID, &isrunning);
512 if (status != kAudioHardwareNoError) {
513 if (status != kAudioHardwareBadObjectError) {
514 coreaudio_logerr(status,
515 "Could not determine whether Device is playing\n");
516 }
517
518 return;
519 }
520
521 if (core->enabled) {
522 /* start playback */
523 if (!isrunning) {
524 status = AudioDeviceStart(core->outputDeviceID, core->ioprocid);
525 if (status != kAudioHardwareBadDeviceError && status != kAudioHardwareNoError) {
526 coreaudio_logerr (status, "Could not resume playback\n");
527 }
528 }
529 } else {
530 /* stop playback */
531 if (isrunning) {
532 status = AudioDeviceStop(core->outputDeviceID,
533 core->ioprocid);
534 if (status != kAudioHardwareBadDeviceError && status != kAudioHardwareNoError) {
535 coreaudio_logerr(status, "Could not pause playback\n");
536 }
537 }
538 }
539}
540
Akihiko Odakieb1a35e2021-06-23 05:17:40 +0900541/* called without iothread lock. */
Akihiko Odaki3ba6e3f2021-03-12 00:15:12 +0900542static OSStatus handle_voice_change(
543 AudioObjectID in_object_id,
544 UInt32 in_number_addresses,
545 const AudioObjectPropertyAddress *in_addresses,
546 void *in_client_data)
547{
Akihiko Odaki3ba6e3f2021-03-12 00:15:12 +0900548 coreaudioVoiceOut *core = in_client_data;
549
Akihiko Odakieb1a35e2021-06-23 05:17:40 +0900550 qemu_mutex_lock_iothread();
Akihiko Odaki3ba6e3f2021-03-12 00:15:12 +0900551
552 if (core->outputDeviceID) {
553 fini_out_device(core);
554 }
555
Akihiko Odaki44ccb2d2022-03-06 21:34:10 +0900556 if (!init_out_device(core)) {
Akihiko Odaki3ba6e3f2021-03-12 00:15:12 +0900557 update_device_playback_state(core);
558 }
559
Akihiko Odakieb1a35e2021-06-23 05:17:40 +0900560 qemu_mutex_unlock_iothread();
Akihiko Odaki44ccb2d2022-03-06 21:34:10 +0900561 return 0;
Akihiko Odaki3ba6e3f2021-03-12 00:15:12 +0900562}
563
Akihiko Odaki7d6948c2021-03-12 00:15:11 +0900564static int coreaudio_init_out(HWVoiceOut *hw, struct audsettings *as,
565 void *drv_opaque)
566{
567 OSStatus status;
568 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
569 int err;
570 Audiodev *dev = drv_opaque;
571 AudiodevCoreaudioPerDirectionOptions *cpdo = dev->u.coreaudio.out;
572 struct audsettings obt_as;
573
574 /* create mutex */
Akihiko Odakieb1a35e2021-06-23 05:17:40 +0900575 err = pthread_mutex_init(&core->buf_mutex, NULL);
Akihiko Odaki7d6948c2021-03-12 00:15:11 +0900576 if (err) {
577 dolog("Could not create mutex\nReason: %s\n", strerror (err));
Akihiko Odakieb1a35e2021-06-23 05:17:40 +0900578 return -1;
Akihiko Odaki7d6948c2021-03-12 00:15:11 +0900579 }
580
581 obt_as = *as;
582 as = &obt_as;
583 as->fmt = AUDIO_FORMAT_F32;
584 audio_pcm_init_info (&hw->info, as);
585
586 core->frameSizeSetting = audio_buffer_frames(
587 qapi_AudiodevCoreaudioPerDirectionOptions_base(cpdo), as, 11610);
588
589 core->bufferCount = cpdo->has_buffer_count ? cpdo->buffer_count : 4;
Akihiko Odaki7d6948c2021-03-12 00:15:11 +0900590
Akihiko Odaki3ba6e3f2021-03-12 00:15:12 +0900591 status = AudioObjectAddPropertyListener(kAudioObjectSystemObject,
592 &voice_addr, handle_voice_change,
593 core);
594 if (status != kAudioHardwareNoError) {
595 coreaudio_playback_logerr (status,
596 "Could not listen to voice property change\n");
Akihiko Odakieb1a35e2021-06-23 05:17:40 +0900597 return -1;
Akihiko Odaki7d6948c2021-03-12 00:15:11 +0900598 }
599
Akihiko Odaki3ba6e3f2021-03-12 00:15:12 +0900600 if (init_out_device(core)) {
Akihiko Odakieb1a35e2021-06-23 05:17:40 +0900601 status = AudioObjectRemovePropertyListener(kAudioObjectSystemObject,
602 &voice_addr,
603 handle_voice_change,
604 core);
605 if (status != kAudioHardwareNoError) {
606 coreaudio_playback_logerr(status,
607 "Could not remove voice property change listener\n");
608 }
Akihiko Odakibd7819d2022-02-26 20:59:53 +0900609
610 return -1;
Akihiko Odaki3ba6e3f2021-03-12 00:15:12 +0900611 }
612
Akihiko Odaki7d6948c2021-03-12 00:15:11 +0900613 return 0;
614}
615
616static void coreaudio_fini_out (HWVoiceOut *hw)
617{
618 OSStatus status;
619 int err;
620 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
621
Akihiko Odaki3ba6e3f2021-03-12 00:15:12 +0900622 status = AudioObjectRemovePropertyListener(kAudioObjectSystemObject,
623 &voice_addr,
624 handle_voice_change,
625 core);
626 if (status != kAudioHardwareNoError) {
627 coreaudio_logerr(status, "Could not remove voice property change listener\n");
628 }
629
Akihiko Odaki7d6948c2021-03-12 00:15:11 +0900630 fini_out_device(core);
bellard1d14ffa2005-10-30 18:58:22 +0000631
632 /* destroy mutex */
Akihiko Odakieb1a35e2021-06-23 05:17:40 +0900633 err = pthread_mutex_destroy(&core->buf_mutex);
bellard1d14ffa2005-10-30 18:58:22 +0000634 if (err) {
bellardc0fe3822005-11-05 18:55:28 +0000635 dolog("Could not destroy mutex\nReason: %s\n", strerror (err));
bellard1d14ffa2005-10-30 18:58:22 +0000636 }
637}
638
Kővágó, Zoltán571a8c52019-09-19 23:24:22 +0200639static void coreaudio_enable_out(HWVoiceOut *hw, bool enable)
bellard1d14ffa2005-10-30 18:58:22 +0000640{
bellard1d14ffa2005-10-30 18:58:22 +0000641 coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
642
Akihiko Odaki3ba6e3f2021-03-12 00:15:12 +0900643 core->enabled = enable;
644 update_device_playback_state(core);
bellard1d14ffa2005-10-30 18:58:22 +0000645}
646
Kővágó, Zoltán71830222019-03-08 23:34:15 +0100647static void *coreaudio_audio_init(Audiodev *dev)
bellard1d14ffa2005-10-30 18:58:22 +0000648{
Kővágó, Zoltán17c56dc2019-03-08 23:34:17 +0100649 return dev;
bellard1d14ffa2005-10-30 18:58:22 +0000650}
651
652static void coreaudio_audio_fini (void *opaque)
653{
bellard1d14ffa2005-10-30 18:58:22 +0000654}
655
blueswir135f4b582008-10-06 18:08:30 +0000656static struct audio_pcm_ops coreaudio_pcm_ops = {
Juan Quintela1dd3e4d2009-08-11 02:31:15 +0200657 .init_out = coreaudio_init_out,
658 .fini_out = coreaudio_fini_out,
Volker Rümelinfdc8c5f2020-01-23 08:49:39 +0100659 /* wrapper for audio_generic_write */
Kővágó, Zoltán2ceb8242019-09-19 23:24:11 +0200660 .write = coreaudio_write,
Volker Rümelin98334382022-03-01 20:13:06 +0100661 /* wrapper for audio_generic_buffer_get_free */
662 .buffer_get_free = coreaudio_buffer_get_free,
Volker Rümelinfdc8c5f2020-01-23 08:49:39 +0100663 /* wrapper for audio_generic_get_buffer_out */
Kővágó, Zoltán2ceb8242019-09-19 23:24:11 +0200664 .get_buffer_out = coreaudio_get_buffer_out,
Volker Rümelinfdc8c5f2020-01-23 08:49:39 +0100665 /* wrapper for audio_generic_put_buffer_out */
666 .put_buffer_out = coreaudio_put_buffer_out,
Kővágó, Zoltán571a8c52019-09-19 23:24:22 +0200667 .enable_out = coreaudio_enable_out
bellard1d14ffa2005-10-30 18:58:22 +0000668};
669
Gerd Hoffmannd3893a32018-03-06 08:40:47 +0100670static struct audio_driver coreaudio_audio_driver = {
Juan Quintelabee37f32009-08-11 02:31:14 +0200671 .name = "coreaudio",
672 .descr = "CoreAudio http://developer.apple.com/audio/coreaudio.html",
Juan Quintelabee37f32009-08-11 02:31:14 +0200673 .init = coreaudio_audio_init,
674 .fini = coreaudio_audio_fini,
675 .pcm_ops = &coreaudio_pcm_ops,
676 .can_be_default = 1,
677 .max_voices_out = 1,
678 .max_voices_in = 0,
679 .voice_size_out = sizeof (coreaudioVoiceOut),
680 .voice_size_in = 0
bellard1d14ffa2005-10-30 18:58:22 +0000681};
Gerd Hoffmannd3893a32018-03-06 08:40:47 +0100682
683static void register_audio_coreaudio(void)
684{
685 audio_driver_register(&coreaudio_audio_driver);
686}
687type_init(register_audio_coreaudio);