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:
Steve Checkoway
2004-06-24 22:04:55 +00:00
parent 69ab1f3007
commit 8b98d83a50
4 changed files with 160 additions and 43 deletions
-8
View File
@@ -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)
{ {
+8 -3
View File
@@ -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;
+119 -22
View File
@@ -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;
+30 -7
View File
@@ -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,