2 * This file is part of DisOrder.
3 * Copyright (C) 2009 Richard Kettlewell
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 /** @file lib/uaudio-coreaudio.c
19 * @brief Support for Core Audio backend */
22 #if HAVE_COREAUDIO_AUDIOHARDWARE_H
24 #include "coreaudio.h"
30 /** @brief Callback to request sample data */
31 static uaudio_callback *coreaudio_callback;
33 /** @brief Userdata for @ref coreaudio_callback */
34 static void *coreaudio_userdata;
36 /** @brief Core Audio device ID */
37 static AudioDeviceID coreaudio_adid;
39 /** @brief Core Audio option names */
40 static const char *const coreaudio_options[] = {
45 /** @brief Callback from Core Audio
47 * Core Audio demands floating point samples but we provide integers.
48 * So there is a conversion step in here.
50 static OSStatus coreaudio_adioproc
51 (AudioDeviceID attribute((unused)) inDevice,
52 const AudioTimeStamp attribute((unused)) *inNow,
53 const AudioBufferList attribute((unused)) *inInputData,
54 const AudioTimeStamp attribute((unused)) *inInputTime,
55 AudioBufferList *outOutputData,
56 const AudioTimeStamp attribute((unused)) *inOutputTime,
57 void attribute((unused)) *inClientData) {
58 /* Number of buffers we must fill */
59 unsigned nbuffers = outOutputData->mNumberBuffers;
60 /* Pointer to buffer to fill */
61 AudioBuffer *ab = outOutputData->mBuffers;
64 /* Where to store converted sample data */
65 float *samples = ab->mData;
66 /* Number of samples left to fill */
67 size_t nsamples = ab->mDataByteSize / sizeof (float);
70 /* Integer-format input buffer */
71 int16_t input[1024], *ptr = input;
72 /* How many samples we'll ask for */
73 const int ask = nsamples > 1024 ? 1024 : (int)nsamples;
77 got = coreaudio_callback(input, ask, coreaudio_userdata);
78 /* Convert the samples and store in the output buffer */
82 *samples++ = *ptr++ * (0.5 / 32767);
85 /* Move on to the next buffer */
92 static void coreaudio_start(uaudio_callback *callback,
96 AudioStreamBasicDescription asbd;
99 coreaudio_callback = callback;
100 coreaudio_userdata = userdata;
101 device = uaudio_get("device");
102 coreaudio_adid = coreaudio_getdevice(device);
103 propertySize = sizeof asbd;
104 status = AudioDeviceGetProperty(coreaudio_adid, 0, false,
105 kAudioDevicePropertyStreamFormat,
106 &propertySize, &asbd);
108 coreaudio_fatal(status, "AudioHardwareGetProperty");
109 D(("mSampleRate %f", asbd.mSampleRate));
110 D(("mFormatID %08lx", asbd.mFormatID));
111 D(("mFormatFlags %08lx", asbd.mFormatFlags));
112 D(("mBytesPerPacket %08lx", asbd.mBytesPerPacket));
113 D(("mFramesPerPacket %08lx", asbd.mFramesPerPacket));
114 D(("mBytesPerFrame %08lx", asbd.mBytesPerFrame));
115 D(("mChannelsPerFrame %08lx", asbd.mChannelsPerFrame));
116 D(("mBitsPerChannel %08lx", asbd.mBitsPerChannel));
117 D(("mReserved %08lx", asbd.mReserved));
118 if(asbd.mFormatID != kAudioFormatLinearPCM)
119 disorder_fatal(0, "audio device does not support kAudioFormatLinearPCM");
120 status = AudioDeviceAddIOProc(coreaudio_adid, coreaudio_adioproc, 0);
122 coreaudio_fatal(status, "AudioDeviceAddIOProc");
125 static void coreaudio_stop(void) {
128 static void coreaudio_activate(void) {
131 status = AudioDeviceStart(coreaudio_adid, coreaudio_adioproc);
133 coreaudio_fatal(status, "AudioDeviceStart");
136 static void coreaudio_deactivate(void) {
139 status = AudioDeviceStop(coreaudio_adid, coreaudio_adioproc);
141 coreaudio_fatal(status, "AudioDeviceStop");
144 const struct uaudio uaudio_coreaudio = {
146 .options = coreaudio_options,
147 .start = coreaudio_start,
148 .stop = coreaudio_stop,
149 .activate = coreaudio_activate,
150 .deactivate = coreaudio_deactivate