Statistics
| Branch: | Revision:

root / audio / coreaudio.c @ d9cbb0f3

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
    const 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, int live)
194
{
195
    int decr;
196
    coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
197

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

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

    
209
    decr = audio_MIN (core->decr, live);
210
    core->decr -= decr;
211

    
212
    core->live = live - decr;
213
    hw->rpos = core->rpos;
214

    
215
    coreaudio_unlock (core, "coreaudio_run_out");
216
    return decr;
217
}
218

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

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

    
248
    frameCount = core->audioDevicePropertyBufferFrameSize;
249
    live = core->live;
250

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

    
258
    rpos = core->rpos;
259
    src = hw->mix_buf + rpos;
260

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

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

    
281
    coreaudio_unlock (core, "audioDeviceIOProc");
282
    return 0;
283
}
284

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

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

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

    
306
    audio_pcm_init_info (&hw->info, as);
307

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

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

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

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

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

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

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

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

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

    
437
    return 0;
438
}
439

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

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

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

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

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

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

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

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

    
508
static void coreaudio_audio_fini (void *opaque)
509
{
510
    (void) opaque;
511
}
512

    
513
static struct audio_option coreaudio_options[] = {
514
    {
515
        .name  = "BUFFER_SIZE",
516
        .tag   = AUD_OPT_INT,
517
        .valp  = &conf.buffer_frames,
518
        .descr = "Size of the buffer in frames"
519
    },
520
    {
521
        .name  = "BUFFER_COUNT",
522
        .tag   = AUD_OPT_INT,
523
        .valp  = &conf.nbuffers,
524
        .descr = "Number of buffers"
525
    },
526
    { /* End of list */ }
527
};
528

    
529
static struct audio_pcm_ops coreaudio_pcm_ops = {
530
    .init_out = coreaudio_init_out,
531
    .fini_out = coreaudio_fini_out,
532
    .run_out  = coreaudio_run_out,
533
    .write    = coreaudio_write,
534
    .ctl_out  = coreaudio_ctl_out
535
};
536

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