formats: clarify setting of reverse_bytes
[sox.git] / src / coreaudio.c
blobf6f20c13c0c10c3e92eea04921f78f764529fd29
1 /* AudioCore sound handler
3 * Copyright 2008 Chris Bagwell And Sundry Contributors
4 */
6 #include "sox_i.h"
8 #include <CoreAudio/CoreAudio.h>
9 #include <pthread.h>
11 #define Buffactor 4
13 typedef struct {
14 AudioDeviceID adid;
15 pthread_mutex_t mutex;
16 pthread_cond_t cond;
17 int device_started;
18 size_t bufsize;
19 size_t bufrd;
20 size_t bufwr;
21 size_t bufrdavail;
22 float *buf;
23 } priv_t;
25 static OSStatus PlaybackIOProc(AudioDeviceID inDevice UNUSED,
26 const AudioTimeStamp *inNow UNUSED,
27 const AudioBufferList *inInputData UNUSED,
28 const AudioTimeStamp *inInputTime UNUSED,
29 AudioBufferList *outOutputData,
30 const AudioTimeStamp *inOutputTime UNUSED,
31 void *inClientData)
33 priv_t *ac = (priv_t*)((sox_format_t*)inClientData)->priv;
34 AudioBuffer *buf;
35 size_t copylen, avail;
37 pthread_mutex_lock(&ac->mutex);
39 for(buf = outOutputData->mBuffers;
40 buf != outOutputData->mBuffers + outOutputData->mNumberBuffers;
41 buf++){
43 copylen = buf->mDataByteSize / sizeof(float);
44 if(copylen > ac->bufrdavail)
45 copylen = ac->bufrdavail;
47 avail = ac->bufsize - ac->bufrd;
48 if(buf->mData == NULL){
49 /*do nothing-hardware can't play audio*/
50 }else if(copylen > avail){
51 memcpy(buf->mData, ac->buf + ac->bufrd, avail * sizeof(float));
52 memcpy((float*)buf->mData + avail, ac->buf, (copylen - avail) * sizeof(float));
53 }else{
54 memcpy(buf->mData, ac->buf + ac->bufrd, copylen * sizeof(float));
57 buf->mDataByteSize = copylen * sizeof(float);
58 ac->bufrd += copylen;
59 if(ac->bufrd >= ac->bufsize)
60 ac->bufrd -= ac->bufsize;
61 ac->bufrdavail -= copylen;
64 pthread_cond_signal(&ac->cond);
65 pthread_mutex_unlock(&ac->mutex);
67 return kAudioHardwareNoError;
70 static OSStatus RecIOProc(AudioDeviceID inDevice UNUSED,
71 const AudioTimeStamp *inNow UNUSED,
72 const AudioBufferList *inInputData,
73 const AudioTimeStamp *inInputTime UNUSED,
74 AudioBufferList *outOutputData UNUSED,
75 const AudioTimeStamp *inOutputTime UNUSED,
76 void *inClientData)
78 priv_t *ac = (priv_t *)((sox_format_t*)inClientData)->priv;
79 AudioBuffer const *buf;
80 size_t nfree, copylen, avail;
82 pthread_mutex_lock(&ac->mutex);
84 for(buf = inInputData->mBuffers;
85 buf != inInputData->mBuffers + inInputData->mNumberBuffers;
86 buf++){
88 if(buf->mData == NULL)
89 continue;
91 copylen = buf->mDataByteSize / sizeof(float);
92 nfree = ac->bufsize - ac->bufrdavail - 1;
93 if(nfree == 0)
94 lsx_warn("coreaudio: unhandled buffer overrun. Data discarded.");
96 if(copylen > nfree)
97 copylen = nfree;
99 avail = ac->bufsize - ac->bufwr;
100 if(copylen > avail){
101 memcpy(ac->buf + ac->bufwr, buf->mData, avail * sizeof(float));
102 memcpy(ac->buf, (float*)buf->mData + avail, (copylen - avail) * sizeof(float));
103 }else{
104 memcpy(ac->buf + ac->bufwr, buf->mData, copylen * sizeof(float));
107 ac->bufwr += copylen;
108 if(ac->bufwr >= ac->bufsize)
109 ac->bufwr -= ac->bufsize;
110 ac->bufrdavail += copylen;
113 pthread_cond_signal(&ac->cond);
114 pthread_mutex_unlock(&ac->mutex);
116 return kAudioHardwareNoError;
119 static int setup(sox_format_t *ft, int is_input)
121 priv_t *ac = (priv_t *)ft->priv;
122 OSStatus status;
123 UInt32 property_size;
124 struct AudioStreamBasicDescription stream_desc;
125 int32_t buf_size;
126 int rc;
128 if (strncmp(ft->filename, "default", (size_t)7) == 0)
130 property_size = sizeof(ac->adid);
131 if (is_input)
132 status = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &property_size, &ac->adid);
133 else
134 status = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &property_size, &ac->adid);
136 else
138 Boolean is_writable;
139 status = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &property_size, &is_writable);
141 if (status == noErr)
143 int device_count = property_size/sizeof(AudioDeviceID);
144 AudioDeviceID *devices;
146 devices = malloc(property_size);
147 status = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &property_size, devices);
149 if (status == noErr)
151 int i;
152 for (i = 0; i < device_count; i++)
154 char name[256];
155 status = AudioDeviceGetProperty(devices[i],0,false,kAudioDevicePropertyDeviceName,&property_size,&name);
157 lsx_report("Found Audio Device \"%s\"\n",name);
159 /* String returned from OS is truncated so only compare
160 * as much as returned.
162 if (strncmp(name,ft->filename,strlen(name)) == 0)
164 ac->adid = devices[i];
165 break;
169 free(devices);
173 if (status || ac->adid == kAudioDeviceUnknown)
175 lsx_fail_errno(ft, SOX_EPERM, "can not open audio device");
176 return SOX_EOF;
179 /* Query device to get initial values */
180 property_size = sizeof(struct AudioStreamBasicDescription);
181 status = AudioDeviceGetProperty(ac->adid, 0, is_input,
182 kAudioDevicePropertyStreamFormat,
183 &property_size, &stream_desc);
184 if (status)
186 lsx_fail_errno(ft, SOX_EPERM, "can not get audio device properties");
187 return SOX_EOF;
190 if (!(stream_desc.mFormatFlags & kLinearPCMFormatFlagIsFloat))
192 lsx_fail_errno(ft, SOX_EPERM, "audio device does not accept floats");
193 return SOX_EOF;
196 /* OS X effectively only supports these values. */
197 ft->signal.channels = 2;
198 ft->signal.rate = 44100;
199 ft->encoding.bits_per_sample = 32;
201 /* TODO: My limited experience with hardware can only get floats working
202 * withh a fixed sample rate and stereo. I know that is a limitiation of
203 * audio device I have so this may not be standard operating orders.
204 * If some hardware supports setting sample rates and channel counts
205 * then should do that over resampling and mixing.
207 #if 0
208 stream_desc.mSampleRate = ft->signal.rate;
209 stream_desc.mChannelsPerFrame = ft->signal.channels;
211 /* Write them back */
212 property_size = sizeof(struct AudioStreamBasicDescription);
213 status = AudioDeviceSetProperty(ac->adid, NULL, 0, is_input,
214 kAudioDevicePropertyStreamFormat,
215 property_size, &stream_desc);
216 if (status)
218 lsx_fail_errno(ft, SOX_EPERM, "can not set audio device properties");
219 return SOX_EOF;
222 /* Query device to see if it worked */
223 property_size = sizeof(struct AudioStreamBasicDescription);
224 status = AudioDeviceGetProperty(ac->adid, 0, is_input,
225 kAudioDevicePropertyStreamFormat,
226 &property_size, &stream_desc);
228 if (status)
230 lsx_fail_errno(ft, SOX_EPERM, "can not get audio device properties");
231 return SOX_EOF;
233 #endif
235 if (stream_desc.mChannelsPerFrame != ft->signal.channels)
237 lsx_debug("audio device did not accept %d channels. Use %d channels instead.", (int)ft->signal.channels,
238 (int)stream_desc.mChannelsPerFrame);
239 ft->signal.channels = stream_desc.mChannelsPerFrame;
242 if (stream_desc.mSampleRate != ft->signal.rate)
244 lsx_debug("audio device did not accept %d sample rate. Use %d instead.", (int)ft->signal.rate,
245 (int)stream_desc.mSampleRate);
246 ft->signal.rate = stream_desc.mSampleRate;
249 ac->bufsize = sox_globals.bufsiz / sizeof(sox_sample_t) * Buffactor;
250 ac->bufrd = 0;
251 ac->bufwr = 0;
252 ac->bufrdavail = 0;
253 ac->buf = lsx_malloc(ac->bufsize * sizeof(float));
255 buf_size = sox_globals.bufsiz / sizeof(sox_sample_t) * sizeof(float);
256 property_size = sizeof(buf_size);
257 status = AudioDeviceSetProperty(ac->adid, NULL, 0, is_input,
258 kAudioDevicePropertyBufferSize,
259 property_size, &buf_size);
261 rc = pthread_mutex_init(&ac->mutex, NULL);
262 if (rc)
264 lsx_fail_errno(ft, SOX_EPERM, "failed initializing mutex");
265 return SOX_EOF;
268 rc = pthread_cond_init(&ac->cond, NULL);
269 if (rc)
271 lsx_fail_errno(ft, SOX_EPERM, "failed initializing condition");
272 return SOX_EOF;
275 ac->device_started = 0;
277 /* Registers callback with the device without activating it. */
278 if (is_input)
279 status = AudioDeviceAddIOProc(ac->adid, RecIOProc, (void *)ft);
280 else
281 status = AudioDeviceAddIOProc(ac->adid, PlaybackIOProc, (void *)ft);
283 return SOX_SUCCESS;
286 static int startread(sox_format_t *ft)
288 return setup(ft, 1);
291 static size_t read_samples(sox_format_t *ft, sox_sample_t *buf, size_t nsamp)
293 priv_t *ac = (priv_t *)ft->priv;
294 size_t len;
295 SOX_SAMPLE_LOCALS;
297 if (!ac->device_started) {
298 AudioDeviceStart(ac->adid, RecIOProc);
299 ac->device_started = 1;
302 pthread_mutex_lock(&ac->mutex);
304 /* Wait until input buffer has been filled by device driver */
305 while (ac->bufrdavail == 0)
306 pthread_cond_wait(&ac->cond, &ac->mutex);
308 len = 0;
309 while(len < nsamp && ac->bufrdavail > 0){
310 buf[len] = SOX_FLOAT_32BIT_TO_SAMPLE(ac->buf[ac->bufrd], ft->clips);
311 len++;
312 ac->bufrd++;
313 if(ac->bufrd == ac->bufsize)
314 ac->bufrd = 0;
315 ac->bufrdavail--;
318 pthread_mutex_unlock(&ac->mutex);
320 return len;
323 static int stopread(sox_format_t * ft)
325 priv_t *ac = (priv_t *)ft->priv;
327 AudioDeviceStop(ac->adid, RecIOProc);
328 AudioDeviceRemoveIOProc(ac->adid, RecIOProc);
329 pthread_cond_destroy(&ac->cond);
330 pthread_mutex_destroy(&ac->mutex);
331 free(ac->buf);
333 return SOX_SUCCESS;
336 static int startwrite(sox_format_t * ft)
338 return setup(ft, 0);
341 static size_t write_samples(sox_format_t *ft, const sox_sample_t *buf, size_t nsamp)
343 priv_t *ac = (priv_t *)ft->priv;
344 size_t i;
346 SOX_SAMPLE_LOCALS;
348 pthread_mutex_lock(&ac->mutex);
350 /* Wait to start until mutex is locked to help prevent callback
351 * getting zero samples.
353 if(!ac->device_started){
354 if(AudioDeviceStart(ac->adid, PlaybackIOProc)){
355 pthread_mutex_unlock(&ac->mutex);
356 return SOX_EOF;
358 ac->device_started = 1;
361 /* globals.bufsize is in samples
362 * buf_offset is in bytes
363 * buf_size is in bytes
365 for(i = 0; i < nsamp; i++){
366 while(ac->bufrdavail == ac->bufsize - 1)
367 pthread_cond_wait(&ac->cond, &ac->mutex);
369 ac->buf[ac->bufwr] = SOX_SAMPLE_TO_FLOAT_32BIT(buf[i], ft->clips);
370 ac->bufwr++;
371 if(ac->bufwr == ac->bufsize)
372 ac->bufwr = 0;
373 ac->bufrdavail++;
376 pthread_mutex_unlock(&ac->mutex);
377 return nsamp;
381 static int stopwrite(sox_format_t * ft)
383 priv_t *ac = (priv_t *)ft->priv;
385 if(ac->device_started){
386 pthread_mutex_lock(&ac->mutex);
388 while (ac->bufrdavail > 0)
389 pthread_cond_wait(&ac->cond, &ac->mutex);
391 pthread_mutex_unlock(&ac->mutex);
393 AudioDeviceStop(ac->adid, PlaybackIOProc);
396 AudioDeviceRemoveIOProc(ac->adid, PlaybackIOProc);
397 pthread_cond_destroy(&ac->cond);
398 pthread_mutex_destroy(&ac->mutex);
399 free(ac->buf);
401 return SOX_SUCCESS;
404 LSX_FORMAT_HANDLER(coreaudio)
406 static char const *const names[] = { "coreaudio", NULL };
407 static unsigned const write_encodings[] = {
408 SOX_ENCODING_FLOAT, 32, 0,
410 static sox_format_handler_t const handler = {SOX_LIB_VERSION_CODE,
411 "Mac AudioCore device driver",
412 names, SOX_FILE_DEVICE | SOX_FILE_NOSTDIO,
413 startread, read_samples, stopread,
414 startwrite, write_samples, stopwrite,
415 NULL, write_encodings, NULL, sizeof(priv_t)
417 return &handler;