Initial revision 6759
[qball-mpd.git] / src / audioOutputs / .svn / text-base / audioOutput_osx.c.svn-base
blob1caebade54a5c4b020d183f8dcffdaac5c70ac1d
1 /* the Music Player Daemon (MPD)
2  * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
3  * This project's homepage is: http://www.musicpd.org
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 2 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  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  */
19 #include "../audioOutput.h"
21 #ifdef HAVE_OSX
23 #include <AudioUnit/AudioUnit.h>
24 #include <stdlib.h>
25 #include <pthread.h>
27 #include "../log.h"
29 typedef struct _OsxData {
30         AudioUnit au;
31         pthread_mutex_t mutex;
32         pthread_cond_t condition;
33         char *buffer;
34         int bufferSize;
35         int pos;
36         int len;
37         int started;
38 } OsxData;
40 static OsxData *newOsxData()
42         OsxData *ret = xmalloc(sizeof(OsxData));
44         pthread_mutex_init(&ret->mutex, NULL);
45         pthread_cond_init(&ret->condition, NULL);
47         ret->pos = 0;
48         ret->len = 0;
49         ret->started = 0;
50         ret->buffer = NULL;
51         ret->bufferSize = 0;
53         return ret;
56 static int osx_testDefault()
58         /*AudioUnit au;
59            ComponentDescription desc;
60            Component comp;
62            desc.componentType = kAudioUnitType_Output;
63            desc.componentSubType = kAudioUnitSubType_Output;
64            desc.componentManufacturer = kAudioUnitManufacturer_Apple;
65            desc.componentFlags = 0;
66            desc.componentFlagsMask = 0;
68            comp = FindNextComponent(NULL, &desc);
69            if(!comp) {
70            ERROR("Unable to open default OS X defice\n");
71            return -1;
72            }
74            if(OpenAComponent(comp, &au) != noErr) {
75            ERROR("Unable to open default OS X defice\n");
76            return -1;
77            }
79            CloseComponent(au); */
81         return 0;
84 static int osx_initDriver(AudioOutput * audioOutput, ConfigParam * param)
86         OsxData *od = newOsxData();
88         audioOutput->data = od;
90         return 0;
93 static void freeOsxData(OsxData * od)
95         if (od->buffer)
96                 free(od->buffer);
97         pthread_mutex_destroy(&od->mutex);
98         pthread_cond_destroy(&od->condition);
99         free(od);
102 static void osx_finishDriver(AudioOutput * audioOutput)
104         OsxData *od = (OsxData *) audioOutput->data;
105         freeOsxData(od);
108 static void osx_dropBufferedAudio(AudioOutput * audioOutput)
110         OsxData *od = (OsxData *) audioOutput->data;
112         pthread_mutex_lock(&od->mutex);
113         od->len = 0;
114         pthread_mutex_unlock(&od->mutex);
117 static void osx_closeDevice(AudioOutput * audioOutput)
119         OsxData *od = (OsxData *) audioOutput->data;
121         pthread_mutex_lock(&od->mutex);
122         while (od->len) {
123                 pthread_cond_wait(&od->condition, &od->mutex);
124         }
125         pthread_mutex_unlock(&od->mutex);
127         if (od->started) {
128                 AudioOutputUnitStop(od->au);
129                 od->started = 0;
130         }
132         CloseComponent(od->au);
133         AudioUnitUninitialize(od->au);
135         audioOutput->open = 0;
138 static OSStatus osx_render(void *vdata,
139                            AudioUnitRenderActionFlags * ioActionFlags,
140                            const AudioTimeStamp * inTimeStamp,
141                            UInt32 inBusNumber, UInt32 inNumberFrames,
142                            AudioBufferList * bufferList)
144         OsxData *od = (OsxData *) vdata;
145         AudioBuffer *buffer = &bufferList->mBuffers[0];
146         int bufferSize = buffer->mDataByteSize;
147         int bytesToCopy;
148         int curpos = 0;
150         /*DEBUG("osx_render: enter : %i\n", (int)bufferList->mNumberBuffers);
151            DEBUG("osx_render: ioActionFlags: %p\n", ioActionFlags);
152            if(ioActionFlags) {
153            if(*ioActionFlags & kAudioUnitRenderAction_PreRender) {
154            DEBUG("prerender\n");
155            }
156            if(*ioActionFlags & kAudioUnitRenderAction_PostRender) {
157            DEBUG("post render\n");
158            }
159            if(*ioActionFlags & kAudioUnitRenderAction_OutputIsSilence) {
160            DEBUG("post render\n");
161            }
162            if(*ioActionFlags & kAudioOfflineUnitRenderAction_Preflight) {
163            DEBUG("prefilight\n");
164            }
165            if(*ioActionFlags & kAudioOfflineUnitRenderAction_Render) {
166            DEBUG("render\n");
167            }
168            if(*ioActionFlags & kAudioOfflineUnitRenderAction_Complete) {
169            DEBUG("complete\n");
170            }
171            } */
173         /* while(bufferSize) {
174            DEBUG("osx_render: lock\n"); */
175         pthread_mutex_lock(&od->mutex);
176         /*
177            DEBUG("%i:%i\n", bufferSize, od->len);
178            while(od->go && od->len < bufferSize && 
179            od->len < od->bufferSize)
180            {
181            DEBUG("osx_render: wait\n");
182            pthread_cond_wait(&od->condition, &od->mutex);
183            }
184          */
186         bytesToCopy = od->len < bufferSize ? od->len : bufferSize;
187         bufferSize = bytesToCopy;
188         od->len -= bytesToCopy;
190         if (od->pos + bytesToCopy > od->bufferSize) {
191                 int bytes = od->bufferSize - od->pos;
192                 memcpy(buffer->mData + curpos, od->buffer + od->pos, bytes);
193                 od->pos = 0;
194                 curpos += bytes;
195                 bytesToCopy -= bytes;
196         }
198         memcpy(buffer->mData + curpos, od->buffer + od->pos, bytesToCopy);
199         od->pos += bytesToCopy;
200         curpos += bytesToCopy;
202         if (od->pos >= od->bufferSize)
203                 od->pos = 0;
204         /* DEBUG("osx_render: unlock\n"); */
205         pthread_mutex_unlock(&od->mutex);
206         pthread_cond_signal(&od->condition);
207         /* } */
209         buffer->mDataByteSize = bufferSize;
211         if (!bufferSize) {
212                 my_usleep(1000);
213         }
215         /* DEBUG("osx_render: leave\n"); */
216         return 0;
219 static int osx_openDevice(AudioOutput * audioOutput)
221         OsxData *od = (OsxData *) audioOutput->data;
222         ComponentDescription desc;
223         Component comp;
224         AURenderCallbackStruct callback;
225         AudioFormat *audioFormat = &audioOutput->outAudioFormat;
226         AudioStreamBasicDescription streamDesc;
228         desc.componentType = kAudioUnitType_Output;
229         desc.componentSubType = kAudioUnitSubType_DefaultOutput;
230         desc.componentManufacturer = kAudioUnitManufacturer_Apple;
231         desc.componentFlags = 0;
232         desc.componentFlagsMask = 0;
234         comp = FindNextComponent(NULL, &desc);
235         if (comp == 0) {
236                 ERROR("Error finding OS X component\n");
237                 return -1;
238         }
240         if (OpenAComponent(comp, &od->au) != noErr) {
241                 ERROR("Unable to open OS X component\n");
242                 return -1;
243         }
245         if (AudioUnitInitialize(od->au) != 0) {
246                 CloseComponent(od->au);
247                 ERROR("Unable to initialize OS X audio unit\n");
248                 return -1;
249         }
251         callback.inputProc = osx_render;
252         callback.inputProcRefCon = od;
254         if (AudioUnitSetProperty(od->au, kAudioUnitProperty_SetRenderCallback,
255                                  kAudioUnitScope_Input, 0,
256                                  &callback, sizeof(callback)) != 0) {
257                 AudioUnitUninitialize(od->au);
258                 CloseComponent(od->au);
259                 ERROR("unable to set callback for OS X audio unit\n");
260                 return -1;
261         }
263         streamDesc.mSampleRate = audioFormat->sampleRate;
264         streamDesc.mFormatID = kAudioFormatLinearPCM;
265         streamDesc.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger;
266 #ifdef WORDS_BIGENDIAN
267         streamDesc.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian;
268 #endif
270         streamDesc.mBytesPerPacket =
271             audioFormat->channels * audioFormat->bits / 8;
272         streamDesc.mFramesPerPacket = 1;
273         streamDesc.mBytesPerFrame = streamDesc.mBytesPerPacket;
274         streamDesc.mChannelsPerFrame = audioFormat->channels;
275         streamDesc.mBitsPerChannel = audioFormat->bits;
277         if (AudioUnitSetProperty(od->au, kAudioUnitProperty_StreamFormat,
278                                  kAudioUnitScope_Input, 0,
279                                  &streamDesc, sizeof(streamDesc)) != 0) {
280                 AudioUnitUninitialize(od->au);
281                 CloseComponent(od->au);
282                 ERROR("Unable to set format on OS X device\n");
283                 return -1;
284         }
286         /* create a buffer of 1s */
287         od->bufferSize = (audioFormat->sampleRate) *
288             (audioFormat->bits >> 3) * (audioFormat->channels);
289         od->buffer = xrealloc(od->buffer, od->bufferSize);
291         od->pos = 0;
292         od->len = 0;
294         audioOutput->open = 1;
296         return 0;
299 static int osx_play(AudioOutput * audioOutput, char *playChunk, int size)
301         OsxData *od = (OsxData *) audioOutput->data;
302         int bytesToCopy;
303         int curpos;
305         /* DEBUG("osx_play: enter\n"); */
307         if (!od->started) {
308                 int err;
309                 od->started = 1;
310                 err = AudioOutputUnitStart(od->au);
311                 if (err) {
312                         ERROR("unable to start audio output: %i\n", err);
313                         return -1;
314                 }
315         }
317         pthread_mutex_lock(&od->mutex);
319         while (size) {
320                 /* DEBUG("osx_play: lock\n"); */
321                 curpos = od->pos + od->len;
322                 if (curpos >= od->bufferSize)
323                         curpos -= od->bufferSize;
325                 bytesToCopy = od->bufferSize < size ? od->bufferSize : size;
327                 while (od->len > od->bufferSize - bytesToCopy) {
328                         /* DEBUG("osx_play: wait\n"); */
329                         pthread_cond_wait(&od->condition, &od->mutex);
330                 }
332                 bytesToCopy = od->bufferSize - od->len;
333                 bytesToCopy = bytesToCopy < size ? bytesToCopy : size;
334                 size -= bytesToCopy;
335                 od->len += bytesToCopy;
337                 if (curpos + bytesToCopy > od->bufferSize) {
338                         int bytes = od->bufferSize - curpos;
339                         memcpy(od->buffer + curpos, playChunk, bytes);
340                         curpos = 0;
341                         playChunk += bytes;
342                         bytesToCopy -= bytes;
343                 }
345                 memcpy(od->buffer + curpos, playChunk, bytesToCopy);
346                 curpos += bytesToCopy;
347                 playChunk += bytesToCopy;
349         }
350         /* DEBUG("osx_play: unlock\n"); */
351         pthread_mutex_unlock(&od->mutex);
353         /* DEBUG("osx_play: leave\n"); */
354         return 0;
357 AudioOutputPlugin osxPlugin = {
358         "osx",
359         osx_testDefault,
360         osx_initDriver,
361         osx_finishDriver,
362         osx_openDevice,
363         osx_play,
364         osx_dropBufferedAudio,
365         osx_closeDevice,
366         NULL,   /* sendMetadataFunc */
369 #else
371 #include <stdio.h>
373 DISABLED_AUDIO_OUTPUT_PLUGIN(osxPlugin)
374 #endif