1 /*****************************************************************************
2 * aout.m: CoreAudio output plugin
3 *****************************************************************************
4 * Copyright (C) 2002 VideoLAN
5 * $Id: aout.m,v 1.12 2002/10/02 22:56:53 massiot Exp $
7 * Authors: Colin Delacroix <colin@zoy.org>
8 * Jon Lech Johansen <jon-vl@nanocrew.net>
9 * Christophe Massiot <massiot@via.ecp.fr>
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.
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.
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 *****************************************************************************/
26 /*****************************************************************************
28 *****************************************************************************/
34 #include "aout_internal.h"
37 #include <Carbon/Carbon.h>
38 #include <CoreAudio/AudioHardware.h>
39 #include <CoreAudio/HostTime.h>
40 #include <AudioToolbox/AudioConverter.h>
42 #define A52_FRAME_NB 1536
44 /*****************************************************************************
45 * aout_sys_t: private audio output method descriptor
46 *****************************************************************************
47 * This structure is part of the audio output thread descriptor.
48 * It describes the CoreAudio specific properties of an output thread.
49 *****************************************************************************/
52 AudioDeviceID device; // the audio device
54 AudioStreamBasicDescription stream_format;
56 UInt32 i_buffer_size; // audio device buffer size
60 /*****************************************************************************
62 *****************************************************************************/
63 static void Play ( aout_instance_t *p_aout );
65 static OSStatus IOCallback ( AudioDeviceID inDevice,
66 const AudioTimeStamp *inNow,
67 const void *inInputData,
68 const AudioTimeStamp *inInputTime,
69 AudioBufferList *outOutputData,
70 const AudioTimeStamp *inOutputTime,
71 void *threadGlobals );
73 /*****************************************************************************
74 * Open: open a CoreAudio HAL device
75 *****************************************************************************/
76 extern MacOSXAudioSystem *gTheMacOSXAudioSystem; // Remove this global, access audio system froma aout some other way
78 int E_(OpenAudio)( vlc_object_t * p_this )
82 aout_instance_t * p_aout = (aout_instance_t *)p_this;
83 struct aout_sys_t * p_sys;
84 msg_Dbg(p_aout, "************************* ENTER OpenAudio ****************************");
86 /* Allocate instance */
87 p_sys = p_aout->output.p_sys = malloc( sizeof( struct aout_sys_t ) );
88 memset( p_sys, 0, sizeof( struct aout_sys_t ) );
89 if( p_aout->output.p_sys == NULL )
91 msg_Err( p_aout, "out of memory" );
95 /* Get the default output device */
96 // We now ask the GUI for the selected device
97 p_sys->device=[gTheMacOSXAudioSystem getSelectedDeviceSetToRate:p_aout->output.output.i_rate];
100 msg_Err( p_aout, "couldn't get output device");
103 msg_Dbg(p_aout, "device returned: %ld", p_sys->device);
105 p_aout->output.pf_play = Play;
106 aout_VolumeSoftInit( p_aout );
108 /* Get a description of the data format used by the device */
109 i_param_size = sizeof(AudioStreamBasicDescription);
110 err = AudioDeviceGetProperty(p_sys->device, 0, false, kAudioDevicePropertyStreamFormat, &i_param_size, &p_sys->stream_format );
113 msg_Err( p_aout, "failed to get stream format: %4.4s", &err );
117 msg_Dbg( p_aout, "mSampleRate %ld, mFormatID %4.4s, mFormatFlags %ld, mBytesPerPacket %ld, mFramesPerPacket %ld, mBytesPerFrame %ld, mChannelsPerFrame %ld, mBitsPerChannel %ld",
118 (UInt32)p_sys->stream_format.mSampleRate, &p_sys->stream_format.mFormatID,
119 p_sys->stream_format.mFormatFlags, p_sys->stream_format.mBytesPerPacket,
120 p_sys->stream_format.mFramesPerPacket, p_sys->stream_format.mBytesPerFrame,
121 p_sys->stream_format.mChannelsPerFrame, p_sys->stream_format.mBitsPerChannel );
123 msg_Dbg( p_aout, "vlc format %4.4s, mac output format '%4.4s'",
124 (char *)&p_aout->output.output.i_format, &p_sys->stream_format.mFormatID );
126 switch(p_sys->stream_format.mFormatID)
129 case kAudioFormatLinearPCM:
130 p_aout->output.output.i_format = VLC_FOURCC('f','l','3','2');
131 if ( p_sys->stream_format.mChannelsPerFrame < 6 )
132 p_aout->output.output.i_channels = AOUT_CHAN_STEREO;
134 p_aout->output.output.i_channels = AOUT_CHAN_3F2R | AOUT_CHAN_LFE;
137 case kAudioFormat60958AC3:
139 p_aout->output.output.i_format = VLC_FOURCC('s','p','d','i');
140 //not necessary, use the input's format by default --Meuuh
141 //p_aout->output.output.i_channels = AOUT_CHAN_DOLBY | AOUT_CHAN_LFE;
142 p_aout->output.output.i_bytes_per_frame = AOUT_SPDIF_SIZE; //p_sys->stream_format.mBytesPerFrame;
143 p_aout->output.output.i_frame_length = A52_FRAME_NB; //p_sys->stream_format.mFramesPerPacket;
147 msg_Err( p_aout, "Unknown hardware format '%4.4s'. Go ask Heiko.", &p_sys->stream_format.mFormatID );
151 /* Set sample rate and channels per frame */
152 p_aout->output.output.i_rate = p_sys->stream_format.mSampleRate;
154 /* Get the buffer size that the device uses for IO */
155 i_param_size = sizeof( p_sys->i_buffer_size );
156 #if 1 // i have a feeling we should use the buffer size imposed by the AC3 device (usually about 6144)
157 err = AudioDeviceGetProperty( p_sys->device, 1, false,
158 kAudioDevicePropertyBufferSize,
159 &i_param_size, &p_sys->i_buffer_size );
161 msg_Err(p_aout, "failed to get buffer size - err %4.4s, device %ld", &err, p_sys->device);
164 else msg_Dbg( p_aout, "native buffer Size: %d", p_sys->i_buffer_size );
166 p_sys->i_buffer_size = p_aout->output.output.i_bytes_per_frame;
167 err = AudioDeviceSetProperty( p_sys->device, 0, 1, false,
168 kAudioDevicePropertyBufferSize,
169 i_param_size, &p_sys->i_buffer_size );
172 msg_Err( p_aout, "failed to set device buffer size: %4.4s", err );
175 else msg_Dbg(p_aout, "bufferSize set to %d", p_sys->i_buffer_size);
178 p_aout->output.i_nb_samples = p_sys->i_buffer_size / p_sys->stream_format.mBytesPerFrame;
181 err = AudioDeviceAddIOProc( p_sys->device,
182 (AudioDeviceIOProc)IOCallback,
185 /* Open the output with callback IOCallback */
186 err = AudioDeviceStart( p_sys->device,
187 (AudioDeviceIOProc)IOCallback );
190 msg_Err( p_aout, "AudioDeviceStart failed: %d", err );
194 /* Let's pray for the following operation to be atomic... */
195 p_sys->clock_diff = - (mtime_t)AudioConvertHostTimeToNanos(
196 AudioGetCurrentHostTime()) / 1000;
197 p_sys->clock_diff += mdate();
202 /*****************************************************************************
203 * Close: close the CoreAudio HAL device
204 *****************************************************************************/
205 void E_(CloseAudio)( aout_instance_t * p_aout )
207 struct aout_sys_t * p_sys = p_aout->output.p_sys;
210 /* Stop playing sound through the device */
211 err = AudioDeviceStop( p_sys->device,
212 (AudioDeviceIOProc)IOCallback );
215 msg_Err( p_aout, "AudioDeviceStop failed: %d", err );
221 /*****************************************************************************
222 * Play: nothing to do
223 *****************************************************************************/
224 static void Play( aout_instance_t * p_aout )
228 /*****************************************************************************
229 * IOCallback : callback for audio output
230 *****************************************************************************/
231 static OSStatus IOCallback( AudioDeviceID inDevice,
232 const AudioTimeStamp *inNow,
233 const void *inInputData,
234 const AudioTimeStamp *inInputTime,
235 AudioBufferList *outOutputData,
236 const AudioTimeStamp *inOutputTime,
237 void *threadGlobals )
239 aout_instance_t * p_aout = (aout_instance_t *)threadGlobals;
240 struct aout_sys_t * p_sys = p_aout->output.p_sys;
241 mtime_t current_date;
242 AudioTimeStamp host_time;
243 aout_buffer_t * p_buffer;
245 host_time.mFlags = kAudioTimeStampHostTimeValid;
246 AudioDeviceTranslateTime( inDevice, inOutputTime, &host_time );
247 current_date = p_sys->clock_diff
248 + AudioConvertHostTimeToNanos(host_time.mHostTime) / 1000;
250 // msg_Dbg(p_aout, "Now fetching audio data");
251 p_buffer = aout_OutputNextBuffer( p_aout, current_date, (p_aout->output.output.i_format == VLC_FOURCC('s','p','d','i')) );
253 /* move data into output data buffer */
254 if ( p_buffer != NULL )
256 BlockMoveData( p_buffer->p_buffer,
257 outOutputData->mBuffers[ 0 ].mData,
258 p_sys->i_buffer_size );
260 // msg_Dbg(p_aout, "This buffer has %d bytes, i take %d", p_buffer->i_nb_bytes, p_sys->i_buffer_size);
262 aout_BufferFree( p_buffer );
266 memset(outOutputData->mBuffers[ 0 ].mData, 0, p_sys->i_buffer_size);