]> git.sesse.net Git - vlc/blob - modules/gui/macosx/aout.m
84316e504423b9691c2964b7786e162e982015cf
[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.8 2002/08/30 23:27:06 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 */
122     if ( p_aout->output.output.i_format != AOUT_FMT_FLOAT32 )
123     {
124         msg_Err( p_aout, "cannot set format 0x%x",
125                  p_aout->output.output.i_format );
126         return -1;
127     }
128
129     /* Set sample rate and channels per frame */
130     p_aout->output.output.i_rate = p_sys->stream_format.mSampleRate;
131     p_aout->output.output.i_channels = p_sys->stream_format.mChannelsPerFrame;
132
133     /* Get the buffer size that the device uses for IO */
134     i_param_size = sizeof( p_sys->i_buffer_size );
135 #if 0
136     err = AudioDeviceGetProperty( p_sys->device, 0, false, 
137                                   kAudioDevicePropertyBufferSize, 
138                                   &i_param_size, &p_sys->i_buffer_size );
139 msg_Dbg( p_aout, "toto : %d", p_sys->i_buffer_size );
140 #else
141     p_sys->i_buffer_size = sizeof(float) * p_aout->output.output.i_channels
142                             * 4096;
143     err = AudioDeviceSetProperty( p_sys->device, 0, 0, false,
144                                   kAudioDevicePropertyBufferSize,
145                                   i_param_size, &p_sys->i_buffer_size );
146 #endif
147     if( err != noErr )
148     {
149         msg_Err( p_aout, "failed to set device buffer size: %d", err );
150         return( -1 );
151     }
152
153     p_aout->output.i_nb_samples = p_sys->i_buffer_size / sizeof(float)
154                                    / p_aout->output.output.i_channels;
155
156     /* Add callback */
157     err = AudioDeviceAddIOProc( p_sys->device,
158                                 (AudioDeviceIOProc)IOCallback,
159                                 (void *)p_aout );
160
161     /* Open the output with callback IOCallback */
162     err = AudioDeviceStart( p_sys->device,
163                             (AudioDeviceIOProc)IOCallback );
164     if( err != noErr )
165     {
166         msg_Err( p_aout, "AudioDeviceStart failed: %d", err );
167         return -1;
168     }
169
170     /* Let's pray for the following operation to be atomic... */
171     p_sys->clock_diff = - (mtime_t)AudioConvertHostTimeToNanos(
172                                  AudioGetCurrentHostTime()) / 1000;
173     p_sys->clock_diff += mdate();
174
175     return 0;
176 }
177
178 /*****************************************************************************
179  * Close: close the CoreAudio HAL device
180  *****************************************************************************/
181 void E_(CloseAudio)( aout_instance_t * p_aout )
182 {
183     struct aout_sys_t * p_sys = p_aout->output.p_sys;
184     OSStatus err; 
185
186     /* Stop playing sound through the device */
187     err = AudioDeviceStop( p_sys->device,
188                            (AudioDeviceIOProc)IOCallback ); 
189     if( err != noErr )
190     {
191         msg_Err( p_aout, "AudioDeviceStop failed: %d", err );
192     }
193
194     free( p_sys );
195 }
196
197 /*****************************************************************************
198  * Play: nothing to do
199  *****************************************************************************/
200 static void Play( aout_instance_t * p_aout )
201 {
202 }
203
204 /*****************************************************************************
205  * IOCallback : callback for audio output
206  *****************************************************************************/
207 static OSStatus IOCallback( AudioDeviceID inDevice,
208                             const AudioTimeStamp *inNow, 
209                             const void *inInputData,
210                             const AudioTimeStamp *inInputTime, 
211                             AudioBufferList *outOutputData,
212                             const AudioTimeStamp *inOutputTime, 
213                             void *threadGlobals )
214 {
215     aout_instance_t * p_aout = (aout_instance_t *)threadGlobals;
216     struct aout_sys_t * p_sys = p_aout->output.p_sys;
217     mtime_t         current_date;
218     AudioTimeStamp  host_time;
219     aout_buffer_t * p_buffer;
220
221     host_time.mFlags = kAudioTimeStampHostTimeValid;
222     AudioDeviceTranslateTime( inDevice, inOutputTime, &host_time );
223     current_date = p_sys->clock_diff
224                  + AudioConvertHostTimeToNanos(host_time.mHostTime) / 1000;
225
226     p_buffer = aout_OutputNextBuffer( p_aout, current_date, VLC_FALSE );
227
228     /* move data into output data buffer */
229     if ( p_buffer != NULL )
230     {
231         BlockMoveData( p_buffer->p_buffer,
232                        outOutputData->mBuffers[ 0 ].mData, 
233                        p_sys->i_buffer_size );
234         aout_BufferFree( p_buffer );
235     }
236     else
237     {
238         memset(outOutputData->mBuffers[ 0 ].mData, 0, p_sys->i_buffer_size);
239     }
240
241     return noErr;     
242 }
243