chiark / gitweb /
Uniform audio backend for Core Audio. There is an untested OSS one
[disorder] / lib / uaudio-coreaudio.c
CommitLineData
7a2c7068
RK
1/*
2 * This file is part of DisOrder.
3 * Copyright (C) 2009 Richard Kettlewell
4 *
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.
9 *
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.
14 *
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/>.
17 */
18/** @file lib/uaudio-coreaudio.c
19 * @brief Support for Core Audio backend */
20#include "common.h"
21
22#if HAVE_COREAUDIO_AUDIOHARDWARE_H
23
24#include "coreaudio.h"
25#include "uaudio.h"
26#include "mem.h"
27#include "log.h"
28#include "syscalls.h"
29
30/** @brief Callback to request sample data */
31static uaudio_callback *coreaudio_callback;
32
33/** @brief Userdata for @ref coreaudio_callback */
34static void *coreaudio_userdata;
35
36/** @brief Core Audio device ID */
37static AudioDeviceID coreaudio_adid;
38
39/** @brief Core Audio option names */
40static const char *const coreaudio_options[] = {
41 "device",
42 NULL
43};
44
45/** @brief Callback from Core Audio
46 *
47 * Core Audio demands floating point samples but we provide integers.
48 * So there is a conversion step in here.
49 */
50static 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;
62
63 while(nbuffers > 0) {
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);
68
69 while(nsamples > 0) {
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;
74 /* How many we get */
75 int got;
76
77 got = coreaudio_callback(input, ask, coreaudio_userdata);
78 /* Convert the samples and store in the output buffer */
79 nsamples -= got;
80 while(got > 0) {
81 --got;
82 *samples++ = *ptr++ * (0.5 / 32767);
83 }
84 }
85 /* Move on to the next buffer */
86 ++ab;
87 --nbuffers;
88 }
89 return 0;
90}
91
92static void coreaudio_start(uaudio_callback *callback,
93 void *userdata) {
94 OSStatus status;
95 UInt32 propertySize;
96 AudioStreamBasicDescription asbd;
97 const char *device;
98
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);
107 if(status)
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);
121 if(status)
122 coreaudio_fatal(status, "AudioDeviceAddIOProc");
123}
124
125static void coreaudio_stop(void) {
126}
127
128static void coreaudio_activate(void) {
129 OSStatus status;
130
131 status = AudioDeviceStart(coreaudio_adid, coreaudio_adioproc);
132 if(status)
133 coreaudio_fatal(status, "AudioDeviceStart");
134}
135
136static void coreaudio_deactivate(void) {
137 OSStatus status;
138
139 status = AudioDeviceStop(coreaudio_adid, coreaudio_adioproc);
140 if(status)
141 coreaudio_fatal(status, "AudioDeviceStop");
142}
143
144const struct uaudio uaudio_coreaudio = {
145 .name = "coreaudio",
146 .options = coreaudio_options,
147 .start = coreaudio_start,
148 .stop = coreaudio_stop,
149 .activate = coreaudio_activate,
150 .deactivate = coreaudio_deactivate
151};
152
153#endif
154
155/*
156Local Variables:
157c-basic-offset:2
158comment-column:40
159fill-column:79
160indent-tabs-mode:nil
161End:
162*/