Commit fb397dc0 authored by Derk-Jan Hartman's avatar Derk-Jan Hartman

* Backport of the Mac OS X audio fixes to 0.8.4a (fixes #456)

parent b759e185
......@@ -577,8 +577,6 @@ VLC-release.app: vlc
cp "$(srcdir)/$$i" $(top_builddir)/tmp; \
done
mkdir -p $(top_builddir)/tmp/modules/audio_output
cp $(srcdir)/modules/audio_output/coreaudio.c \
$(top_builddir)/tmp/modules/audio_output/coreaudio.c
mkdir -p $(top_builddir)/tmp/modules/gui/macosx
for i in \
about.h \
......@@ -691,8 +689,6 @@ VLC.app: vlc
cp "$(srcdir)/$$i" $(top_builddir)/tmp; \
done
mkdir -p $(top_builddir)/tmp/modules/audio_output
cp $(srcdir)/modules/audio_output/coreaudio.c \
$(top_builddir)/tmp/modules/audio_output/coreaudio.c
mkdir -p $(top_builddir)/tmp/modules/gui/macosx
for i in \
about.h \
......
......@@ -3627,14 +3627,14 @@ fi
dnl
dnl CoreAudio plugin
dnl
AC_ARG_ENABLE(coreaudio,
[ --enable-coreaudio CoreAudio module (default enabled on MacOS X)])
if test "${enable_coreaudio}" != "no" &&
(test "${SYS}" = "darwin" || test "${enable_coreaudio}" = "yes")
AC_ARG_ENABLE(macosx-audio,
[ --enable-macosx-audio Mac OS X audio module (default enabled on MacOS X)])
if test "${enable_macosx-audio}" != "no" &&
(test "${SYS}" = "darwin" || test "${enable_macosx-audio}" = "yes")
then
AC_CHECK_HEADERS(CoreAudio/CoreAudio.h,
[ VLC_ADD_BUILTINS([coreaudio auhal])
VLC_ADD_LDFLAGS([coreaudio auhal],[-framework CoreAudio -framework AudioUnit -framework AudioToolbox])
[ VLC_ADD_BUILTINS([auhal])
VLC_ADD_LDFLAGS([auhal],[-framework CoreAudio -framework AudioUnit -framework AudioToolbox])
], [ AC_MSG_ERROR([cannot find CoreAudio headers]) ])
fi
......
......@@ -41,14 +41,17 @@
# define AOUT_FMT_S16_NE VLC_FOURCC('s','1','6','b')
# define AOUT_FMT_U16_NE VLC_FOURCC('u','1','6','b')
# define AOUT_FMT_S24_NE VLC_FOURCC('s','2','4','b')
# define AOUT_FMT_SPDIF_NE VLC_FOURCC('s','p','d','b')
#else
# define AOUT_FMT_S16_NE VLC_FOURCC('s','1','6','l')
# define AOUT_FMT_U16_NE VLC_FOURCC('u','1','6','l')
# define AOUT_FMT_S24_NE VLC_FOURCC('s','2','4','l')
# define AOUT_FMT_SPDIF_NE VLC_FOURCC('s','p','d','i')
#endif
#define AOUT_FMT_NON_LINEAR( p_format ) \
( ((p_format)->i_format == VLC_FOURCC('s','p','d','i')) \
|| ((p_format)->i_format == VLC_FOURCC('s','p','d','b')) \
|| ((p_format)->i_format == VLC_FOURCC('a','5','2',' ')) \
|| ((p_format)->i_format == VLC_FOURCC('d','t','s',' ')) )
......
......@@ -62,8 +62,9 @@ static int Create( vlc_object_t *p_this )
{
aout_filter_t * p_filter = (aout_filter_t *)p_this;
if ( p_filter->input.i_format != VLC_FOURCC('a','5','2',' ')
|| p_filter->output.i_format != VLC_FOURCC('s','p','d','i') )
if ( p_filter->input.i_format != VLC_FOURCC('a','5','2',' ') ||
( p_filter->output.i_format != VLC_FOURCC('s','p','d','b') &&
p_filter->output.i_format != VLC_FOURCC('s','p','d','i') ) )
{
return -1;
}
......@@ -80,43 +81,49 @@ static int Create( vlc_object_t *p_this )
static void DoWork( aout_instance_t * p_aout, aout_filter_t * p_filter,
aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
{
/* It is not entirely clear which endianness the AC3 stream should have.
* I have been told endianness does not matter, AC3 can be both endian.
* But then, I could not get it to work on Mac OS X and a JVC RX-6000R
* decoder without using little endian. So right now, I convert to little
* endian.
/* AC3 is natively big endian. Most SPDIF devices have the native
* endianness of the computersystem.
* On MAc OS X however, little endian devices are also common.
*/
static const uint8_t p_sync[6] = { 0x72, 0xF8, 0x1F, 0x4E, 0x01, 0x00 };
static const uint8_t p_sync_le[6] = { 0x72, 0xF8, 0x1F, 0x4E, 0x01, 0x00 };
static const uint8_t p_sync_be[6] = { 0xF8, 0x72, 0x4E, 0x1F, 0x00, 0x01 };
#ifndef HAVE_SWAB
byte_t * p_tmp;
uint16_t i;
#endif
uint16_t i_length = p_in_buf->i_nb_bytes;
uint8_t * pi_length;
uint16_t i_frame_size = p_in_buf->i_nb_bytes / 2;
byte_t * p_in = p_in_buf->p_buffer;
byte_t * p_out = p_out_buf->p_buffer;
/* Copy the S/PDIF headers. */
memcpy( p_out, p_sync, 6 );
pi_length = (p_out + 6);
*pi_length = (i_length * 8) & 0xff;
*(pi_length + 1) = (i_length * 8) >> 8;
#ifdef HAVE_SWAB
swab( p_in, p_out + 8, i_length );
#else
p_tmp = p_out + 8;
for ( i = i_length / 2 ; i-- ; )
if( p_filter->output.i_format == VLC_FOURCC('s','p','d','b') )
{
p_tmp[0] = p_in[1];
p_tmp[1] = p_in[0];
p_tmp += 2; p_in += 2;
p_filter->p_vlc->pf_memcpy( p_out, p_sync_be, 6 );
p_out[4] = p_in[5] & 0x7; /* bsmod */
p_out[6] = (i_frame_size >> 4) & 0xff;
p_out[7] = (i_frame_size << 4) & 0xff;
p_filter->p_vlc->pf_memcpy( &p_out[8], p_in, i_frame_size * 2 );
}
else
{
p_filter->p_vlc->pf_memcpy( p_out, p_sync_le, 6 );
p_out[5] = p_in[5] & 0x7; /* bsmod */
p_out[6] = (i_frame_size << 4) & 0xff;
p_out[7] = (i_frame_size >> 4) & 0xff;
#ifdef HAVE_SWAB
swab( p_in, &p_out[8], i_frame_size * 2 );
#else
p_tmp = &p_out[8];
for( i = i_frame_size; i-- ; )
{
p_tmp[0] = p_in[1];
p_tmp[1] = p_in[0];
p_tmp += 2; p_in += 2;
}
#endif
p_filter->p_vlc->pf_memset( p_out + 8 + i_length, 0,
AOUT_SPDIF_SIZE - i_length - 8 );
}
p_filter->p_vlc->pf_memset( p_out + 8 + i_frame_size * 2, 0,
AOUT_SPDIF_SIZE - i_frame_size * 2 - 8 );
p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
p_out_buf->i_nb_bytes = AOUT_SPDIF_SIZE;
......
......@@ -79,8 +79,9 @@ static int Create( vlc_object_t *p_this )
{
aout_filter_t * p_filter = (aout_filter_t *)p_this;
if ( p_filter->input.i_format != VLC_FOURCC('d','t','s',' ')
|| p_filter->output.i_format != VLC_FOURCC('s','p','d','i') )
if( p_filter->input.i_format != VLC_FOURCC('d','t','s',' ') ||
( p_filter->output.i_format != VLC_FOURCC('s','p','d','i') &&
p_filter->output.i_format != VLC_FOURCC('s','p','d','b') ) )
{
return -1;
}
......@@ -117,9 +118,11 @@ static void Close( vlc_object_t * p_this )
static void DoWork( aout_instance_t * p_aout, aout_filter_t * p_filter,
aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
{
uint32_t i_ac5_spdif_type = 0;
uint16_t i_fz = p_in_buf->i_nb_samples * 4;
uint16_t i_frame, i_length = p_in_buf->i_nb_bytes;
static const uint8_t p_sync[6] = { 0x72, 0xF8, 0x1F, 0x4E, 0x00, 0x00 };
static const uint8_t p_sync_le[6] = { 0x72, 0xF8, 0x1F, 0x4E, 0x00, 0x00 };
static const uint8_t p_sync_be[6] = { 0xF8, 0x72, 0x4E, 0x1F, 0x00, 0x00 };
if( p_in_buf->i_nb_bytes != p_filter->p_sys->i_frame_size )
{
......@@ -156,23 +159,35 @@ static void DoWork( aout_instance_t * p_aout, aout_filter_t * p_filter,
byte_t * p_out = p_out_buf->p_buffer + (i_frame * i_fz);
byte_t * p_in = p_filter->p_sys->p_buf + (i_frame * i_length);
/* Copy the S/PDIF headers. */
memcpy( p_out, p_sync, 6 );
switch( p_in_buf->i_nb_samples )
{
case 512: *(p_out + 4) = 0x0B; break;
case 1024: *(p_out + 4) = 0x0C; break;
case 2048: *(p_out + 4) = 0x0D; break;
case 512: i_ac5_spdif_type = 0x0B; break;
case 1024: i_ac5_spdif_type = 0x0C; break;
case 2048: i_ac5_spdif_type = 0x0D; break;
}
*(p_out + 6) = (i_length * 8) & 0xff;
*(p_out + 7) = (i_length * 8) >> 8;
/* Copy the S/PDIF headers. */
if( p_filter->output.i_format == VLC_FOURCC('s','p','d','b') )
{
p_filter->p_vlc->pf_memcpy( p_out, p_sync_be, 6 );
p_out[5] = i_ac5_spdif_type;
p_out[6] = (( i_length ) >> 5 ) & 0xFF;
p_out[7] = ( i_length << 3 ) & 0xFF;
}
else
{
p_filter->p_vlc->pf_memcpy( p_out, p_sync_le, 6 );
p_out[4] = i_ac5_spdif_type;
p_out[6] = ( i_length << 3 ) & 0xFF;
p_out[7] = (( i_length ) >> 5 ) & 0xFF;
}
if( p_in[0] == 0x1f || p_in[0] == 0x7f )
if( ( (p_in[0] == 0x1F || p_in[0] == 0x7F) && p_filter->output.i_format == VLC_FOURCC('s','p','d','i') ) ||
( (p_in[0] == 0xFF || p_in[0] == 0xFE) && p_filter->output.i_format == VLC_FOURCC('s','p','d','b') ) )
{
/* We are dealing with a big endian bitstream.
* Convert to little endian */
/* We are dealing with a big endian bitstream and a little endian output
* or a little endian bitstream and a big endian output.
* Byteswap the stream */
#ifdef HAVE_SWAB
swab( p_in, p_out + 8, i_length );
#else
......@@ -190,8 +205,7 @@ static void DoWork( aout_instance_t * p_aout, aout_filter_t * p_filter,
}
else
{
/* Little endian */
memcpy( p_out + 8, p_in, i_length );
p_filter->p_vlc->pf_memcpy( p_out + 8, p_in, i_length );
}
if( i_fz > i_length + 8 )
......
......@@ -2,4 +2,3 @@ SOURCES_trivial_resampler = trivial.c
SOURCES_ugly_resampler = ugly.c
SOURCES_linear_resampler = linear.c
SOURCES_bandlimited_resampler = bandlimited.c bandlimited.h
SOURCES_coreaudio_resampler = coreaudio.c
/*****************************************************************************
* coreaudio.c resampler based on CoreAudio's AudioConverter
*****************************************************************************
* Copyright (C) 2003 the VideoLAN team
* $Id$
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
* Jon Lech Johansen <jon-vl@nanocrew.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*****************************************************************************/
/*****************************************************************************
* Preamble
*****************************************************************************/
#include <stdlib.h> /* malloc(), free() */
#include <string.h>
#include <AudioToolbox/AudioConverter.h>
#include <vlc/vlc.h>
#include "audio_output.h"
#include "aout_internal.h"
/*****************************************************************************
* Local prototypes
*****************************************************************************/
static int Create ( vlc_object_t * );
static void Close ( vlc_object_t * );
static void DoWork ( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
aout_buffer_t * );
/*****************************************************************************
* Local structures
*****************************************************************************/
struct aout_filter_sys_t
{
aout_filter_t * p_secondary_resampler;
aout_alloc_t alloc;
AudioStreamBasicDescription s_src_stream_format;
AudioStreamBasicDescription s_dst_stream_format;
AudioConverterRef s_converter;
unsigned int i_remainder;
unsigned int i_first_rate;
};
/*****************************************************************************
* Module descriptor
*****************************************************************************/
vlc_module_begin();
set_description( _("audio filter using CoreAudio for resampling") );
set_category( CAT_AUDIO );
set_subcategory( SUBCAT_AUDIO_MISC );
set_capability( "audio filter", 40 );
set_callbacks( Create, Close );
vlc_module_end();
/*****************************************************************************
* Create: allocate resampler
*****************************************************************************/
static int Create( vlc_object_t *p_this )
{
aout_filter_t * p_filter = (aout_filter_t *)p_this;
struct aout_filter_sys_t * p_sys = p_filter->p_sys;
unsigned int i_nb_channels;
OSStatus err;
uint32_t i_prop;
unsigned int i_first_rate;
if ( p_filter->input.i_rate == p_filter->output.i_rate
|| p_filter->input.i_format != p_filter->output.i_format
|| p_filter->input.i_physical_channels
!= p_filter->output.i_physical_channels
|| p_filter->input.i_original_channels
!= p_filter->output.i_original_channels
|| p_filter->input.i_format != VLC_FOURCC('f','l','3','2') )
{
return VLC_EGENERIC;
}
if ( p_filter->input.i_rate >= 48000 * (100 + AOUT_MAX_RESAMPLING) / 100 )
i_first_rate = 48000;
else
i_first_rate = 44100;
if ( p_filter->output.i_rate == i_first_rate )
{
return VLC_EGENERIC;
}
i_nb_channels = aout_FormatNbChannels( &p_filter->input );
/* Allocate the memory needed to store the module's structure */
p_sys = p_filter->p_sys = malloc( sizeof(struct aout_filter_sys_t) );
if( p_filter->p_sys == NULL )
{
msg_Err( p_filter, "out of memory" );
return VLC_ENOMEM;
}
memset( p_filter->p_sys, 0, sizeof(struct aout_filter_sys_t) );
p_sys->i_first_rate = i_first_rate;
p_sys->i_remainder = 0;
p_sys->s_src_stream_format.mFormatID = kAudioFormatLinearPCM;
p_sys->s_src_stream_format.mFormatFlags
= kLinearPCMFormatFlagIsFloat | kAudioFormatFlagsNativeEndian
| kAudioFormatFlagIsPacked;
p_sys->s_src_stream_format.mBytesPerPacket = i_nb_channels * 4;
p_sys->s_src_stream_format.mFramesPerPacket = 1;
p_sys->s_src_stream_format.mBytesPerFrame = i_nb_channels * 4;
p_sys->s_src_stream_format.mChannelsPerFrame = i_nb_channels;
p_sys->s_src_stream_format.mBitsPerChannel = 32;
memcpy( &p_sys->s_dst_stream_format, &p_sys->s_src_stream_format,
sizeof(AudioStreamBasicDescription) );
p_sys->s_src_stream_format.mSampleRate = p_sys->i_first_rate;
p_sys->s_dst_stream_format.mSampleRate = p_filter->output.i_rate;
err = AudioConverterNew( &p_sys->s_src_stream_format,
&p_sys->s_dst_stream_format,
&p_sys->s_converter );
if( err != noErr )
{
msg_Err( p_filter, "AudioConverterNew failed: [%4.4s]",
(char *)&err );
free(p_sys);
return VLC_EGENERIC;
}
i_prop = kConverterPrimeMethod_None;
err = AudioConverterSetProperty( p_sys->s_converter,
kAudioConverterPrimeMethod, sizeof(i_prop), &i_prop );
if( err != noErr )
{
msg_Err( p_filter, "AudioConverterSetProperty failed: [%4.4s]",
(char *)&err );
free(p_sys);
return VLC_EGENERIC;
}
/* Allocate a secondary resampler for the remainder. */
p_sys->p_secondary_resampler = vlc_object_create( p_filter,
sizeof(aout_filter_t) );
if ( p_sys->p_secondary_resampler == NULL )
{
free(p_sys);
return VLC_EGENERIC;
}
vlc_object_attach( p_sys->p_secondary_resampler, p_filter );
memcpy( &p_sys->p_secondary_resampler->input, &p_filter->input,
sizeof(audio_sample_format_t) );
memcpy( &p_sys->p_secondary_resampler->output, &p_filter->output,
sizeof(audio_sample_format_t) );
p_sys->p_secondary_resampler->p_module
= module_Need( p_sys->p_secondary_resampler, "audio filter",
"ugly_resampler", VLC_TRUE );
if ( p_sys->p_secondary_resampler->p_module == NULL )
{
vlc_object_detach( p_sys->p_secondary_resampler );
vlc_object_destroy( p_sys->p_secondary_resampler );
free(p_sys);
return VLC_EGENERIC;
}
p_sys->p_secondary_resampler->b_continuity = VLC_FALSE;
p_sys->alloc.i_alloc_type = AOUT_ALLOC_STACK;
p_sys->alloc.i_bytes_per_sec = p_filter->output.i_bytes_per_frame
* p_filter->output.i_rate
/ p_filter->output.i_frame_length;
p_filter->pf_do_work = DoWork;
/* We don't want a new buffer to be created because we're not sure we'll
* actually need to resample anything. */
p_filter->b_in_place = VLC_FALSE;
return VLC_SUCCESS;
}
/*****************************************************************************
* Close: free our resources
*****************************************************************************/
static void Close( vlc_object_t * p_this )
{
aout_filter_t * p_filter = (aout_filter_t *)p_this;
struct aout_filter_sys_t * p_sys = p_filter->p_sys;
OSErr err;
module_Unneed( p_sys->p_secondary_resampler,
p_sys->p_secondary_resampler->p_module );
vlc_object_detach( p_sys->p_secondary_resampler );
vlc_object_destroy( p_sys->p_secondary_resampler );
/* Destroy the AudioConverter */
err = AudioConverterDispose( p_sys->s_converter );
if( err != noErr )
{
msg_Err( p_this, "AudioConverterDispose failed: %u", err );
}
free( p_filter->p_sys );
}
/*****************************************************************************
* DoWork: convert a buffer
*****************************************************************************/
static void DoWork( aout_instance_t * p_aout, aout_filter_t * p_filter,
aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
{
struct aout_filter_sys_t * p_sys = p_filter->p_sys;
int32_t *p_in = (int32_t *)p_in_buf->p_buffer;
int32_t *p_out;
UInt32 i_output_size;
unsigned int i_out_nb, i_wanted_nb, i_new_rate;
OSErr err;
aout_buffer_t * p_middle_buf;
unsigned int i_nb_channels = aout_FormatNbChannels( &p_filter->input );
#if 1
if ( !p_filter->b_continuity )
{
err = AudioConverterReset( p_sys->s_converter );
if( err != noErr )
{
msg_Err( p_filter, "AudioConverterReset failed: [%4.4s]",
(char *)&err );
}
p_filter->b_continuity = VLC_TRUE;
p_sys->i_remainder = 0;
}
#endif
i_out_nb = (p_in_buf->i_nb_samples * p_filter->output.i_rate
+ p_sys->i_remainder) / p_sys->i_first_rate;
p_sys->i_remainder = (p_in_buf->i_nb_samples * p_filter->output.i_rate
+ p_sys->i_remainder) % p_sys->i_first_rate;
i_output_size = i_out_nb * 4 * i_nb_channels;
if ( i_output_size > p_out_buf->i_size )
{
aout_BufferAlloc( &p_sys->alloc,
i_out_nb * 1000000 / p_filter->output.i_rate,
NULL, p_middle_buf );
}
else
{
p_middle_buf = p_out_buf;
}
p_out = (int32_t*)p_middle_buf->p_buffer;
err = AudioConverterConvertBuffer( p_sys->s_converter,
p_in_buf->i_nb_samples * 4 * i_nb_channels, p_in,
&i_output_size, p_out );
if( err != noErr )
{
msg_Warn( p_filter, "AudioConverterConvertBuffer failed: [%4.4s] (%u:%u)",
(char *)&err, i_out_nb * 4 * i_nb_channels, i_output_size );
i_output_size = i_out_nb * 4 * i_nb_channels;
memset( p_out, 0, i_output_size );
}
p_middle_buf->i_nb_samples = i_output_size / 4 / i_nb_channels;
p_middle_buf->i_nb_bytes = i_output_size;
p_middle_buf->start_date = p_in_buf->start_date;
p_middle_buf->end_date = p_middle_buf->start_date + p_middle_buf->i_nb_samples *
1000000 / p_filter->output.i_rate;
i_wanted_nb = p_in_buf->i_nb_samples * p_filter->output.i_rate
/ p_filter->input.i_rate;
i_new_rate = p_middle_buf->i_nb_samples * p_filter->output.i_rate
/ i_wanted_nb;
p_sys->p_secondary_resampler->input.i_rate = i_new_rate;
p_sys->p_secondary_resampler->pf_do_work( p_aout,
p_sys->p_secondary_resampler, p_middle_buf, p_out_buf );
if ( p_middle_buf != p_out_buf )
{
aout_BufferFree( p_middle_buf );
}
}
SOURCES_alsa = alsa.c
SOURCES_arts = arts.c
SOURCES_coreaudio = coreaudio.c
SOURCES_aout_directx = directx.c
SOURCES_esd = esd.c
SOURCES_aout_file = file.c
......
......@@ -40,6 +40,13 @@
#include <AudioToolbox/AudioFormat.h>
#define STREAM_FORMAT_MSG( pre, sfm ) \
pre "[%ld][%4.4s][%ld][%ld][%ld][%ld][%ld][%ld]", \
(UInt32)sfm.mSampleRate, (char *)&sfm.mFormatID, \
sfm.mFormatFlags, sfm.mBytesPerPacket, \
sfm.mFramesPerPacket, sfm.mBytesPerFrame, \
sfm.mChannelsPerFrame, sfm.mBitsPerChannel
#define STREAM_FORMAT_MSG_FULL( pre, sfm ) \
pre ":\nsamplerate: [%ld]\nFormatID: [%4.4s]\nFormatFlags: [%ld]\nBypesPerPacket: [%ld]\nFramesPerPacket: [%ld]\nBytesPerFrame: [%ld]\nChannelsPerFrame: [%ld]\nBitsPerChannel[%ld]", \
(UInt32)sfm.mSampleRate, (char *)&sfm.mFormatID, \
sfm.mFormatFlags, sfm.mBytesPerPacket, \
......@@ -47,6 +54,7 @@
sfm.mChannelsPerFrame, sfm.mBitsPerChannel
#define BUFSIZE 0xffffff
#define AOUT_VAR_SPDIF_FLAG 0xf00000
/*****************************************************************************
* aout_sys_t: private audio output method descriptor
......@@ -61,33 +69,48 @@ struct aout_sys_t
UInt32 i_devices; /* Number of CoreAudio Devices */
vlc_bool_t b_supports_digital;/* Does the currently selected device support digital mode? */
vlc_bool_t b_digital; /* Are we running in digital mode? */
mtime_t clock_diff; /* Difference between VLC clock and Device clock */
/* AUHAL specific */
Component au_component; /* The Audiocomponent we use */
AudioUnit au_unit; /* The AudioUnit we use */
mtime_t clock_diff;
uint8_t p_remainder_buffer[BUFSIZE];
uint8_t p_remainder_buffer[BUFSIZE];
uint32_t i_read_bytes;
uint32_t i_total_bytes;
audio_date_t end_date_t;
/* CoreAudio SPDIF mode specific */
pid_t i_hog_pid; /* The keep the pid of our hog status */
AudioStreamID i_stream_id; /* The StreamID that has a cac3 streamformat */
int i_stream_index; /* The index of i_stream_id in an AudioBufferList */
AudioStreamBasicDescription stream_format; /* The format we changed the to */
AudioStreamBasicDescription sfmt_revert; /* The original format of the stream */
vlc_bool_t b_revert; /* Wether we need to revert the stream format */
vlc_bool_t b_changed_mixing;/* Wether we need to set the mixing mode back */
};
/*****************************************************************************
* Local prototypes.
*****************************************************************************/
static int Open ( vlc_object_t * );
static int OpenAnalog ( aout_instance_t * );
static int OpenSPDIF ( aout_instance_t * );
static void Close ( vlc_object_t * );
static void Play ( aout_instance_t *);
static void Play ( aout_instance_t * );
static void Probe ( aout_instance_t * );
static int Probe ( aout_instance_t * );
static int DeviceDigitalMode ( aout_instance_t *, AudioDeviceID );
int AudioDeviceHasOutput ( AudioDeviceID );
static int DigitalInit ( aout_instance_t * );
static int AudioDeviceHasOutput ( AudioDeviceID );
static int AudioDeviceSupportsDigital( aout_instance_t *, AudioDeviceID );
static int AudioStreamSupportsDigital( aout_instance_t *, AudioStreamID );
static OSStatus RenderCallbackAnalog ( vlc_object_t *, AudioUnitRenderActionFlags *, const AudioTimeStamp *,
unsigned int, unsigned int, AudioBufferList *);
static OSStatus RenderCallbackSPDIF ( AudioDeviceID, const AudioTimeStamp *, const void *, const AudioTimeStamp *,
AudioBufferList *, const AudioTimeStamp *, void * );
static OSStatus HardwareListener ( AudioHardwarePropertyID, void *);
static OSStatus StreamListener ( AudioStreamID, UInt32,
AudioDevicePropertyID, void * );
static int AudioDeviceCallback ( vlc_object_t *, const char *,
vlc_value_t, vlc_value_t, void * );
/*****************************************************************************
* Module descriptor
......@@ -104,82 +127,148 @@ vlc_module_begin();
set_category( CAT_AUDIO );
set_subcategory( SUBCAT_AUDIO_AOUT );
set_callbacks( Open, Close );
//add_integer( "coreaudio-dev", -1, NULL, ADEV_TEXT, ADEV_LONGTEXT, VLC_FALSE );
add_integer( "macosx-audio-device", 0, NULL, ADEV_TEXT, ADEV_LONGTEXT, VLC_FALSE );
vlc_module_end();
/*****************************************************************************
* Open: open a HAL AudioUnit
* Open: open macosx audio output
*****************************************************************************/
static int Open( vlc_object_t * p_this )
{
OSStatus err = noErr;
ComponentDescription desc;
UInt32 i_param_size,i;
struct aout_sys_t *p_sys;
UInt32 i_param_size = 0;
struct aout_sys_t *p_sys = NULL;
vlc_bool_t b_alive = VLC_FALSE;
vlc_value_t val;
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 )
p_aout->output.p_sys = malloc( sizeof( aout_sys_t ) );
if( p_aout->output.p_sys == NULL )
{
msg_Err( p_aout, "out of memory" );
return( VLC_ENOMEM );
}
memset( p_sys, 0, sizeof( struct aout_sys_t ) );
p_sys->b_digital = VLC_FALSE; /* We assume we are not digital */
p_sys = p_aout->output.p_sys;
p_sys->i_default_dev = 0;
p_sys->i_selected_dev = 0;
p_sys->i_devices = 0;
p_sys->b_supports_digital = VLC_FALSE;
p_sys->b_digital = VLC_FALSE;
p_sys->au_component = NULL;
p_sys->au_unit = NULL;
p_sys->clock_diff = (mtime_t) 0;
p_sys->i_read_bytes = 0;
p_sys->i_total_bytes = 0;
p_sys->i_hog_pid = -1;
p_sys->i_stream_id = 0;
p_sys->i_stream_index = 0;
p_sys->b_revert = VLC_FALSE;
p_sys->b_changed_mixing = VLC_FALSE;
memset( p_sys->p_remainder_buffer, 0, sizeof(uint8_t) * BUFSIZE );
p_aout->output.p_sys = p_sys;
p_aout->output.pf_play = Play;
aout_FormatPrint( p_aout, "VLC is looking for:\n", (audio_sample_format_t *)&p_aout->output.output );
aout_FormatPrint( p_aout, "VLC is looking for:", (audio_sample_format_t *)&p_aout->output.output );
/* Persistent device variable */
if( var_Type( p_aout->p_vlc, "macosx-audio-device" ) == 0 )
{
msg_Dbg( p_aout, "create macosx-audio-device" );
var_Create( p_aout->p_vlc, "macosx-audio-device", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
}
/* Build a list of devices */
if( var_Type( p_aout, "audio-device" ) == 0 )
{
Probe( p_aout );
/*if( Probe( p_aout ) != VLC_SUCCESS );
{
msg_Err( p_aout, "Probe failed" );
free( p_sys );
return VLC_EGENERIC;
}*/
}
/* What device do we want? */
if( var_Get( p_aout, "audio-device", &val ) < 0 )
{
msg_Err( p_aout, "audio-device var does not exist" );
msg_Err( p_aout, "audio-device var does not exist. device probe failed." );
free( p_sys );
return( VLC_ENOVAR );
}
p_sys->i_selected_dev = val.i_int;
/* what is vlc format? if digital, take digital route else AUHAL route */
DeviceDigitalMode( p_aout, p_sys->i_selected_dev );
/*if( DeviceDigitalMode( p_aout, p_sys->i_selected_dev ) != VLC_SUCCESS );
p_sys->i_selected_dev = val.i_int & ~AOUT_VAR_SPDIF_FLAG;
p_sys->b_supports_digital = ( val.i_int & AOUT_VAR_SPDIF_FLAG ) ? VLC_TRUE : VLC_FALSE;
/* Check if the desired device is alive and usable */
i_param_size = sizeof( b_alive );
err = AudioDeviceGetProperty( p_sys->i_selected_dev, 0, FALSE,
kAudioDevicePropertyDeviceIsAlive,
&i_param_size, &b_alive );
if( err != noErr )
{
msg_Err( p_aout, "could not check whether device is alive: %4.4s",
(char *)&err );
return VLC_EGENERIC;
}
if( b_alive == VLC_FALSE )
{
msg_Err( p_aout, "Selected audio device is not alive switching to default device" );
p_sys->i_selected_dev = p_sys->i_default_dev;
}
i_param_size = sizeof( p_sys->i_hog_pid );
err = AudioDeviceGetProperty( p_sys->i_selected_dev, 0, FALSE,
kAudioDevicePropertyHogMode,
&i_param_size, &p_sys->i_hog_pid );
if( err != noErr )
{
msg_Err( p_aout, "could not check whether device is hogged: %4.4s",
(char *)&err );
return VLC_EGENERIC;
}
if( p_sys->i_hog_pid != -1 && p_sys->i_hog_pid != getpid() )
{
msg_Err( p_aout, "DeviceDigitalMode failed" );
msg_Err( p_aout, "Selected audio device is exclusively in use by another program" );
var_Destroy( p_aout, "audio-device" );
free( p_sys );
return VLC_EGENERIC;
}
*/
/* Check for Digital mode or Analog output mode */
if( AOUT_FMT_NON_LINEAR( &p_aout->output.output ) && p_sys->b_supports_digital )
{
p_sys->b_digital = VLC_TRUE;
p_aout->output.output.i_format = VLC_FOURCC('s','p','d','i');
msg_Dbg( p_aout, "we found a digital stream, and we WANT a digital stream" );
if( OpenSPDIF( p_aout ) )
return VLC_SUCCESS;
}
else if( AOUT_FMT_NON_LINEAR( &p_aout->output.output ) && !p_sys->b_supports_digital )
else
{
if( OpenAnalog( p_aout ) )
return VLC_SUCCESS;
}
/* If we reach this, the Open* failed */
var_Destroy( p_aout, "audio-device" );
free( p_sys );
return VLC_EGENERIC;
}
/*****************************************************************************
* Open: open and setup a HAL AudioUnit
*****************************************************************************/
static int OpenAnalog( aout_instance_t *p_aout )
{
struct aout_sys_t *p_sys = p_aout->output.p_sys;
OSStatus err = noErr;
UInt32 i_param_size = 0, i = 0;
ComponentDescription desc;
if( AOUT_FMT_NON_LINEAR( &p_aout->output.output ) && !p_sys->b_supports_digital )
{
msg_Dbg( p_aout, "we had requested a digital stream, but it's not possible for this device" );
}
/* If analog only start setting up AUHAL */
/* If analog only start setting up AUHAL */
/* Lets go find our Component */
desc.componentType = kAudioUnitType_Output;
desc.componentSubType = kAudioUnitSubType_HALOutput;
......@@ -191,20 +280,18 @@ static int Open( vlc_object_t * p_this )
if( p_sys->au_component == NULL )
{
msg_Err( p_aout, "we cannot find our HAL component" );
free( p_sys );
return VLC_EGENERIC;
return VLC_FALSE;
}
err = OpenAComponent( p_sys->au_component, &p_sys->au_unit );
if( err )
{
msg_Err( p_aout, "we cannot find our HAL component" );
free( p_sys );
return VLC_EGENERIC;
return VLC_FALSE;
}
/* Enable IO for the component */
msg_Dbg( p_aout, "Device: %#x", (int)p_sys->i_selected_dev );
/* Set the device */
verify_noerr( AudioUnitSetProperty( p_sys->au_unit,
......@@ -212,7 +299,7 @@ static int Open( vlc_object_t * p_this )
kAudioUnitScope_Global,
0,
&p_sys->i_selected_dev,
sizeof(p_sys->i_selected_dev)));
sizeof( AudioDeviceID )));
/* Get the current format */
AudioStreamBasicDescription DeviceFormat;
......@@ -226,7 +313,7 @@ static int Open( vlc_object_t * p_this )
&DeviceFormat,
&i_param_size ));
msg_Dbg( p_aout, STREAM_FORMAT_MSG( "current format is " , DeviceFormat ) );
msg_Dbg( p_aout, STREAM_FORMAT_MSG( "current format is: " , DeviceFormat ) );
/* Get the channel layout */
AudioChannelLayout *layout;
......@@ -442,13 +529,10 @@ static int Open( vlc_object_t * p_this )
p_aout->output.i_nb_samples = 2048;
aout_VolumeSoftInit( p_aout );
/* Let's pray for the following operation to be atomic... */
/* Find the difference between device clock and mdate clock */
p_sys->clock_diff = - (mtime_t)
AudioConvertHostTimeToNanos( AudioGetCurrentHostTime() ) / 1000;
p_sys->clock_diff += mdate();
p_sys->i_read_bytes = 0;
p_sys->i_total_bytes = 0;
/* set the IOproc callback */
AURenderCallbackStruct input;
......@@ -473,9 +557,268 @@ static int Open( vlc_object_t * p_this )
verify_noerr( AudioUnitInitialize(p_sys->au_unit) );
verify_noerr( AudioOutputUnitStart(p_sys->au_unit) );
return( VLC_SUCCESS );
return VLC_TRUE;
}
/*****************************************************************************
* Setup a encoded digital stream (SPDIF)
*****************************************************************************/
static int OpenSPDIF( aout_instance_t * p_aout )
{
struct aout_sys_t *p_sys = p_aout->output.p_sys;
OSStatus err = noErr;
UInt32 i_param_size = 0, b_mix = 0;
Boolean b_writeable = VLC_FALSE;
AudioStreamID *p_streams = NULL;
int i = 0, i_streams = 0;
struct timeval now;
struct timespec timeout;
struct { vlc_mutex_t lock; vlc_cond_t cond; } w;
/* Start doing the SPDIF setup proces */
p_sys->b_digital = VLC_TRUE;
msg_Dbg( p_aout, "opening in SPDIF mode" );
/* Hog the device */
i_param_size = sizeof( p_sys->i_hog_pid );
p_sys->i_hog_pid = getpid() ;
err = AudioDeviceSetProperty( p_sys->i_selected_dev, 0, 0, FALSE,
kAudioDevicePropertyHogMode, i_param_size, &p_sys->i_hog_pid );
if( err != noErr )
{
msg_Err( p_aout, "failed to set hogmode: : [%4.4s]", (char *)&err );
return VLC_FALSE;
}
/* Set mixable to false if we are allowed to */
err = AudioDeviceGetPropertyInfo( p_sys->i_selected_dev, 0, FALSE, kAudioDevicePropertySupportsMixing,
&i_param_size, &b_writeable );
err = AudioDeviceGetProperty( p_sys->i_selected_dev, 0, FALSE, kAudioDevicePropertySupportsMixing,
&i_param_size, &b_mix );
if( !err && b_writeable )
{
b_mix = 0;
err = AudioDeviceSetProperty( p_sys->i_selected_dev, 0, 0, FALSE,
kAudioDevicePropertySupportsMixing, i_param_size, &b_mix );
p_sys->b_changed_mixing = VLC_TRUE;
}
if( err != noErr )
{
msg_Err( p_aout, "failed to set mixmode: [%4.4s]", (char *)&err );
return VLC_FALSE;
}
// Find stream_id of selected device with a cac3 stream
err = AudioDeviceGetPropertyInfo( p_sys->i_selected_dev, 0, FALSE,
kAudioDevicePropertyStreams,
&i_param_size, NULL );
if( err != noErr )
{
msg_Err( p_aout, "could not get number of streams: [%4.4s]", (char *)&err );
return VLC_FALSE;
}
i_streams = i_param_size / sizeof( AudioStreamID );
p_streams = (AudioStreamID *)malloc( i_param_size );
if( p_streams == NULL )
{
msg_Err( p_aout, "Out of memory" );
return VLC_FALSE;
}
err = AudioDeviceGetProperty( p_sys->i_selected_dev, 0, FALSE,
kAudioDevicePropertyStreams,
&i_param_size, p_streams );
if( err != noErr )
{
msg_Err( p_aout, "could not get number of streams: [%4.4s]", (char *)&err );
if( p_streams ) free( p_streams );
return VLC_FALSE;
}
for( i = 0; i < i_streams; i++ )
{
// Find a stream with a cac3 stream
AudioStreamBasicDescription *p_format_list = NULL;
int i_formats = 0, j = 0;
/* Retrieve all the stream formats supported by each output stream */
err = AudioStreamGetPropertyInfo( p_streams[i], 0,
kAudioStreamPropertyPhysicalFormats,
&i_param_size, NULL );
if( err != noErr )
{
msg_Err( p_aout, "could not get number of streamformats: [%4.4s]", (char *)&err );
continue;
}
i_formats = i_param_size / sizeof( AudioStreamBasicDescription );
p_format_list = (AudioStreamBasicDescription *)malloc( i_param_size );
if( p_format_list == NULL )
{
msg_Err( p_aout, "Could not malloc the memory" );
continue;
}
err = AudioStreamGetProperty( p_streams[i], 0,
kAudioStreamPropertyPhysicalFormats,
&i_param_size, p_format_list );
if( err != noErr )
{
msg_Err( p_aout, "could not get the list of streamformats: [%4.4s]", (char *)&err );
if( p_format_list) free( p_format_list);
continue;
}
for( j = 0; j < i_formats; j++ )
{
if( p_format_list[j].mFormatID == 'IAC3' ||
p_format_list[j].mFormatID == kAudioFormat60958AC3 )
{
// found a cac3 format
p_sys->i_stream_id = p_streams[i];
p_sys->i_stream_index = i;
if( p_sys->b_revert == VLC_FALSE )
{
i_param_size = sizeof( p_sys->sfmt_revert );
err = AudioStreamGetProperty( p_sys->i_stream_id, 0,
kAudioStreamPropertyPhysicalFormat,
&i_param_size,
&p_sys->sfmt_revert );
if( err != noErr )
{
msg_Err( p_aout, "could not retrieve the original streamformat: [%4.4s]", (char *)&err );
continue;
}
p_sys->b_revert = VLC_TRUE;
}
if( p_format_list[j].mSampleRate == p_sys->sfmt_revert.mSampleRate )
{
p_sys->stream_format = p_format_list[j];
}
}
}
if( p_format_list ) free( p_format_list );
}
if( p_streams ) free( p_streams );
msg_Dbg( p_aout, STREAM_FORMAT_MSG( "original stream format: ", p_sys->sfmt_revert ) );
msg_Dbg( p_aout, STREAM_FORMAT_MSG( "setting stream format: ", p_sys->stream_format ) );
/* Install the callback */
err = AudioStreamAddPropertyListener( p_sys->i_stream_id, 0,
kAudioStreamPropertyPhysicalFormat,
StreamListener, (void *)&w );
if( err != noErr )
{
msg_Err( p_aout, "AudioStreamAddPropertyListener failed: [%4.4s]", (char *)&err );
return VLC_FALSE;
}
/* Condition because SetProperty is asynchronious */
vlc_cond_init( p_aout, &w.cond );
vlc_mutex_init( p_aout, &w.lock );
vlc_mutex_lock( &w.lock );
/* change the format */
err = AudioStreamSetProperty( p_sys->i_stream_id, 0, 0,
kAudioStreamPropertyPhysicalFormat,
sizeof( AudioStreamBasicDescription ),
&p_sys->stream_format );
if( err != noErr )
{
msg_Err( p_aout, "could not set the stream format: [%4.4s]", (char *)&err );
vlc_mutex_unlock( &w.lock );
vlc_mutex_destroy( &w.lock );
vlc_cond_destroy( &w.cond );
return VLC_FALSE;
}
gettimeofday( &now, NULL );
timeout.tv_sec = now.tv_sec;
timeout.tv_nsec = (now.tv_usec + 900000) * 1000;
pthread_cond_timedwait( &w.cond.cond, &w.lock.mutex, &timeout );
vlc_mutex_unlock( &w.lock );
err = AudioStreamRemovePropertyListener( p_sys->i_stream_id, 0,
kAudioStreamPropertyPhysicalFormat,
StreamListener );
if( err != noErr )
{
msg_Err( p_aout, "AudioStreamRemovePropertyListener failed: [%4.4s]", (char *)&err );
vlc_mutex_destroy( &w.lock );
vlc_cond_destroy( &w.cond );
return VLC_FALSE;
}
vlc_mutex_destroy( &w.lock );
vlc_cond_destroy( &w.cond );
i_param_size = sizeof( AudioStreamBasicDescription );
err = AudioStreamGetProperty( p_sys->i_stream_id, 0,
kAudioStreamPropertyPhysicalFormat,
&i_param_size,
&p_sys->stream_format );
msg_Dbg( p_aout, STREAM_FORMAT_MSG( "actual format in use: ", p_sys->stream_format ) );
/* set the format flags */
if( p_sys->stream_format.mFormatFlags & kAudioFormatFlagIsBigEndian )
p_aout->output.output.i_format = VLC_FOURCC('s','p','d','b');
else
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;
p_aout->output.output.i_rate = (unsigned int)p_sys->stream_format.mSampleRate;
aout_VolumeNoneInit( p_aout );
/* Add IOProc callback */
err = AudioDeviceAddIOProc( p_sys->i_selected_dev,
(AudioDeviceIOProc)RenderCallbackSPDIF,
(void *)p_aout );
if( err != noErr )
{
msg_Err( p_aout, "AudioDeviceAddIOProc failed: [%4.4s]", (char *)&err );
return VLC_FALSE;
}
/* Check for the difference between the Device clock and mdate */
p_sys->clock_diff = - (mtime_t)
AudioConvertHostTimeToNanos( AudioGetCurrentHostTime() ) / 1000;
p_sys->clock_diff += mdate();
/* Start device */
err = AudioDeviceStart( p_sys->i_selected_dev, (AudioDeviceIOProc)RenderCallbackSPDIF );
if( err != noErr )
{
msg_Err( p_aout, "AudioDeviceStart failed: [%4.4s]", (char *)&err );
err = AudioDeviceRemoveIOProc( p_sys->i_selected_dev,
(AudioDeviceIOProc)RenderCallbackSPDIF );
if( err != noErr )
{
msg_Err( p_aout, "AudioDeviceRemoveIOProc failed: [%4.4s]", (char *)&err );
}
return VLC_FALSE;
}
return VLC_TRUE;
}
/*****************************************************************************
* Close: Close HAL AudioUnit
*****************************************************************************/
......@@ -483,6 +826,8 @@ static void Close( vlc_object_t * p_this )
{
aout_instance_t *p_aout = (aout_instance_t *)p_this;
struct aout_sys_t *p_sys = p_aout->output.p_sys;
OSStatus err = noErr;
UInt32 i_param_size = 0;
if( p_sys->au_unit )
{
......@@ -490,7 +835,127 @@ static void Close( vlc_object_t * p_this )
verify_noerr( AudioUnitUninitialize( p_sys->au_unit ) );
verify_noerr( CloseComponent( p_sys->au_unit ) );
}
free( p_sys );
if( p_sys->b_digital )
{
/* Stop device */
err = AudioDeviceStop( p_sys->i_selected_dev,
(AudioDeviceIOProc)RenderCallbackSPDIF );
if( err != noErr )
{
msg_Err( p_aout, "AudioDeviceStop failed: [%4.4s]", (char *)&err );
}
/* Remove callback */
err = AudioDeviceRemoveIOProc( p_sys->i_selected_dev,
(AudioDeviceIOProc)RenderCallbackSPDIF );
if( err != noErr )
{
msg_Err( p_aout, "AudioDeviceRemoveIOProc failed: [%4.4s]", (char *)&err );
}
if( p_sys->b_revert )
{
struct timeval now;
struct timespec timeout;
struct { vlc_mutex_t lock; vlc_cond_t cond; } w;
/* Install the callback */
err = AudioStreamAddPropertyListener( p_sys->i_stream_id, 0,
kAudioStreamPropertyPhysicalFormat,
StreamListener, (void *)&w );
if( err != noErr )
{
msg_Err( p_aout, "AudioStreamAddPropertyListener failed: [%4.4s]", (char *)&err );
}
/* Condition because SetProperty is asynchronious */
vlc_cond_init( p_aout, &w.cond );
vlc_mutex_init( p_aout, &w.lock );
vlc_mutex_lock( &w.lock );
msg_Dbg( p_aout, STREAM_FORMAT_MSG( "setting stream format: ", p_sys->sfmt_revert ) );
err = AudioStreamSetProperty( p_sys->i_stream_id, NULL, 0,
kAudioStreamPropertyPhysicalFormat,
sizeof( AudioStreamBasicDescription ),
&p_sys->sfmt_revert );
if( err != noErr )
{
msg_Err( p_aout, "Streamformat reverse failed: [%4.4s]", (char *)&err );
}
gettimeofday( &now, NULL );
timeout.tv_sec = now.tv_sec;
timeout.tv_nsec = (now.tv_usec + 900000) * 1000;
pthread_cond_timedwait( &w.cond.cond, &w.lock.mutex, &timeout );
vlc_mutex_unlock( &w.lock );
err = AudioStreamRemovePropertyListener( p_sys->i_stream_id, 0,
kAudioStreamPropertyPhysicalFormat,
StreamListener );
if( err != noErr )
{
msg_Err( p_aout, "AudioStreamRemovePropertyListener failed: [%4.4s]", (char *)&err );
}
vlc_mutex_destroy( &w.lock );
vlc_cond_destroy( &w.cond );
i_param_size = sizeof( AudioStreamBasicDescription );
err = AudioStreamGetProperty( p_sys->i_stream_id, 0,
kAudioStreamPropertyPhysicalFormat,
&i_param_size,
&p_sys->stream_format );
msg_Dbg( p_aout, STREAM_FORMAT_MSG( "actual format in use: ", p_sys->stream_format ) );
}
if( p_sys->b_changed_mixing && p_sys->sfmt_revert.mFormatID != kAudioFormat60958AC3 )
{
int b_mix;
Boolean b_writeable;
/* Revert mixable to true if we are allowed to */
err = AudioDeviceGetPropertyInfo( p_sys->i_selected_dev, 0, FALSE, kAudioDevicePropertySupportsMixing,
&i_param_size, &b_writeable );
err = AudioDeviceGetProperty( p_sys->i_selected_dev, 0, FALSE, kAudioDevicePropertySupportsMixing,
&i_param_size, &b_mix );
if( !err && b_writeable )
{
msg_Dbg( p_aout, "mixable is: %d", b_mix );
b_mix = 1;
err = AudioDeviceSetProperty( p_sys->i_selected_dev, 0, 0, FALSE,
kAudioDevicePropertySupportsMixing, i_param_size, &b_mix );
}
if( err != noErr )
{
msg_Err( p_aout, "failed to set mixmode: [%4.4s]", (char *)&err );
}
}
}
err = AudioHardwareRemovePropertyListener( kAudioHardwarePropertyDevices,
HardwareListener );
if( err != noErr )
{
msg_Err( p_aout, "AudioHardwareRemovePropertyListener failed: [%4.4s]", (char *)&err );
}
if( p_sys->i_hog_pid == getpid() )
{
p_sys->i_hog_pid = -1;
i_param_size = sizeof( p_sys->i_hog_pid );
err = AudioDeviceSetProperty( p_sys->i_selected_dev, 0, 0, FALSE,
kAudioDevicePropertyHogMode, i_param_size, &p_sys->i_hog_pid );
if( err != noErr ) msg_Err( p_aout, "Could not release hogmode: [%4.4s]", (char *)&err );
}
if( p_sys ) free( p_sys );
}
/*****************************************************************************
......@@ -504,11 +969,11 @@ static void Play( aout_instance_t * p_aout )
/*****************************************************************************
* Probe
*****************************************************************************/
static int Probe( aout_instance_t * p_aout )
static void Probe( aout_instance_t * p_aout )
{
OSStatus err = noErr;
UInt32 i, i_param_size;
AudioDeviceID devid_def;
UInt32 i = 0, i_param_size = 0;
AudioDeviceID devid_def = 0;
AudioDeviceID *p_devices = NULL;
vlc_value_t val, text;
......@@ -534,7 +999,7 @@ static int Probe( aout_instance_t * p_aout )
msg_Dbg( p_aout, "system has [%ld] device(s)", p_sys->i_devices );
/* Allocate DeviceID array */
p_devices = (AudioDeviceID *)malloc( i_param_size );
p_devices = (AudioDeviceID*)malloc( sizeof(AudioDeviceID) * p_sys->i_devices );
if( p_devices == NULL )
{
msg_Err( p_aout, "out of memory" );
......@@ -543,7 +1008,7 @@ static int Probe( aout_instance_t * p_aout )
/* Populate DeviceID array */
err = AudioHardwareGetProperty( kAudioHardwarePropertyDevices,
&i_param_size, (void *)p_devices );
&i_param_size, p_devices );
if( err != noErr )
{
msg_Err( p_aout, "could not get the device ID's: [%4.4s]", (char *)&err );
......@@ -553,7 +1018,7 @@ static int Probe( aout_instance_t * p_aout )
/* Find the ID of the default Device */
i_param_size = sizeof( AudioDeviceID );
err = AudioHardwareGetProperty( kAudioHardwarePropertyDefaultOutputDevice,
&i_param_size, (void *)&devid_def );
&i_param_size, &devid_def );
if( err != noErr )
{
msg_Err( p_aout, "could not get default audio device: [%4.4s]", (char *)&err );
......@@ -567,29 +1032,25 @@ static int Probe( aout_instance_t * p_aout )
for( i = 0; i < p_sys->i_devices; i++ )
{
char psz_devuid[1024];
char psz_name[1024];
CFStringRef devUID;
char *psz_name;
i_param_size = 0;
i_param_size = sizeof psz_name;
err = AudioDeviceGetProperty(
/* Retrieve the length of the device name */
err = AudioDeviceGetPropertyInfo(
p_devices[i], 0, VLC_FALSE,
kAudioDevicePropertyDeviceName,
&i_param_size, psz_name);
if( err )
goto error;
&i_param_size, NULL);
if( err ) goto error;
i_param_size = sizeof(CFStringRef);
/* Retrieve the name of the device */
psz_name = (char *)malloc( i_param_size );
err = AudioDeviceGetProperty(
p_devices[i], 0, VLC_FALSE,
kAudioDevicePropertyDeviceUID,
&i_param_size, &devUID);
if( err )
goto error;
kAudioDevicePropertyDeviceName,
&i_param_size, psz_name);
if( err ) goto error;
CFStringGetCString( devUID, psz_devuid, sizeof psz_devuid, CFStringGetSystemEncoding() );
msg_Dbg( p_aout, "DevID: %lu DevName: %s DevUID: %s", p_devices[i], psz_name, psz_devuid );
CFRelease( devUID );
msg_Dbg( p_aout, "DevID: %lu DevName: %s", p_devices[i], psz_name );
if( !AudioDeviceHasOutput( p_devices[i]) )
{
......@@ -597,70 +1058,160 @@ static int Probe( aout_instance_t * p_aout )
continue;
}
val.i_int = (int) p_devices[i];
text.psz_string = psz_name;
val.i_int = (int)p_devices[i];
text.psz_string = strdup( psz_name );
var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
if( devid_def == p_devices[i] )
if( p_sys->i_default_dev == p_devices[i] )
{
var_Change( p_aout, "audio-device", VLC_VAR_SETDEFAULT, &val, NULL );
var_Set( p_aout, "audio-device", val );
}
if( AudioDeviceSupportsDigital( p_aout, p_devices[i] ) )
{
val.i_int = (int)p_devices[i] | AOUT_VAR_SPDIF_FLAG;
asprintf( &text.psz_string, "%s (Encoded Output)", psz_name );
var_Change( p_aout, "audio-device", VLC_VAR_ADDCHOICE, &val, &text );
if( p_sys->i_default_dev == p_devices[i] && config_GetInt( p_aout, "spdif" ) )
{
var_Change( p_aout, "audio-device", VLC_VAR_SETDEFAULT, &val, NULL );
var_Set( p_aout, "audio-device", val );
}
}
free( psz_name);
}
var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL );
var_Get( p_aout->p_vlc, "macosx-audio-device", &val );
msg_Dbg( p_aout, "device value override1: %#x", val.i_int );
if( val.i_int > 0 )
{
msg_Dbg( p_aout, "device value override2: %#x", val.i_int );
var_Change( p_aout, "audio-device", VLC_VAR_SETDEFAULT, &val, NULL );
var_Set( p_aout, "audio-device", val );
}
var_AddCallback( p_aout, "audio-device", AudioDeviceCallback, NULL );
/* attach a Listener so that we are notified of a change in the Device setup */
/* err = AudioHardwareAddPropertyListener( kAudioHardwarePropertyDevices,
err = AudioHardwareAddPropertyListener( kAudioHardwarePropertyDevices,
HardwareListener,
(void *)p_aout );
if( err )
goto error;*/
goto error;
msg_Dbg( p_aout, "succesful finish of deviceslist" );
if( p_devices ) free( p_devices );
return (VLC_SUCCESS);
return;
error:
var_Destroy( p_aout, "audio-device" );
if( p_devices ) free( p_devices );
return VLC_EGENERIC;
return;
}
/*****************************************************************************
* DeviceDigitalMode: Check i_dev_id for digital stream support.
* AudioDeviceHasOutput: Checks if the Device actually provides any outputs at all
*****************************************************************************/
static int DeviceDigitalMode( aout_instance_t *p_aout, AudioDeviceID i_dev_id )
static int AudioDeviceHasOutput( AudioDeviceID i_dev_id )
{
OSStatus err = noErr;
UInt32 i_param_size;
AudioStreamBasicDescription *p_format_list;
int i, i_formats;
struct aout_sys_t *p_sys = p_aout->output.p_sys;
UInt32 dataSize;
Boolean isWritable;
verify_noerr( AudioDeviceGetPropertyInfo( i_dev_id, 0, FALSE, kAudioDevicePropertyStreams, &dataSize, &isWritable) );
if (dataSize == 0) return FALSE;
p_sys->b_supports_digital = VLC_FALSE;
return TRUE;
}
/*****************************************************************************
* AudioDeviceSupportsDigital: Check i_dev_id for digital stream support.
*****************************************************************************/
static int AudioDeviceSupportsDigital( aout_instance_t *p_aout, AudioDeviceID i_dev_id )
{
OSStatus err = noErr;
UInt32 i_param_size = 0;
AudioStreamID *p_streams = NULL;
int i = 0, i_streams = 0;
vlc_bool_t b_return = VLC_FALSE;
/* Retrieve all the output streams */
err = AudioDeviceGetPropertyInfo( i_dev_id, 0, FALSE,
kAudioDevicePropertyStreamFormats,
kAudioDevicePropertyStreams,
&i_param_size, NULL );
if( err != noErr )
{
msg_Err( p_aout, "could not get number of streamsformats: [%4.4s]", (char *)&err );
return( VLC_EGENERIC );
msg_Err( p_aout, "could not get number of streams: [%4.4s]", (char *)&err );
return VLC_FALSE;
}
i_streams = i_param_size / sizeof( AudioStreamID );
p_streams = (AudioStreamID *)malloc( i_param_size );
if( p_streams == NULL )
{
msg_Err( p_aout, "Out of memory" );
return VLC_ENOMEM;
}
err = AudioDeviceGetProperty( i_dev_id, 0, FALSE,
kAudioDevicePropertyStreams,
&i_param_size, p_streams );
if( err != noErr )
{
msg_Err( p_aout, "could not get number of streams: [%4.4s]", (char *)&err );
return VLC_FALSE;
}
for( i = 0; i < i_streams; i++ )
{
if( AudioStreamSupportsDigital( p_aout, p_streams[i] ) )
b_return = VLC_TRUE;
}
if( p_streams ) free( p_streams );
return b_return;
}
/*****************************************************************************
* AudioStreamSupportsDigital: Check i_stream_id for digital stream support.
*****************************************************************************/
static int AudioStreamSupportsDigital( aout_instance_t *p_aout, AudioStreamID i_stream_id )
{
OSStatus err = noErr;
UInt32 i_param_size = 0;
AudioStreamBasicDescription *p_format_list = NULL;
int i = 0, i_formats = 0;
vlc_bool_t b_return = VLC_FALSE;
/* Retrieve all the stream formats supported by each output stream */
err = AudioStreamGetPropertyInfo( i_stream_id, 0,
kAudioStreamPropertyPhysicalFormats,
&i_param_size, NULL );
if( err != noErr )
{
msg_Err( p_aout, "could not get number of streamformats: [%4.4s]", (char *)&err );
return VLC_FALSE;
}
i_formats = i_param_size / sizeof( AudioStreamBasicDescription );
msg_Dbg( p_aout, "number of formats: %d", i_formats );
p_format_list = (AudioStreamBasicDescription *)malloc( i_param_size );
if( p_format_list == NULL )
{
return( VLC_ENOMEM );
msg_Err( p_aout, "Could not malloc the memory" );
return VLC_FALSE;
}
err = AudioDeviceGetProperty( i_dev_id, 0, FALSE,
kAudioDevicePropertyStreamFormats,
&i_param_size, (void *)p_format_list );
err = AudioStreamGetProperty( i_stream_id, 0,
kAudioStreamPropertyPhysicalFormats,
&i_param_size, p_format_list );
if( err != noErr )
{
msg_Err( p_aout, "could not get the list of formats: [%4.4s]", (char *)&err );
return( VLC_EGENERIC );
msg_Err( p_aout, "could not get the list of streamformats: [%4.4s]", (char *)&err );
free( p_format_list);
p_format_list = NULL;
return VLC_FALSE;
}
for( i = 0; i < i_formats; i++ )
......@@ -670,14 +1221,12 @@ static int DeviceDigitalMode( aout_instance_t *p_aout, AudioDeviceID i_dev_id )
if( p_format_list[i].mFormatID == 'IAC3' ||
p_format_list[i].mFormatID == kAudioFormat60958AC3 )
{
p_sys->b_supports_digital = VLC_TRUE;
msg_Dbg( p_aout, "this device supports a digital stream" );
break;
b_return = VLC_TRUE;
}
}
free( (void *)p_format_list );
return VLC_SUCCESS;
if( p_format_list ) free( p_format_list );
return b_return;
}
/*****************************************************************************
......@@ -703,12 +1252,14 @@ static OSStatus RenderCallbackAnalog( vlc_object_t *_p_aout,
host_time.mFlags = kAudioTimeStampHostTimeValid;
AudioDeviceTranslateTime( p_sys->i_selected_dev, inTimeStamp, &host_time );
/* Check for the difference between the Device clock and mdate */
p_sys->clock_diff = - (mtime_t)
AudioConvertHostTimeToNanos( AudioGetCurrentHostTime() ) / 1000;
p_sys->clock_diff += mdate();
current_date = p_sys->clock_diff +
AudioConvertHostTimeToNanos( host_time.mHostTime ) / 1000;
//- ((mtime_t) 1000000 / p_aout->output.output.i_rate * 31 ); // 31 = Latency in Frames. retrieve somewhere
if( ioData == NULL && ioData->mNumberBuffers < 1 )
{
......@@ -766,39 +1317,53 @@ static OSStatus RenderCallbackAnalog( vlc_object_t *_p_aout,
return( noErr );
}
/*****************************************************************************
* Setup a digital stream
* RenderCallbackSPDIF: callback for SPDIF audio output
*****************************************************************************/
static int DigitalInit( aout_instance_t * p_aout )
static OSStatus RenderCallbackSPDIF( AudioDeviceID inDevice,
const AudioTimeStamp * inNow,
const void * inInputData,
const AudioTimeStamp * inInputTime,
AudioBufferList * outOutputData,
const AudioTimeStamp * inOutputTime,
void * threadGlobals )
{
OSStatus err = noErr;
UInt32 i, i_param_size;
AudioDeviceID devid_def;
AudioDeviceID *p_devices = NULL;
vlc_value_t val, text;
aout_buffer_t * p_buffer;
mtime_t current_date;
struct aout_sys_t *p_sys = p_aout->output.p_sys;
aout_instance_t * p_aout = (aout_instance_t *)threadGlobals;
struct aout_sys_t * p_sys = p_aout->output.p_sys;
return (VLC_SUCCESS);
/* Check for the difference between the Device clock and mdate */
p_sys->clock_diff = - (mtime_t)
AudioConvertHostTimeToNanos( inNow->mHostTime ) / 1000;
p_sys->clock_diff += mdate();
error:
return VLC_EGENERIC;
}
current_date = p_sys->clock_diff +
AudioConvertHostTimeToNanos( inOutputTime->mHostTime ) / 1000;
//- ((mtime_t) 1000000 / p_aout->output.output.i_rate * 31 ); // 31 = Latency in Frames. retrieve somewhere
int AudioDeviceHasOutput( AudioDeviceID i_dev_id )
{
UInt32 dataSize;
Boolean isWritable;
verify_noerr( AudioDeviceGetPropertyInfo( i_dev_id, 0, FALSE, kAudioDevicePropertyStreams, &dataSize, &isWritable) );
if (dataSize == 0) return FALSE;
return TRUE;
}
p_buffer = aout_OutputNextBuffer( p_aout, current_date, VLC_TRUE );
#define BUFFER outOutputData->mBuffers[p_sys->i_stream_index]
if( p_buffer != NULL )
{
if( (int)BUFFER.mDataByteSize != (int)p_buffer->i_nb_bytes)
msg_Warn( p_aout, "bytesize: %d nb_bytes: %d", (int)BUFFER.mDataByteSize, (int)p_buffer->i_nb_bytes );
/* move data into output data buffer */
p_aout->p_vlc->pf_memcpy( BUFFER.mData,
p_buffer->p_buffer, p_buffer->i_nb_bytes );
aout_BufferFree( p_buffer );
}
else
{
p_aout->p_vlc->pf_memset( BUFFER.mData, 0, BUFFER.mDataByteSize );
}
#undef BUFFER
return( noErr );
}
/*****************************************************************************
* HardwareListener: Warns us of changes in the list of registered devices
......@@ -807,9 +1372,7 @@ static OSStatus HardwareListener( AudioHardwarePropertyID inPropertyID,
void * inClientData )
{
OSStatus err = noErr;
aout_instance_t *p_aout = (aout_instance_t *)inClientData;
/* struct aout_sys_t *p_sys = p_aout->output.p_sys; */
switch( inPropertyID )
{
......@@ -818,9 +1381,48 @@ static OSStatus HardwareListener( AudioHardwarePropertyID inPropertyID,
/* something changed in the list of devices */
/* We trigger the audio-device's aout_ChannelsRestart callback */
var_Change( p_aout, "audio-device", VLC_VAR_TRIGGER_CALLBACKS, NULL, NULL );
var_Destroy( p_aout, "audio-device" );
}
break;
}
return( err );
}
/*****************************************************************************
* StreamListener
*****************************************************************************/
static OSStatus StreamListener( AudioStreamID inStream,
UInt32 inChannel,
AudioDevicePropertyID inPropertyID,
void * inClientData )
{
OSStatus err = noErr;
struct { vlc_mutex_t lock; vlc_cond_t cond; } * w = inClientData;
switch( inPropertyID )
{
case kAudioStreamPropertyPhysicalFormat:
vlc_mutex_lock( &w->lock );
vlc_cond_signal( &w->cond );
vlc_mutex_unlock( &w->lock );
break;
default:
break;
}
return( err );
}
/*****************************************************************************
* AudioDeviceCallback: Callback triggered when the audio-device variable is changed
*****************************************************************************/
static int AudioDeviceCallback( vlc_object_t *p_this, const char *psz_variable,
vlc_value_t old_val, vlc_value_t new_val, void *param )
{
aout_instance_t *p_aout = (aout_instance_t *)p_this;
var_Set( p_aout->p_vlc, "macosx-audio-device", new_val );
msg_Dbg( p_aout, "Set Device: %#x", new_val.i_int );
return aout_ChannelsRestart( p_this, psz_variable, old_val, new_val, param );
}
......@@ -158,6 +158,7 @@ struct aout_sys_t
UInt32 i_stream_index;
AudioStreamBasicDescription stream_format;
UInt32 b_dev_alive;
pid_t i_hog_pid;
vlc_bool_t b_revert_sfmt;
AudioStreamBasicDescription sfmt_revert;
......@@ -253,6 +254,7 @@ static int Open( vlc_object_t * p_this )
p_aout->output.p_sys = p_sys;
p_aout->output.pf_play = Play;
p_sys->i_hog_pid = -1;
vlc_mutex_init( p_aout, &p_sys->lock );
......@@ -281,7 +283,6 @@ static int Open( vlc_object_t * p_this )
/* get starting channel for the selected stream */
p_option = &p_sys->p_options[p_sys->i_sel_opt];
i_param_size = sizeof( UInt32 );
err = AudioStreamGetProperty( p_option->i_sid, 0,
kAudioStreamPropertyStartingChannel,
......@@ -337,34 +338,34 @@ static int Open( vlc_object_t * p_this )
free( (void *)p_sys );
return( VLC_EGENERIC );
}
msg_Dbg( p_aout, "device bufframe size: [%ld]", p_sys->i_bufframe_size );
msg_Dbg( p_aout, "device buffer index: [%ld]", p_sys->i_stream_index );
/* 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_bufframe_size != A52_FRAME_NB )
{
p_sys->i_bufframe_size = A52_FRAME_NB;
i_param_size = sizeof( p_sys->i_bufframe_size );
err = AudioDeviceSetProperty( p_sys->devid, 0, 0, FALSE,
kAudioDevicePropertyBufferFrameSize,
i_param_size, &p_sys->i_bufframe_size );
if( err != noErr )
{
msg_Err( p_aout, "failed to set bufframe size (%ld): [%4.4s]",
p_sys->i_bufframe_size, (char *)&err );
FreeDevice( p_aout );
FreeHardwareInfo( p_aout );
vlc_mutex_destroy( &p_sys->lock );
free( (void *)p_sys );
return( VLC_EGENERIC );
}
msg_Dbg( p_aout, "device bufframe size set to: [%ld]",
p_sys->i_bufframe_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_bufframe_size != A52_FRAME_NB )
{
p_sys->i_bufframe_size = A52_FRAME_NB;
i_param_size = sizeof( p_sys->i_bufframe_size );
err = AudioDeviceSetProperty( p_sys->devid, 0, 0, FALSE,
kAudioDevicePropertyBufferFrameSize,
i_param_size, &p_sys->i_bufframe_size );
if( err != noErr )
{
msg_Err( p_aout, "failed to set bufframe size (%ld): [%4.4s]",
p_sys->i_bufframe_size, (char *)&err );
FreeDevice( p_aout );
FreeHardwareInfo( p_aout );
vlc_mutex_destroy( &p_sys->lock );
free( (void *)p_sys );
return( VLC_EGENERIC );
}
msg_Dbg( p_aout, "device bufframe size set to: [%ld]",
p_sys->i_bufframe_size );
}
switch( p_sys->stream_format.mFormatID )
{
......@@ -420,7 +421,10 @@ static int Open( vlc_object_t * p_this )
case 'IAC3':
case kAudioFormat60958AC3:
p_aout->output.output.i_format = VLC_FOURCC('s','p','d','i');
if( p_sys->stream_format.mFormatFlags & kAudioFormatFlagIsBigEndian )
p_aout->output.output.i_format = VLC_FOURCC('s','p','d','b');
else
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;
......@@ -584,35 +588,30 @@ static OSStatus IOCallback( AudioDeviceID inDevice,
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;
host_time.mFlags = kAudioTimeStampHostTimeValid;
AudioDeviceTranslateTime( inDevice, inOutputTime, &host_time );
#if 1
p_sys->clock_diff = - (mtime_t)
AudioConvertHostTimeToNanos( AudioGetCurrentHostTime() ) / 1000;
AudioConvertHostTimeToNanos( inNow->mHostTime ) / 1000;
p_sys->clock_diff += mdate();
#endif
current_date = p_sys->clock_diff +
AudioConvertHostTimeToNanos( host_time.mHostTime ) / 1000;
AudioConvertHostTimeToNanos( inOutputTime->mHostTime ) / 1000;
#define B_SPDI (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_aout->output.output.i_format == VLC_FOURCC('s','p','d','b') )
p_buffer = aout_OutputNextBuffer( p_aout, current_date, B_SPDI );
#undef B_SPDI
#define BUFFER outOutputData->mBuffers[ p_sys->i_stream_index ]
#define BUFFER outOutputData->mBuffers[p_sys->i_stream_index]
if( p_buffer != NULL )
{
/* move data into output data buffer */
p_aout->p_vlc->pf_memcpy( BUFFER.mData,
p_buffer->p_buffer, p_buffer->i_nb_bytes );
aout_BufferFree( p_buffer );
}
else
......@@ -993,7 +992,6 @@ static int InitStreamInfo( UInt32 i_dev, aout_instance_t * p_aout,
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 );
......@@ -1214,6 +1212,81 @@ static int InitDevice( aout_instance_t * p_aout )
vlc_mutex_lock( &w.lock );
/* If we do AC3 over SPDIF, take hog mode and non mixable mode */
if( P_STREAMS[i_stream].mFormatID == kAudioFormat60958AC3 ||
P_STREAMS[i_stream].mFormatID == 'IAC3' )
{
UInt32 b_mix;
i_param_size = sizeof( p_sys->i_hog_pid );
err = AudioDeviceGetProperty( p_dev->devid, 0, FALSE, kAudioDevicePropertyHogMode,
&i_param_size, &p_sys->i_hog_pid );
if( !err )
{
msg_Dbg( p_aout, "Current status of hog mode: pid=%d vlc pid=%d\n", (int)p_sys->i_hog_pid, (int)getpid() );
if( p_sys->i_hog_pid != getpid() ) {
p_sys->i_hog_pid = getpid() ;
err = AudioDeviceSetProperty( p_dev->devid, 0, 0, FALSE,
kAudioDevicePropertyHogMode, i_param_size, &p_sys->i_hog_pid );
if( !err )
{
msg_Dbg( p_aout, "Successfully set hog mode - new pid=%d!\n", (int)p_sys->i_hog_pid );
err = AudioDeviceGetProperty( p_dev->devid, 0, FALSE,
kAudioDevicePropertyHogMode, &i_param_size, &p_sys->i_hog_pid );
if( !err )
{
msg_Dbg( p_aout, "Checking new status of hog mode: pid=%d vlc pid=%d\n",
(int)p_sys->i_hog_pid, (int)getpid() );
}
}
}
}
if( err != noErr )
{
msg_Err( p_aout, "failed to set hogmode: : [%4.4s]", (char *)&err );
FreeDevice( p_aout );
FreeHardwareInfo( p_aout );
vlc_mutex_destroy( &p_sys->lock );
free( (void *)p_sys );
return( VLC_EGENERIC );
}
/*
i_param_size = sizeof( b_mix );
err = AudioDeviceGetProperty( p_dev->devid, 0, FALSE, kAudioDevicePropertySupportsMixing,
&i_param_size, &b_mix );
if( !err )
{
msg_Dbg( p_aout, "Current status of mix mode: %i\n", (int)b_mix );
b_mix = 0;
err = AudioDeviceSetProperty( p_dev->devid, 0, 0, FALSE,
kAudioDevicePropertySupportsMixing, i_param_size, &b_mix );
if( !err )
{
msg_Dbg( p_aout, "Successfully set mix mode - new mix=%d!\n", (int)b_mix );
err = AudioDeviceGetProperty( p_dev->devid, 0, FALSE,
kAudioDevicePropertySupportsMixing, &i_param_size, &b_mix );
if( !err )
{
msg_Dbg( p_aout, "Checking new status of mix mode: %d\n", (int)b_mix );
}
}
}
if( err != noErr )
{
msg_Err( p_aout, "failed to set mixmode: : [%4.4s]", (char *)&err );
FreeDevice( p_aout );
FreeHardwareInfo( p_aout );
vlc_mutex_destroy( &p_sys->lock );
free( (void *)p_sys );
return( VLC_EGENERIC );
}*/
}
msg_Dbg( p_aout, STREAM_FORMAT_MSG( "setting format",
P_STREAMS[i_stream] ) );
......@@ -1325,6 +1398,29 @@ static void FreeDevice( aout_instance_t * p_aout )
msg_Err( p_aout, "AudioStreamSetProperty revert format failed: [%4.4s]",
(char *)&err );
}
}
if( (int)p_sys->i_hog_pid != -1 )
{
/*UInt32 b_mix = 1;
err = AudioDeviceSetProperty( p_sys->devid, 0, 0, FALSE,
kAudioDevicePropertySupportsMixing, sizeof(b_mix), &b_mix );
if( err != noErr )
{
msg_Err( p_aout, "Resetting mix mode failed: [%4.4s]",
(char *)&err );
}
*/
p_sys->i_hog_pid = (pid_t) -1;
err = AudioDeviceSetProperty( p_sys->devid, 0, 0, FALSE,
kAudioDevicePropertyHogMode, sizeof(p_sys->i_hog_pid), &p_sys->i_hog_pid );
if( err != noErr )
{
msg_Err( p_aout, "Releasing hog mode failed: [%4.4s]",
(char *)&err );
}
}
}
......@@ -1440,8 +1536,9 @@ static OSStatus StreamListener( AudioStreamID inStream,
void * inClientData )
{
OSStatus err = noErr;
struct { vlc_mutex_t lock; vlc_cond_t cond; } * w = inClientData;
aout_instance_t * p_aout = (aout_instance_t *)inClientData;
struct aout_sys_t * p_sys = p_aout->output.p_sys;
switch( inPropertyID )
{
......@@ -1454,7 +1551,6 @@ static OSStatus StreamListener( AudioStreamID inStream,
default:
break;
}
return( err );
}
......
......@@ -142,6 +142,7 @@ void aout_FormatPrepare( audio_sample_format_t * p_format )
break;
case VLC_FOURCC('s','p','d','i'):
case VLC_FOURCC('s','p','d','b'): /* Big endian spdif output */
case VLC_FOURCC('a','5','2',' '):
case VLC_FOURCC('d','t','s',' '):
case VLC_FOURCC('m','p','g','a'):
......
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