Statistics
| Branch: | Revision:

root / audio / coreaudio.c @ 35f4b58c

History | View | Annotate | Download (15.3 kB)

1
/*
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

    
25
#include <CoreAudio/CoreAudio.h>
26
#include <string.h>             /* strerror */
27
#include <pthread.h>            /* pthread_X */
28

    
29
#include "qemu-common.h"
30
#include "audio.h"
31

    
32
#define AUDIO_CAP "coreaudio"
33
#include "audio_int.h"
34

    
35
struct {
36
    int buffer_frames;
37
    int nbuffers;
38
    int isAtexit;
39
} conf = {
40
    .buffer_frames = 512,
41
    .nbuffers = 4,
42
    .isAtexit = 0
43
};
44

    
45
typedef struct coreaudioVoiceOut {
46
    HWVoiceOut hw;
47
    pthread_mutex_t mutex;
48
    int isAtexit;
49
    AudioDeviceID outputDeviceID;
50
    UInt32 audioDevicePropertyBufferFrameSize;
51
    AudioStreamBasicDescription outputStreamBasicDescription;
52
    int live;
53
    int decr;
54
    int rpos;
55
} coreaudioVoiceOut;
56

    
57
static void coreaudio_logstatus (OSStatus status)
58
{
59
    char *str = "BUG";
60

    
61
    switch(status) {
62
    case kAudioHardwareNoError:
63
        str = "kAudioHardwareNoError";
64
        break;
65

    
66
    case kAudioHardwareNotRunningError:
67
        str = "kAudioHardwareNotRunningError";
68
        break;
69

    
70
    case kAudioHardwareUnspecifiedError:
71
        str = "kAudioHardwareUnspecifiedError";
72
        break;
73

    
74
    case kAudioHardwareUnknownPropertyError:
75
        str = "kAudioHardwareUnknownPropertyError";
76
        break;
77

    
78
    case kAudioHardwareBadPropertySizeError:
79
        str = "kAudioHardwareBadPropertySizeError";
80
        break;
81

    
82
    case kAudioHardwareIllegalOperationError:
83
        str = "kAudioHardwareIllegalOperationError";
84
        break;
85

    
86
    case kAudioHardwareBadDeviceError:
87
        str = "kAudioHardwareBadDeviceError";
88
        break;
89

    
90
    case kAudioHardwareBadStreamError:
91
        str = "kAudioHardwareBadStreamError";
92
        break;
93

    
94
    case kAudioHardwareUnsupportedOperationError:
95
        str = "kAudioHardwareUnsupportedOperationError";
96
        break;
97

    
98
    case kAudioDeviceUnsupportedFormatError:
99
        str = "kAudioDeviceUnsupportedFormatError";
100
        break;
101

    
102
    case kAudioDevicePermissionsError:
103
        str = "kAudioDevicePermissionsError";
104
        break;
105

    
106
    default:
107
        AUD_log (AUDIO_CAP, "Reason: status code %ld\n", status);
108
        return;
109
    }
110

    
111
    AUD_log (AUDIO_CAP, "Reason: %s\n", str);
112
}
113

    
114
static void GCC_FMT_ATTR (2, 3) coreaudio_logerr (
115
    OSStatus status,
116
    const char *fmt,
117
    ...
118
    )
119
{
120
    va_list ap;
121

    
122
    va_start (ap, fmt);
123
    AUD_log (AUDIO_CAP, fmt, ap);
124
    va_end (ap);
125

    
126
    coreaudio_logstatus (status);
127
}
128

    
129
static void GCC_FMT_ATTR (3, 4) coreaudio_logerr2 (
130
    OSStatus status,
131
    const char *typ,
132
    const char *fmt,
133
    ...
134
    )
135
{
136
    va_list ap;
137

    
138
    AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ);
139

    
140
    va_start (ap, fmt);
141
    AUD_vlog (AUDIO_CAP, fmt, ap);
142
    va_end (ap);
143

    
144
    coreaudio_logstatus (status);
