fix potential memory leak
increase decoder thread priority init the hardware stream in the driver, not in the converter
This commit is contained in:
@@ -2,48 +2,24 @@
|
|||||||
#include "RageSoundDriver_CA.h"
|
#include "RageSoundDriver_CA.h"
|
||||||
#include "CAHelpers.h"
|
#include "CAHelpers.h"
|
||||||
|
|
||||||
#include "CAAudioHardwareDevice.h"
|
const UInt32 kFramesPerPacket = 1;
|
||||||
#include "CAAudioHardwareStream.h"
|
const UInt32 kChannelsPerFrame = 2;
|
||||||
#include "CAException.h"
|
const UInt32 kBitsPerChannel = 16;
|
||||||
|
const UInt32 kBytesPerPacket = kChannelsPerFrame * kBitsPerChannel / 8;
|
||||||
|
const UInt32 kBytesPerFrame = kBytesPerPacket;
|
||||||
|
const UInt32 kFormatFlags = kAudioFormatFlagsNativeEndian |
|
||||||
|
kAudioFormatFlagIsSignedInteger;
|
||||||
|
|
||||||
AudioConverter::AudioConverter(CAAudioHardwareDevice *dev, RageSound_CA *driver)
|
AudioConverter::AudioConverter( RageSound_CA *driver, const Desc &procFormat )
|
||||||
: mBuffer(NULL), mBufferSize(0)
|
: mBuffer(NULL), mBufferSize(0)
|
||||||
{
|
{
|
||||||
AudioStreamID sID = dev->GetStreamByIndex(kAudioDeviceSectionOutput, 0);
|
|
||||||
CAAudioHardwareStream stream(sID);
|
|
||||||
vector<Desc> procFormats;
|
|
||||||
vector<Desc> physicalFormats;
|
|
||||||
UInt32 numFormats = stream.GetNumberAvailableIOProcFormats();
|
|
||||||
|
|
||||||
for (UInt32 i=0; i<numFormats; ++i)
|
|
||||||
{
|
|
||||||
Desc desc;
|
|
||||||
|
|
||||||
stream.GetAvailableIOProcFormatByIndex(i, desc);
|
|
||||||
procFormats.push_back(desc);
|
|
||||||
}
|
|
||||||
|
|
||||||
const Desc& procFormat = FindClosestFormat(procFormats);
|
|
||||||
stream.SetCurrentIOProcFormat(procFormat);
|
|
||||||
|
|
||||||
numFormats = stream.GetNumberAvailablePhysicalFormats();
|
|
||||||
for (UInt32 i=0; i<numFormats; ++i)
|
|
||||||
{
|
|
||||||
Desc desc;
|
|
||||||
|
|
||||||
stream.GetAvailablePhysicalFormatByIndex(i, desc);
|
|
||||||
physicalFormats.push_back(desc);
|
|
||||||
}
|
|
||||||
|
|
||||||
const Desc& physicalFormat = FindClosestFormat(physicalFormats);
|
|
||||||
stream.SetCurrentPhysicalFormat(physicalFormat);
|
|
||||||
|
|
||||||
const Desc SMFormat(44100.0, kAudioFormatLinearPCM, kBytesPerPacket,
|
const Desc SMFormat(44100.0, kAudioFormatLinearPCM, kBytesPerPacket,
|
||||||
kFramesPerPacket, kBytesPerFrame, kChannelsPerFrame,
|
kFramesPerPacket, kBytesPerFrame, kChannelsPerFrame,
|
||||||
kBitsPerChannel, kFormatFlags);
|
kBitsPerChannel, kFormatFlags);
|
||||||
|
|
||||||
SMFormat.Print();
|
SMFormat.Print();
|
||||||
procFormat.Print();
|
procFormat.Print();
|
||||||
|
|
||||||
if( this->Initialize(SMFormat, procFormat) )
|
if( this->Initialize(SMFormat, procFormat) )
|
||||||
RageException::ThrowNonfatal( "Couldn't create the converter." );
|
RageException::ThrowNonfatal( "Couldn't create the converter." );
|
||||||
|
|
||||||
@@ -59,7 +35,7 @@ OSStatus AudioConverter::FormatConverterInputProc(UInt32& ioNumberDataPackets,
|
|||||||
// This really shouldn't happen more than once, but better be sure.
|
// This really shouldn't happen more than once, but better be sure.
|
||||||
if( mBufferSize != buf.mDataByteSize )
|
if( mBufferSize != buf.mDataByteSize )
|
||||||
{
|
{
|
||||||
delete mBuffer; // deleting NULL does not crash, unlike free(NULL)
|
delete mBuffer;
|
||||||
mBufferSize = buf.mDataByteSize;
|
mBufferSize = buf.mDataByteSize;
|
||||||
mBuffer = new UInt8[mBufferSize];
|
mBuffer = new UInt8[mBufferSize];
|
||||||
}
|
}
|
||||||
@@ -69,36 +45,3 @@ OSStatus AudioConverter::FormatConverterInputProc(UInt32& ioNumberDataPackets,
|
|||||||
return noErr;
|
return noErr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Desc AudioConverter::FindClosestFormat(const vector<Desc>& formats)
|
|
||||||
{
|
|
||||||
vector<Desc> v;
|
|
||||||
|
|
||||||
vector<Desc>::const_iterator i;
|
|
||||||
for (i = formats.begin(); i != formats.end(); ++i)
|
|
||||||
{
|
|
||||||
const Desc& format = *i;
|
|
||||||
|
|
||||||
if (!format.IsPCM() || format.mSampleRate != 44100.0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (format.SampleWordSize() == 2 &&
|
|
||||||
(format.mFormatFlags & kAudioFormatFlagIsSignedInteger) ==
|
|
||||||
kAudioFormatFlagIsSignedInteger)
|
|
||||||
{ // exact match
|
|
||||||
return format;
|
|
||||||
}
|
|
||||||
v.push_back(format);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = v.begin(); i != v.end(); ++i)
|
|
||||||
{
|
|
||||||
const Desc& format = *i;
|
|
||||||
if (format.SampleWordSize() == 2)
|
|
||||||
{
|
|
||||||
return format; // close
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (v.empty())
|
|
||||||
RageException::ThrowNonfatal("Couldn't find a close format.");
|
|
||||||
return v[0]; // something is better than nothing.
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,24 +1,16 @@
|
|||||||
#ifndef CA_HELPERS_H
|
#ifndef CA_HELPERS_H
|
||||||
#define CA_HELPERS_H
|
#define CA_HELPERS_H
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
#include "FormatConverterClient.h"
|
#include "FormatConverterClient.h"
|
||||||
#include "CAStreamBasicDescription.h"
|
#include "CAStreamBasicDescription.h"
|
||||||
|
|
||||||
const UInt32 kFramesPerPacket = 1;
|
|
||||||
const UInt32 kChannelsPerFrame = 2;
|
|
||||||
const UInt32 kBitsPerChannel = 16;
|
|
||||||
const UInt32 kBytesPerPacket = kChannelsPerFrame * kBitsPerChannel / 8;
|
|
||||||
const UInt32 kBytesPerFrame = kBytesPerPacket;
|
|
||||||
const UInt32 kFormatFlags = kAudioFormatFlagsNativeEndian |
|
|
||||||
kAudioFormatFlagIsSignedInteger;
|
|
||||||
typedef CAStreamBasicDescription Desc;
|
typedef CAStreamBasicDescription Desc;
|
||||||
|
|
||||||
|
|
||||||
class AudioConverter : public FormatConverterClient
|
class AudioConverter : public FormatConverterClient
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
AudioConverter(CAAudioHardwareDevice *dev, RageSound_CA *driver);
|
AudioConverter( RageSound_CA *driver, const Desc &procFormat );
|
||||||
~AudioConverter() { delete mBuffer; }
|
~AudioConverter() { delete mBuffer; }
|
||||||
protected:
|
protected:
|
||||||
OSStatus FormatConverterInputProc(UInt32& ioNumberDataPackets,
|
OSStatus FormatConverterInputProc(UInt32& ioNumberDataPackets,
|
||||||
|
|||||||
@@ -4,16 +4,78 @@
|
|||||||
|
|
||||||
#include "CAAudioHardwareSystem.h"
|
#include "CAAudioHardwareSystem.h"
|
||||||
#include "CAAudioHardwareDevice.h"
|
#include "CAAudioHardwareDevice.h"
|
||||||
|
#include "CAAudioHardwareStream.h"
|
||||||
#include "CAStreamBasicDescription.h"
|
#include "CAStreamBasicDescription.h"
|
||||||
#include "CAException.h"
|
#include "CAException.h"
|
||||||
#include "archutils/Unix/CrashHandler.h"
|
#include "archutils/Unix/CrashHandler.h"
|
||||||
|
#include <mach/thread_act.h>
|
||||||
|
#include <mach/mach_init.h>
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
AudioConverter *gConverter;
|
AudioConverter *gConverter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static Desc FindClosestFormat(const vector<Desc>& formats)
|
||||||
|
{
|
||||||
|
vector<Desc> v;
|
||||||
|
|
||||||
|
vector<Desc>::const_iterator i;
|
||||||
|
for (i = formats.begin(); i != formats.end(); ++i)
|
||||||
|
{
|
||||||
|
const Desc& format = *i;
|
||||||
|
|
||||||
|
if (!format.IsPCM() || format.mSampleRate != 44100.0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (format.SampleWordSize() == 2 &&
|
||||||
|
(format.mFormatFlags & kAudioFormatFlagIsSignedInteger) ==
|
||||||
|
kAudioFormatFlagIsSignedInteger)
|
||||||
|
{ // exact match
|
||||||
|
return format;
|
||||||
|
}
|
||||||
|
v.push_back(format);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = v.begin(); i != v.end(); ++i)
|
||||||
|
{
|
||||||
|
const Desc& format = *i;
|
||||||
|
if (format.SampleWordSize() == 2)
|
||||||
|
{
|
||||||
|
return format; // close
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (v.empty())
|
||||||
|
RageException::ThrowNonfatal("Couldn't find a close format.");
|
||||||
|
return v[0]; // something is better than nothing.
|
||||||
|
}
|
||||||
|
|
||||||
|
static void GetIOProcFormats( CAAudioHardwareStream stream, vector<Desc> &procFormats )
|
||||||
|
{
|
||||||
|
UInt32 numFormats = stream.GetNumberAvailableIOProcFormats();
|
||||||
|
|
||||||
|
for( UInt32 i=0; i<numFormats; ++i )
|
||||||
|
{
|
||||||
|
Desc desc;
|
||||||
|
|
||||||
|
stream.GetAvailableIOProcFormatByIndex( i, desc );
|
||||||
|
procFormats.push_back( desc );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void GetPhysicalFormats( CAAudioHardwareStream stream, vector<Desc> &physicalFormats )
|
||||||
|
{
|
||||||
|
UInt32 numFormats = stream.GetNumberAvailablePhysicalFormats();
|
||||||
|
for( UInt32 i=0; i<numFormats; ++i )
|
||||||
|
{
|
||||||
|
Desc desc;
|
||||||
|
|
||||||
|
stream.GetAvailablePhysicalFormatByIndex( i, desc );
|
||||||
|
physicalFormats.push_back( desc );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
RageSound_CA::RageSound_CA()
|
RageSound_CA::RageSound_CA()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -36,7 +98,22 @@ RageSound_CA::RageSound_CA()
|
|||||||
RageException::ThrowNonfatal("Couldn't get Latency.");
|
RageException::ThrowNonfatal("Couldn't get Latency.");
|
||||||
}
|
}
|
||||||
|
|
||||||
gConverter = new AudioConverter(mOutputDevice, this);
|
AudioStreamID sID = mOutputDevice->GetStreamByIndex( kAudioDeviceSectionOutput, 0 );
|
||||||
|
CAAudioHardwareStream stream( sID );
|
||||||
|
|
||||||
|
vector<Desc> procFormats;
|
||||||
|
GetIOProcFormats( sID, procFormats );
|
||||||
|
|
||||||
|
vector<Desc> physicalFormats;
|
||||||
|
GetPhysicalFormats( sID, physicalFormats );
|
||||||
|
|
||||||
|
const Desc& procFormat = FindClosestFormat( procFormats );
|
||||||
|
stream.SetCurrentIOProcFormat( procFormat );
|
||||||
|
|
||||||
|
const Desc& physicalFormat = FindClosestFormat( physicalFormats );
|
||||||
|
stream.SetCurrentPhysicalFormat( physicalFormat );
|
||||||
|
|
||||||
|
gConverter = new AudioConverter( this, procFormat );
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -45,6 +122,7 @@ RageSound_CA::RageSound_CA()
|
|||||||
}
|
}
|
||||||
catch(const CAException& e)
|
catch(const CAException& e)
|
||||||
{
|
{
|
||||||
|
delete gConverter;
|
||||||
RageException::Throw("Couldn't start the IOProc.");
|
RageException::Throw("Couldn't start the IOProc.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -87,3 +165,12 @@ OSStatus RageSound_CA::GetData(AudioDeviceID inDevice,
|
|||||||
gConverter->FillComplexBuffer(dataPackets, *outOutputData, NULL);
|
gConverter->FillComplexBuffer(dataPackets, *outOutputData, NULL);
|
||||||
return noErr;
|
return noErr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RageSound_CA::SetupDecodingThread()
|
||||||
|
{
|
||||||
|
/* Increase the scheduling precedence of the decoder thread. */
|
||||||
|
thread_precedence_policy po;
|
||||||
|
po.importance = 5;
|
||||||
|
thread_policy_set( mach_thread_self(), THREAD_PRECEDENCE_POLICY, (int *)&po, THREAD_PRECEDENCE_POLICY_COUNT );
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ public:
|
|||||||
~RageSound_CA();
|
~RageSound_CA();
|
||||||
float GetPlayLatency() const { return mLatency; }
|
float GetPlayLatency() const { return mLatency; }
|
||||||
int64_t GetPosition(const RageSoundBase *sound) const;
|
int64_t GetPosition(const RageSoundBase *sound) const;
|
||||||
//void VolumeChanged();
|
void SetupDecodingThread();
|
||||||
};
|
};
|
||||||
|
|
||||||
#define RAGE_SOUND_CA
|
#define RAGE_SOUND_CA
|
||||||
|
|||||||
Reference in New Issue
Block a user