* aout.m: CoreAudio output plugin
*****************************************************************************
* Copyright (C) 2002 VideoLAN
- * $Id: aout.m,v 1.16 2002/11/28 23:24:15 massiot Exp $
+ * $Id: aout.m,v 1.17 2003/01/01 11:14:50 jlj Exp $
*
* Authors: Colin Delacroix <colin@zoy.org>
* Jon Lech Johansen <jon-vl@nanocrew.net>
#include <vlc/vlc.h>
#include <vlc/aout.h>
+
#include "aout_internal.h"
-#include "asystm.h"
#include <Carbon/Carbon.h>
-#include <CoreAudio/AudioHardware.h>
#include <CoreAudio/HostTime.h>
-#include <AudioToolbox/AudioConverter.h>
+#include <CoreAudio/AudioHardware.h>
#define A52_FRAME_NB 1536
+/*****************************************************************************
+ * aout_class_t
+ ****************************************************************************/
+enum AudioDeviceClass
+{
+ AudioDeviceClassA52 = 1 << 0,
+ AudioDeviceClassPCM2 = 1 << 1,
+ AudioDeviceClassPCM6 = 1 << 2
+};
+
+static struct aout_class_t
+{
+ UInt32 mFormatID;
+ UInt32 mChannelsPerFrame;
+ enum AudioDeviceClass class;
+ const char *psz_class;
+}
+aout_classes[] =
+{
+ { /* old A/52 format type */
+ 'IAC3',
+ 0,
+ AudioDeviceClassA52,
+ "Digital A/52"
+ },
+
+ { /* new A/52 format type */
+ kAudioFormat60958AC3,
+ 0,
+ AudioDeviceClassA52,
+ "Digital A/52"
+ },
+
+ {
+ kAudioFormatLinearPCM,
+ 2,
+ AudioDeviceClassPCM2,
+ "Stereo PCM"
+ },
+
+ {
+ kAudioFormatLinearPCM,
+ 6,
+ AudioDeviceClassPCM6,
+ "6 Channel PCM"
+ }
+};
+
+#define N_AOUT_CLASSES (sizeof(aout_classes)/sizeof(aout_classes[0]))
+
+/*****************************************************************************
+ * aout_option_t
+ ****************************************************************************/
+struct aout_option_t
+{
+ char sz_option[64];
+ UInt32 i_dev, i_idx;
+ UInt32 i_sdx, i_cdx;
+ AudioStreamID i_sid;
+};
+
+/*****************************************************************************
+ * aout_dev_t
+ ****************************************************************************/
+struct aout_dev_t
+{
+ AudioDeviceID devid;
+ char *psz_device_name;
+ UInt32 i_streams;
+ AudioStreamBasicDescription ** pp_streams;
+};
+
/*****************************************************************************
* aout_sys_t: private audio output method descriptor
*****************************************************************************
*****************************************************************************/
struct aout_sys_t
{
- AudioDeviceID device; // the audio device
+ UInt32 i_devices;
+ struct aout_dev_t * p_devices;
+ UInt32 i_options;
+ struct aout_option_t * p_options;
+ AudioDeviceID devid;
AudioStreamBasicDescription stream_format;
- UInt32 i_buffer_size; // audio device buffer size
- mtime_t clock_diff;
+ UInt32 i_buffer_size;
+ mtime_t clock_diff;
};
/*****************************************************************************
* Local prototypes.
*****************************************************************************/
+static int InitHardware ( aout_instance_t *p_aout );
+static int InitDevice ( UInt32 i_dev, aout_instance_t *p_aout );
+static void FreeDevice ( UInt32 i_dev, aout_instance_t *p_aout );
+static void FreeHardware ( aout_instance_t *p_aout );
+static int GetDevice ( aout_instance_t *p_aout,
+ AudioDeviceID *p_devid );
+static int GetStreamID ( AudioDeviceID devid, UInt32 i_idx,
+ AudioStreamID * p_sid );
+static int InitStream ( UInt32 i_dev, aout_instance_t *p_aout,
+ UInt32 i_idx );
+static void FreeStream ( UInt32 i_dev, aout_instance_t *p_aout,
+ UInt32 i_idx );
+
static void Play ( aout_instance_t *p_aout );
static OSStatus IOCallback ( AudioDeviceID inDevice,
/*****************************************************************************
* Open: open a CoreAudio HAL device
*****************************************************************************/
-extern MacOSXAudioSystem *gTheMacOSXAudioSystem; // Remove this global, access audio system froma aout some other way
-
int E_(OpenAudio)( vlc_object_t * p_this )
{
OSStatus err;
- UInt32 i_param_size;
- aout_instance_t * p_aout = (aout_instance_t *)p_this;
+ UInt32 i, i_param_size;
struct aout_sys_t * p_sys;
-
- /* Allocate instance */
- p_sys = p_aout->output.p_sys = malloc( sizeof( struct aout_sys_t ) );
- memset( p_sys, 0, sizeof( struct aout_sys_t ) );
- if( p_aout->output.p_sys == NULL )
+ aout_instance_t * p_aout = (aout_instance_t *)p_this;
+
+ /* Allocate structure */
+ p_sys = (struct aout_sys_t *)malloc( sizeof( struct aout_sys_t ) );
+ if( p_sys == NULL )
{
msg_Err( p_aout, "out of memory" );
- return( 1 );
+ return( VLC_ENOMEM );
}
- /* Get the default output device */
- // We now ask the GUI for the selected device
- p_sys->device=[gTheMacOSXAudioSystem getSelectedDeviceSetToRate:p_aout->output.output.i_rate];
- if(p_sys->device==0)
+ memset( p_sys, 0, sizeof( struct aout_sys_t ) );
+ p_aout->output.p_sys = p_sys;
+
+ if( InitHardware( p_aout ) )
+ {
+ msg_Err( p_aout, "InitHardware failed" );
+ free( (void *)p_sys );
+ return( VLC_EGENERIC );
+ }
+
+ if( var_Type( p_aout, "audio-device" ) == 0 )
{
- msg_Err( p_aout, "couldn't get output device");
- return( -1 );
+ vlc_value_t val;
+
+ var_Create( p_aout, "audio-device", VLC_VAR_STRING |
+ VLC_VAR_HASCHOICE );
+
+ for( i = 0; i < p_sys->i_options; i++ )
+ {
+ val.psz_string = p_sys->p_options[i].sz_option;
+ var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val );
+ }
+
+ val.b_bool = VLC_TRUE;
+ var_Set( p_aout, "intf-change", val );
}
- msg_Dbg(p_aout, "device returned: %ld", p_sys->device);
+
+ /* Get selected device */
+ if( GetDevice( p_aout, &p_sys->devid ) )
+ {
+ msg_Err( p_aout, "GetDevice failed" );
+ FreeHardware( p_aout );
+ free( (void *)p_sys );
+ return( VLC_EGENERIC );
+ }
p_aout->output.pf_play = Play;
aout_VolumeSoftInit( p_aout );
- /* Get a description of the data format used by the device */
- i_param_size = sizeof(AudioStreamBasicDescription);
- err = AudioDeviceGetProperty(p_sys->device, 0, false, kAudioDevicePropertyStreamFormat,
- &i_param_size, &p_sys->stream_format );
+ /* Get a description of the stream format */
+ i_param_size = sizeof( AudioStreamBasicDescription );
+ err = AudioDeviceGetProperty( p_sys->devid, 0, false,
+ kAudioDevicePropertyStreamFormat,
+ &i_param_size, &p_sys->stream_format );
if( err != noErr )
{
- msg_Err( p_aout, "failed to get stream format: %4.4s", &err );
- return -1 ;
+ msg_Err( p_aout, "failed to get stream format: [%4.4s]",
+ (char *)&err );
+ FreeHardware( p_aout );
+ free( (void *)p_sys );
+ return( VLC_EGENERIC );
}
- /* Now we know the sample rate of the device */
- p_aout->output.output.i_rate = p_sys->stream_format.mSampleRate;
-
- msg_Dbg( p_aout, "mSampleRate %ld, mFormatID %4.4s, mFormatFlags %ld, mBytesPerPacket %ld, mFramesPerPacket %ld, mBytesPerFrame %ld, mChannelsPerFrame %ld, mBitsPerChannel %ld",
- (UInt32)p_sys->stream_format.mSampleRate, &p_sys->stream_format.mFormatID,
- p_sys->stream_format.mFormatFlags, p_sys->stream_format.mBytesPerPacket,
- p_sys->stream_format.mFramesPerPacket, p_sys->stream_format.mBytesPerFrame,
- p_sys->stream_format.mChannelsPerFrame, p_sys->stream_format.mBitsPerChannel );
-
- msg_Dbg( p_aout, "vlc format %4.4s, mac output format '%4.4s'",
- (char *)&p_aout->output.output.i_format, &p_sys->stream_format.mFormatID );
-
- /* Get the buffer size that the device uses for IO */
- // If we do PCM, use the device's given buffer size
- // If we do raw AC3, we could use the devices given size too
- // If we do AC3 over SPDIF, force the size of one AC3 frame
- // (I think we need to do that because of the packetizer)
+ /* Set the output sample rate */
+ p_aout->output.output.i_rate =
+ (unsigned int)p_sys->stream_format.mSampleRate;
+
+ msg_Dbg( p_aout, "format: [%ld][%4.4s][%ld][%ld][%ld][%ld][%ld][%ld]",
+ (UInt32)p_sys->stream_format.mSampleRate,
+ (char *)&p_sys->stream_format.mFormatID,
+ p_sys->stream_format.mFormatFlags,
+ p_sys->stream_format.mBytesPerPacket,
+ p_sys->stream_format.mFramesPerPacket,
+ p_sys->stream_format.mBytesPerFrame,
+ p_sys->stream_format.mChannelsPerFrame,
+ p_sys->stream_format.mBitsPerChannel );
+
+ /* Get the buffer size */
i_param_size = sizeof( p_sys->i_buffer_size );
- err = AudioDeviceGetProperty( p_sys->device, 0, false,
+ err = AudioDeviceGetProperty( p_sys->devid, 0, false,
kAudioDevicePropertyBufferSize,
&i_param_size, &p_sys->i_buffer_size );
- if(err) {
- msg_Err(p_aout, "failed to get buffer size - err %4.4s, device %ld", &err, p_sys->device);
- return -1;
- }
- else msg_Dbg( p_aout, "native buffer Size: %d", p_sys->i_buffer_size );
-
- if((p_sys->stream_format.mFormatID==kAudioFormat60958AC3
- || p_sys->stream_format.mFormatID=='IAC3')
- && p_sys->i_buffer_size != AOUT_SPDIF_SIZE)
- {
- p_sys->i_buffer_size = AOUT_SPDIF_SIZE;
- i_param_size = sizeof( p_sys->i_buffer_size );
- err = AudioDeviceSetProperty( p_sys->device, 0, 0, false,
- kAudioDevicePropertyBufferSize,
- i_param_size, &p_sys->i_buffer_size );
- if( err != noErr )
- {
- msg_Err( p_aout, "failed to set device buffer size: %4.4s", &err );
- return -1;
- }
- else msg_Dbg(p_aout, "bufferSize set to %d", p_sys->i_buffer_size);
- };
-
-
- // We now know the buffer size in bytes. Set the values for the vlc converters.
- switch(p_sys->stream_format.mFormatID)
- {
- case 0:
- case kAudioFormatLinearPCM:
- p_aout->output.output.i_format = VLC_FOURCC('f','l','3','2');
- if ( p_sys->stream_format.mChannelsPerFrame < 6 )
- p_aout->output.output.i_physical_channels
- = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
- else
- p_aout->output.output.i_physical_channels
- = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
- | AOUT_CHAN_CENTER | AOUT_CHAN_REARRIGHT
- | AOUT_CHAN_REARLEFT | AOUT_CHAN_LFE;
-
- p_aout->output.i_nb_samples = p_sys->i_buffer_size / p_sys->stream_format.mBytesPerFrame;
- break;
-
- case kAudioFormat60958AC3:
- case 'IAC3':
- p_aout->output.output.i_format = VLC_FOURCC('s','p','d','i');
- msg_Dbg(p_aout, "phychan %d, ochan %d, bytes/fr %d, frlen %d",
- p_aout->output.output.i_physical_channels,
- p_aout->output.output.i_original_channels,
- p_aout->output.output.i_bytes_per_frame,
- p_aout->output.output.i_frame_length);
-
- p_aout->output.output.i_bytes_per_frame = AOUT_SPDIF_SIZE; //p_sys->stream_format.mBytesPerFrame;
- p_aout->output.output.i_frame_length = A52_FRAME_NB; //p_sys->stream_format.mFramesPerPacket;
- p_aout->output.i_nb_samples = p_aout->output.output.i_frame_length;
-
-
- //Probably not needed after all
-
- // Some more settings to make the SPDIF device work... Other SPDIF Devices might need additional
- // values here. But don't change these, in order to not break existing devices. Either add values
- // which are not being set here, or check if the SetProperty was successful, and try another version
- // if not.
-// p_sys->stream_format.mBytesPerFrame=4; // usually set to 0 for AC3 by the system
-// p_sys->stream_format.mFormatFlags|=kAudioFormatFlagIsBigEndian;
-// +kAudioFormatFlagIsPacked
-// +kAudioFormatFlagIsNonInterleaved;
-// p_sys->stream_format.mBytesPerPacket=6144;
-// p_sys->stream_format.mFramesPerPacket=1536;
-
- break;
-
- default:
- msg_Err( p_aout, "Unknown hardware format '%4.4s'. Go ask Heiko.", &p_sys->stream_format.mFormatID );
- return -1;
- }
-
-
- // Now tell the device how many sample frames to expect in each buffer
- i_param_size=sizeof(p_aout->output.i_nb_samples);
-#if 0
- err = AudioDeviceGetProperty( p_sys->device, 0, false,
- kAudioDevicePropertyBufferFrameSize,
- &i_param_size, &p_aout->output.i_nb_samples);
- if(err) {
- msg_Err(p_aout, "failed to get BufferFrameSize - err %4.4s, device %ld", &err, p_sys->device);
- return -1;
- }
- else msg_Dbg( p_aout, "native BufferFrameSize: %d", p_aout->output.i_nb_samples);
-#else
- err = AudioDeviceSetProperty( p_sys->device, 0, 0, false,
- kAudioDevicePropertyBufferFrameSize,
- i_param_size, &p_aout->output.i_nb_samples);
if( err != noErr )
{
- msg_Err( p_aout, "failed to set BufferFrameSize: %4.4s", &err );
- return -1;
+ msg_Err( p_aout, "failed to get buffer size: [%4.4s]",
+ (char *)&err );
+ FreeHardware( p_aout );
+ free( (void *)p_sys );
+ return( VLC_EGENERIC );
}
- else msg_Dbg(p_aout, "bufferFrameSize set to %d", p_aout->output.i_nb_samples);
-#endif
-/*
- // And set the device format, since we might have changed some of it above
- i_param_size = sizeof(AudioStreamBasicDescription);
- err = AudioDeviceSetProperty(p_sys->device, 0, 0, false, kAudioDevicePropertyStreamFormat,
- i_param_size, &p_sys->stream_format );
+ msg_Dbg( p_aout, "device buffer size: [%ld]", p_sys->i_buffer_size );
+
+ /* If we do AC3 over SPDIF, set buffer size to one AC3 frame */
+ if( ( p_sys->stream_format.mFormatID == kAudioFormat60958AC3 ||
+ p_sys->stream_format.mFormatID == 'IAC3' ) &&
+ p_sys->i_buffer_size != AOUT_SPDIF_SIZE )
+ {
+ p_sys->i_buffer_size = AOUT_SPDIF_SIZE;
+ i_param_size = sizeof( p_sys->i_buffer_size );
+ err = AudioDeviceSetProperty( p_sys->devid, 0, 0, false,
+ kAudioDevicePropertyBufferSize,
+ i_param_size, &p_sys->i_buffer_size );
+ if( err != noErr )
+ {
+ msg_Err( p_aout, "failed to set buffer size: [%4.4s]",
+ (char *)&err );
+ FreeHardware( p_aout );
+ free( (void *)p_sys );
+ return( VLC_EGENERIC );
+ }
+
+ msg_Dbg( p_aout, "device buffer size set to: [%ld]",
+ p_sys->i_buffer_size );
+ }
+
+ switch( p_sys->stream_format.mFormatID )
+ {
+ case kAudioFormatLinearPCM:
+ p_aout->output.output.i_format = VLC_FOURCC('f','l','3','2');
+
+ if( p_sys->stream_format.mChannelsPerFrame < 6 )
+ {
+ p_aout->output.output.i_physical_channels =
+ AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
+ }
+ else
+ {
+ p_aout->output.output.i_physical_channels =
+ AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT |
+ AOUT_CHAN_CENTER | AOUT_CHAN_REARRIGHT |
+ AOUT_CHAN_REARLEFT | AOUT_CHAN_LFE;
+ }
+
+ p_aout->output.i_nb_samples = (int)( p_sys->i_buffer_size /
+ p_sys->stream_format.mBytesPerFrame );
+ break;
+
+ case 'IAC3':
+ case kAudioFormat60958AC3:
+ p_aout->output.output.i_format = VLC_FOURCC('s','p','d','i');
+ p_aout->output.output.i_bytes_per_frame = AOUT_SPDIF_SIZE;
+ p_aout->output.output.i_frame_length = A52_FRAME_NB;
+ p_aout->output.i_nb_samples = p_aout->output.output.i_frame_length;
+ break;
+
+ default:
+ msg_Err( p_aout, "unknown hardware format: [%4.4s]",
+ (char *)&p_sys->stream_format.mFormatID );
+ FreeHardware( p_aout );
+ free( (void *)p_sys );
+ return( VLC_EGENERIC );
+ }
+
+ /* Set buffer frame size */
+ i_param_size = sizeof( p_aout->output.i_nb_samples );
+ err = AudioDeviceSetProperty( p_sys->devid, 0, 0, false,
+ kAudioDevicePropertyBufferFrameSize,
+ i_param_size,
+ &p_aout->output.i_nb_samples );
if( err != noErr )
{
- msg_Err( p_aout, "failed to set stream format: %4.4s", &err );
- return -1 ;
+ msg_Err( p_aout, "failed to set buffer frame size: [%4.4s]",
+ (char *)&err );
+ FreeHardware( p_aout );
+ free( (void *)p_sys );
+ return( VLC_EGENERIC );
}
- else
- msg_Dbg( p_aout, "set: mSampleRate %ld, mFormatID %4.4s, mFormatFlags %ld, mBytesPerPacket %ld, mFramesPerPacket %ld, mBytesPerFrame %ld, mChannelsPerFrame %ld, mBitsPerChannel %ld",
- (UInt32)p_sys->stream_format.mSampleRate, &p_sys->stream_format.mFormatID,
- p_sys->stream_format.mFormatFlags, p_sys->stream_format.mBytesPerPacket,
- p_sys->stream_format.mFramesPerPacket, p_sys->stream_format.mBytesPerFrame,
- p_sys->stream_format.mChannelsPerFrame, p_sys->stream_format.mBitsPerChannel );
- */
-
-
+
+ msg_Dbg( p_aout, "device buffer frame size set to: [%d]",
+ p_aout->output.i_nb_samples );
+
/* Add callback */
- err = AudioDeviceAddIOProc( p_sys->device,
+ err = AudioDeviceAddIOProc( p_sys->devid,
(AudioDeviceIOProc)IOCallback,
(void *)p_aout );
if( err != noErr )
{
- msg_Err( p_aout, "AudioDeviceAddIOProc failed: %4.4s", &err );
- return -1;
+ msg_Err( p_aout, "AudioDeviceAddIOProc failed: [%4.4s]",
+ (char *)&err );
+ FreeHardware( p_aout );
+ free( (void *)p_sys );
+ return( VLC_EGENERIC );
}
-
- /* Open the output with callback IOCallback */
- err = AudioDeviceStart( p_sys->device,
- (AudioDeviceIOProc)IOCallback );
+
+ /* Start device */
+ err = AudioDeviceStart( p_sys->devid, (AudioDeviceIOProc)IOCallback );
if( err != noErr )
{
- msg_Err( p_aout, "AudioDeviceStart failed: %d", err );
- return -1;
+ msg_Err( p_aout, "AudioDeviceStart failed: [%4.4s]",
+ (char *)&err );
+ FreeHardware( p_aout );
+ free( (void *)p_sys );
+ return( VLC_EGENERIC );
}
/* Let's pray for the following operation to be atomic... */
- p_sys->clock_diff = - (mtime_t)AudioConvertHostTimeToNanos(
- AudioGetCurrentHostTime()) / 1000;
+ p_sys->clock_diff = - (mtime_t)
+ AudioConvertHostTimeToNanos( AudioGetCurrentHostTime() ) / 1000;
p_sys->clock_diff += mdate();
- return 0;
+ return( VLC_SUCCESS );
}
/*****************************************************************************
*****************************************************************************/
void E_(CloseAudio)( aout_instance_t * p_aout )
{
- struct aout_sys_t * p_sys = p_aout->output.p_sys;
OSStatus err;
+ struct aout_sys_t * p_sys = p_aout->output.p_sys;
- /* Stop playing sound through the device */
- err = AudioDeviceStop( p_sys->device,
- (AudioDeviceIOProc)IOCallback );
+ /* Stop device */
+ err = AudioDeviceStop( p_sys->devid, (AudioDeviceIOProc)IOCallback );
if( err != noErr )
{
- msg_Err( p_aout, "AudioDeviceStop failed: %4.4s", &err );
+ msg_Err( p_aout, "AudioDeviceStop failed: [%4.4s]", (char *)&err );
}
- err = AudioDeviceRemoveIOProc( p_sys->device,
- (AudioDeviceIOProc)IOCallback );
+ /* Remove callback */
+ err = AudioDeviceRemoveIOProc( p_sys->devid,
+ (AudioDeviceIOProc)IOCallback );
if( err != noErr )
{
- msg_Err( p_aout, "AudioDeviceRemoveIOProc failed: %4.4s", &err );
+ msg_Err( p_aout, "AudioDeviceRemoveIOProc failed: [%4.4s]",
+ (char *)&err );
}
+ err = AudioHardwareUnload();
+ if( err != noErr )
+ {
+ msg_Err( p_aout, "AudioHardwareUnload failed: [%4.4s]",
+ (char *)&err );
+ }
+
+ FreeHardware( p_aout );
+
free( p_sys );
}
{
}
-#include <syslog.h>
/*****************************************************************************
- * IOCallback : callback for audio output
+ * IOCallback: callback for audio output
*****************************************************************************/
static OSStatus IOCallback( AudioDeviceID inDevice,
const AudioTimeStamp *inNow,
const AudioTimeStamp *inOutputTime,
void *threadGlobals )
{
+ aout_buffer_t * p_buffer;
+ AudioTimeStamp host_time;
+ mtime_t current_date;
+
aout_instance_t * p_aout = (aout_instance_t *)threadGlobals;
struct aout_sys_t * p_sys = p_aout->output.p_sys;
- mtime_t current_date;
- AudioTimeStamp host_time;
- aout_buffer_t * p_buffer;
-
+
host_time.mFlags = kAudioTimeStampHostTimeValid;
AudioDeviceTranslateTime( inDevice, inOutputTime, &host_time );
- current_date = p_sys->clock_diff
- + AudioConvertHostTimeToNanos(host_time.mHostTime) / 1000;
+ current_date = p_sys->clock_diff +
+ AudioConvertHostTimeToNanos( host_time.mHostTime ) / 1000;
- p_buffer = aout_OutputNextBuffer( p_aout, current_date, (p_aout->output.output.i_format == VLC_FOURCC('s','p','d','i')) );
+#define B_SPDI (p_aout->output.output.i_format == VLC_FOURCC('s','p','d','i'))
+ p_buffer = aout_OutputNextBuffer( p_aout, current_date, B_SPDI );
+#undef B_SPDI
- /* move data into output data buffer */
- if ( p_buffer != NULL )
+ if( p_buffer != NULL )
{
- BlockMoveData( p_buffer->p_buffer,
+ /* move data into output data buffer */
+ BlockMoveData( p_buffer->p_buffer,
outOutputData->mBuffers[ 0 ].mData,
p_sys->i_buffer_size );
-// syslog(LOG_INFO, "convert: %08lX %08lX %08lX", ((long*)p_buffer->p_buffer)[0], ((long*)p_buffer->p_buffer)[1], ((long*)p_buffer->p_buffer)[2]);
- aout_BufferFree( p_buffer );
+
+ aout_BufferFree( p_buffer );
}
else
{
- memset(outOutputData->mBuffers[ 0 ].mData, 0, p_sys->i_buffer_size);
+ memset( outOutputData->mBuffers[ 0 ].mData,
+ 0, p_sys->i_buffer_size );
+ }
+
+ return( noErr );
+}
+
+/*****************************************************************************
+ * InitHardware
+ *****************************************************************************/
+static int InitHardware( aout_instance_t * p_aout )
+{
+ OSStatus err;
+ UInt32 i, i_param_size;
+ AudioDeviceID * p_devices;
+
+ struct aout_sys_t * p_sys = p_aout->output.p_sys;
+
+ /* Get number of devices */
+ err = AudioHardwareGetPropertyInfo( kAudioHardwarePropertyDevices,
+ &i_param_size, NULL );
+ if( err != noErr )
+ {
+ msg_Err( p_aout, "AudioHardwareGetPropertyInfo failed: [%4.4s]",
+ (char *)&err );
+ return( VLC_EGENERIC );
+ }
+
+ p_sys->i_devices = i_param_size / sizeof( AudioDeviceID );
+
+ if( p_sys->i_devices < 1 )
+ {
+ msg_Err( p_aout, "no devices found" );
+ return( VLC_EGENERIC );
+ }
+
+ msg_Dbg( p_aout, "system has [%ld] device(s)", p_sys->i_devices );
+
+ /* Allocate DeviceID array */
+ p_devices = (AudioDeviceID *)malloc( i_param_size );
+ if( p_devices == NULL )
+ {
+ msg_Err( p_aout, "out of memory" );
+ return( VLC_ENOMEM );
}
+ /* Populate DeviceID array */
+ err = AudioHardwareGetProperty( kAudioHardwarePropertyDevices,
+ &i_param_size, (void *)p_devices );
+ if( err != noErr )
+ {
+ msg_Err( p_aout, "AudioHardwareGetProperty failed: [%4.4s]",
+ (char *)&err );
+ free( (void *)p_devices );
+ return( VLC_EGENERIC );
+ }
-// outOutputData->mBuffers[0].mDataByteSize=p_sys->i_buffer_size;
+ p_sys->p_devices = (struct aout_dev_t *)
+ malloc( sizeof( struct aout_dev_t ) * p_sys->i_devices );
+ if( p_sys->p_devices == NULL )
+ {
+ msg_Err( p_aout, "out of memory" );
+ free( (void *)p_devices );
+ return( VLC_ENOMEM );
+ }
+
+ for( i = 0; i < p_sys->i_devices; i++ )
+ {
+ p_sys->p_devices[i].devid = p_devices[i];
+
+ if( InitDevice( i, p_aout ) )
+ {
+ UInt32 j;
+
+ msg_Err( p_aout, "InitDevice(%ld) failed", i );
+
+ for( j = 0; j < i; j++ )
+ {
+ FreeDevice( j, p_aout );
+ }
- return noErr;
+ free( (void *)p_sys->p_devices );
+ free( (void *)p_devices );
+
+ return( VLC_EGENERIC );
+ }
+ }
+
+ free( (void *)p_devices );
+
+ return( VLC_SUCCESS );
}
+/*****************************************************************************
+ * InitDevice
+ *****************************************************************************/
+static int InitDevice( UInt32 i_dev, aout_instance_t * p_aout )
+{
+ OSStatus err;
+ UInt32 i, i_param_size;
+ AudioBufferList *p_buffer_list;
+
+ struct aout_sys_t * p_sys = p_aout->output.p_sys;
+ struct aout_dev_t * p_dev = &p_sys->p_devices[i_dev];
+
+ /* Get length of device name */
+ err = AudioDeviceGetPropertyInfo( p_dev->devid, 0, FALSE,
+ kAudioDevicePropertyDeviceName,
+ &i_param_size, NULL );
+ if( err != noErr )
+ {
+ msg_Err( p_aout, "AudioDeviceGetPropertyInfo failed: [%4.4s]",
+ (char *)&err );
+ return( VLC_EGENERIC );
+ }
+
+ /* Allocate memory for device name */
+ p_dev->psz_device_name = (char *)malloc( i_param_size );
+ if( p_dev->psz_device_name == NULL )
+ {
+ msg_Err( p_aout, "out of memory" );
+ return( VLC_ENOMEM );
+ }
+
+ /* Get device name */
+ err = AudioDeviceGetProperty( p_dev->devid, 0, FALSE,
+ kAudioDevicePropertyDeviceName,
+ &i_param_size, p_dev->psz_device_name );
+ if( err != noErr )
+ {
+ msg_Err( p_aout, "AudioDeviceGetProperty failed: [%4.4s]",
+ (char *)&err );
+ free( (void *)p_dev->psz_device_name );
+ return( VLC_EGENERIC );
+ }
+
+ msg_Dbg( p_aout, "device [%ld] has name [%s]",
+ i_dev, p_dev->psz_device_name );
+
+ err = AudioDeviceGetPropertyInfo( p_dev->devid, 0, FALSE,
+ kAudioDevicePropertyStreamConfiguration,
+ &i_param_size, NULL );
+ if( err != noErr )
+ {
+ msg_Err( p_aout, "AudioDeviceGetPropertyInfo failed: [%4.4s]",
+ (char *)&err );
+ free( (void *)p_dev->psz_device_name );
+ return( VLC_EGENERIC );
+ }
+
+ p_buffer_list = (AudioBufferList *)malloc( i_param_size );
+ if( p_buffer_list == NULL )
+ {
+ msg_Err( p_aout, "out of memory" );
+ free( (void *)p_dev->psz_device_name );
+ return( VLC_ENOMEM );
+ }
+
+ err = AudioDeviceGetProperty( p_dev->devid, 0, FALSE,
+ kAudioDevicePropertyStreamConfiguration,
+ &i_param_size, p_buffer_list );
+ if( err != noErr )
+ {
+ msg_Err( p_aout, "AudioDeviceGetProperty failed: [%4.4s]",
+ (char *)&err );
+ free( (void *)p_dev->psz_device_name );
+ free( (void *)p_buffer_list );
+ return( VLC_EGENERIC );
+ }
+
+ p_dev->i_streams = p_buffer_list->mNumberBuffers;
+ free( (void *)p_buffer_list );
+
+ msg_Dbg( p_aout, "device [%ld] has [%ld] streams",
+ i_dev, p_dev->i_streams );
+
+ p_dev->pp_streams = (AudioStreamBasicDescription **)
+ malloc( p_dev->i_streams *
+ sizeof( *p_dev->pp_streams ) );
+ if( p_dev->pp_streams == NULL )
+ {
+ msg_Err( p_aout, "out of memory" );
+ free( (void *)p_dev->psz_device_name );
+ return( VLC_ENOMEM );
+ }
+
+ for( i = 0; i < p_dev->i_streams; i++ )
+ {
+ if( InitStream( i_dev, p_aout, i ) )
+ {
+ UInt32 j;
+
+ msg_Err( p_aout, "InitStream(%ld, %ld) failed", i_dev, i );
+
+ for( j = 0; j < i; j++ )
+ {
+ FreeStream( i_dev, p_aout, j );
+ }
+
+ free( (void *)p_dev->psz_device_name );
+ free( (void *)p_dev->pp_streams );
+
+ return( VLC_EGENERIC );
+ }
+ }
+
+ return( VLC_SUCCESS );
+}
+
+/*****************************************************************************
+ * FreeDevice
+ *****************************************************************************/
+static void FreeDevice( UInt32 i_dev, aout_instance_t * p_aout )
+{
+ UInt32 i;
+
+ struct aout_sys_t * p_sys = p_aout->output.p_sys;
+ struct aout_dev_t * p_dev = &p_sys->p_devices[i_dev];
+
+ for( i = 0; i < p_dev->i_streams; i++ )
+ {
+ FreeStream( i_dev, p_aout, i );
+ }
+
+ free( (void *)p_dev->pp_streams );
+ free( (void *)p_dev->psz_device_name );
+}
+
+/*****************************************************************************
+ * FreeHardware
+ *****************************************************************************/
+static void FreeHardware( aout_instance_t * p_aout )
+{
+ UInt32 i;
+
+ struct aout_sys_t * p_sys = p_aout->output.p_sys;
+
+ for( i = 0; i < p_sys->i_devices; i++ )
+ {
+ FreeDevice( i, p_aout );
+ }
+
+ free( (void *)p_sys->p_options );
+ free( (void *)p_sys->p_devices );
+}
+
+/*****************************************************************************
+ * GetStreamID
+ *****************************************************************************/
+static int GetStreamID( AudioDeviceID devid, UInt32 i_idx,
+ AudioStreamID * p_sid )
+{
+ OSStatus err;
+ UInt32 i_param_size;
+ AudioStreamID * p_stream_list;
+
+ err = AudioDeviceGetPropertyInfo( devid, 0, FALSE,
+ kAudioDevicePropertyStreams,
+ &i_param_size, NULL );
+ if( err != noErr )
+ {
+ return( VLC_EGENERIC );
+ }
+
+ p_stream_list = (AudioStreamID *)malloc( i_param_size );
+ if( p_stream_list == NULL )
+ {
+ return( VLC_ENOMEM );
+ }
+
+ err = AudioDeviceGetProperty( devid, 0, FALSE,
+ kAudioDevicePropertyStreams,
+ &i_param_size, p_stream_list );
+ if( err != noErr )
+ {
+ free( (void *)p_stream_list );
+ return( VLC_EGENERIC );
+ }
+
+ *p_sid = p_stream_list[i_idx - 1];
+
+ free( (void *)p_stream_list );
+
+ return( VLC_SUCCESS );
+}
+
+/*****************************************************************************
+ * InitStream
+ *****************************************************************************/
+static int InitStream( UInt32 i_dev, aout_instance_t *p_aout,
+ UInt32 i_idx )
+{
+ OSStatus err;
+ AudioStreamID i_sid;
+ UInt32 i, i_streams;
+ UInt32 j, i_param_size;
+
+ struct aout_sys_t * p_sys = p_aout->output.p_sys;
+ struct aout_dev_t * p_dev = &p_sys->p_devices[i_dev];
+
+ if( GetStreamID( p_dev->devid, i_idx + 1, &i_sid ) )
+ {
+ msg_Err( p_aout, "GetStreamID(%ld, %ld) failed", i_dev, i_idx );
+ return( VLC_EGENERIC );
+ }
+
+ err = AudioStreamGetPropertyInfo( i_sid, 0,
+ kAudioStreamPropertyPhysicalFormats,
+ &i_param_size, NULL );
+ if( err != noErr )
+ {
+ msg_Err( p_aout, "AudioStreamGetPropertyInfo failed: [%4.4s]",
+ (char *)&err );
+ return( VLC_EGENERIC );
+ }
+
+ i_streams = i_param_size / sizeof( AudioStreamBasicDescription );
+
+#define P_STREAMS p_dev->pp_streams[i_idx]
+
+ P_STREAMS = (AudioStreamBasicDescription *)malloc( i_param_size );
+ if( P_STREAMS == NULL )
+ {
+ msg_Err( p_aout, "out of memory" );
+ return( VLC_ENOMEM );
+ }
+
+ err = AudioStreamGetProperty( i_sid, 0,
+ kAudioStreamPropertyPhysicalFormats,
+ &i_param_size, P_STREAMS );
+ if( err != noErr )
+ {
+ msg_Err( p_aout, "AudioStreamGetProperty failed: [%4.4s]",
+ (char *)&err );
+ free( (void *)P_STREAMS );
+ return( VLC_EGENERIC );
+ }
+
+ for( j = 0; j < N_AOUT_CLASSES; j++ )
+ {
+ vlc_bool_t b_found = 0;
+ UInt32 i_channels = 0xFFFFFFFF;
+ UInt32 i_sdx = 0;
+
+ for( i = 0; i < i_streams; i++ )
+ {
+ if( ( P_STREAMS[i].mFormatID != aout_classes[j].mFormatID ) ||
+ ( P_STREAMS[i].mChannelsPerFrame <
+ aout_classes[j].mChannelsPerFrame ) )
+ {
+ continue;
+ }
+
+ if( P_STREAMS[i].mChannelsPerFrame < i_channels )
+ {
+ i_channels = P_STREAMS[i].mChannelsPerFrame;
+ i_sdx = i;
+ b_found = 1;
+ }
+ }
+
+ if( b_found )
+ {
+ p_sys->p_options = (struct aout_option_t *)
+ realloc( p_sys->p_options,
+ ( p_sys->i_options + 1 ) *
+ sizeof( struct aout_option_t ) );
+ if( p_sys->p_options == NULL )
+ {
+ msg_Err( p_aout, "out of memory" );
+ free( (void *)P_STREAMS );
+ return( VLC_ENOMEM );
+ }
+
+#define AOUT_OPTION p_sys->p_options[p_sys->i_options]
+
+ snprintf( AOUT_OPTION.sz_option,
+ sizeof( AOUT_OPTION.sz_option ) /
+ sizeof( AOUT_OPTION.sz_option[0] ) - 1,
+ "%ld: %s (%s)",
+ p_sys->i_options,
+ p_dev->psz_device_name,
+ aout_classes[j].psz_class );
+
+ AOUT_OPTION.i_sid = i_sid;
+ AOUT_OPTION.i_dev = i_dev;
+ AOUT_OPTION.i_idx = i_idx;
+ AOUT_OPTION.i_sdx = i_sdx;
+ AOUT_OPTION.i_cdx = j;
+
+#undef AOUT_OPTION
+
+ p_sys->i_options++;
+ }
+ }
+
+#undef P_STREAMS
+
+ return( VLC_SUCCESS );
+}
+
+/*****************************************************************************
+ * FreeStream
+ *****************************************************************************/
+static void FreeStream( UInt32 i_dev, aout_instance_t *p_aout,
+ UInt32 i_idx )
+{
+ struct aout_sys_t * p_sys = p_aout->output.p_sys;
+ struct aout_dev_t * p_dev = &p_sys->p_devices[i_dev];
+
+ free( (void *)p_dev->pp_streams[i_idx] );
+}
+
+/*****************************************************************************
+ * GetDevice
+ *****************************************************************************/
+static int GetDevice( aout_instance_t *p_aout, AudioDeviceID *p_devid )
+{
+ OSStatus err;
+ char *psz_tmp;
+ vlc_value_t val;
+ UInt32 i_option;
+
+ struct aout_dev_t * p_dev;
+ struct aout_option_t * p_option;
+ struct aout_sys_t * p_sys = p_aout->output.p_sys;
+
+ if( var_Get( p_aout, "audio-device", &val ) < 0 )
+ {
+ msg_Err( p_aout, "audio-device var does not exist" );
+ return( VLC_ENOVAR );
+ }
+
+ psz_tmp = strchr( val.psz_string, ':' );
+ if( psz_tmp == NULL )
+ {
+ msg_Err( p_aout, "audio-device value missing seperator" );
+ free( (void *)val.psz_string );
+ return( VLC_EGENERIC );
+ }
+
+ *psz_tmp = '\0';
+ i_option = atol( val.psz_string );
+ free( (void *)val.psz_string );
+
+ p_option = &p_sys->p_options[i_option];
+ p_dev = &p_sys->p_devices[p_option->i_dev];
+
+#define P_STREAMS p_dev->pp_streams[p_option->i_idx]
+
+ err = AudioStreamSetProperty( p_option->i_sid, 0, 0,
+ kAudioStreamPropertyPhysicalFormat,
+ sizeof( P_STREAMS[p_option->i_sdx] ),
+ &P_STREAMS[p_option->i_sdx] );
+ if( err != noErr )
+ {
+ msg_Err( p_aout, "AudioStreamSetProperty failed: [%4.4s]",
+ (char *)&err );
+ return( VLC_EGENERIC );
+ }
+
+#undef P_STREAMS
+
+ msg_Dbg( p_aout, "getting device [%ld]", p_option->i_dev );
+
+ *p_devid = p_dev->devid;
+
+ return( VLC_SUCCESS );
+}
+++ /dev/null
-//
-// asystm.m
-//
-//
-// Created by Heiko Panther on Tue Sep 10 2002.
-//
-
-#import "asystm.h"
-#define MAXINT 0x7fffffff
-
-#define DEBUG_ASYSTM 1
-
-// this is a basic set of rules
-#define gNumClassificationRules 4
-
-const struct classificationRule gClassificationRules[gNumClassificationRules]=
-{
-{ // The old AC3 format type
- 'IAC3',
- 0,
- audiodevice_class_ac3,
- "Digital AC3"
-},
-{ // The new AC3 format type
- kAudioFormat60958AC3,
- 0,
- audiodevice_class_ac3,
- "Digital AC3"
-},
-{
- kAudioFormatLinearPCM,
- 2,
- audiodevice_class_pcm2,
- "Stereo PCM"
-},
-{
- kAudioFormatLinearPCM,
- 6,
- audiodevice_class_pcm6,
- "6 Channel PCM"
-}
-};
-
-MacOSXAudioSystem *gTheMacOSXAudioSystem; // Remove this global, access audio system froma aout some other way
-
-@implementation MacOSXSoundOption
-
-- (id)initWithName:(NSString*)_name deviceID:(AudioDeviceID)devID streamIndex:(UInt32)strInd formatID:(UInt32)formID chans:(UInt32)chans;
-{
- id me=0;
- if((me=[super init]))
- {
- name = _name;
- [name retain];
- deviceID=devID;
- streamIndex=strInd;
- mFormatID=formID;
- mChannels=chans;
- }
- return(me);
-}
-
-- (NSString*)name {return name;};
-
-- (AudioDeviceID)deviceID {return deviceID;};
-
-- (UInt32)streamIndex {return streamIndex;};
-
-- (UInt32)mFormatID {return mFormatID;};
-
-- (UInt32)mChannels {return mChannels;};
-
-- (void)dealloc {[name release];};
-
-@end
-
-
-@implementation MacOSXAudioSystem
-
-OSStatus listenerProc (AudioDeviceID inDevice,
- UInt32 inChannel,
- Boolean isInput,
- AudioDevicePropertyID inPropertyID,
- void* inClientData)
-{
- intf_thread_t * p_intf = [NSApp getIntf];
- msg_Dbg(p_intf, "********** Property Listener called! device %d, channel %d, isInput %d, propertyID %4.4s",
- inDevice, inChannel, isInput, &inPropertyID);
- return 0;
-};
-
-OSStatus streamListenerProc (AudioStreamID inStream,
- UInt32 inChannel,
- AudioDevicePropertyID inPropertyID,
- void* inClientData)
-{
- intf_thread_t * p_intf = [NSApp getIntf];
- msg_Dbg(p_intf, "********** Property Listener called! stream %d, channel %d, propertyID %4.4s",
- inStream, inChannel, &inPropertyID);
- return 0;
-};
-
-- (id)initWithGUI:(VLCMain*)_main
-{
- id me=0;
- if((me=[super init]))
- {
- gTheMacOSXAudioSystem=self;
- main=_main;
- [main retain];
- intf_thread_t * p_intf = [NSApp getIntf];
- selectedOutput=0;
-
- // find audio devices
- // find out how many audio devices there are, if any
- OSStatus status = noErr;
- UInt32 theSize;
- Boolean outWritable;
- AudioDeviceID *deviceList = NULL;
- UInt32 i;
-
- status = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &theSize, &outWritable);
- if(status != noErr)
- {
- msg_Err(p_intf, "AudioHardwareGetPropertyInfo failed");
- };
-
- // calculate the number of device available
- UInt32 devicesAvailable = theSize / sizeof(AudioDeviceID);
- // Bail if there aren't any devices
- if(devicesAvailable < 1)
- {
- msg_Err(p_intf, "no devices found");
- }
- if(DEBUG_ASYSTM) msg_Dbg(p_intf, "Have %i devices!", devicesAvailable);
-
- // make space for the devices we are about to get
- deviceList = (AudioDeviceID*)malloc(theSize);
- // get an array of AudioDeviceIDs
- status = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &theSize, (void *) deviceList);
- if(status != noErr)
- {
- msg_Err(p_intf, "could not get Device list");
- };
-
- // Build a menu
- NSMenuItem *newItem;
- newItem = [main getMIDevice]; //[[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:@"Sound output" action:NULL keyEquivalent:@""];
- newMenu = [newItem submenu]; //[[NSMenu allocWithZone:[NSMenu menuZone]] initWithTitle:@"Sound output"];
- //[newItem setSubmenu:newMenu];
- //[[NSApp mainMenu] addItem:newItem];
- //[newItem release];
-
- // check which devices can do what class of audio
- // struct mosx_AudioDeviceData deviceData;
- for(i=0; i<devicesAvailable; i++)
- [self CheckDevice:deviceList[i] isInput:false]; // only check the output part
-
- //[newMenu release];
- free(deviceList);
- };
- return me;
-};
-
-- (AudioStreamID) getStreamIDForIndex:(UInt32)streamIndex device:(AudioDeviceID)deviceID
-{
- // Does not currently use the stream index, but just returns the stream ID of the first stream.
- // Get the stream ID
- Boolean isInput=false, outWritable;
- UInt32 theSize;
- OSStatus err = AudioDeviceGetPropertyInfo(deviceID, 0, isInput, kAudioDevicePropertyStreams, &theSize, &outWritable);
- AudioStreamID *streamList = (AudioStreamID*)malloc(theSize);
- err = AudioDeviceGetProperty(deviceID, 0, isInput, kAudioDevicePropertyStreams, &theSize, streamList);
- AudioStreamID streamID = streamList[streamIndex - 1];
- free(streamList);
- return streamID;
-}
-
-- (void)CheckDevice:(AudioDeviceID)deviceID isInput:(bool)isInput
-{
- OSStatus err;
- UInt32 theSize;
- Boolean outWritable;
- AudioBufferList *bufferList = 0;
- UInt32 i, j;
- intf_thread_t * p_intf = [NSApp getIntf];
- char deviceName[32]; // Make this a CFString!
-
- // Add property listener
- err=AudioDeviceAddPropertyListener(deviceID, 1, isInput, kAudioDevicePropertyStreams, listenerProc, 0);
- if(err) msg_Err(p_intf, "Add Property Listener failed, err=%4.4s", &err);
- err=AudioDeviceAddPropertyListener(deviceID, 1, isInput, kAudioDevicePropertyStreamConfiguration, listenerProc, 0);
- if(err) msg_Err(p_intf, "Add Property Listener failed, err=%4.4s", &err);
- err=AudioDeviceAddPropertyListener(deviceID, 1, isInput, kAudioDevicePropertyStreamFormat, listenerProc, 0);
- if(err) msg_Err(p_intf, "Add Property Listener failed, err=%4.4s", &err);
-
- // Get the device name
- err = AudioDeviceGetPropertyInfo(deviceID, 0, isInput, kAudioDevicePropertyDeviceName, &theSize, &outWritable);
- theSize=sizeof(deviceName);
- err = AudioDeviceGetProperty(deviceID, 0, isInput, kAudioDevicePropertyDeviceName, &theSize, deviceName);
-
- // Get the stream configuration
- err = AudioDeviceGetPropertyInfo(deviceID, 0, isInput, kAudioDevicePropertyStreamConfiguration, &theSize, &outWritable);
- bufferList = (AudioBufferList*)malloc(theSize);
- err = AudioDeviceGetProperty(deviceID, 0, isInput, kAudioDevicePropertyStreamConfiguration, &theSize, bufferList);
-
- if(DEBUG_ASYSTM) msg_Dbg(p_intf, "\nFound a %s, examing its %s, it has %i streams.", deviceName, (isInput?"Input":"Output"), bufferList->mNumberBuffers);
-
- // find details of each stream
- for (i=0; i < bufferList->mNumberBuffers; i++)
- {
- short streamIndex=i+1;
- UInt32 nActFormats;
- AudioStreamBasicDescription *formatsAvailable;
-
- AudioStreamID streamID=[self getStreamIDForIndex:streamIndex device:deviceID];
-
- // Add property listener
- err=AudioStreamAddPropertyListener(streamID, 0, kAudioDevicePropertyStreams, streamListenerProc, 0);
- if(err) msg_Err(p_intf, "Add Property Listener failed, err=%4.4s", &err);
- err=AudioStreamAddPropertyListener(streamID, 0, kAudioDevicePropertyStreamConfiguration, streamListenerProc, 0);
- if(err) msg_Err(p_intf, "Add Property Listener failed, err=%4.4s", &err);
- err=AudioStreamAddPropertyListener(streamID, 0, kAudioDevicePropertyStreamFormat, streamListenerProc, 0);
- if(err) msg_Err(p_intf, "Add Property Listener failed, err=%4.4s", &err);
- err=AudioStreamAddPropertyListener(streamID, 0, kAudioStreamPropertyPhysicalFormat, streamListenerProc, 0);
- if(err) msg_Err(p_intf, "Add Property Listener failed, err=%4.4s", &err);
-
- // Get the # of actual formats in the current stream
- err = AudioStreamGetPropertyInfo(streamID, 0, kAudioStreamPropertyPhysicalFormats, &theSize, &outWritable);
- nActFormats = theSize / sizeof(AudioStreamBasicDescription);
- if(DEBUG_ASYSTM) msg_Dbg(p_intf, "stream index %i, streamID %i, nActFormats %d", streamIndex, streamID, nActFormats);
-
- // Get the format specifications
- formatsAvailable=(AudioStreamBasicDescription*) malloc(theSize);
- err = AudioStreamGetProperty(streamID, 0, kAudioStreamPropertyPhysicalFormats, &theSize, formatsAvailable);
- if(err) msg_Err(p_intf, "AudioDeviceGetProperty err %d", err);
-
- // now classify the device and add a menu entry for each device class it matches
- for(j=0; j<gNumClassificationRules; j++)
- {
- UInt32 numChans=MAXINT, format=0;
- for(i=0; i<theSize/sizeof(AudioStreamBasicDescription); i++)
- {
- if(DEBUG_ASYSTM) msg_Dbg(p_intf, "Finding formats: %4.4s - %d chans, %d Hz, %d bits/sample, %d bytes/frame",
- &formatsAvailable[i].mFormatID, formatsAvailable[i].mChannelsPerFrame,
- (UInt32)formatsAvailable[i].mSampleRate,
- formatsAvailable[i].mBitsPerChannel, formatsAvailable[i].mBytesPerFrame);
-
- if(formatsAvailable[i].mFormatID != gClassificationRules[j].mFormatID && gClassificationRules[j].mFormatID!=0) continue;
- if(formatsAvailable[i].mChannelsPerFrame < gClassificationRules[j].mChannelsPerFrame && gClassificationRules[j].mChannelsPerFrame!=0) continue;
- // we want to choose the format with the smallest allowable channel number for this class
- if(formatsAvailable[i].mChannelsPerFrame < numChans)
- {
- numChans=formatsAvailable[i].mChannelsPerFrame;
- format=i;
- };
- };
- if(numChans!=MAXINT) // we found a good setting
- {
- if(DEBUG_ASYSTM) msg_Dbg(p_intf, "classified into %d", gClassificationRules[j].characteristic);
- // make a sound option object
- char menuentry[48];
- snprintf(menuentry, 48, "%.32s: %.16s", deviceName, gClassificationRules[j].qualifierString);
- MacOSXSoundOption *device=[[MacOSXSoundOption alloc] initWithName:[NSString stringWithCString:menuentry] deviceID:deviceID streamIndex:streamIndex formatID:formatsAvailable[format].mFormatID chans:formatsAvailable[format].mChannelsPerFrame];
- [self registerSoundOption:device];
- };
- };
- free(formatsAvailable);
- }
-
- free(bufferList);
-};
-
-- (void)registerSoundOption:(MacOSXSoundOption*)option {
- NSMenuItem *newItem;
- newItem = [[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:[option name] action:NULL keyEquivalent:@""];
- [newItem setImage:[NSImage imageNamed:@"eomt_browsedata"]];
- [newItem setTarget:self];
- [newItem setAction:@selector(selectAction:)];
- [newItem setRepresentedObject:option];
- [newMenu addItem:newItem];
- if(selectedOutput==0) [self selectAction:newItem];
- [newItem release];
-};
-
-- (void)selectAction:(id)sender {
- [selectedOutput setState:NSOffState];
- selectedOutput=sender;
- [sender setState:NSOnState];
-};
-
-static void printStreamDescription(char *description, AudioStreamBasicDescription *format)
-{
- intf_thread_t * p_intf = [NSApp getIntf];
- if(DEBUG_ASYSTM) msg_Dbg(p_intf, "%s: mSampleRate %ld, mFormatID %4.4s, mFormatFlags %ld, mBytesPerPacket %ld, mFramesPerPacket %ld, mBytesPerFrame %ld, mChannelsPerFrame %ld, mBitsPerChannel %ld",
- description,
- (UInt32)format->mSampleRate, &format->mFormatID,
- format->mFormatFlags, format->mBytesPerPacket,
- format->mFramesPerPacket, format->mBytesPerFrame,
- format->mChannelsPerFrame, format->mBitsPerChannel);
-};
-
-
-- (AudioDeviceID)getSelectedDeviceSetToRate:(int)preferredSampleRate{
- // I know the selected device, stream, and the required format ID. Now find a format
- // that comes closest to the preferred rate
- // For sample size, it is assumed that 16 bits will always be enough.
- // Note that the caller is not guranteed to get the rate she preferred.
- AudioStreamBasicDescription *formatsAvailable;
- MacOSXSoundOption *selectedOption=[selectedOutput representedObject];
- bool foundFormat=false;
- UInt32 theSize;
- Boolean outWritable;
- OSStatus err;
- UInt32 i;
- intf_thread_t * p_intf = [NSApp getIntf];
- AudioDeviceID deviceID=[selectedOption deviceID];
-
- // get the streamID (it might have changed)
- AudioStreamID streamID=[self getStreamIDForIndex:[selectedOption streamIndex] device:deviceID];
-
- // Find the actual formats
- err = AudioStreamGetPropertyInfo(streamID, 0, kAudioStreamPropertyPhysicalFormats, &theSize, &outWritable);
- formatsAvailable=(AudioStreamBasicDescription*) malloc(theSize);
- err = AudioStreamGetProperty(streamID, 0, kAudioStreamPropertyPhysicalFormats, &theSize, formatsAvailable);
- if(err)
- {
- msg_Err(p_intf, "Error %4.4s getting the stream formats", &err);
- return 0;
- };
-
- UInt32 formtmp=[selectedOption mFormatID];
- if(DEBUG_ASYSTM) msg_Dbg(p_intf, "looking for: %4.4s - %d chans, %d Hz", &formtmp,
- [selectedOption mChannels], preferredSampleRate);
-
- // Check if there's a "best match" which has our required rate
- for(i=0; i<theSize/sizeof(AudioStreamBasicDescription); i++)
- {
- if(DEBUG_ASYSTM) msg_Dbg(p_intf, "actual: %4.4s - %d chans, %d Hz, %d bits/sample, %d bytes/frame",
- &formatsAvailable[i].mFormatID, formatsAvailable[i].mChannelsPerFrame,
- (int)formatsAvailable[i].mSampleRate,
- formatsAvailable[i].mBitsPerChannel, formatsAvailable[i].mBytesPerFrame);
-
- if(formatsAvailable[i].mChannelsPerFrame<0 || formatsAvailable[i].mChannelsPerFrame>100) {
- msg_Err(p_intf, "bogus format! index %i", i);
- return 0;
- };
-
- if( formatsAvailable[i].mFormatID == [selectedOption mFormatID]
- && formatsAvailable[i].mChannelsPerFrame == [selectedOption mChannels]
- && (int)formatsAvailable[i].mSampleRate == preferredSampleRate)
- {
- if(DEBUG_ASYSTM) msg_Dbg(p_intf, "Found the perfect format!!");
- foundFormat=true;
- break;
- };
- };
-
- int rate=MAXINT, format=0;
- if(!foundFormat)
- {
- for(i=0; i<theSize/sizeof(AudioStreamBasicDescription); i++)
- {
- // We don't have one... check if there's one with a higher sample rate.
- // Upsampling should be better than downsampling.
- // Select the smallest of the higher sample rates, to save resources.
- int actrate=(int)formatsAvailable[i].mSampleRate;
- if( formatsAvailable[i].mFormatID == [selectedOption mFormatID]
- && formatsAvailable[i].mChannelsPerFrame == [selectedOption mChannels]
- && actrate > preferredSampleRate)
- {
- if(actrate < rate)
- {
- rate=actrate;
- format=i;
- }
- };
- };
- if(rate!=MAXINT) // This means we have found a rate!! Yes!
- {
- if(DEBUG_ASYSTM) msg_Dbg(p_intf, "Only got a format with higher sample rate");
- foundFormat=true;
- i=format;
- };
- };
-
- if(!foundFormat)
- {
- rate=0;
- for(i=0; i<theSize/sizeof(AudioStreamBasicDescription); i++)
- {
- // Our last chance: select the highest lower sample rate.
- int actrate=(int)formatsAvailable[i].mSampleRate;
- if( actrate >= preferredSampleRate) // We must have done something wrong
- {
- if(DEBUG_ASYSTM) msg_Err(p_intf, "Found a rate that should have been selected previously.");
- free(formatsAvailable);
- return 0;
- };
-
- if(actrate > rate)
- {
- rate=actrate;
- format=i;
- }
- };
-
- if(rate!=0) // This means we have found a rate!! Yes!
- {
- if(DEBUG_ASYSTM) msg_Dbg(p_intf, "Only got a format with lower sample rate");
- foundFormat=true;
- i=format;
- }
- else // We must have done something wrong
- {
- msg_Err(p_intf, "Found no rate which is equal, higher or lower to requested rate. That means our device either: a) didn't exist in the first place or b) has been removed since.");
- free(formatsAvailable);
- return 0;
- };
- };
- AudioStreamBasicDescription desc=formatsAvailable[i];
- free(formatsAvailable);
-
- // Set the device stream format
- Boolean isWriteable;
-
- err = AudioStreamGetPropertyInfo(streamID, 0, kAudioStreamPropertyPhysicalFormat, &theSize, &isWriteable);
- if(err) msg_Err(p_intf, "GetPropertyInfo (stream format) error %4.4s - theSize %d", &err, theSize);
- if(DEBUG_ASYSTM) msg_Dbg(p_intf, "size %d, writable %d", theSize, isWriteable);
-
- if(DEBUG_ASYSTM) printStreamDescription("want to set", &desc);
-
- err = AudioStreamSetProperty(streamID, 0, 0, kAudioStreamPropertyPhysicalFormat, theSize, &desc);
- if(err) msg_Err(p_intf, "SetProperty (stream format) error %4.4s - theSize %d", &err, theSize);
-
- // Because of the format change, the streamID has changed!
- // That's why we return the deviceID.
- return deviceID;
-};
-
-
-- (void)dealloc
-{
- [main release];
-};
-
-
-@end