145
}
146

    
147
static inline UInt32 isPlaying (AudioDeviceID outputDeviceID)
148
{
149
    OSStatus status;
150
    UInt32 result = 0;
151
    UInt32 propertySize = sizeof(outputDeviceID);
152
    status = AudioDeviceGetProperty(
153
        outputDeviceID, 0, 0,
154
        kAudioDevicePropertyDeviceIsRunning, &propertySize, &result);
155
    if (status != kAudioHardwareNoError) {
156
        coreaudio_logerr(status,
157
                         "Could not determine whether Device is playing\n");
158
    }
159
    return result;
160
}
161

    
162
static void coreaudio_atexit (void)
163
{
164
    conf.isAtexit = 1;
165
}
166

    
167
static int coreaudio_lock (coreaudioVoiceOut *core, const char *fn_name)
168
{
169
    int err;
170

    
171
    err = pthread_mutex_lock (&core->mutex);
172
    if (err) {
173
        dolog ("Could not lock voice for %s\nReason: %s\n",
174
               fn_name, strerror (err));
175
        return -1;
176
    }
177
    return 0;
178
}
179

    
180
static int coreaudio_unlock (coreaudioVoiceOut *core, const char *fn_name)
181
{
182
    int err;
183

    
184
    err = pthread_mutex_unlock (&core->mutex);
185
    if (err) {
186
        dolog ("Could not unlock voice for %s\nReason: %s\n",
187
               fn_name, strerror (err));
188
        return -1;
189
    }
190
    return 0;
191
}
192

    
193
static int coreaudio_run_out (HWVoiceOut *hw)
194
{
195
    int live, decr;
196
    coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
197

    
198
    if (coreaudio_lock (core, "coreaudio_run_out")) {
199
        return 0;
200
    }
201

    
202
    live = audio_pcm_hw_get_live_out (hw);
203

    
204
    if (core->decr > live) {
205
        ldebug ("core->decr %d live %d core->live %d\n",
206
                core->decr,
207
                live,
208
                core->live);
209
    }
210

    
211
    decr = audio_MIN (core->decr, live);
212
    core->decr -= decr;
213

    
214
    core->live = live - decr;
215
    hw->rpos = core->rpos;
216

    
217
    coreaudio_unlock (core, "coreaudio_run_out");
218
    return decr;
219
}
220

    
221
/* callback to feed audiooutput buffer */
222
static OSStatus audioDeviceIOProc(
223
    AudioDeviceID inDevice,
224
    const AudioTimeStamp* inNow,
225
    const AudioBufferList* inInputData,
226
    const AudioTimeStamp* inInputTime,
227
    AudioBufferList* outOutputData,
228
    const AudioTimeStamp* inOutputTime,
229
    void* hwptr)
