]> git.sesse.net Git - vlc/blob - modules/gui/macosx/aout.m
The liba52 "codec" is now an audio filter. It means we are now able to
[vlc] / modules / gui / macosx / aout.m
1 /*****************************************************************************
2  * aout.m: CoreAudio output plugin
3  *****************************************************************************
4  * Copyright (C) 2002 VideoLAN
5  * $Id: aout.m,v 1.9 2002/09/02 23:17:05 massiot Exp $
6  *
7  * Authors: Colin Delacroix <colin@zoy.org>
8  *          Jon Lech Johansen <jon-vl@nanocrew.net>
9  *          Christophe Massiot <massiot@via.ecp.fr>
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  * 
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
24  *****************************************************************************/
25
26 /*****************************************************************************
27  * Preamble
28  *****************************************************************************/
29 #include <string.h>
30 #include <stdlib.h>
31
32 #include <vlc/vlc.h>
33 #include <vlc/aout.h>
34 #include "aout_internal.h"
35
36 #include <Carbon/Carbon.h>
37 #include <CoreAudio/AudioHardware.h>
38 #include <CoreAudio/HostTime.h>
39 #include <AudioToolbox/AudioConverter.h>
40
41 /*****************************************************************************
42  * aout_sys_t: private audio output method descriptor
43  *****************************************************************************
44  * This structure is part of the audio output thread descriptor.
45  * It describes the CoreAudio specific properties of an output thread.
46  *****************************************************************************/
47 struct aout_sys_t
48 {
49     AudioDeviceID       device;         // the audio device
50
51     AudioStreamBasicDescription stream_format;
52
53     UInt32              i_buffer_size;  // audio device buffer size
54     mtime_t             clock_diff;
55 };
56
57 /*****************************************************************************
58  * Local prototypes.
59  *****************************************************************************/
60 static void     Play            ( aout_instance_t *p_aout );
61
62 static OSStatus IOCallback      ( AudioDeviceID inDevice,
63                                   const AudioTimeStamp *inNow, 
64                                   const void *inInputData, 
65                                   const AudioTimeStamp *inInputTime,
66                                   AudioBufferList *outOutputData, 
67                                   const AudioTimeStamp *inOutputTime, 
68                                   void *threadGlobals );
69
70 /*****************************************************************************
71  * Open: open a CoreAudio HAL device
72  *****************************************************************************/
73 int E_(OpenAudio)( vlc_object_t * p_this )
74 {
75     OSStatus err;
76     UInt32 i_param_size;
77     aout_instance_t * p_aout = (aout_instance_t *)p_this;
78     struct aout_sys_t * p_sys;
79
80     /* Allocate instance */
81     p_sys = p_aout->output.p_sys = malloc( sizeof( struct aout_sys_t ) );
82     memset( p_sys, 0, sizeof( struct aout_sys_t ) );
83     if( p_aout->output.p_sys == NULL )
84     {
85         msg_Err( p_aout, "out of memory" );
86         return( 1 );
87     }
88
89     /* Get the default output device */
90     /* FIXME : be more clever in choosing from several devices */
91     i_param_size = sizeof( p_sys->device );
92     err = AudioHardwareGetProperty( kAudioHardwarePropertyDefaultOutputDevice,
93                                     &i_param_size, 
94                                     (void *)&p_sys->device );
95     if( err != noErr ) 
96     {
97         msg_Err( p_aout, "failed to get the device: %d", err );
98         return( -1 );
99     }
100
101     p_aout->output.pf_play = Play;
102
103     /* Get a description of the data format used by the device */
104     i_param_size = sizeof( p_sys->stream_format ); 
105     err = AudioDeviceGetProperty( p_sys->device, 0, false, 
106                                   kAudioDevicePropertyStreamFormat, 
107                                   &i_param_size,
108                                   &p_sys->stream_format );
109     if( err != noErr )
110     {
111         msg_Err( p_aout, "failed to get stream format: %d", err );
112         return -1 ;
113     }
114
115     if( p_sys->stream_format.mFormatID != kAudioFormatLinearPCM )
116     {
117         msg_Err( p_aout, "kAudioFormatLinearPCM required" );
118         return -1 ;
119     }
120
121     /* We only deal with floats. FIXME : this is where we should do S/PDIF. */
122     p_aout->output.output.i_format = AOUT_FMT_FLOAT32;
123
124     /* Set sample rate and channels per frame */
125     p_aout->output.output.i_rate = p_sys->stream_format.mSampleRate;
126     /* FIXME : this is where we should ask for downmixing. */
127     p_aout->output.output.i_channels = 2; //p_sys->stream_format.mChannelsPerFrame;
128
129     /* Get the buffer size that the device uses for IO */
130     i_param_size = sizeof( p_sys->i_buffer_size );
131 #if 0
132     err = AudioDeviceGetProperty( p_sys->device, 0, false, 
133                                   kAudioDevicePropertyBufferSize, 
134                                   &i_param_size, &p_sys->i_buffer_size );
135 msg_Dbg( p_aout, "toto : %d", p_sys->i_buffer_size );
136 #else
137     p_sys->i_buffer_size = sizeof(float) * p_aout->output.output.i_channels
138                             * 4096;
139     err = AudioDeviceSetProperty( p_sys->device, 0, 0, false,
140                                   kAudioDevicePropertyBufferSize,
141                                   i_param_size, &p_sys->i_buffer_size );
142 #endif
143     if( err != noErr )
144     {
145         msg_Err( p_aout, "failed to set device buffer size: %d", err );
146         return( -1 );
147     }
148
149     p_aout->output.i_nb_samples = p_sys->i_buffer_size / sizeof(float)
150                                    / p_aout->output.output.i_channels;
151
152     /* Add callback */
153     err = AudioDeviceAddIOProc( p_sys->device,
154                                 (AudioDeviceIOProc)IOCallback,
155                                 (void *)p_aout );
156
157     /* Open the output with callback IOCallback */
158     err = AudioDeviceStart( p_sys->device,
159                             (AudioDeviceIOProc)IOCallback );
160     if( err != noErr )
161     {
162         msg_Err( p_aout, "AudioDeviceStart failed: %d", err );
163         return -1;
164     }
165
166     /* Let's pray for the following operation to be atomic... */
167     p_sys->clock_diff = - (mtime_t)AudioConvertHostTimeToNanos(
168                                  AudioGetCurrentHostTime()) / 1000;
169     p_sys->clock_diff += mdate();
170
171     return 0;
172 }
173
174 /*****************************************************************************
175  * Close: close the CoreAudio HAL device
176  *****************************************************************************/
177 void E_(CloseAudio)( aout_instance_t * p_aout )
178 {
179     struct aout_sys_t * p_sys = p_aout->output.p_sys;
180     OSStatus err; 
181
182     /* Stop playing sound through the device */
183     err = AudioDeviceStop( p_sys->device,
184                            (AudioDeviceIOProc)IOCallback ); 
185     if( err != noErr )
186     {
187         msg_Err( p_aout, "AudioDeviceStop failed: %d", err );
188     }
189
190     free( p_sys );
191 }
192
193 /*****************************************************************************
194  * Play: nothing to do
195  *****************************************************************************/
196 static void Play( aout_instance_t * p_aout )
197 {
198 }
199
200 /*****************************************************************************
201  * IOCallback : callback for audio output
202  *****************************************************************************/
203 static OSStatus IOCallback( AudioDeviceID inDevice,
204                             const AudioTimeStamp *inNow, 
205                             const void *inInputData,
206                             const AudioTimeStamp *inInputTime, 
207                             AudioBufferList *outOutputData,
208                             const AudioTimeStamp *inOutputTime, 
209                             void *threadGlobals )
210 {
211     aout_instance_t * p_aout = (aout_instance_t *)threadGlobals;
212     struct aout_sys_t * p_sys = p_aout->output.p_sys;
213     mtime_t         current_date;
214     AudioTimeStamp  host_time;
215     aout_buffer_t * p_buffer;
216
217     host_time.mFlags = kAudioTimeStampHostTimeValid;
218     AudioDeviceTranslateTime( inDevice, inOutputTime, &host_time );
219     current_date = p_sys->clock_diff
220                  + AudioConvertHostTimeToNanos(host_time.mHostTime) / 1000;
221
222     p_buffer = aout_OutputNextBuffer( p_aout, current_date, VLC_FALSE );
223
224     /* move data into output data buffer */
225     if ( p_buffer != NULL )
226     {
227         BlockMoveData( p_buffer->p_buffer,
228                        outOutputData->mBuffers[ 0 ].mData, 
229                        p_sys->i_buffer_size );
230         aout_BufferFree( p_buffer );
231     }
232     else
233     {
234         memset(outOutputData->mBuffers[ 0 ].mData, 0, p_sys->i_buffer_size);
235     }
236
237     return noErr;     
238 }
239