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,50 +2,26 @@
|
||||
#include "RageSoundDriver_CA.h"
|
||||
#include "CAHelpers.h"
|
||||
|
||||
#include "CAAudioHardwareDevice.h"
|
||||
#include "CAAudioHardwareStream.h"
|
||||
#include "CAException.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;
|
||||
|
||||
AudioConverter::AudioConverter(CAAudioHardwareDevice *dev, RageSound_CA *driver)
|
||||
AudioConverter::AudioConverter( RageSound_CA *driver, const Desc &procFormat )
|
||||
: 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,
|
||||
kFramesPerPacket, kBytesPerFrame, kChannelsPerFrame,
|
||||
kBitsPerChannel, kFormatFlags);
|
||||
|
||||
SMFormat.Print();
|
||||
procFormat.Print();
|
||||
if (this->Initialize(SMFormat, procFormat))
|
||||
RageException::ThrowNonfatal("Couldn't create the converter.");
|
||||
|
||||
if( this->Initialize(SMFormat, procFormat) )
|
||||
RageException::ThrowNonfatal( "Couldn't create the converter." );
|
||||
|
||||
mDriver = driver;
|
||||
}
|
||||
@@ -57,9 +33,9 @@ OSStatus AudioConverter::FormatConverterInputProc(UInt32& ioNumberDataPackets,
|
||||
AudioBuffer& buf = ioData.mBuffers[0];
|
||||
|
||||
// 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;
|
||||
mBuffer = new UInt8[mBufferSize];
|
||||
}
|
||||
@@ -69,36 +45,3 @@ OSStatus AudioConverter::FormatConverterInputProc(UInt32& ioNumberDataPackets,
|
||||
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
|
||||
#define CA_HELPERS_H
|
||||
|
||||
#include <vector>
|
||||
#include "FormatConverterClient.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;
|
||||
|
||||
|
||||
class AudioConverter : public FormatConverterClient
|
||||
{
|
||||
public:
|
||||
AudioConverter(CAAudioHardwareDevice *dev, RageSound_CA *driver);
|
||||
AudioConverter( RageSound_CA *driver, const Desc &procFormat );
|
||||
~AudioConverter() { delete mBuffer; }
|
||||
protected:
|
||||
OSStatus FormatConverterInputProc(UInt32& ioNumberDataPackets,
|
||||
|
||||
@@ -4,16 +4,78 @@
|
||||
|
||||
#include "CAAudioHardwareSystem.h"
|
||||
#include "CAAudioHardwareDevice.h"
|
||||
#include "CAAudioHardwareStream.h"
|
||||
#include "CAStreamBasicDescription.h"
|
||||
#include "CAException.h"
|
||||
#include "archutils/Unix/CrashHandler.h"
|
||||
|
||||
#include <mach/thread_act.h>
|
||||
#include <mach/mach_init.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
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()
|
||||
{
|
||||
try
|
||||
@@ -36,7 +98,22 @@ RageSound_CA::RageSound_CA()
|
||||
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
|
||||
{
|
||||
@@ -45,6 +122,7 @@ RageSound_CA::RageSound_CA()
|
||||
}
|
||||
catch(const CAException& e)
|
||||
{
|
||||
delete gConverter;
|
||||
RageException::Throw("Couldn't start the IOProc.");
|
||||
}
|
||||
}
|
||||
@@ -87,3 +165,12 @@ OSStatus RageSound_CA::GetData(AudioDeviceID inDevice,
|
||||
gConverter->FillComplexBuffer(dataPackets, *outOutputData, NULL);
|
||||
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();
|
||||
float GetPlayLatency() const { return mLatency; }
|
||||
int64_t GetPosition(const RageSoundBase *sound) const;
|
||||
//void VolumeChanged();
|
||||
void SetupDecodingThread();
|
||||
};
|
||||
|
||||
#define RAGE_SOUND_CA
|
||||
|
||||
Reference in New Issue
Block a user