230
{
231
    UInt32 frame, frameCount;
232
    float *out = outOutputData->mBuffers[0].mData;
233
    HWVoiceOut *hw = hwptr;
234
    coreaudioVoiceOut *core = (coreaudioVoiceOut *) hwptr;
235
    int rpos, live;
236
    st_sample_t *src;
237
#ifndef FLOAT_MIXENG
238
#ifdef RECIPROCAL
239
    const float scale = 1.f / UINT_MAX;
240
#else
241
    const float scale = UINT_MAX;
242
#endif
243
#endif
244

    
245
    if (coreaudio_lock (core, "audioDeviceIOProc")) {
246
        inInputTime = 0;
247
        return 0;
248
    }
249

    
250
    frameCount = core->audioDevicePropertyBufferFrameSize;
251
    live = core->live;
252

    
253
    /* if there are not enough samples, set signal and return */
254
    if (live < frameCount) {
255
        inInputTime = 0;
256
        coreaudio_unlock (core, "audioDeviceIOProc(empty)");
257
        return 0;
258
    }
259

    
260
    rpos = core->rpos;
261
    src = hw->mix_buf + rpos;
262

    
263
    /* fill buffer */
264
    for (frame = 0; frame < frameCount; frame++) {
265
#ifdef FLOAT_MIXENG
266
        *out++ = src[frame].l; /* left channel */
267
        *out++ = src[frame].r; /* right channel */
268
#else
269
#ifdef RECIPROCAL
270
        *out++ = src[frame].l * scale; /* left channel */
271
        *out++ = src[frame].r * scale; /* right channel */
272
#else
273
        *out++ = src[frame].l / scale; /* left channel */
274
        *out++ = src[frame].r / scale; /* right channel */
275
#endif
276
#endif
277
    }
278

    
279
    rpos = (rpos + frameCount) % hw->samples;
280
    core->decr += frameCount;
281
    core->rpos = rpos;
282

    
283
    coreaudio_unlock (core, "audioDeviceIOProc");
284
    return 0;
285
}
286

    
287
static int coreaudio_write (SWVoiceOut *sw, void *buf, int len)
288
{
289
    return audio_pcm_sw_write (sw, buf, len);
290
}
291

    
292
static int coreaudio_init_out (HWVoiceOut *hw, audsettings_t *as)
293
{
294
    OSStatus status;
295
    coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
296
    UInt32 propertySize;
297
    int err;
298
    const char *typ = "playback";
299
    AudioValueRange frameRange;
300

    
301
    /* create mutex */
302
    err = pthread_mutex_init(&core->mutex, NULL);
303
    if (err) {
304
        dolog("Could not create mutex\nReason: %s\n", strerror (err));
305
        return -1;
306
    }
307

    
308
    audio_pcm_init_info (&hw->info, as);
309

    
310
    /* open default output device */
311
    propertySize = sizeof(core->outputDeviceID);
312
    status = AudioHardwareGetProperty(
313
        kAudioHardwarePropertyDefaultOutputDevice,
314
        &propertySize,
315
        &core->outputDeviceID);
316
    if (status != kAudioHardwareNoError) {
317
        coreaudio_logerr2 (status, typ,
318
                           "Could not get default output Device\n");
319
        return -1;
320
    }
321
    if (core->outputDeviceID == kAudioDeviceUnknown) {
322
        dolog ("Could not initialize %s - Unknown Audiodevice\n", typ);
323
        return -1;
324
    }
325

    
326
    /* get minimum and maximum buffer frame sizes */
327
    propertySize = sizeof(frameRange);
328
    status = AudioDeviceGetProperty(
329
        core->outputDeviceID,
330
        0,
331
        0,
332
        kAudioDevicePropertyBufferFrameSizeRange,
333
        &propertySize,
334
        &frameRange);
335
    if (status != kAudioHardwareNoError) {
336
        coreaudio_logerr2 (status, typ,
337
                           "Could not get device buffer frame range\n");
338
        return -1;
339
    }
340

    
341
    if (frameRange.mMinimum > conf.buffer_frames) {
342
        core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMinimum;
343
        dolog ("warning: Upsizing Buffer Frames to %f\n", frameRange.mMinimum);
344
    }
345
    else if (frameRange.mMaximum < conf.buffer_frames) {
346
        core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMaximum;
347
        dolog ("warning: Downsizing Buffer Frames to %f\n", frameRange.mMaximum);
348
    }
349
    else {
350
        core->audioDevicePropertyBufferFrameSize = conf.buffer_frames;
351
    }
352

    
353
    /* set Buffer Frame Size */
354
    propertySize = sizeof(core->audioDevicePropertyBufferFrameSize);
355
    status = AudioDeviceSetProperty(
356
        core->outputDeviceID,
357
        NULL,
358
        0,
359
        false,
360
        kAudioDevicePropertyBufferFrameSize,
361
        propertySize,
362
        &core->audioDevicePropertyBufferFrameSize);
363
    if (status != kAudioHardwareNoError) {
364
        coreaudio_logerr2 (status, typ,
365
                           "Could not set device buffer frame size %ld\n",
366
                           core->audioDevicePropertyBufferFrameSize);
367
        return -1;
368
    }
369

    
370
    /* get Buffer Frame Size */
371
    propertySize = sizeof(core->audioDevicePropertyBufferFrameSize);
372
    status = AudioDeviceGetProperty(
373
        core->outputDeviceID,
374
        0,
375
        false,
376
        kAudioDevicePropertyBufferFrameSize,
377
        &propertySize,
378
        &core->audioDevicePropertyBufferFrameSize);
379
    if (status != kAudioHardwareNoError) {
380
        coreaudio_logerr2 (status, typ,
381
                           "Could not get device buffer frame size\n");
382
        return -1;
383
    }
384
    hw->samples = conf.nbuffers * core->audioDevicePropertyBufferFrameSize;
385

    
386
    /* get StreamFormat */
387
    propertySize = sizeof(core->outputStreamBasicDescription);
388
    status = AudioDeviceGetProperty(
389
        core->outputDeviceID,
390
        0,
391
        false,
392
        kAudioDevicePropertyStreamFormat,
393
        &propertySize,
394
        &core->outputStreamBasicDescription);
395
    if (status != kAudioHardwareNoError) {
396
        coreaudio_logerr2 (status, typ,
397
                           "Could not get Device Stream properties\n");
398
        core->outputDeviceID = kAudioDeviceUnknown;
399
        return -1;
400
    }
401

    
402
    /* set Samplerate */
403
    core->outputStreamBasicDescription.mSampleRate = (Float64) as->freq;
404
    propertySize = sizeof(core->outputStreamBasicDescription);
405
    status = AudioDeviceSetProperty(
406
        core->outputDeviceID,
407
        0,
408
        0,
409
        0,
410
        kAudioDevicePropertyStreamFormat,
411
        propertySize,
412
        &core->outputStreamBasicDescription);
413
    if (status != kAudioHardwareNoError) {
414
        coreaudio_logerr2 (status, typ, "Could not set samplerate %d\n",
415
                           as->freq);
416
        core->outputDeviceID = kAudioDeviceUnknown;
417
        return -1;
418
    }
419

    
420
    /* set Callback */
421
    status = AudioDeviceAddIOProc(core->outputDeviceID, audioDeviceIOProc, hw);
422
    if (status != kAudioHardwareNoError) {
423
        coreaudio_logerr2 (status, typ, "Could not set IOProc\n");
424
        core->outputDeviceID = kAudioDeviceUnknown;
425
        return -1;
426
    }
427

    
428
    /* start Playback */
429
    if (!isPlaying(core->outputDeviceID)) {
430
        status = AudioDeviceStart(core->outputDeviceID, audioDeviceIOProc);
431
        if (status != kAudioHardwareNoError) {
432
            coreaudio_logerr2 (status, typ, "Could not start playback\n");
433
            AudioDeviceRemoveIOProc(core->outputDeviceID, audioDeviceIOProc);
434
            core->outputDeviceID = kAudioDeviceUnknown;
435
            return -1;
436
        }
437
    }
438

    
439
    return 0;
440
}
441

    
442
static void coreaudio_fini_out (HWVoiceOut *hw)
443
{
444
    OSStatus status;
445
    int err;
446
    coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
447

    
448
    if (!conf.isAtexit) {
449
        /* stop playback */
450
        if (isPlaying(core->outputDeviceID)) {
451
            status = AudioDeviceStop(core->outputDeviceID, audioDeviceIOProc);
452
            if (status != kAudioHardwareNoError) {
453
                coreaudio_logerr (status, "Could not stop playback\n");
454
            }
455
        }
456

    
457
        /* remove callback */
458
        status = AudioDeviceRemoveIOProc(core->outputDeviceID,
459
                                         audioDeviceIOProc);
460
        if (status != kAudioHardwareNoError) {
461
            coreaudio_logerr (status, "Could not remove IOProc\n");
462
        }
463
    }
464
    core->outputDeviceID = kAudioDeviceUnknown;
465

    
466
    /* destroy mutex */
467
    err = pthread_mutex_destroy(&core->mutex);
468
    if (err) {
469
        dolog("Could not destroy mutex\nReason: %s\n", strerror (err));
470
    }
471
}
472

    
473
static int coreaudio_ctl_out (HWVoiceOut *hw, int cmd, ...)
474
{
475
    OSStatus status;
476
    coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
477

    
478
    switch (cmd) {
479
    case VOICE_ENABLE:
480
        /* start playback */
481
        if (!isPlaying(core->outputDeviceID)) {
482
            status = AudioDeviceStart(core->outputDeviceID, audioDeviceIOProc);
483
            if (status != kAudioHardwareNoError) {
484
                coreaudio_logerr (status, "Could not resume playback\n");
485
            }
486
        }
487
        break;
488

    
489
    case VOICE_DISABLE:
490
        /* stop playback */
491
        if (!conf.isAtexit) {
492
            if (isPlaying(core->outputDeviceID)) {
493
                status = AudioDeviceStop(core->outputDeviceID, audioDeviceIOProc);
494
                if (status != kAudioHardwareNoError) {
495
                    coreaudio_logerr (status, "Could not pause playback\n");
496
                }
497
            }
498
        }
499
        break;
500
    }
501
    return 0;
502
}
503

    
504
static void *coreaudio_audio_init (void)
505
{
506
    atexit(coreaudio_atexit);
507
    return &coreaudio_audio_init;
508
}
509

    
510
static void coreaudio_audio_fini (void *opaque)
511
{
512
    (void) opaque;
513
}
514

    
515
static struct audio_option coreaudio_options[] = {
516
    {"BUFFER_SIZE", AUD_OPT_INT, &conf.buffer_frames,
517
     "Size of the buffer in frames", NULL, 0},
518
    {"BUFFER_COUNT", AUD_OPT_INT, &conf.nbuffers,
519
     "Number of buffers", NULL, 0},
520
    {NULL, 0, NULL, NULL, NULL, 0}
521
};
522

    
523
static struct audio_pcm_ops coreaudio_pcm_ops = {
524
    coreaudio_init_out,
525
    coreaudio_fini_out,
526
    coreaudio_run_out,
527
    coreaudio_write,
528
    coreaudio_ctl_out,
529

    
530
    NULL,
531
    NULL,
532
    NULL,
533
    NULL,
534
    NULL
535
};
536

    
537
struct audio_driver coreaudio_audio_driver = {
538
    INIT_FIELD (name           = ) "coreaudio",
539
    INIT_FIELD (descr          = )
540
    "CoreAudio http://developer.apple.com/audio/coreaudio.html",
541
    INIT_FIELD (options        = ) coreaudio_options,
542
    INIT_FIELD (init           = ) coreaudio_audio_init,
543
    INIT_FIELD (fini           = ) coreaudio_audio_fini,
544
    INIT_FIELD (pcm_ops        = ) &coreaudio_pcm_ops,
545
    INIT_FIELD (can_be_default = ) 1,
546
    INIT_FIELD (max_voices_out = ) 1,
547
    INIT_FIELD (max_voices_in  = ) 0,
548
    INIT_FIELD (voice_size_out = ) sizeof (coreaudioVoiceOut),
549
    INIT_FIELD (voice_size_in  = ) 0
550
};