Attempt to make the callback faster when the proc format is either exactly what SM wants (unlikely from what I've read) or the canonical format (according to apple).
This commit is contained in:
@@ -2,14 +2,6 @@
|
|||||||
#include "RageSoundDriver_CA.h"
|
#include "RageSoundDriver_CA.h"
|
||||||
#include "CAHelpers.h"
|
#include "CAHelpers.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( RageSound_CA *driver, const Desc &procFormat )
|
AudioConverter::AudioConverter( RageSound_CA *driver, const Desc &procFormat )
|
||||||
: mBuffer(NULL), mBufferSize(0)
|
: mBuffer(NULL), mBufferSize(0)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -4,8 +4,15 @@
|
|||||||
#include "FormatConverterClient.h"
|
#include "FormatConverterClient.h"
|
||||||
#include "CAStreamBasicDescription.h"
|
#include "CAStreamBasicDescription.h"
|
||||||
|
|
||||||
typedef CAStreamBasicDescription Desc;
|
static const UInt32 kFramesPerPacket = 1;
|
||||||
|
static const UInt32 kChannelsPerFrame = 2;
|
||||||
|
static const UInt32 kBitsPerChannel = 16;
|
||||||
|
static const UInt32 kBytesPerPacket = kChannelsPerFrame * kBitsPerChannel / 8;
|
||||||
|
static const UInt32 kBytesPerFrame = kBytesPerPacket;
|
||||||
|
static const UInt32 kFormatFlags = kAudioFormatFlagsNativeEndian |
|
||||||
|
kAudioFormatFlagIsSignedInteger;
|
||||||
|
|
||||||
|
typedef CAStreamBasicDescription Desc;
|
||||||
|
|
||||||
class AudioConverter : public FormatConverterClient
|
class AudioConverter : public FormatConverterClient
|
||||||
{
|
{
|
||||||
@@ -17,8 +24,6 @@ protected:
|
|||||||
AudioBufferList& ioData,
|
AudioBufferList& ioData,
|
||||||
AudioStreamPacketDescription **outDesc);
|
AudioStreamPacketDescription **outDesc);
|
||||||
private:
|
private:
|
||||||
static Desc FindClosestFormat(const vector<Desc>& formats);
|
|
||||||
|
|
||||||
RageSound_CA *mDriver;
|
RageSound_CA *mDriver;
|
||||||
UInt8 *mBuffer;
|
UInt8 *mBuffer;
|
||||||
UInt32 mBufferSize;
|
UInt32 mBufferSize;
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
#include <mach/mach_init.h>
|
#include <mach/mach_init.h>
|
||||||
#include <mach/mach_error.h>
|
#include <mach/mach_error.h>
|
||||||
|
|
||||||
static AudioConverter *gConverter;
|
static AudioConverter *gConverter = NULL;
|
||||||
|
|
||||||
/* temporary hack: */
|
/* temporary hack: */
|
||||||
static float g_fLastIOProcTime = 0;
|
static float g_fLastIOProcTime = 0;
|
||||||
@@ -40,7 +40,8 @@ static CString FormatToString( int fmt )
|
|||||||
return ssprintf( "%c%c%c%c", c[0], c[1], c[2], c[3] );
|
return ssprintf( "%c%c%c%c", c[0], c[1], c[2], c[3] );
|
||||||
}
|
}
|
||||||
|
|
||||||
static Desc FindClosestFormat(const vector<Desc>& formats)
|
static Desc FindClosestFormat(const vector<Desc>& formats,
|
||||||
|
RageSound_CA::format& type)
|
||||||
{
|
{
|
||||||
vector<Desc> v;
|
vector<Desc> v;
|
||||||
|
|
||||||
@@ -56,24 +57,30 @@ static Desc FindClosestFormat(const vector<Desc>& formats)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (format.SampleWordSize() == 2 &&
|
if (format.SampleWordSize() == 2 &&
|
||||||
(format.mFormatFlags & kAudioFormatFlagIsSignedInteger) ==
|
(format.mFormatFlags & kFormatFlags) == kFormatFlags)
|
||||||
kAudioFormatFlagIsSignedInteger)
|
|
||||||
{ // exact match
|
{ // exact match
|
||||||
|
type = RageSound_CA::EXACT;
|
||||||
return format;
|
return format;
|
||||||
}
|
}
|
||||||
v.push_back(format);
|
v.push_back(format);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Desc CanonicalFormat(44100.0, kAudioFormatLinearPCM, 8, 1, 8, 2, 32,
|
||||||
|
kAudioFormatFlagsNativeFloatPacked);
|
||||||
|
|
||||||
for (i = v.begin(); i != v.end(); ++i)
|
for (i = v.begin(); i != v.end(); ++i)
|
||||||
{
|
{
|
||||||
const Desc& format = *i;
|
const Desc& format = *i;
|
||||||
if (format.SampleWordSize() == 2)
|
|
||||||
|
if (format == CanonicalFormat)
|
||||||
{
|
{
|
||||||
return format; // close
|
type = RageSound_CA::CANONICAL;
|
||||||
|
return format;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (v.empty())
|
if (v.empty())
|
||||||
RageException::ThrowNonfatal("Couldn't find a close format.");
|
RageException::ThrowNonfatal("Couldn't find a close format.");
|
||||||
|
type = RageSound_CA::OTHER;
|
||||||
return v[0]; // something is better than nothing.
|
return v[0]; // something is better than nothing.
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -157,7 +164,7 @@ RageSound_CA::RageSound_CA()
|
|||||||
f.mBytesPerPacket, f.mFramesPerPacket, f.mBytesPerFrame,
|
f.mBytesPerPacket, f.mFramesPerPacket, f.mBytesPerFrame,
|
||||||
f.mChannelsPerFrame, f.mBitsPerChannel);
|
f.mChannelsPerFrame, f.mBitsPerChannel);
|
||||||
}
|
}
|
||||||
const Desc& physicalFormat = FindClosestFormat( physicalFormats );
|
const Desc& physicalFormat = FindClosestFormat( physicalFormats, mFormat );
|
||||||
stream.SetCurrentPhysicalFormat( physicalFormat );
|
stream.SetCurrentPhysicalFormat( physicalFormat );
|
||||||
|
|
||||||
vector<Desc> procFormats;
|
vector<Desc> procFormats;
|
||||||
@@ -173,9 +180,13 @@ RageSound_CA::RageSound_CA()
|
|||||||
f.mBytesPerPacket, f.mFramesPerPacket, f.mBytesPerFrame,
|
f.mBytesPerPacket, f.mFramesPerPacket, f.mBytesPerFrame,
|
||||||
f.mChannelsPerFrame, f.mBitsPerChannel);
|
f.mChannelsPerFrame, f.mBitsPerChannel);
|
||||||
}
|
}
|
||||||
const Desc& procFormat = FindClosestFormat( procFormats );
|
|
||||||
|
const Desc& procFormat = FindClosestFormat( procFormats, mFormat );
|
||||||
stream.SetCurrentIOProcFormat( procFormat );
|
stream.SetCurrentIOProcFormat( procFormat );
|
||||||
|
|
||||||
|
LOG->Info("Proc format is %s.",
|
||||||
|
mFormat == EXACT ? "exact" : (mFormat == CANONICAL ?
|
||||||
|
"canonical" : "other"));
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -212,12 +223,26 @@ RageSound_CA::RageSound_CA()
|
|||||||
|
|
||||||
StartDecodeThread();
|
StartDecodeThread();
|
||||||
|
|
||||||
gConverter = new AudioConverter( this, procFormat );
|
if (mFormat = OTHER)
|
||||||
|
gConverter = new AudioConverter( this, procFormat );
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
mOutputDevice->AddIOProc(GetData, this);
|
switch (mFormat)
|
||||||
mOutputDevice->StartIOProc(GetData);
|
{
|
||||||
|
case EXACT:
|
||||||
|
mOutputDevice->AddIOProc(GetDataExact, this);
|
||||||
|
mOutputDevice->StartIOProc(GetDataExact);
|
||||||
|
break;
|
||||||
|
case CANONICAL:
|
||||||
|
mOutputDevice->AddIOProc(GetDataCanonical, this);
|
||||||
|
mOutputDevice->StartIOProc(GetDataCanonical);
|
||||||
|
break;
|
||||||
|
case OTHER:
|
||||||
|
mOutputDevice->AddIOProc(GetDataOther, this);
|
||||||
|
mOutputDevice->StartIOProc(GetDataOther);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch(const CAException& e)
|
catch(const CAException& e)
|
||||||
{
|
{
|
||||||
@@ -229,8 +254,19 @@ RageSound_CA::RageSound_CA()
|
|||||||
|
|
||||||
RageSound_CA::~RageSound_CA()
|
RageSound_CA::~RageSound_CA()
|
||||||
{
|
{
|
||||||
mOutputDevice->StopIOProc(GetData);
|
switch (mFormat)
|
||||||
delete gConverter;
|
{
|
||||||
|
case EXACT:
|
||||||
|
mOutputDevice->StopIOProc(GetDataExact);
|
||||||
|
break;
|
||||||
|
case CANONICAL:
|
||||||
|
mOutputDevice->StopIOProc(GetDataCanonical);
|
||||||
|
break;
|
||||||
|
case OTHER:
|
||||||
|
mOutputDevice->StopIOProc(GetDataOther);
|
||||||
|
delete gConverter;
|
||||||
|
break;
|
||||||
|
}
|
||||||
delete mOutputDevice;
|
delete mOutputDevice;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -242,24 +278,85 @@ int64_t RageSound_CA::GetPosition(const RageSoundBase *sound) const
|
|||||||
return int64_t(time.mSampleTime);
|
return int64_t(time.mSampleTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OSStatus RageSound_CA::GetDataExact(AudioDeviceID inDevice,
|
||||||
|
const AudioTimeStamp *inNow,
|
||||||
|
const AudioBufferList *inInputData,
|
||||||
|
const AudioTimeStamp *inInputTime,
|
||||||
|
AudioBufferList *outOutputData,
|
||||||
|
const AudioTimeStamp *inOutputTime,
|
||||||
|
void *inClientData)
|
||||||
|
{
|
||||||
|
RageTimer tm;
|
||||||
|
RageSound_CA *This = (RageSound_CA *)inClientData;
|
||||||
|
AudioBuffer& buf = outOutputData->mBuffers[0];
|
||||||
|
UInt32 dataPackets = buf.mDataByteSize / kBytesPerPacket;
|
||||||
|
int64_t decodePos = int64_t(inOutputTime->mSampleTime);
|
||||||
|
RageTimer mixTM;
|
||||||
|
|
||||||
|
This->Mix((int16_t *)buf.mData, dataPackets, decodePos,
|
||||||
|
int64_t(inNow->mSampleTime));
|
||||||
|
g_fLastMixTimes[g_fLastMixTimePos] = tm.GetDeltaTime();
|
||||||
|
++g_fLastMixTimePos;
|
||||||
|
wrap(g_fLastMixTimePos, NUM_MIX_TIMES);
|
||||||
|
|
||||||
|
g_fLastIOProcTime = tm.GetDeltaTime();
|
||||||
|
++g_iNumIOProcCalls;
|
||||||
|
|
||||||
|
return noErr;
|
||||||
|
}
|
||||||
|
|
||||||
|
OSStatus RageSound_CA::GetDataCanonical(AudioDeviceID inDevice,
|
||||||
|
const AudioTimeStamp *inNow,
|
||||||
|
const AudioBufferList *inInputData,
|
||||||
|
const AudioTimeStamp *inInputTime,
|
||||||
|
AudioBufferList *outOutputData,
|
||||||
|
const AudioTimeStamp *inOutputTime,
|
||||||
|
void *inClientData)
|
||||||
|
{
|
||||||
|
RageTimer tm;
|
||||||
|
RageSound_CA *This = (RageSound_CA *)inClientData;
|
||||||
|
AudioBuffer& buf = outOutputData->mBuffers[0];
|
||||||
|
UInt32 dataPackets = buf.mDataByteSize / 8;
|
||||||
|
int64_t decodePos = int64_t(inOutputTime->mSampleTime);
|
||||||
|
int16_t buffer[dataPackets * kBytesPerPacket];
|
||||||
|
RageTimer mixTM;
|
||||||
|
|
||||||
|
This->Mix(buffer, dataPackets, decodePos, int64_t(inNow->mSampleTime));
|
||||||
|
g_fLastMixTimes[g_fLastMixTimePos] = tm.GetDeltaTime();
|
||||||
|
++g_fLastMixTimePos;
|
||||||
|
wrap(g_fLastMixTimePos, NUM_MIX_TIMES);
|
||||||
|
|
||||||
|
int16_t *ip = buffer;
|
||||||
|
float *fp = (float *)buf.mData;
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < dataPackets; ++i)
|
||||||
|
{
|
||||||
|
int16_t val = *(++ip);
|
||||||
|
|
||||||
|
*(++fp) = val < 0 ? val / 32768.0 : val / 32767.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return noErr;
|
||||||
|
}
|
||||||
|
|
||||||
void RageSound_CA::FillConverter( void *data, UInt32 frames )
|
void RageSound_CA::FillConverter( void *data, UInt32 frames )
|
||||||
{
|
{
|
||||||
RageTimer tm;
|
RageTimer tm;
|
||||||
|
|
||||||
this->Mix( (int16_t *)data, frames, mDecodePos, int64_t(mNow->mSampleTime) );
|
Mix( (int16_t *)data, frames, mDecodePos, int64_t(mNow->mSampleTime) );
|
||||||
|
|
||||||
g_fLastMixTimes[g_fLastMixTimePos] = tm.GetDeltaTime();
|
g_fLastMixTimes[g_fLastMixTimePos] = tm.GetDeltaTime();
|
||||||
++g_fLastMixTimePos;
|
++g_fLastMixTimePos;
|
||||||
wrap( g_fLastMixTimePos, NUM_MIX_TIMES );
|
wrap( g_fLastMixTimePos, NUM_MIX_TIMES );
|
||||||
}
|
}
|
||||||
|
|
||||||
OSStatus RageSound_CA::GetData(AudioDeviceID inDevice,
|
OSStatus RageSound_CA::GetDataOther(AudioDeviceID inDevice,
|
||||||
const AudioTimeStamp *inNow,
|
const AudioTimeStamp *inNow,
|
||||||
const AudioBufferList *inInputData,
|
const AudioBufferList *inInputData,
|
||||||
const AudioTimeStamp *inInputTime,
|
const AudioTimeStamp *inInputTime,
|
||||||
AudioBufferList *outOutputData,
|
AudioBufferList *outOutputData,
|
||||||
const AudioTimeStamp *inOutputTime,
|
const AudioTimeStamp *inOutputTime,
|
||||||
void *inClientData)
|
void *inClientData)
|
||||||
{
|
{
|
||||||
RageTimer tm;
|
RageTimer tm;
|
||||||
|
|
||||||
@@ -291,7 +388,7 @@ OSStatus RageSound_CA::OverloadListener(AudioDeviceID inDevice,
|
|||||||
Output += ssprintf( "%.3f ", g_fLastMixTimes[pos] );
|
Output += ssprintf( "%.3f ", g_fLastMixTimes[pos] );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( g_iNumIOProcCalls >= 100 )
|
//if( g_iNumIOProcCalls >= 100 )
|
||||||
LOG->Warn( "Audio overload. Last IOProc time: %f IOProc calls: %i (%s)",
|
LOG->Warn( "Audio overload. Last IOProc time: %f IOProc calls: %i (%s)",
|
||||||
g_fLastIOProcTime, g_iNumIOProcCalls, Output.c_str() );
|
g_fLastIOProcTime, g_iNumIOProcCalls, Output.c_str() );
|
||||||
g_iNumIOProcCalls = 0;
|
g_iNumIOProcCalls = 0;
|
||||||
|
|||||||
@@ -15,19 +15,42 @@ class RageSoundBase;
|
|||||||
|
|
||||||
class RageSound_CA : public RageSound_Generic_Software
|
class RageSound_CA : public RageSound_Generic_Software
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
enum format
|
||||||
|
{
|
||||||
|
EXACT,
|
||||||
|
CANONICAL,
|
||||||
|
OTHER
|
||||||
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int64_t mDecodePos;
|
int64_t mDecodePos;
|
||||||
float mLatency;
|
float mLatency;
|
||||||
CAAudioHardwareDevice *mOutputDevice;
|
CAAudioHardwareDevice *mOutputDevice;
|
||||||
const AudioTimeStamp *mNow;
|
const AudioTimeStamp *mNow;
|
||||||
|
format mFormat;
|
||||||
|
|
||||||
static OSStatus GetData(AudioDeviceID inDevice,
|
static OSStatus GetDataExact(AudioDeviceID inDevice,
|
||||||
const AudioTimeStamp *inNow,
|
const AudioTimeStamp *inNow,
|
||||||
const AudioBufferList *inInputData,
|
const AudioBufferList *inInputData,
|
||||||
const AudioTimeStamp *inInputTime,
|
const AudioTimeStamp *inInputTime,
|
||||||
AudioBufferList *outOutputData,
|
AudioBufferList *outOutputData,
|
||||||
const AudioTimeStamp *inOutputTime,
|
const AudioTimeStamp *inOutputTime,
|
||||||
void *inClientData);
|
void *inClientData);
|
||||||
|
static OSStatus GetDataCanonical(AudioDeviceID inDevice,
|
||||||
|
const AudioTimeStamp *inNow,
|
||||||
|
const AudioBufferList *inInputData,
|
||||||
|
const AudioTimeStamp *inInputTime,
|
||||||
|
AudioBufferList *outOutputData,
|
||||||
|
const AudioTimeStamp *inOutputTime,
|
||||||
|
void *inClientData);
|
||||||
|
static OSStatus GetDataOther(AudioDeviceID inDevice,
|
||||||
|
const AudioTimeStamp *inNow,
|
||||||
|
const AudioBufferList *inInputData,
|
||||||
|
const AudioTimeStamp *inInputTime,
|
||||||
|
AudioBufferList *outOutputData,
|
||||||
|
const AudioTimeStamp *inOutputTime,
|
||||||
|
void *inClientData);
|
||||||
static OSStatus OverloadListener(AudioDeviceID inDevice,
|
static OSStatus OverloadListener(AudioDeviceID inDevice,
|
||||||
UInt32 inChannel,
|
UInt32 inChannel,
|
||||||
Boolean isInput,
|
Boolean isInput,
|
||||||
|
|||||||
Reference in New Issue
Block a user