~ubuntu-branches/ubuntu/lucid/mpg123/lucid

« back to all changes in this revision

Viewing changes to src/audio_macosx.c

Tags: upstream-0.60
ImportĀ upstreamĀ versionĀ 0.60

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
        audio_macosx: audio output on MacOS X
 
3
 
 
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
 
8
*/
 
9
 
 
10
 
 
11
#include "config.h"
 
12
#include "debug.h"
 
13
#include "sfifo.h"
 
14
#include "mpg123.h"
 
15
 
 
16
#include <CoreAudio/AudioHardware.h>
 
17
#include <stdio.h>
 
18
#include <stdlib.h>
 
19
#include <errno.h>
 
20
 
 
21
#define FIFO_DURATION           (0.5f)
 
22
 
 
23
 
 
24
struct anEnv
 
25
{
 
26
        AudioDeviceID device;
 
27
        char play;
 
28
        
 
29
        /* Convertion buffer */
 
30
        float * buffer;
 
31
        size_t buffer_size;
 
32
        
 
33
        /* Ring buffer */
 
34
        sfifo_t fifo;
 
35
};
 
36
 
 
37
static struct anEnv *env=NULL;
 
38
 
 
39
 
 
40
 
 
41
static OSStatus playProc(AudioDeviceID inDevice, const AudioTimeStamp * inNow,
 
42
                                                 const AudioBufferList * inInputData, const AudioTimeStamp * inInputTime,
 
43
                         AudioBufferList * outOutputData, const AudioTimeStamp * inOutputTime, void * inClientData)
 
44
{
 
45
        
 
46
        long n;
 
47
        
 
48
        for(n = 0; n < outOutputData->mNumberBuffers; n++)
 
49
        {
 
50
                unsigned int wanted = outOutputData->mBuffers[n].mDataByteSize;
 
51
                unsigned char *dest = outOutputData->mBuffers[n].mData;
 
52
                unsigned int read;
 
53
                
 
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)");
 
57
                        return -1;
 
58
                }
 
59
                
 
60
                /* Read audio from FIFO to SDL's buffer */
 
61
                read = sfifo_read( &env->fifo, dest, wanted );
 
62
                
 
63
                if (wanted!=read)
 
64
                        warning2("Error reading from the ring buffer (wanted=%u, read=%u).\n", wanted, read);
 
65
                
 
66
        }
 
67
        
 
68
        return (0); 
 
69
}
 
70
 
 
71
 
 
72
 
 
73
int audio_open(struct audio_info_struct *ai)
 
74
{
 
75
        AudioStreamBasicDescription format;
 
76
        Float64 devicerate;
 
77
        UInt32 size;
 
78
        
 
79
        /* Allocate memory for data structure */
 
80
        if (!env) {
 
81
                env = (struct anEnv*)malloc( sizeof( struct anEnv ) );
 
82
                if (!env) {
 
83
                        perror("failed to malloc memory for 'struct anEnv'");
 
84
                        exit(-1);
 
85
                }
 
86
        }
 
87
 
 
88
        /* Initialize our environment */
 
89
        env->device = 0;
 
90
        env->play = 0;
 
91
        env->buffer = NULL;
 
92
        env->buffer_size = 0;
 
93
        
 
94
 
 
95
        
 
96
        /* Get the default audio output device */
 
97
        size = sizeof(env->device);
 
98
        if(AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &size, &env->device)) {
 
99
                error("AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice) failed");
 
100
                return(-1);
 
101
        }
 
102
        
 
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");
 
107
                return(-1);
 
108
        }
 
109
        if(format.mFormatID != kAudioFormatLinearPCM) {
 
110
                error("format.mFormatID != kAudioFormatLinearPCM");
 
111
                return(-1);
 
112
        }
 
113
        
 
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");
 
118
                return(-1);
 
119
        }
 
120
                
 
121
        /* Add our callback - but don't start it yet */
 
122
        if(AudioDeviceAddIOProc(env->device, playProc, env)) {
 
123
                error("AudioDeviceAddIOProc failed");
 
124
                return(-1);
 
125
        }
 
126
        
 
127
        
 
128
        /* Open an audio I/O stream. */
 
129
        if (ai->rate > 0 && ai->channels >0 ) {
 
130
                int ringbuffer_len;
 
131
                
 
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);
 
135
                        return(-1);
 
136
                }
 
137
                
 
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 );
 
142
                                                                           
 
143
        }
 
144
        
 
145
        return(0);
 
146
}
 
147
 
 
148
 
 
149
int audio_get_formats(struct audio_info_struct *ai)
 
150
{
 
151
        /* Only support Signed 16-bit output */
 
152
        return AUDIO_FORMAT_SIGNED_16;
 
153
}
 
154
 
 
155
 
 
156
int audio_play_samples(struct audio_info_struct *ai, unsigned char *buf, int len)
 
157
{
 
158
        short *src = (short *)buf;
 
159
        int samples = len/sizeof(short);
 
160
        int flen = samples*sizeof(float);
 
161
        int written, n;
 
162
 
 
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 );
 
166
        }
 
167
 
 
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;
 
173
        }
 
174
        
 
175
        /* Convert audio samples to 32-bit float */
 
176
        for( n=0; n<samples; n++) {
 
177
                env->buffer[n] = src[n] / 32768.0f;
 
178
        }
 
179
        
 
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" );
 
184
                return -1;
 
185
        }
 
186
        
 
187
        /* Start playback now that we have something to play */
 
188
        if(!env->play)
 
189
        {
 
190
                if(AudioDeviceStart(env->device, playProc)) {
 
191
                        error("AudioDeviceStart failed");
 
192
                        return(-1);
 
193
                }
 
194
                env->play = 1;
 
195
        }
 
196
        
 
197
        return len;
 
198
}
 
199
 
 
200
int audio_close(struct audio_info_struct *ai)
 
201
{
 
202
 
 
203
        if (env) {
 
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);
 
207
        
 
208
            /* Free the ring buffer */
 
209
                sfifo_close( &env->fifo );
 
210
                
 
211
                /* Free the conversion buffer */
 
212
                if (env->buffer) free( env->buffer );
 
213
                
 
214
                /* Free environment data structure */
 
215
                free(env);
 
216
                env=NULL;
 
217
        }
 
218
        
 
219
        return 0;
 
220
}
 
221
 
 
222
void audio_queueflush(struct audio_info_struct *ai)
 
223
{
 
224
 
 
225
        /* Stop playback */
 
226
        if(AudioDeviceStop(env->device, playProc)) {
 
227
                error("AudioDeviceStop failed");
 
228
        }
 
229
        env->play=0;
 
230
        
 
231
        /* Empty out the ring buffer */
 
232
        sfifo_flush( &env->fifo );      
 
233
}