Commit 08f42608 authored by Jon Lech Johansen's avatar Jon Lech Johansen

* ./modules/gui/macosx/aout.m: cleaned up the code, removed intf dep.

  * ./src/misc/darwin_specific.m: fixed segfault (o_enumerator was being
                                  released twice) and memory leak.

    Bonne Ann�e!
parent 06fa8a6f
......@@ -12,8 +12,5 @@ SOURCES_macosx = \
modules/gui/macosx/playlist.m \
modules/gui/macosx/playlist.h \
modules/gui/macosx/controls.m \
modules/gui/macosx/asystm.m \
modules/gui/macosx/asystm.h \
modules/gui/macosx/adev_discovery.h \
$(NULL)
//
// main.h
// FindHW
//
// Created by Heiko Panther on Sun Sep 08 2002.
//
#import <Foundation/Foundation.h>
#import <CoreAudio/CoreAudio.h>
enum audiodeviceClasses
{
audiodevice_class_ac3 =1<<0, // compressed AC3
audiodevice_class_pcm2 =1<<1, // stereo PCM (uncompressed)
audiodevice_class_pcm6 =1<<2 // 6-channel PCM (uncompressed)
};
// specifies a rule for finding if a Device belongs to a class from above.
// if value==0, the value is ignored when matching. All other values must match.
struct classificationRule
{
UInt32 mFormatID;
UInt32 mChannelsPerFrame;
enum audiodeviceClasses characteristic;
char qualifierString[16];
};
......@@ -2,7 +2,7 @@
* 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>
......@@ -32,16 +32,87 @@
#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
*****************************************************************************
......@@ -50,17 +121,34 @@
*****************************************************************************/
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
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,
......@@ -74,212 +162,213 @@ 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;
aout_instance_t * p_aout = (aout_instance_t *)p_this;
/* 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 )
/* 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, "couldn't get output device");
return( -1 );
msg_Err( p_aout, "InitHardware failed" );
free( (void *)p_sys );
return( VLC_EGENERIC );
}
if( var_Type( p_aout, "audio-device" ) == 0 )
{
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 );
}
/* 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 );
}
msg_Dbg(p_aout, "device returned: %ld", p_sys->device);
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,
/* 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;
if( err != noErr )
{
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, "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)
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->device, 0, 0, false,
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 device buffer size: %4.4s", &err );
return -1;
msg_Err( p_aout, "failed to set buffer size: [%4.4s]",
(char *)&err );
FreeHardware( p_aout );
free( (void *)p_sys );
return( VLC_EGENERIC );
}
else msg_Dbg(p_aout, "bufferSize set to %d", p_sys->i_buffer_size);
};
msg_Dbg( p_aout, "device buffer size set to: [%ld]",
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)
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;
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.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;
p_aout->output.i_nb_samples = (int)( p_sys->i_buffer_size /
p_sys->stream_format.mBytesPerFrame );
break;
case kAudioFormat60958AC3:
case 'IAC3':
case kAudioFormat60958AC3:
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.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;
//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;
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 );
}
// 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,
/* 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);
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 set buffer frame 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 );
if( err != noErr )
{
msg_Err( p_aout, "failed to set stream format: %4.4s", &err );
return -1 ;
}
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 );
}
/*****************************************************************************
......@@ -287,24 +376,34 @@ int E_(OpenAudio)( vlc_object_t * p_this )
*****************************************************************************/
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,
/* 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 );
}
......@@ -315,9 +414,8 @@ static void Play( aout_instance_t * p_aout )
{
}
#include <syslog.h>
/*****************************************************************************
* IOCallback : callback for audio output
* IOCallback: callback for audio output
*****************************************************************************/
static OSStatus IOCallback( AudioDeviceID inDevice,
const AudioTimeStamp *inNow,
......@@ -327,36 +425,499 @@ static OSStatus IOCallback( AudioDeviceID inDevice,
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 )
{
/* 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 );
}
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 );
}
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;
// outOutputData->mBuffers[0].mDataByteSize=p_sys->i_buffer_size;
msg_Err( p_aout, "InitDevice(%ld) failed", i );
return noErr;
for( j = 0; j < i; j++ )
{
FreeDevice( j, p_aout );
}
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 );
}
//
// asystm.h
//
//
// Created by Heiko Panther on Tue Sep 10 2002.
// Copyright (c) 2002 __MyCompanyName__. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <CoreAudio/CoreAudio.h>
#import "adev_discovery.h"
#import "intf.h"
/*****************************************************************************
* MacOSXSoundOption
* Each audio device can give several sound options: there might be several
* streams on one device, each can have different formats which might qualify
* as an option.
* We record format and channels, since these attributes are requirements
* from the user and the aout should deliver what the user wants. This
* selection is basically done when the user chooses the output option.
* We do not record sample rate and bit depth, since these attributes are
* tied to the media source, and the device format that matches these media
* formats best should be selected. This selection is done when the aout
* module is created with a certain stream, and asks the asystm for a device.
*****************************************************************************/
@interface MacOSXSoundOption:NSObject
{
NSString *name;
AudioDeviceID deviceID;
UInt32 streamIndex;
UInt32 mFormatID;
UInt32 mChannels;
}
- (id)initWithName:(NSString*)_name deviceID:(AudioDeviceID)devID streamIndex:(UInt32)strInd formatID:(UInt32)formID chans:(UInt32)chans;
- (AudioDeviceID)deviceID;
- (UInt32)streamIndex;
- (UInt32)mFormatID;
- (UInt32)mChannels;
- (void)dealloc;
- (NSString*)name;
@end
@interface MacOSXAudioSystem : NSObject {
VLCMain *main;
/* selected output device */
NSMenuItem *selectedOutput;
NSMenu *newMenu;
}
- (id)initWithGUI:(VLCMain*)main;
- (AudioStreamID) getStreamIDForIndex:(UInt32)streamIndex device:(AudioDeviceID)deviceID;
- (void)CheckDevice:(AudioDeviceID)deviceID isInput:(bool)isInput;
- (void)registerSoundOption:(MacOSXSoundOption*)option;
- (void)selectAction:(id)sender;
- (AudioStreamID)getSelectedDeviceSetToRate:(int)preferredSampleRate;
- (void)dealloc;
@end
//
// 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
......@@ -2,7 +2,7 @@
* intf.h: MacOS X interface plugin
*****************************************************************************
* Copyright (C) 2002 VideoLAN
* $Id: intf.h,v 1.6 2002/12/25 02:23:36 massiot Exp $
* $Id: intf.h,v 1.7 2003/01/01 11:14:50 jlj Exp $
*
* Authors: Jon Lech Johansen <jon-vl@nanocrew.net>
* Christophe Massiot <massiot@via.ecp.fr>
......@@ -154,8 +154,6 @@ struct intf_sys_t
IBOutlet id o_dmi_play;
IBOutlet id o_dmi_pause;
IBOutlet id o_dmi_stop;
id asystm; // MacOSXAudioSystem
}
- (void)terminate;
......
......@@ -2,7 +2,7 @@
* intf.m: MacOS X interface plugin
*****************************************************************************
* Copyright (C) 2002 VideoLAN
* $Id: intf.m,v 1.13 2002/12/29 01:16:28 massiot Exp $
* $Id: intf.m,v 1.14 2003/01/01 11:14:50 jlj Exp $
*
* Authors: Jon Lech Johansen <jon-vl@nanocrew.net>
* Christophe Massiot <massiot@via.ecp.fr>
......@@ -35,7 +35,6 @@
#include "vout.h"
#include "prefs.h"
#include "playlist.h"
#include "asystm.h"
/*****************************************************************************
* Local prototypes.
......@@ -258,11 +257,6 @@ static void Run( intf_thread_t *p_intf )
[[NSRunLoop currentRunLoop]
addPort: p_intf->p_sys->o_sendport
forMode: NSDefaultRunLoopMode];
// Since we need the sound menu now, it's a good time to create the sound system class
asystm=[[MacOSXAudioSystem alloc] initWithGUI:self];
[asystm retain];
}
- (void)noopAction:(id)sender {
......@@ -493,8 +487,6 @@ static void Run( intf_thread_t *p_intf )
context: [NSGraphicsContext currentContext] eventNumber: 1
clickCount: 1 pressure: 0.0];
[NSApp postEvent: pEvent atStart: YES];
[asystm release];
}
- (void)manageMode
......
......@@ -2,7 +2,7 @@
* darwin_specific.m: Darwin specific features
*****************************************************************************
* Copyright (C) 2001 VideoLAN
* $Id: darwin_specific.m,v 1.2 2002/12/31 01:54:36 massiot Exp $
* $Id: darwin_specific.m,v 1.3 2003/01/01 11:14:50 jlj Exp $
*
* Authors: Samuel Hocevar <sam@zoy.org>
* Christophe Massiot <massiot@via.ecp.fr>
......@@ -118,26 +118,31 @@ void system_Init( vlc_t *p_this, int *pi_argc, char *ppsz_argv[] )
/* Check if $LANG is set. */
if ( (p_char = getenv("LANG")) == NULL )
{
vlc_bool_t b_found = 0;
NSAutoreleasePool * o_pool = [[NSAutoreleasePool alloc] init];
/* Retrieve user's preferences. */
NSUserDefaults * p_defs =
[[NSUserDefaults standardUserDefaults] autorelease];
NSArray * p_languages =
[[p_defs objectForKey:@"AppleLanguages"] autorelease];
NSEnumerator * p_enumerator =
[[p_languages objectEnumerator] autorelease];
NSString * p_lang;
NSUserDefaults * o_defs = [NSUserDefaults standardUserDefaults];
NSArray * o_languages = [o_defs objectForKey:@"AppleLanguages"];
NSEnumerator * o_enumerator = [o_languages objectEnumerator];
NSString * o_lang;
while ( (p_lang = [[p_enumerator nextObject] autorelease]) )
while ( (o_lang = [o_enumerator nextObject]) )
{
if( !b_found )
{
const char * psz_string = [p_lang lossyCString];
const char * psz_string = [o_lang lossyCString];
if ( FindLanguage( psz_string ) )
{
break;
b_found = 1;
}
}
/* FIXME : why does it segfault ??? */
//[o_pool release];
[o_lang release];
}
[o_languages release];
[o_pool release];
}
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment