2
audio_macosx: audio output on MacOS X
4
copyright ?-2006 by the mpg123 project - free software under the terms of the GPL 2
5
see COPYING and AUTHORS files in distribution or http://mpg123.de
6
initially written by Guillaume Outters
7
modified by Nicholas J Humfrey to use SFIFO code
16
#include <CoreAudio/AudioHardware.h>
21
#define FIFO_DURATION (0.5f)
29
/* Convertion buffer */
37
static struct anEnv *env=NULL;
41
static OSStatus playProc(AudioDeviceID inDevice, const AudioTimeStamp * inNow,
42
const AudioBufferList * inInputData, const AudioTimeStamp * inInputTime,
43
AudioBufferList * outOutputData, const AudioTimeStamp * inOutputTime, void * inClientData)
48
for(n = 0; n < outOutputData->mNumberBuffers; n++)
50
unsigned int wanted = outOutputData->mBuffers[n].mDataByteSize;
51
unsigned char *dest = outOutputData->mBuffers[n].mData;
54
/* Only play if we have data left */
55
if ( sfifo_used( &env->fifo ) < wanted ) {
56
warning("Didn't have any audio data in callback (buffer underflow)");
60
/* Read audio from FIFO to SDL's buffer */
61
read = sfifo_read( &env->fifo, dest, wanted );
64
warning2("Error reading from the ring buffer (wanted=%u, read=%u).\n", wanted, read);
73
int audio_open(struct audio_info_struct *ai)
75
AudioStreamBasicDescription format;
79
/* Allocate memory for data structure */
81
env = (struct anEnv*)malloc( sizeof( struct anEnv ) );
83
perror("failed to malloc memory for 'struct anEnv'");
88
/* Initialize our environment */
96
/* Get the default audio output device */
97
size = sizeof(env->device);
98
if(AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &size, &env->device)) {
99
error("AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice) failed");
103
/* Ensure that the device supports PCM */
104
size = sizeof(format);
105
if(AudioDeviceGetProperty(env->device, 0, 0, kAudioDevicePropertyStreamFormat, &size, &format)) {
106
fprintf(stderr, "AudioDeviceGetProperty(kAudioDevicePropertyStreamFormat) failed");
109
if(format.mFormatID != kAudioFormatLinearPCM) {
110
error("format.mFormatID != kAudioFormatLinearPCM");
114
/* Get the nominal sample rate of the device */
115
size = sizeof(devicerate);
116
if(AudioDeviceGetProperty(env->device, 0, 0, kAudioDevicePropertyNominalSampleRate, &size, &devicerate)) {
117
fprintf(stderr, "AudioDeviceGetProperty(kAudioDevicePropertyNominalSampleRate) failed");
121
/* Add our callback - but don't start it yet */
122
if(AudioDeviceAddIOProc(env->device, playProc, env)) {
123
error("AudioDeviceAddIOProc failed");
128
/* Open an audio I/O stream. */
129
if (ai->rate > 0 && ai->channels >0 ) {
132
/* Check sample rate */
133
if (devicerate != ai->rate) {
134
error2("Error: sample rate of device doesn't match playback rate (%d != %d)", (int)devicerate, (int)ai->rate);
138
/* Initialise FIFO */
139
ringbuffer_len = ai->rate * FIFO_DURATION * sizeof(float) *ai->channels;
140
debug2( "Allocating %d byte ring-buffer (%f seconds)", ringbuffer_len, (float)FIFO_DURATION);
141
sfifo_init( &env->fifo, ringbuffer_len );
149
int audio_get_formats(struct audio_info_struct *ai)
151
/* Only support Signed 16-bit output */
152
return AUDIO_FORMAT_SIGNED_16;
156
int audio_play_samples(struct audio_info_struct *ai, unsigned char *buf, int len)
158
short *src = (short *)buf;
159
int samples = len/sizeof(short);
160
int flen = samples*sizeof(float);
163
/* If there is no room, then sleep for half the length of the FIFO */
164
while (sfifo_space( &env->fifo ) < flen ) {
165
usleep( (FIFO_DURATION/2) * 1000000 );
168
/* Ensure conversion buffer is big enough */
169
if (env->buffer_size < flen) {
170
debug1("Allocating %d byte sample conversion buffer", flen);
171
env->buffer = realloc( env->buffer, flen);
172
env->buffer_size = flen;
175
/* Convert audio samples to 32-bit float */
176
for( n=0; n<samples; n++) {
177
env->buffer[n] = src[n] / 32768.0f;
180
/* Store converted audio in ring buffer */
181
written = sfifo_write( &env->fifo, (char*)env->buffer, flen);
182
if (written != flen) {
183
warning( "Failed to write audio to ring buffer" );
187
/* Start playback now that we have something to play */
190
if(AudioDeviceStart(env->device, playProc)) {
191
error("AudioDeviceStart failed");
200
int audio_close(struct audio_info_struct *ai)
204
/* No matter the error code, we want to close it (by brute force if necessary) */
205
AudioDeviceStop(env->device, playProc);
206
AudioDeviceRemoveIOProc(env->device, playProc);
208
/* Free the ring buffer */
209
sfifo_close( &env->fifo );
211
/* Free the conversion buffer */
212
if (env->buffer) free( env->buffer );
214
/* Free environment data structure */
222
void audio_queueflush(struct audio_info_struct *ai)
226
if(AudioDeviceStop(env->device, playProc)) {
227
error("AudioDeviceStop failed");
231
/* Empty out the ring buffer */
232
sfifo_flush( &env->fifo );