[plain text]
#define CONTINUOUS_STREAMING FALSE
#define DEBUGTIMESTAMPS FALSE
#define DEBUGZEROTIME FALSE
#define FIXEDSIZEPACKETS TRUE
#define TIMERSTREAM FALSE
#define DOUBLEPARENT TRUE
#include "AppleUSBAudioCommon.h"
#include "AppleUSBAudioEngine.h"
#include "AppleUSBAudioDevice.h"
#include "AppleUSBAudioLevelControl.h"
#include "AppleUSBAudioMuteControl.h"
#include "AppleUSBAudioClip.h"
#include "AppleiSubEngine.h"
#include <IOKit/IOLib.h>
#include <IOKit/IOSyncer.h>
#include <IOKit/IOMessage.h>
#include <IOKit/IOMemoryCursor.h>
#include <IOKit/IOMemoryDescriptor.h>
#include <IOKit/audio/IOAudioDevice.h>
#include <IOKit/audio/IOAudioPort.h>
#include <IOKit/audio/IOAudioTypes.h>
#include <IOKit/audio/IOAudioDefines.h>
#include <IOKit/audio/IOAudioLevelControl.h>
#include <libkern/OSByteOrder.h>
#include <libkern/c++/OSCollectionIterator.h>
#define super IOAudioEngine
OSDefineMetaClassAndStructors(AppleUSBAudioEngine, IOAudioEngine)
#pragma mark -IOKit Routines-
void AppleUSBAudioEngine::free () {
UInt32 i;
debug2IOLog ("+AppleUSBAudioEngine[%p]::free ()\n", this);
for (i = 0; i < numFrameLists; i++) {
if (NULL != soundBuffer) {
if (soundBuffer[i]) {
soundBuffer[i]->release ();
soundBuffer[i] = NULL;
}
IOFree (soundBuffer, numFrameLists * sizeof (IOMemoryDescriptor *));
soundBuffer = NULL;
}
}
if (NULL != usbCompletion) {
IOFree (usbCompletion, numFrameLists * sizeof (IOUSBIsocCompletion *));
usbCompletion = NULL;
}
if (NULL != theFrames) {
IOFree (theFrames, numFramesPerList * numFrameListsToQueue * sizeof (IOUSBIsocFrame *));
theFrames = NULL;
}
if (neededSampleRate) {
neededSampleRate->release ();
neededSampleRate = NULL;
}
if (signal) {
signal->release ();
}
if (streamNotifier) {
streamNotifier->remove ();
streamNotifier = 0;
}
if (interfaceVendor) {
interfaceVendor->release ();
interfaceVendor = 0;
}
if (interfaceProduct) {
interfaceProduct->release ();
interfaceProduct = 0;
}
if (deviceReleaseNumber) {
deviceReleaseNumber->release ();
deviceReleaseNumber = 0;
}
if (configurationValue) {
configurationValue->release ();
configurationValue = 0;
}
if (interfaceNumber) {
interfaceNumber->release ();
interfaceNumber = 0;
}
if (readBuffer) {
IOFree (readBuffer, readFrameListSize * numFrameLists);
readBuffer = NULL;
}
if (NULL != getSampleBuffer ()) {
IOFree (getSampleBuffer (), getSampleBufferSize ());
}
if (NULL != lowFreqSamples) {
IOFree (lowFreqSamples, getSampleBufferSize () * 2);
}
if (NULL != highFreqSamples) {
IOFree (highFreqSamples, getSampleBufferSize () * 2);
}
if (mainStream) {
mainStream->release ();
mainStream = NULL;
}
super::free ();
debug2IOLog ("-AppleUSBAudioEngine[%p]::free()\n", this);
}
bool AppleUSBAudioEngine::init (OSDictionary *properties) {
Boolean result;
debug2IOLog("+AppleUSBAudioEngine[%p]::init ()\n", this);
result = FALSE;
FailIf (FALSE == super::init (NULL), Exit);
setProperty ("IOAudioStreamSampleFormatByteOrder", "Little Endian");
signal = IOSyncer::create (FALSE);
result = TRUE;
Exit:
debug2IOLog("-AppleUSBAudioEngine[%p]::init ()\n", this);
return result;
}
#if TIMERSTREAM
bool AppleUSBAudioEngine::interfacePublished (AppleUSBAudioEngine *audioEngine, void *ref, IOService *newService) {
IOUSBInterface * interface;
bool result;
IOCommandGate * cg;
debugIOLog ("+AppleUSBAudioEngine::interfacePublished ()\n");
result = TRUE;
if (interface = OSDynamicCast (IOUSBInterface, newService)) {
cg = audioEngine->getCommandGate ();
if (cg) {
cg->runAction (reinitWithInterfaceAction, interface, (void *)&result);
}
}
debugIOLog ("-AppleUSBAudioEngine::interfacePublished ()\n");
return result;
}
#endif
IOReturn AppleUSBAudioEngine::message (UInt32 type, IOService * provider, void * arg) {
debug4IOLog("+AppleUSBAudioEngine[%p]::message (0x%x, %p)\n", this, type, provider);
switch (type) {
case kIOMessageServiceIsTerminated:
if (iSubEngine == (AppleiSubEngine *)provider) {
debugIOLog ("iSub requesting termination\n");
iSubTeardownConnection ();
iSubEngineNotifier = addNotification (gIOPublishNotification, serviceMatching ("AppleiSubEngine"), (IOServiceNotificationHandler)&iSubEnginePublished, this);
}
case kIOMessageServiceIsRequestingClose:
if ((streamInterface != NULL) && (streamInterface == provider)) {
shouldStop = 1;
streamInterface->close (this);
streamInterface = NULL;
}
break;
default:
;
}
debug4IOLog("-AppleUSBAudioEngine[%p]::message (0x%x, %p)\n", this, type, provider);
return kIOReturnSuccess;
}
#if DOUBLEPARENT
bool AppleUSBAudioEngine::requestTerminate (IOService * provider, IOOptionBits options) {
bool result;
debug4IOLog ("+AppleUSBAudioEngine[%p]::requestTerminate (%p, %x)\n", this, provider, options);
if (usbAudioDevice == provider || streamInterface == provider) {
result = TRUE; } else {
result = FALSE; }
debug4IOLog ("-AppleUSBAudioEngine[%p]::requestTerminate (%p, %x)\n", this, provider, options);
return result;
}
#endif
bool AppleUSBAudioEngine::start (IOService * provider) {
IONotifier * audioDeviceNotifier;
bool resultCode;
USBAudioConfigObject * usbAudio;
debug3IOLog ("+AppleUSBAudioEngine[%p]::start (%p)\n", this, provider);
resultCode = FALSE;
audioDeviceNotifier = addNotification (gIOPublishNotification,
serviceMatching ("AppleUSBAudioDevice"),
(IOServiceNotificationHandler)&audioDevicePublished,
this,
NULL);
signal->wait (FALSE);
audioDeviceNotifier->remove ();
signal->reinit ();
FailIf (NULL == usbAudioDevice, Exit);
usbAudio = usbAudioDevice->GetUSBAudioConfigObject ();
FailIf (NULL == usbAudio, Exit);
FailIf (usbAudio->GetNumOutputTerminals (0, 0) == 1 && usbAudio->GetIndexedOutputTerminalType (0, 0, 0) == OUTPUT_LOW_FREQUENCY_EFFECTS_SPEAKER, Exit);
resultCode = super::start (provider, usbAudioDevice);
debug4IOLog ("-%d = AppleUSBAudioEngine[%p]::start (%p)\n", resultCode, this, provider);
Exit:
return resultCode;
}
void AppleUSBAudioEngine::stop (IOService * provider) {
#if TIMERSTREAM
bool performStop;
#endif
debug3IOLog("+AppleUSBAudioEngine[%p]::stop (%p)\n", this, provider);
#if TIMERSTREAM
if (!didStop) {
performStop = isInactive ();
if (!performStop) {
if (!timerStreamThread) { IOCommandGate *cg;
cg = getCommandGate ();
performStop = TRUE;
if (cg) {
bool timerStreamStarted;
if (cg->runAction (startTimerStreamIfNecessaryAction, (void *)&timerStreamStarted) == kIOReturnSuccess) {
performStop = !timerStreamStarted;
}
}
}
}
if (performStop) {
#endif
if (NULL != iSubEngineNotifier) {
iSubEngineNotifier->remove ();
iSubEngineNotifier = NULL;
}
if (NULL != iSubEngine) {
iSubTeardownConnection ();
}
if (usbAudioDevice) {
usbAudioDevice->release ();
usbAudioDevice = 0;
}
#if TIMERSTREAM
if (isUnattachedStreamRegistered ()) {
unregisterUnattachedStream ();
stopTimerStream ();
}
#endif
#if CONTINUOUS_STREAMING
if (usbStreamRunning) {
stopUSBStream ();
}
#endif
#if TIMERSTREAM
if (!didStop) {
didStop = TRUE;
#endif
super::stop (provider);
#if TIMERSTREAM
}
}
#endif
if (thePipe) {
thePipe->release ();
thePipe = NULL;
}
if (theAssociatedPipe) {
theAssociatedPipe->release ();
theAssociatedPipe = NULL;
}
if (streamInterface) {
streamInterface->close (this);
streamInterface = NULL;
}
#if TIMERSTREAM
if (!performStop && !isUnattachedStreamRegistered ()) {
debug2IOLog ("++AppleUSBAudioEngine[%p]::stop () - keeping the stream around\n", this);
registerUnattachedStream ();
}
}
#endif
debug3IOLog ("-AppleUSBAudioEngine[%p]::stop (%p)\n", this, provider);
}
bool AppleUSBAudioEngine::terminate (IOOptionBits options = 0) {
#if TIMERSTREAM
IOCommandGate * cg;
#endif
bool shouldTerminate;
bool result;
result = TRUE;
shouldTerminate = TRUE;
debug2IOLog ("+AppleUSBAudioEngine[%p]::terminate ()\n", this);
#if TIMERSTREAM
cg = getCommandGate ();
if (cg) {
bool timerStreamStarted;
if (cg->runAction (startTimerStreamIfNecessaryAction, (void *)&timerStreamStarted) == kIOReturnSuccess) {
shouldTerminate = !timerStreamStarted;
}
}
#endif
if (shouldTerminate) {
result = super::terminate (options);
}
debug2IOLog ("-AppleUSBAudioEngine[%p]::terminate ()\n", this);
return result;
}
#pragma mark -USB Audio driver-
IOAudioEngineState AppleUSBAudioEngine::_setState(IOAudioEngineState newState) {
IOAudioEngineState oldState;
oldState = super::setState(newState);
if (notifyDeviceOfStop && (newState != oldState) && (newState == kIOAudioEngineStopped)) {
FailIf (NULL == usbAudioDevice, Exit);
usbAudioDevice->streamStopped(this);
}
Exit:
return oldState;
}
IOReturn AppleUSBAudioEngine::AddAvailableFormatsFromDevice (USBAudioConfigObject *usbAudio) {
IOAudioStreamFormat streamFormat;
IOAudioSampleRate lowSampleRate;
IOAudioSampleRate highSampleRate;
UInt32 * sampleRates;
IOReturn result;
UInt16 numAltInterfaces;
UInt8 numSampleRates;
UInt8 altInterfaceIndx;
UInt8 rateIndx;
result = kIOReturnError;
FailIf (NULL == usbAudio, Exit);
FailIf (NULL == mainStream, Exit);
numAltInterfaces = usbAudio->GetNumAltStreamInterfaces (ourInterfaceNumber);
debug3IOLog ("There are %d alternate stream interfaces on interface %d\n", numAltInterfaces, ourInterfaceNumber);
for (altInterfaceIndx = 1; altInterfaceIndx < numAltInterfaces; altInterfaceIndx++) {
numSampleRates = usbAudio->GetNumSampleRates (ourInterfaceNumber, altInterfaceIndx);
sampleRates = usbAudio->GetSampleRates (ourInterfaceNumber, altInterfaceIndx);
switch (usbAudio->GetFormat (ourInterfaceNumber, altInterfaceIndx)) {
case PCM:
streamFormat.fSampleFormat = kIOAudioStreamSampleFormatLinearPCM;
streamFormat.fNumericRepresentation = kIOAudioStreamNumericRepresentationSignedInt;
streamFormat.fIsMixable = TRUE;
break;
case AC3: debugIOLog ("AC-3 audio format type!\n");
streamFormat.fSampleFormat = 'AC-3';
streamFormat.fNumericRepresentation = kIOAudioStreamNumericRepresentationSignedInt;
streamFormat.fIsMixable = FALSE;
break;
case IEC1937_AC3:
debugIOLog ("IEC1937 AC-3 audio format type!\n");
streamFormat.fSampleFormat = 'IAC3';
streamFormat.fNumericRepresentation = kIOAudioStreamNumericRepresentationSignedInt;
streamFormat.fIsMixable = FALSE;
break;
default:
debug2IOLog ("interface format = %x\n", usbAudio->GetFormat (ourInterfaceNumber, altInterfaceIndx));
debugIOLog ("interface doesn't support a format that we can deal with, so we're not making it available\n");
continue; }
streamFormat.fNumChannels = usbAudio->GetNumChannels (ourInterfaceNumber, altInterfaceIndx);
streamFormat.fBitDepth = usbAudio->GetSampleSize (ourInterfaceNumber, altInterfaceIndx);
streamFormat.fBitWidth = usbAudio->GetSubframeSize (ourInterfaceNumber, altInterfaceIndx) * 8;
streamFormat.fAlignment = kIOAudioStreamAlignmentLowByte;
streamFormat.fByteOrder = kIOAudioStreamByteOrderLittleEndian;
streamFormat.fDriverTag = (ourInterfaceNumber << 16) | altInterfaceIndx;
debug3IOLog ("Interface %d, Alt %d has a ", ourInterfaceNumber, altInterfaceIndx);
debug2IOLog ("%d bit interface, ", streamFormat.fBitDepth);
debug2IOLog ("%d channels, and ", streamFormat.fNumChannels);
debug2IOLog ("%d sample rates, which are:\n", numSampleRates);
if (numSampleRates) {
for (rateIndx = 0; rateIndx < numSampleRates; rateIndx++) {
debug2IOLog (" %d", sampleRates[rateIndx]);
lowSampleRate.whole = sampleRates[rateIndx];
lowSampleRate.fraction = 0;
mainStream->addAvailableFormat (&streamFormat, &lowSampleRate, &lowSampleRate);
}
debugIOLog ("\n");
} else if (sampleRates) {
debug3IOLog (" %d to %d\n", sampleRates[0], sampleRates[1]);
lowSampleRate.whole = sampleRates[0];
lowSampleRate.fraction = 0;
highSampleRate.whole = sampleRates[1];
highSampleRate.fraction = 0;
mainStream->addAvailableFormat (&streamFormat, &lowSampleRate, &highSampleRate);
}
}
result = kIOReturnSuccess;
Exit:
return result;
}
bool AppleUSBAudioEngine::audioDevicePublished (AppleUSBAudioEngine * audioEngine, void * ref, IOService * newService) {
AppleUSBAudioDevice * audioDevice;
IOUSBInterface * thisControlInterface;
IOUSBInterface * thisStreamInterface;
bool resultCode;
debug4IOLog ("+AppleUSBAudioEngine::audioDevicePublished (%p, %p, %p)\n", audioEngine, (UInt32*)ref, newService);
resultCode = FALSE;
FailIf (NULL == audioEngine, Exit);
FailIf (NULL == newService, Exit);
audioDevice = OSDynamicCast (AppleUSBAudioDevice, newService);
FailIf (NULL == audioDevice, Exit);
thisControlInterface = OSDynamicCast (IOUSBInterface, audioDevice->getProvider ());
FailIf (NULL == thisControlInterface, Exit);
thisStreamInterface = OSDynamicCast (IOUSBInterface, audioEngine->getProvider ());
FailIf (NULL == thisStreamInterface, Exit);
if (thisControlInterface->GetDevice () == thisStreamInterface->GetDevice ()) {
debug4IOLog ("++AppleUSBAudioEngine[%p]: found device (%p) for Audio Engine (%p)\n", audioEngine, audioDevice, audioEngine);
audioEngine->usbAudioDevice = audioDevice;
audioEngine->signal->signal (kIOReturnSuccess, FALSE);
resultCode = TRUE; }
Exit:
debug4IOLog ("-AppleUSBAudioEngine::audioDevicePublished (%p, %p, %p)\n", audioEngine, (UInt32 *)ref, newService);
return resultCode;
}
UInt32 AppleUSBAudioEngine::CalculateNumSamplesPerFrameList (UInt32 sampleRate, UInt32 numFrames, UInt32 theNumFrameLists) {
UInt32 numSamples;
UInt32 i;
UInt32 sampleNum;
UInt32 sum;
UInt16 samplesThisFrame;
IOFixed fixedSampleRate;
numSamples = 0;
fixedSampleRate = IOUFixedDivide (sampleRate << 16, 1000 << 16); samplesThisFrame = fixedSampleRate >> 16;
sampleNum = 2;
sum = samplesThisFrame;
for (i = 0; i < numFrames * theNumFrameLists; i++) {
numSamples += samplesThisFrame;
samplesThisFrame = (IOUFixedMultiply (fixedSampleRate, sampleNum << 16) >> 16) - sum;
sum += samplesThisFrame;
sampleNum++;
if (1000 == sampleNum) {
samplesThisFrame = fixedSampleRate >> 16;
sampleNum = 2;
sum = samplesThisFrame;
}
}
return numSamples;
}
void AppleUSBAudioEngine::CalculateSamplesPerFrame (UInt32 sampleRate, UInt16 * averageFrameSamples, UInt16 * additionalSampleFrameFreq) {
UInt32 divisor;
*averageFrameSamples = sampleRate / 1000;
divisor = (sampleRate % 1000);
if (divisor)
*additionalSampleFrameFreq = 1000 / divisor;
else
*additionalSampleFrameFreq = 0;
}
IOReturn AppleUSBAudioEngine::CheckForAssociatedEndpoint (USBAudioConfigObject *usbAudio) {
IOUSBFindEndpointRequest associatedEndpoint;
IOReturn result;
UInt8 assocEndpoint;
UInt8 address;
UInt8 syncType;
result = kIOReturnSuccess;
theAssociatedPipe = NULL;
address = usbAudio->GetIsocEndpointAddress (ourInterfaceNumber, alternateInterfaceID, direction);
syncType = usbAudio->GetIsocEndpointSyncType (ourInterfaceNumber, alternateInterfaceID, address);
if (kAsynchSyncType == syncType) {
debug2IOLog ("checking endpoint %d for an associated endpoint\n", address);
assocEndpoint = usbAudio->GetIsocAssociatedEndpointAddress (ourInterfaceNumber, alternateInterfaceID, address);
if (assocEndpoint != 0) {
debugIOLog ("This endpoint has an associated synch endpoint!\n");
refreshInterval = usbAudio->GetIsocAssociatedEndpointRefreshInt (ourInterfaceNumber, alternateInterfaceID, assocEndpoint);
debug2IOLog ("The refresh interval is %d\n", refreshInterval);
framesUntilRefresh = 1 << (10 - refreshInterval); if (framesUntilRefresh < numFramesPerList)
numFramesPerList = framesUntilRefresh; associatedEndpoint.type = kUSBIsoc;
associatedEndpoint.direction = direction == kUSBOut ? kUSBIn : kUSBOut; associatedEndpoint.maxPacketSize = 3; associatedEndpoint.interval = 0xFF; theAssociatedPipe = streamInterface->FindNextPipe (NULL, &associatedEndpoint);
FailWithAction (NULL == theAssociatedPipe, result = kIOReturnError, Exit);
theAssociatedPipe->retain ();
} else {
debugIOLog ("Couldn't find the associated synch endpoint!\n");
}
} else {
debugIOLog ("This endpoint does not have an associated synch endpoint\n");
}
Exit:
return result;
}
IOReturn AppleUSBAudioEngine::clipOutputSamples (const void *mixBuf,
void *sampleBuf,
UInt32 firstSampleFrame,
UInt32 numSampleFrames,
const IOAudioStreamFormat *streamFormat,
IOAudioStream *audioStream) {
void * iSubBuffer = NULL;
UInt32 iSubBufferLen = 0;
UInt32 sampleRate;
SInt32 offsetDelta;
IOReturn result;
#if 0
#ifdef DEBUGLOG
UInt32 currentLocation = getCurrentSampleFrame ();
if (firstSampleFrame <= currentLocation && (firstSampleFrame + numSampleFrames) > currentLocation) {
IOLog ("!!!!!!!!!!Buffer problems!!!!!!!!!\n");
IOLog ("currentLocation = 0x%lX, firstSampleFrame = 0x%lX, numSampleFrames = 0x%lX\n", currentLocation, firstSampleFrame, numSampleFrames);
} else if (((currentLocation + 96) - firstSampleFrame) < numSampleFrames) { IOLog("!!!!!! Possible buffer problem !!!!!!\n");
IOLog ("currentLocation = 0x%lX, firstSampleFrame = 0x%lX, numSampleFrames = 0x%lX\n", currentLocation, firstSampleFrame, numSampleFrames);
IOLog ("overlap = 0x%X [%d]\n", (currentLocation + 96) - firstSampleFrame, (currentLocation + 96) - firstSampleFrame);
}
#endif
#endif
if (TRUE == streamFormat->fIsMixable) {
if (iSubBufferMemory) {
iSubBufferLen = iSubBufferMemory->getLength ();
iSubBuffer = (void*)iSubBufferMemory->getVirtualSegment (0, &iSubBufferLen);
iSubBufferLen = iSubBufferLen / 2;
sampleRate = getSampleRate()->whole;
if (FALSE == needToSync && previousClippedToFrame != firstSampleFrame && !(previousClippedToFrame == getNumSampleFramesPerBuffer () && firstSampleFrame == 0)) {
#if DEBUGLOG
IOLog ("iSubBufferOffset was %ld\n", iSubBufferOffset);
#endif
if (firstSampleFrame < previousClippedToFrame) {
offsetDelta = (getNumSampleFramesPerBuffer () - previousClippedToFrame + firstSampleFrame) * streamFormat->fNumChannels;
} else {
offsetDelta = (firstSampleFrame - previousClippedToFrame) * streamFormat->fNumChannels;
}
iSubBufferOffset += offsetDelta;
#if DEBUGLOG
IOLog ("clip to point was %ld, now %ld (delta = %ld)\n", previousClippedToFrame, firstSampleFrame, offsetDelta);
IOLog ("iSubBufferOffset is now %ld\n", iSubBufferOffset);
#endif
if (iSubBufferOffset > (SInt32)iSubBufferLen) {
iSubLoopCount += iSubBufferOffset / iSubBufferLen;
iSubBufferOffset = iSubBufferOffset % iSubBufferLen;
#if DEBUGLOG
IOLog ("iSubBufferOffset > iSubBufferLen, iSubBufferOffset is now %ld\n", iSubBufferOffset);
#endif
} else if (iSubBufferOffset < 0) {
iSubBufferOffset += iSubBufferLen;
#if DEBUGLOG
IOLog ("iSubBufferOffset < 0, iSubBufferOffset is now %ld\n", iSubBufferOffset);
#endif
}
}
previousClippedToFrame = firstSampleFrame + numSampleFrames;
#if 0
if (iSubBufferOffset > (iSubEngine->GetCurrentByteCount () / 2)) {
iSubLead = iSubBufferOffset - (iSubEngine->GetCurrentByteCount () / 2);
} else {
iSubLead = iSubBufferLen - (iSubEngine->GetCurrentByteCount () / 2) + iSubBufferOffset;
}
if (FALSE == needToSync && (iSubEngine->GetCurrentLoopCount () > iSubLoopCount || iSubLead < (initialiSubLead / 2))) {
#if DEBUGLOG
IOLog ("iSubLoopCount=%ld, iSubCurrentLoopCount=%ld, iSubCurrentByteCount=%ld, iSubBufferOffset=%ld\n", iSubLoopCount, iSubEngine->GetCurrentLoopCount (), iSubEngine->GetCurrentByteCount (), iSubBufferOffset);
#endif
needToSync = true;
}
#endif
if (TRUE == needToSync) {
needToSync = FALSE;
iSubLoopCount = iSubEngine->GetCurrentLoopCount ();
iSubBufferOffset = (firstSampleFrame - getCurrentSampleFrame ()) * streamFormat->fNumChannels;
#if DEBUGLOG
IOLog ("starting iSubBufferOffset = %ld, iSubLoopCount = %ld\n", iSubBufferOffset, iSubLoopCount);
#endif
iSubBufferOffset -= 88 * 5;
}
if (iSubBufferOffset > (SInt32)iSubBufferLen) {
iSubLoopCount += iSubBufferOffset / iSubBufferLen;
iSubBufferOffset = iSubBufferOffset % iSubBufferLen;
#if DEBUGLOG
IOLog ("iSubBufferOffset > iSubBufferLen, iSubBufferOffset is now %ld\n", iSubBufferOffset);
#endif
} else if (iSubBufferOffset < 0) {
iSubBufferOffset += iSubBufferLen;
#if DEBUGLOG
IOLog ("iSubBufferOffset < 0, iSubBufferOffset is now %ld\n", iSubBufferOffset);
#endif
}
result = clipAppleUSBAudioToOutputStreamiSub (mixBuf, sampleBuf, &filterState, lowFreqSamples, highFreqSamples, firstSampleFrame, numSampleFrames, sampleRate, streamFormat, (SInt16*)iSubBuffer, &iSubLoopCount, &iSubBufferOffset, iSubBufferLen);
if (TRUE == startiSub) {
iSubEngine->StartiSub ();
startiSub = FALSE;
}
} else {
result = clipAppleUSBAudioToOutputStream (mixBuf, sampleBuf, firstSampleFrame, numSampleFrames, streamFormat);
}
} else {
memcpy (sampleBuf, (UInt8 *)mixBuf + (firstSampleFrame * streamFormat->fNumChannels), numSampleFrames * streamFormat->fNumChannels * (streamFormat->fBitWidth / 8));
result = kIOReturnSuccess;
}
return result;
}
IOReturn AppleUSBAudioEngine::convertInputSamples (const void *sampleBuf,
void *destBuf,
UInt32 firstSampleFrame,
UInt32 numSampleFrames,
const IOAudioStreamFormat *streamFormat,
IOAudioStream *audioStream) {
#if 0
#if DEBUGLOG
UInt32 lastSampleFrame = firstSampleFrame + numSampleFrames;
UInt32 numSampleFramesPerBuffer, currentSampleFrame;
numSampleFramesPerBuffer = getNumSampleFramesPerBuffer();
if (lastSampleFrame >= numSampleFramesPerBuffer) {
lastSampleFrame -= numSampleFramesPerBuffer;
}
currentSampleFrame = getCurrentSampleFrame();
if (firstSampleFrame < lastSampleFrame) {
if ((currentSampleFrame > firstSampleFrame) && (currentSampleFrame < lastSampleFrame)) {
IOLog("input error - samples not input yet! (%lx, %lx, curr = %lx)\n", firstSampleFrame, numSampleFrames, currentSampleFrame);
}
} else {
if ((currentSampleFrame > firstSampleFrame) || (currentSampleFrame < lastSampleFrame)) {
IOLog("input error - samples not input yet! (%lx, %lx, curr = %lx)\n", firstSampleFrame, numSampleFrames, currentSampleFrame);
}
}
#endif
#endif
return convertFromAppleUSBAudioInputStream_NoWrap (sampleBuf, destBuf, firstSampleFrame, numSampleFrames, streamFormat);
}
UInt32 AppleUSBAudioEngine::getCurrentSampleFrame () {
const IOAudioStreamFormat *theFormat;
UInt32 currentSampleFrame;
UInt32 i;
UInt32 offset;
UInt32 thisFrameListSize;
UInt16 averageFrameSamples;
UInt16 additionalSampleFrameFreq;
#if 0
AbsoluteTime uptime;
static AbsoluteTime lastUptime = {0, 0};
AbsoluteTime delta;
UInt64 nanos;
#endif
currentSampleFrame = 0;
FailIf (NULL == mainStream, Exit);
theFormat = mainStream->getFormat ();
if (getDirection () == kIOAudioStreamDirectionOutput) {
CalculateSamplesPerFrame (curSampleRate.whole, &averageFrameSamples, &additionalSampleFrameFreq);
if (additionalSampleFrameFreq) {
offset = 0;
if (additionalSampleFrameFreq == numFramesPerList) {
thisFrameListSize = frameListSize;
} else {
thisFrameListSize = frameListSize - ((theFormat->fBitWidth / 8) * theFormat->fNumChannels);
}
for (i = 0; i < currentFrameList; i++) {
offset += thisFrameListSize;
if (i % (additionalSampleFrameFreq / numFramesPerList) == 0) {
thisFrameListSize = frameListSize;
} else {
thisFrameListSize = frameListSize - ((theFormat->fBitWidth / 8) * theFormat->fNumChannels);
}
}
currentSampleFrame = offset;
} else {
currentSampleFrame = currentFrameList * frameListSize;
}
} else {
currentSampleFrame = bufferOffset == bufferSize ? 0 : bufferOffset;
}
currentSampleFrame /= (theFormat->fNumChannels * (theFormat->fBitWidth / 8));
#if 0
clock_get_uptime (&uptime);
delta = uptime;
SUB_ABSOLUTETIME (&delta, &lastUptime);
absolutetime_to_nanoseconds (delta, &nanos);
debug3IOLog ("getCurrentSampleFrame = %ld, delta = %ld\n", currentSampleFrame, (UInt32)(nanos / (1000 * 1000)));
lastUptime = uptime;
#endif
Exit:
#if DEBUGLOG
if (currentSampleFrame > getNumSampleFramesPerBuffer ()) {
char panicString[255];
sprintf (panicString, "currentSampleFrame = %d, getNumSampleFramesPerBuffer () = %d, currentFrameList = %d, frameListSize = %d, bufferOffset = %d", currentSampleFrame, getNumSampleFramesPerBuffer (), currentFrameList, frameListSize, bufferOffset);
panic (panicString);
}
#endif
return currentSampleFrame;
}
void AppleUSBAudioEngine::GetDeviceInfo (void) {
OSObject *obj;
if (obj = streamInterface->getProperty (kUSBVendorName)) {
obj->retain();
interfaceVendor = obj;
}
if (obj = streamInterface->getProperty (kUSBProductName)) {
obj->retain();
interfaceProduct = obj;
}
if (obj = streamInterface->getProperty (kUSBDeviceReleaseNumber)) {
obj->retain();
deviceReleaseNumber = obj;
}
if (obj = streamInterface->getProperty (kUSBConfigurationValue)) {
obj->retain();
configurationValue = obj;
}
if (obj = streamInterface->getProperty (kUSBInterfaceNumber)) {
obj->retain();
interfaceNumber = obj;
}
}
IOAudioStreamDirection AppleUSBAudioEngine::getDirection () {
IOAudioStreamDirection direction;
direction = kIOAudioStreamDirectionOutput;
FailIf (NULL == mainStream, Exit);
direction = mainStream->getDirection ();
Exit:
return direction;
}
OSString * AppleUSBAudioEngine::getGlobalUniqueID () {
char * uniqueIDStr;
OSString * localID;
OSString * uniqueID;
OSNumber * usbLocation;
IOReturn err;
UInt32 uniqueIDSize;
UInt32 locationID;
UInt8 stringIndex;
UInt8 interfaceNumber;
char productString[kStringBufferSize];
char manufacturerString[kStringBufferSize];
char serialNumberString[kStringBufferSize];
char locationIDString[kStringBufferSize];
char interfaceNumberString[4];
usbLocation = NULL;
uniqueIDStr = NULL;
localID = NULL;
uniqueID = NULL;
uniqueIDSize = 5; uniqueIDSize += strlen ("AppleUSBAudioEngine");
err = kIOReturnSuccess;
manufacturerString[0] = 0;
stringIndex = streamInterface->GetDevice()->GetManufacturerStringIndex ();
if (0 != stringIndex) {
err = streamInterface->GetDevice()->GetStringDescriptor (stringIndex, manufacturerString, kStringBufferSize);
}
if (0 == manufacturerString[0] || kIOReturnSuccess != err) {
strcpy (manufacturerString, "Unknown Manufacturer");
}
uniqueIDSize += strlen (manufacturerString);
err = kIOReturnSuccess;
productString[0] = 0;
stringIndex = streamInterface->GetDevice()->GetProductStringIndex ();
if (0 != stringIndex) {
err = streamInterface->GetDevice()->GetStringDescriptor (stringIndex, productString, kStringBufferSize);
}
if (0 == productString[0] || kIOReturnSuccess != err) {
strcpy (productString, "Unknown USB Audio Device");
}
uniqueIDSize += strlen (productString);
err = kIOReturnSuccess;
serialNumberString[0] = 0;
stringIndex = streamInterface->GetDevice()->GetSerialNumberStringIndex ();
if (0 != stringIndex) {
err = streamInterface->GetDevice()->GetStringDescriptor (stringIndex, serialNumberString, kStringBufferSize);
}
if (0 == serialNumberString[0] || kIOReturnSuccess != err) {
usbLocation = (OSNumber *) streamInterface->GetDevice()->getProperty (kUSBDevicePropertyLocationID);
if (NULL != usbLocation) {
locationID = usbLocation->unsigned32BitValue ();
sprintf (locationIDString, "%x", locationID);
} else {
strcpy (locationIDString, "Unknown location");
}
uniqueIDSize += strlen (locationIDString);
} else {
debug2IOLog ("device has a serial number = %s\n", serialNumberString);
uniqueIDSize += strlen (serialNumberString);
}
interfaceNumber = streamInterface->GetInterfaceNumber ();
sprintf (interfaceNumberString, "%d", interfaceNumber);
uniqueIDSize += strlen (interfaceNumberString);
uniqueIDStr = (char *)IOMalloc (uniqueIDSize);
if (NULL != uniqueIDStr) {
uniqueIDStr[0] = 0;
if (0 == serialNumberString[0]) {
sprintf (uniqueIDStr, "AppleUSBAudioEngine:%s:%s:%s:%s", manufacturerString, productString, locationIDString, interfaceNumberString);
} else {
sprintf (uniqueIDStr, "AppleUSBAudioEngine:%s:%s:%s:%s", manufacturerString, productString, serialNumberString, interfaceNumberString);
}
uniqueID = OSString::withCString (uniqueIDStr);
IOFree (uniqueIDStr, uniqueIDSize);
}
debug2IOLog ("getGlobalUniqueID = %s\n", uniqueIDStr);
return uniqueID;
}
void * AppleUSBAudioEngine::getSampleBuffer (void) {
void * sampleBuffer;
sampleBuffer = NULL;
FailIf (NULL == mainStream, Exit);
sampleBuffer = mainStream->getSampleBuffer ();
Exit:
return sampleBuffer;
}
UInt32 AppleUSBAudioEngine::getSampleBufferSize (void) {
UInt32 bufferSize;
bufferSize = 0;
FailIf (NULL == mainStream, Exit);
bufferSize = mainStream->getSampleBufferSize ();
Exit:
return bufferSize;
}
bool AppleUSBAudioEngine::initHardware (IOService *provider) {
USBAudioConfigObject * usbAudio;
IOAudioStreamFormat streamFormat;
Boolean resultCode;
debug3IOLog ("+AppleUSBAudioEngine[%p]::initHardware (%p)\n", this, provider);
resultCode = FALSE;
FailIf (FALSE == super::initHardware (provider), Exit);
streamInterface = OSDynamicCast (IOUSBInterface, provider);
FailIf (NULL == streamInterface, Exit);
previousInterface = streamInterface;
numFrameLists = NUM_FRAME_LISTS;
numFramesPerList = NUM_FRAMES_PER_LIST;
numFrameListsToQueue = NUM_FRAME_LISTS_TO_QUEUE;
ourInterfaceNumber = streamInterface->GetInterfaceNumber ();
debug2IOLog ("ourInterfaceNumber = %d\n", ourInterfaceNumber);
usbAudio = usbAudioDevice->GetUSBAudioConfigObject ();
FailIf (NULL == usbAudio, Exit);
mainStream = new IOAudioStream;
FailIf (NULL == mainStream, Exit);
sampleRate.whole = kDefaultSamplingRate;
sampleRate.fraction = 0;
alternateInterfaceID = usbAudio->FindAltInterfaceWithSettings (ourInterfaceNumber, kChannelDepth_STEREO, kBitDepth_16bits, sampleRate.whole);
if (255 == alternateInterfaceID) {
alternateInterfaceID = usbAudio->FindAltInterfaceWithSettings (ourInterfaceNumber, kChannelDepth_MONO, kBitDepth_16bits, sampleRate.whole);
}
if (255 == alternateInterfaceID) {
alternateInterfaceID = usbAudio->FindAltInterfaceWithSettings (ourInterfaceNumber, kChannelDepth_STEREO, kBitDepth_16bits);
sampleRate.whole = usbAudio->GetHighestSampleRate (ourInterfaceNumber, alternateInterfaceID); }
if (255 == alternateInterfaceID) {
alternateInterfaceID = usbAudio->FindAltInterfaceWithSettings (ourInterfaceNumber, kChannelDepth_MONO, kBitDepth_16bits);
sampleRate.whole = usbAudio->GetHighestSampleRate (ourInterfaceNumber, alternateInterfaceID); }
if (255 == alternateInterfaceID) {
alternateInterfaceID = 1;
sampleRate.whole = usbAudio->GetHighestSampleRate (ourInterfaceNumber, alternateInterfaceID);
}
debug2IOLog ("default sample rate is %d\n", sampleRate.whole);
FailIf (0 == sampleRate.whole, Exit);
direction = usbAudio->GetIsocEndpointDirection (ourInterfaceNumber, alternateInterfaceID);
mainStream->initWithAudioEngine (this, (IOAudioStreamDirection)direction, 1);
if (kUSBIn == direction) {
debugIOLog ("This is an input type endpoint (mic, etc.)\n");
} else if (kUSBOut == direction) {
debugIOLog ("This is an output type endpoint (speaker, etc.)\n");
} else {
FailMessage ("Couldn't get the endpoint direction!\n", Exit);
}
FailIf (kIOReturnSuccess != AddAvailableFormatsFromDevice (usbAudio), Exit);
curSampleRate = sampleRate;
setSampleRate (&sampleRate);
switch (usbAudio->GetFormat (ourInterfaceNumber, alternateInterfaceID)) {
case PCM:
streamFormat.fSampleFormat = kIOAudioStreamSampleFormatLinearPCM;
streamFormat.fNumericRepresentation = kIOAudioStreamNumericRepresentationSignedInt;
streamFormat.fIsMixable = TRUE;
break;
case AC3: streamFormat.fSampleFormat = 'AC-3';
streamFormat.fNumericRepresentation = kIOAudioStreamNumericRepresentationSignedInt;
streamFormat.fIsMixable = FALSE;
break;
case IEC1937_AC3:
streamFormat.fSampleFormat = 'IAC3';
streamFormat.fNumericRepresentation = kIOAudioStreamNumericRepresentationSignedInt;
streamFormat.fIsMixable = FALSE;
default:
FailMessage ("!!!!interface doesn't support a format that we can deal with!!!!\n", Exit);
}
streamFormat.fNumChannels = usbAudio->GetNumChannels (ourInterfaceNumber, alternateInterfaceID);
streamFormat.fBitDepth = usbAudio->GetSampleSize (ourInterfaceNumber, alternateInterfaceID);
streamFormat.fBitWidth = usbAudio->GetSubframeSize (ourInterfaceNumber, alternateInterfaceID) * 8;
streamFormat.fAlignment = kIOAudioStreamAlignmentLowByte;
streamFormat.fByteOrder = kIOAudioStreamByteOrderLittleEndian;
streamFormat.fDriverTag = (ourInterfaceNumber << 16) | alternateInterfaceID;
FailIf (FALSE == streamInterface->open (this), Exit); FailIf (kIOReturnSuccess != mainStream->setFormat (&streamFormat), Exit);
FailIf (kIOReturnSuccess != addAudioStream (mainStream), Exit);
FailIf (kUSBAudioClass != usbAudio->GetInterfaceClass (ourInterfaceNumber, alternateInterfaceID), Exit);
FailIf (kUSBAudioStreamInterfaceSubclass != usbAudio->GetInterfaceSubClass (ourInterfaceNumber, alternateInterfaceID), Exit);
GetDeviceInfo ();
usbAudioDevice->activateAudioEngine (this, FALSE, ourInterfaceNumber, alternateInterfaceID);
#if CONTINUOUS_STREAMING
if (!usbStreamRunning) {
resetStatusBuffer ();
resultCode = (startUSBStream () == kIOReturnSuccess);
} else {
resultCode = TRUE;
}
#else
resultCode = TRUE;
#endif
if (resultCode) {
usbAudioDevice->retain ();
}
if (kUSBOut == direction) {
iSubBufferMemory = NULL;
iSubEngineNotifier = addNotification (gIOPublishNotification, serviceMatching ("AppleiSubEngine"), (IOServiceNotificationHandler)&iSubEnginePublished, this);
if (NULL != iSubBufferMemory) {
iSubEngineNotifier->remove ();
iSubEngineNotifier = NULL;
}
}
Exit:
debug4IOLog("-%d = AppleUSBAudioEngine[%p]::initHardware(%p)\n", resultCode, this, provider);
return resultCode;
}
IOReturn AppleUSBAudioEngine::iSubCloseAction (OSObject *owner, void *arg1, void *arg2, void *arg3, void *arg4) {
if (NULL != arg1) {
AppleUSBAudioEngine *audioEngine = OSDynamicCast (AppleUSBAudioEngine, owner);
if (NULL != audioEngine) {
audioEngine->pauseAudioEngine ();
audioEngine->iSubEngine = NULL;
audioEngine->iSubBufferMemory = NULL;
if (NULL != audioEngine->lowFreqSamples) {
IOFree (audioEngine->lowFreqSamples, audioEngine->getSampleBufferSize () * 2);
}
if (NULL != audioEngine->highFreqSamples) {
IOFree (audioEngine->highFreqSamples, audioEngine->getSampleBufferSize () * 2);
}
audioEngine->resumeAudioEngine ();
((AppleiSubEngine *)arg1)->close (audioEngine);
}
}
return kIOReturnSuccess;
}
bool AppleUSBAudioEngine::iSubEnginePublished (AppleUSBAudioEngine * usbAudioEngineObject, void * refCon, IOService * newService) {
IOReturn result;
bool resultCode;
OSCollectionIterator * collectionIterator;
AppleUSBAudioMuteControl * ourMuteControl;
AppleUSBAudioLevelControl * masterVolumeControl;
AppleUSBAudioLevelControl * volumeControl;
AppleUSBAudioLevelControl * leftVolumeControl;
AppleUSBAudioLevelControl * rightVolumeControl;
IOCommandGate * cg;
UInt32 i;
UInt32 numControls;
debug4IOLog ("+AppleUSBAudioEngine::iSubEnginePublished (%p, %p, %p)\n", usbAudioEngineObject, (UInt32*)refCon, newService);
resultCode = false;
FailIf (NULL == usbAudioEngineObject, Exit);
FailIf (NULL == newService, Exit);
usbAudioEngineObject->iSubEngine = (AppleiSubEngine *)newService;
FailIf (NULL == usbAudioEngineObject->iSubEngine, Exit);
debugIOLog ("Looking for our volume controls to set the initial iSub volume\n");
collectionIterator = OSCollectionIterator::withCollection (usbAudioEngineObject->defaultAudioControls);
FailIf (NULL == collectionIterator, Exit);
i = 0;
numControls = usbAudioEngineObject->defaultAudioControls->getCount ();
volumeControl = NULL;
masterVolumeControl = NULL;
leftVolumeControl = NULL;
rightVolumeControl = NULL;
while (i < numControls) {
volumeControl = OSDynamicCast (AppleUSBAudioLevelControl, collectionIterator->getNextObject ());
if (NULL != volumeControl && volumeControl->getUsage () == kIOAudioControlUsageOutput) {
if (volumeControl->getChannelID () == 1) {
leftVolumeControl = volumeControl;
debugIOLog ("Got our left volume control\n");
} else if (volumeControl->getChannelID () == 2) {
rightVolumeControl = volumeControl;
debugIOLog ("Got our right volume control\n");
} else if (volumeControl->getChannelID () == 0) {
masterVolumeControl = volumeControl;
debugIOLog ("Got our master volume control\n");
}
}
i++;
}
collectionIterator->release ();
debugIOLog ("Looking for our mute control to set the initial iSub mute\n");
collectionIterator = OSCollectionIterator::withCollection (usbAudioEngineObject->defaultAudioControls);
i = 0;
ourMuteControl = NULL;
while (i < numControls && NULL == ourMuteControl) {
ourMuteControl = OSDynamicCast (AppleUSBAudioMuteControl, collectionIterator->getNextObject ());
i++;
}
collectionIterator->release ();
usbAudioEngineObject->lowFreqSamples = (float *)IOMallocAligned (round_page (usbAudioEngineObject->getSampleBufferSize () * 2), PAGE_SIZE);
FailIf (NULL == usbAudioEngineObject->lowFreqSamples, Exit);
usbAudioEngineObject->highFreqSamples = (float *)IOMallocAligned (round_page (usbAudioEngineObject->getSampleBufferSize () * 2), PAGE_SIZE);
FailIf (NULL == usbAudioEngineObject->highFreqSamples, Exit);
usbAudioEngineObject->attach (usbAudioEngineObject->iSubEngine);
cg = usbAudioEngineObject->getCommandGate ();
FailIf (NULL == cg, Exit);
result = cg->runAction (iSubOpenAction, usbAudioEngineObject);
FailIf (kIOReturnSuccess != result, Exit);
usbAudioEngineObject->iSubBufferMemory = usbAudioEngineObject->iSubEngine->GetSampleBuffer ();
if (NULL != leftVolumeControl && NULL != rightVolumeControl) {
debug3IOLog ("setting initial iSub volumes to L:%ld R:%ld\n", leftVolumeControl->getIntValue (), rightVolumeControl->getIntValue ());
leftVolumeControl->flushValue ();
rightVolumeControl->flushValue ();
} else if (NULL != masterVolumeControl) {
debug2IOLog ("setting initial iSub volume using master control to %ld\n", masterVolumeControl->getIntValue ());
masterVolumeControl->flushValue ();
}
if (NULL != ourMuteControl) {
debug2IOLog ("setting initial iSub mute state to %ld\n", ourMuteControl->getIntValue ());
ourMuteControl->flushValue ();
}
if (NULL != usbAudioEngineObject->iSubEngineNotifier) {
usbAudioEngineObject->iSubEngineNotifier->remove ();
usbAudioEngineObject->iSubEngineNotifier = NULL;
}
resultCode = true;
Exit:
debug5IOLog ("- %d = AppleUSBAudioEngine::iSubEnginePublished (%p, %p, %p)\n", resultCode, usbAudioEngineObject, (UInt32 *)refCon, newService);
return resultCode;
}
IOReturn AppleUSBAudioEngine::iSubOpenAction (OSObject *owner, void *arg1, void *arg2, void *arg3, void *arg4) {
IOReturn result;
bool resultBool;
result = kIOReturnError;
resultBool = FALSE;
if (NULL != owner && NULL != arg1) {
AppleUSBAudioEngine *audioEngine = OSDynamicCast (AppleUSBAudioEngine, owner);
if (audioEngine) {
resultBool = audioEngine->iSubEngine->open ((IOService *)arg1);
}
}
if (TRUE == resultBool) {
result = kIOReturnSuccess;
}
return result;
}
void AppleUSBAudioEngine::iSubTeardown (AppleUSBAudioEngine *usbAudioEngine, thread_call_t iSubTeardownThreadCall) {
IOCommandGate * cg;
debugIOLog ("+AppleUSBAudioEngine::iSubTeardown ()\n");
if (NULL != usbAudioEngine) {
cg = usbAudioEngine->getCommandGate ();
if (NULL != cg) {
cg->runAction (iSubCloseAction, usbAudioEngine->oldiSubEngine);
}
usbAudioEngine->detach (usbAudioEngine->oldiSubEngine);
}
if (NULL != iSubTeardownThreadCall) {
thread_call_free(iSubTeardownThreadCall);
}
debugIOLog ("-AppleUSBAudioEngine::iSubTeardown ()\n");
}
void AppleUSBAudioEngine::iSubTeardownConnection (void) {
thread_call_t iSubTeardownThreadCall;
oldiSubEngine = iSubEngine;
iSubTeardownThreadCall = thread_call_allocate ((thread_call_func_t)iSubTeardown, (thread_call_param_t)this);
if (NULL != iSubTeardownThreadCall) {
thread_call_enter1 (iSubTeardownThreadCall, iSubTeardownThreadCall);
} else {
}
return;
}
#if TIMERSTREAM
bool AppleUSBAudioEngine::isUnattachedStreamRegistered () {
debugIOLog ("+AppleUSBAudioEngine::isUnattachedStreamRegistered ()\n");
debugIOLog ("-AppleUSBAudioEngine::isUnattachedStreamRegistered ()\n");
return (streamNotifier != NULL);
}
#endif
IOReturn AppleUSBAudioEngine::performAudioEngineStart () {
IOReturn resultCode;
debug2IOLog ("+AppleUSBAudioEngine[%p]::performAudioEngineStart ()\n", this);
resultCode = kIOReturnSuccess;
filterState.xl_1 = 0.0;
filterState.xr_1 = 0.0;
filterState.xl_2 = 0.0;
filterState.xr_2 = 0.0;
filterState.yl_1 = 0.0;
filterState.yr_1 = 0.0;
filterState.yl_2 = 0.0;
filterState.yr_2 = 0.0;
if (NULL != iSubEngine) {
startiSub = TRUE;
needToSync = TRUE;
}
#if !CONTINUOUS_STREAMING
if (!usbStreamRunning) {
resultCode = startUSBStream ();
}
#endif
debug2IOLog("++AppleUSBAudioEngine[%p]::performAudioEngineStart () - started.\n", this);
debug2IOLog("-AppleUSBAudioEngine[%p]::performAudioEngineStart ()\n", this);
return resultCode;
}
IOReturn AppleUSBAudioEngine::performAudioEngineStop() {
debug2IOLog("+AppleUSBAudioEngine[%p]::performAudioEngineStop ()\n", this);
if (NULL != iSubEngine) {
iSubEngine->StopiSub ();
needToSync = TRUE;
}
#if !CONTINUOUS_STREAMING
if (usbStreamRunning) {
stopUSBStream();
}
#endif
debug2IOLog("++AppleUSBAudioEngine[%p]::performAudioEngineStop() - stopped\n", this);
debug2IOLog("-AppleUSBAudioEngine[%p]::performAudioEngineStop()\n", this);
return kIOReturnSuccess;
}
IOReturn AppleUSBAudioEngine::performFormatChange (IOAudioStream *audioStream, const IOAudioStreamFormat *newFormat, const IOAudioSampleRate *newSampleRate) {
USBAudioConfigObject * usbAudio;
IOUSBFindEndpointRequest audioIsochEndpoint;
IOReturn result;
void * sampleBuffer;
UInt32 i;
UInt32 oldBufferSize;
UInt32 totalFrames;
UInt32 numAlternateFrames;
UInt32 numAverageFrames;
UInt16 averageFrameSamples;
UInt16 averageFrameSize;
UInt16 alternateFrameSize;
UInt16 additionalSampleFrameFreq;
UInt16 oldNumFrameLists;
UInt16 oldReadFrameListSize;
UInt8 ourInterfaceNumber;
UInt8 alternateInterfaceID;
UInt8 newDirection;
debugIOLog ("+AppleUSBAudioEngine::performFormatChange\n");
result = kIOReturnError;
oldBufferSize = bufferSize;
FailIf (NULL == streamInterface, Exit);
FailIf (NULL == usbAudioDevice, Exit);
usbAudio = usbAudioDevice->GetUSBAudioConfigObject ();
FailIf (NULL == usbAudio, Exit);
FailIf (NULL == newFormat, Exit);
ourInterfaceNumber = (UInt8)(newFormat->fDriverTag >> 16);
alternateInterfaceID = (UInt8)(newFormat->fDriverTag);
if (newSampleRate) {
FailWithAction (FALSE == usbAudio->VerifySampleRateIsSupported (ourInterfaceNumber, alternateInterfaceID, newSampleRate->whole), result = kIOReturnError, Exit);
}
newDirection = usbAudio->GetIsocEndpointDirection (ourInterfaceNumber, alternateInterfaceID);
FailIf (newDirection != direction, Exit);
debug3IOLog ("++about to set: ourInterfaceNumber = %d & alternateInterfaceID = %d\n", ourInterfaceNumber, alternateInterfaceID);
if (thePipe) {
thePipe->release ();
thePipe = NULL;
}
if (theAssociatedPipe) {
theAssociatedPipe->release ();
theAssociatedPipe = NULL;
}
result = streamInterface->SetAlternateInterface (this, kRootAlternateSetting);
FailIf (kIOReturnSuccess != result, Exit);
debug2IOLog ("streamInterface->SetAlternateInterface (this, kRootAlternateSetting) = 0x%X\n", result);
result = streamInterface->SetAlternateInterface (this, alternateInterfaceID);
FailIf (kIOReturnSuccess != result, Exit);
debug2IOLog ("streamInterface->SetAlternateInterface (this, alternateInterfaceID) = 0x%X\n", result);
if (newSampleRate) {
debug2IOLog ("changing sampling rate to %d\n", newSampleRate->whole);
curSampleRate = *newSampleRate;
} else {
debug2IOLog ("keeping the existing sampling rate of %d\n", curSampleRate.whole);
}
result = SetSampleRate (usbAudio, curSampleRate.whole);
FailIf (kIOReturnSuccess != result, Exit);
result = kIOReturnError;
audioIsochEndpoint.type = kUSBIsoc;
audioIsochEndpoint.direction = direction;
audioIsochEndpoint.maxPacketSize = 0xFF; audioIsochEndpoint.interval = 0xFF;
thePipe = streamInterface->FindNextPipe (NULL, &audioIsochEndpoint);
FailIf (NULL == thePipe, Exit);
result = CheckForAssociatedEndpoint (usbAudio);
thePipe->retain ();
theMaxPacket = thePipe->GetEndpoint()->maxPacketSize;
FailIf (0 == theMaxPacket, Exit);
averageSampleRate = curSampleRate.whole; debug2IOLog ("averageSampleRate = %d\n", averageSampleRate);
CalculateSamplesPerFrame (curSampleRate.whole, &averageFrameSamples, &additionalSampleFrameFreq);
debug3IOLog ("averageFrameSamples = %d, additionalSampleFrameFreq = %d\n", averageFrameSamples, additionalSampleFrameFreq);
oldNumFrameLists = numFrameLists;
oldReadFrameListSize = readFrameListSize;
if (additionalSampleFrameFreq) {
if (kUSBIn == direction) {
numFramesPerList = additionalSampleFrameFreq;
} else {
if (newFormat->fNumChannels <= 2) {
numFramesPerList = additionalSampleFrameFreq;
} else {
numFramesPerList = additionalSampleFrameFreq / 2; }
}
}
if (additionalSampleFrameFreq) {
while (numFrameLists % additionalSampleFrameFreq != 0) {
numFrameLists++;
}
debug2IOLog ("numFramelists = %d\n", numFrameLists);
while (additionalSampleFrameFreq % numFramesPerList != 0) {
numFramesPerList++;
}
debug2IOLog ("numFramesPerList = %d\n", numFramesPerList);
}
averageFrameSize = averageFrameSamples * (newFormat->fNumChannels * (newFormat->fBitWidth / 8));
alternateFrameSize = (averageFrameSamples + 1) * (newFormat->fNumChannels * (newFormat->fBitWidth / 8));
debug3IOLog ("averageFrameSize = %d, alternateFrameSize = %d\n", averageFrameSize, alternateFrameSize);
if (additionalSampleFrameFreq) {
if (kUSBIn == direction) {
readFrameListSize = alternateFrameSize * numFramesPerList;
debug2IOLog ("readFrameListSize = %d\n", readFrameListSize);
}
debug3IOLog ("newFormat->fNumChannels = %d, averageFrameSize = %d\n", newFormat->fNumChannels, averageFrameSize);
totalFrames = numFrameLists * numFramesPerList;
numAlternateFrames = totalFrames / additionalSampleFrameFreq;
numAverageFrames = totalFrames - numAlternateFrames;
bufferSize = (averageFrameSize * numAverageFrames) + (alternateFrameSize * numAlternateFrames);
frameListSize = bufferSize / numFrameLists;
debug3IOLog ("the frameListSize is %d, the bufferSize is %d\n", frameListSize, bufferSize);
} else {
frameListSize = averageFrameSize * numFramesPerList;
bufferSize = frameListSize * numFrameLists;
readFrameListSize = frameListSize;
debug2IOLog ("frameListSize is averageFrameSize * numFramesPerList = %d\n", frameListSize);
}
if (NULL != soundBuffer) {
for (i = 0; i < oldNumFrameLists; i++) {
if (NULL != soundBuffer[i]) {
soundBuffer[i]->release ();
soundBuffer[i] = NULL;
}
}
}
if (oldNumFrameLists != numFrameLists) {
if (NULL != usbCompletion) {
IOFree (usbCompletion, oldNumFrameLists * sizeof (IOUSBIsocCompletion));
usbCompletion = NULL;
}
if (NULL != theFrames) {
IOFree (theFrames, oldNumFrameLists * numFrameListsToQueue * sizeof (IOUSBIsocFrame));
theFrames = NULL;
}
}
if (NULL == usbCompletion) {
usbCompletion = (IOUSBIsocCompletion *)IOMalloc (numFrameLists * sizeof (IOUSBIsocCompletion));
FailIf (NULL == usbCompletion, Exit);
}
if (NULL == theFrames) {
theFrames = (IOUSBIsocFrame *)IOMalloc (numFrameLists * numFrameListsToQueue * sizeof (IOUSBIsocFrame));
FailIf (NULL == theFrames, Exit);
}
if (oldBufferSize != bufferSize) {
if (NULL != soundBuffer) {
IOFree (soundBuffer, oldNumFrameLists * sizeof (IOMemoryDescriptor *));
}
soundBuffer = (IOMemoryDescriptor **)IOMalloc (numFrameLists * sizeof (IOMemoryDescriptor *));
FailIf (NULL == soundBuffer, Exit);
if (kUSBIn == direction) {
if (NULL != readBuffer) {
IOFree (readBuffer, oldNumFrameLists * oldReadFrameListSize);
}
readBuffer = IOMallocAligned (round_page (numFrameLists * readFrameListSize), PAGE_SIZE);
FailIf (NULL == readBuffer, Exit);
}
if (NULL != iSubBufferMemory) {
if (NULL != lowFreqSamples) {
IOFree (lowFreqSamples, getSampleBufferSize () * 2);
}
lowFreqSamples = (float *)IOMallocAligned (round_page (bufferSize * 2), PAGE_SIZE);
if (NULL != highFreqSamples) {
IOFree (highFreqSamples, getSampleBufferSize () * 2);
}
highFreqSamples = (float *)IOMallocAligned (round_page (bufferSize * 2), PAGE_SIZE);
}
if (NULL != getSampleBuffer ()) {
IOFree (getSampleBuffer (), getSampleBufferSize ());
}
sampleBuffer = IOMallocAligned (round_page (bufferSize), PAGE_SIZE);
FailIf (NULL == sampleBuffer, Exit);
mainStream->setSampleBuffer (sampleBuffer, bufferSize);
}
setNumSampleFramesPerBuffer (bufferSize / (newFormat->fNumChannels * (newFormat->fBitWidth / 8)));
if (kUSBIn == direction) {
setSampleOffset (frameListSize / (newFormat->fNumChannels * (newFormat->fBitWidth / 8)));
setSampleLatency (averageFrameSamples * kMinimumFrameOffset);
} else {
setSampleOffset (numFramesPerList);
setSampleLatency (averageFrameSamples * kMinimumFrameOffset);
}
debug2IOLog ("called setNumSampleFramesPerBuffer with %d\n", bufferSize / (newFormat->fNumChannels * (newFormat->fBitWidth / 8)));
debug4IOLog ("frameListSize = %d, newFormat->fNumChannels = %d, newFormat->fBitWidth %d\n", frameListSize, newFormat->fNumChannels, newFormat->fBitWidth);
debug2IOLog ("called setSampleOffset with %d\n", numFramesPerList);
result = PrepareFrameLists (numFrameLists, (newFormat->fBitWidth / 8), newFormat->fNumChannels);
FailIf (kIOReturnSuccess != result, Exit);
Exit:
debug2IOLog ("-AppleUSBAudioEngine::performFormatChange, result = %x\n", result);
return result;
}
IOReturn AppleUSBAudioEngine::PrepareFrameLists (UInt32 numFrameLists, UInt8 sampleSize, UInt8 numChannels) {
IOReturn result;
UInt32 i;
UInt32 offset;
UInt32 thisFrameListSize;
UInt16 averageFrameSamples;
UInt16 additionalSampleFrameFreq;
debug4IOLog ("+AppleUSBAudioEngine::PrepareFrameLists (%ld, %d, %d)\n", numFrameLists, sampleSize, numChannels);
result = kIOReturnError; for (i = 0; i < numFrameLists; i++) {
usbCompletion[i].target = (void *)this;
usbCompletion[i].parameter = (void *)i; }
CalculateSamplesPerFrame (curSampleRate.whole, &averageFrameSamples, &additionalSampleFrameFreq);
if (getDirection () == kIOAudioStreamDirectionOutput) {
if (NULL != theAssociatedPipe) {
sampleRateCompletion.target = (void *)this;
sampleRateCompletion.parameter = 0;
sampleRateCompletion.action = sampleRateHandler;
neededSampleRate = IOMemoryDescriptor::withAddress (&aveSampleRateBuf, 4, kIODirectionNone);
FailIf (NULL == neededSampleRate, Exit);
}
offset = 0;
if (additionalSampleFrameFreq == numFramesPerList) {
thisFrameListSize = frameListSize;
} else {
thisFrameListSize = frameListSize - (sampleSize * numChannels);
}
for (i = 0; i < numFrameLists; i++) {
usbCompletion[i].action = writeHandler;
if (additionalSampleFrameFreq) {
soundBuffer[i] = IOMemoryDescriptor::withAddress (((UInt8 *)getSampleBuffer ()) + offset, thisFrameListSize, kIODirectionNone);
FailIf (NULL == soundBuffer[i], Exit);
offset += thisFrameListSize;
if (i % (additionalSampleFrameFreq / numFramesPerList) == 0) {
thisFrameListSize = frameListSize;
} else {
thisFrameListSize = frameListSize - (sampleSize * numChannels);
}
} else {
soundBuffer[i] = IOMemoryDescriptor::withAddress (((UInt8 *)getSampleBuffer ()) + (i * frameListSize), frameListSize, kIODirectionNone);
}
}
} else if (getDirection () == kIOAudioStreamDirectionInput) {
for (i = 0; i < numFrameLists; i++) {
usbCompletion[i].action = readHandler;
soundBuffer[i] = IOMemoryDescriptor::withAddress (((UInt8 *)readBuffer) + (i * readFrameListSize), readFrameListSize, kIODirectionNone);
FailIf (NULL == soundBuffer[i], Exit);
}
}
result = kIOReturnSuccess;
Exit:
debugIOLog ("-AppleUSBAudioEngine::PrepareFrameLists ()\n");
return result;
}
IOReturn AppleUSBAudioEngine::readFrameList (UInt32 frameListNum) {
const IOAudioStreamFormat * theFormat;
UInt32 i,
firstFrame;
UInt16 averageFrameSamples;
UInt16 additionalSampleFrameFreq;
UInt16 bytesToRead;
IOReturn result;
result = kIOReturnError;
firstFrame = (frameListNum % numFrameListsToQueue) * numFramesPerList;
theFormat = mainStream->getFormat ();
CalculateSamplesPerFrame (curSampleRate.whole, &averageFrameSamples, &additionalSampleFrameFreq);
bytesPerSampleFrame = theFormat->fNumChannels * (theFormat->fBitWidth / 8);
if (0 != additionalSampleFrameFreq) {
bytesToRead = (averageFrameSamples + 1) * bytesPerSampleFrame;
} else {
bytesToRead = averageFrameSamples * bytesPerSampleFrame;
}
for (i = 0; i < numFramesPerList; i++) {
theFrames[firstFrame + i].frStatus = -1;
theFrames[firstFrame + i].frReqCount = bytesToRead;
theFrames[firstFrame + i].frActCount = 0;
}
FailIf (NULL == thePipe, Exit);
retain (); result = thePipe->Read (soundBuffer[frameListNum], theFirstFrame, numFramesPerList, &theFrames[firstFrame], &usbCompletion[frameListNum]);
if (result) debug2IOLog ("error from thePipe->Read 0x%X\n", result);
theFirstFrame += numFramesPerList;
Exit:
return result;
}
void AppleUSBAudioEngine::readHandler (AppleUSBAudioEngine * self, void * parameter, IOReturn result, IOUSBIsocFrame * pFrames) {
AbsoluteTime timestampOffset;
AbsoluteTime uptime;
#if DEBUGTIMESTAMPS
static AbsoluteTime lastTimeCalled = {0, 0};
AbsoluteTime timeAdded;
#endif
#if DEBUGTIMESTAMPS || DEBUGZEROTIME
AbsoluteTime diff;
UInt64 nanos;
#endif
UInt64 currentUSBFrame;
UInt32 frameIndex;
UInt32 frameListIndex;
UInt32 frameListToRead;
UInt32 numBytesToCopy;
UInt32 numBytesToEnd;
UInt32 numBytesCopied;
UInt8 * source;
UInt8 * dest;
Boolean haveWrapped;
frameListIndex = (UInt32)parameter;
#if DEBUGTIMESTAMPS
clock_get_uptime (&diff);
if (lastTimeCalled.hi == 0 && lastTimeCalled.lo == 0) {
lastTimeCalled.hi = self->status->fLastLoopTime.hi;
lastTimeCalled.lo = self->status->fLastLoopTime.lo;
nanoseconds_to_absolutetime ((self->numFramesPerList) * (1000 * 1000), &timeAdded);
SUB_ABSOLUTETIME (&lastTimeCalled, &timeAdded);
}
SUB_ABSOLUTETIME (&diff, &lastTimeCalled);
absolutetime_to_nanoseconds (diff, &nanos);
IOLog ("%ld\n", (UInt32)(nanos / (1000 * 1000)));
clock_get_uptime (&diff);
lastTimeCalled = diff;
#endif
if (kIOReturnSuccess != result) {
#if DEBUGLOG
IOLog ("Error 0x%X from USB read\n", result);
#endif
currentUSBFrame = self->streamInterface->GetDevice()->GetBus()->GetFrameNumber ();
FailIf (NULL == self->streamInterface, Exit);
if (self->theFirstFrame <= currentUSBFrame) {
self->theFirstFrame = currentUSBFrame + kMinimumFrameOffset;
}
}
haveWrapped = FALSE;
dest = (UInt8 *)(self->getSampleBuffer ()) + self->bufferOffset;
source = ((UInt8 *)self->readBuffer) + (frameListIndex * self->readFrameListSize);
if (self->bufferOffset == 0 && !self->startingEngine) {
haveWrapped = TRUE;
}
self->startingEngine = FALSE; for (frameIndex = 0; frameIndex < self->numFramesPerList; frameIndex++) {
if (pFrames[frameIndex].frActCount < (pFrames[frameIndex].frReqCount - self->bytesPerSampleFrame)) {
#if DEBUGLOG
IOLog ("short read packet!!! %d\n", (UInt32)(pFrames[frameIndex].frActCount));
#endif
}
numBytesToEnd = self->getSampleBufferSize () - self->bufferOffset;
if ((UInt32)(pFrames[frameIndex].frActCount) > numBytesToEnd)
numBytesToCopy = numBytesToEnd;
else
numBytesToCopy = pFrames[frameIndex].frActCount;
memcpy (dest, source, numBytesToCopy);
self->bufferOffset += numBytesToCopy;
numBytesCopied = numBytesToCopy;
if ((UInt32)(pFrames[frameIndex].frActCount) > numBytesToEnd) {
numBytesToCopy = (pFrames[frameIndex].frActCount) - numBytesToEnd;
dest = (UInt8 *)self->getSampleBuffer ();
memcpy (dest, source + numBytesCopied, numBytesToCopy);
self->bufferOffset = numBytesToCopy;
haveWrapped = TRUE;
}
if (haveWrapped) {
nanoseconds_to_absolutetime (self->numFramesPerList * 1000 * 1000, ×tampOffset);
clock_get_uptime (&uptime);
ADD_ABSOLUTETIME (&uptime, ×tampOffset);
#if DEBUGZEROTIME
diff = uptime;
SUB_ABSOLUTETIME (&diff, &self->status->fLastLoopTime);
absolutetime_to_nanoseconds (diff, &nanos);
IOLog ("delta=%ld, frameListIndex = %d\n", (UInt32)(nanos / (1000 * 1000)), frameListIndex);
#endif
self->status->fLastLoopTime.hi = uptime.hi;
self->status->fLastLoopTime.lo = uptime.lo;
++self->status->fCurrentLoopCount;
haveWrapped = FALSE;
}
dest += numBytesToCopy;
if (self->bufferOffset >= self->getSampleBufferSize ()) {
haveWrapped = TRUE;
if (self->bufferOffset > self->getSampleBufferSize ()) {
#if DEBUGLOG
IOLog ("readjusting bufferOffset, shouldn't be here.\n");
#endif
}
self->bufferOffset -= self->getSampleBufferSize ();
}
source += pFrames[frameIndex].frReqCount;
}
if (self->shouldStop > 0) {
#if DEBUGLOG
IOLog("++AppleUSBAudioEngine::readHandler() - stopping: %d\n", self->shouldStop);
#endif
self->shouldStop++;
if (self->shouldStop > self->numFrameListsToQueue) {
FailIf (NULL == self->signal, Exit);
self->signal->signal (kIOReturnSuccess, FALSE);
}
} else {
if (((UInt32)self->numFrameLists - 1) == self->currentFrameList) {
self->currentFrameList = 0;
} else {
self->currentFrameList++;
}
frameListToRead = self->currentFrameList + self->numFrameListsToQueue - 1;
if (frameListToRead >= self->numFrameLists) {
frameListToRead -= self->numFrameLists;
}
self->readFrameList (frameListToRead);
}
Exit:
self->release (); return;
}
#if TIMERSTREAM
void AppleUSBAudioEngine::registerUnattachedStream () {
OSDictionary * matchingDict;
debugIOLog ("+AppleUSBAudioEngine::registerUnattachedStream()\n");
if (!streamNotifier) {
matchingDict = serviceMatching ("IOUSBInterface");
matchingDict->setObject (kUSBVendorName, interfaceVendor);
matchingDict->setObject (kUSBProductName, interfaceProduct);
matchingDict->setObject (kUSBDeviceReleaseNumber, deviceReleaseNumber);
matchingDict->setObject (kUSBConfigurationValue, configurationValue);
matchingDict->setObject (kUSBInterfaceNumber, interfaceNumber);
streamNotifier = addNotification (gIOPublishNotification,
matchingDict,
(IOServiceNotificationHandler)&interfacePublished,
this,
NULL,
1000);
} else {
debug2IOLog ("++AppleUSBAudioEngine[%p]::registerUnattachedStream () - error - already have a stream notifier - inconsistent state.\n", this);
}
debugIOLog ("-AppleUSBAudioEngine::registerUnattachedStream ()\n");
}
bool AppleUSBAudioEngine::reinitWithInterface (IOUSBInterface *interface) {
IOUSBFindEndpointRequest audioIsochEndpoint;
bool result;
debugIOLog ("+AppleUSBAudioEngine::reinitWithInterface ()\n");
result = FALSE;
FailIf (NULL == interface, Exit);
FailIf (interface == previousInterface, Exit);
FailIf (kIOReturnSuccess != interface->open (this), Exit);
interface->SetAlternateInterface (this, kRootAlternateSetting);
interface->SetAlternateInterface (this, alternateInterfaceID);
streamInterface = interface;
previousInterface = interface;
this->attach (streamInterface);
audioIsochEndpoint.type = kUSBIsoc;
if (getDirection () == kIOAudioStreamDirectionOutput) {
audioIsochEndpoint.direction = kUSBOut;
} else { audioIsochEndpoint.direction = kUSBIn;
}
audioIsochEndpoint.maxPacketSize = 0xFF; audioIsochEndpoint.interval = 0xFF;
thePipe = streamInterface->FindNextPipe (NULL, &audioIsochEndpoint);
FailIf (NULL == thePipe, Exit);
thePipe->retain ();
FailIf (usbStreamRunning, Exit);
stopTimerStream ();
if (startUSBStream () == kIOReturnSuccess) {
debugIOLog ("++AppleUSBAudioEngine::reinitWithInterface () - successfully re-attached to interface.\n");
result = TRUE;
}
Exit:
debugIOLog ("-AppleUSBAudioEngine::reinitWithInterface ()\n");
return result;
}
IOReturn AppleUSBAudioEngine::reinitWithInterfaceAction (OSObject *owner, void *arg1, void *arg2, void *arg3, void *arg4) {
IOReturn result = kIOReturnBadArgument;
if (owner && arg1 && arg2) {
AppleUSBAudioEngine *audioEngine = OSDynamicCast (AppleUSBAudioEngine, owner);
IOUSBInterface *interface = OSDynamicCast (IOUSBInterface, (OSObject *)arg1);
if (audioEngine) {
*(bool *)arg2 = audioEngine->reinitWithInterface (interface);
result = kIOReturnSuccess;
}
}
return result;
}
#endif
void AppleUSBAudioEngine::resetClipPosition (IOAudioStream *audioStream, UInt32 clipSampleFrame) {
iSubBufferOffset -= (previousClippedToFrame - clipSampleFrame) * 2; previousClippedToFrame = clipSampleFrame;
#if DEBUGLOG
IOLog ("resetClipPosition, iSubBufferOffset=%ld, previousClippedToFrame=%ld\n", iSubBufferOffset, previousClippedToFrame);
#endif
}
#if RETRY_WRITES
void AppleUSBAudioEngine::retryWriteFrameList (void *arg) {
FrameListWriteInfo * info;
debug2IOLog ("+AppleUSBAudioEngine::retryWriteFrameList (%p)\n", (UInt32*)arg);
info = (FrameListWriteInfo *)arg;
if (info->audioEngine) {
info->audioEngine->writeFrameList (info->frameListNum);
}
debug2IOLog ("-AppleUSBAudioEngine::retryWriteFrameList (%p)\n", (UInt32*)arg);
}
#endif
void AppleUSBAudioEngine::sampleRateHandler (void * target, void * parameter, IOReturn result, IOUSBIsocFrame * pFrames) {
AppleUSBAudioEngine * self;
IOFixed sampleRate;
UInt16 fixed;
IOFixed fract;
UInt32 oldSampleRate;
self = (AppleUSBAudioEngine *)target;
sampleRate = USBToHostLong (self->aveSampleRateBuf);
oldSampleRate = self->averageSampleRate;
sampleRate = sampleRate << 2;
fixed = sampleRate >> 16;
self->averageSampleRate = fixed * 1000;
fract = IOFixedMultiply (sampleRate & 0x0000FFFF, 1000 << 16);
self->averageSampleRate += (fract & 0xFFFF0000) >> 16;
if (self->averageSampleRate != oldSampleRate) {
self->sampleNum = 0; debugIOLog ("sample rate changed!!!!!\n");
debug2IOLog ("requestedFrameRate = %d\n", self->averageSampleRate);
}
self->theSampleRateFrame.frStatus = -1;
self->theSampleRateFrame.frReqCount = 3;
self->theSampleRateFrame.frActCount = 0;
if (0 == self->shouldStop) {
self->nextSynchReadFrame += (1 << (10 - self->refreshInterval));
self->retain (); result = self->theAssociatedPipe->Read (self->neededSampleRate, self->nextSynchReadFrame, 1, &self->theSampleRateFrame, &self->sampleRateCompletion);
}
self->release (); return;
}
IOReturn AppleUSBAudioEngine::SetSampleRate (USBAudioConfigObject *usbAudio, UInt32 sampleRate) {
IOUSBDevRequest devReq;
UInt32 theSampleRate;
IOReturn result;
result = kIOReturnError;
if (usbAudio->IsocEndpointHasSampleFreqControl (ourInterfaceNumber, alternateInterfaceID)) {
devReq.bmRequestType = USBmakebmRequestType (kUSBOut, kUSBClass, kUSBEndpoint);
devReq.bRequest = SET_CUR;
devReq.wValue = (SAMPLING_FREQ_CONTROL << 8) | 0;
devReq.wIndex = usbAudio->GetIsocEndpointAddress (ourInterfaceNumber, alternateInterfaceID, direction);
devReq.wLength = 3;
theSampleRate = OSSwapHostToLittleInt32 (sampleRate);
devReq.pData = &theSampleRate;
debug5IOLog ("Set freq control interface %d, alt interface %d, endpoint address 0x%X, sample rate (little endian) 0x%X\n", ourInterfaceNumber, alternateInterfaceID, devReq.wIndex, theSampleRate);
result = streamInterface->GetDevice()->DeviceRequest (&devReq);
FailIf (kIOReturnSuccess != result, Exit);
} else {
result = kIOReturnSuccess;
debugIOLog ("Device doesn't have a sample freq control!\n");
}
Exit:
return result;
}
#if TIMERSTREAM
void AppleUSBAudioEngine::startTimerStream() {
debug2IOLog("+AppleUSBAudioEngine[%p]::startTimerStream()\n", this);
if (!timerStreamThread) {
if (getDirection () == kIOAudioStreamDirectionInput) {
FailIf (NULL == mainStream, Exit);
mainStream->clearSampleBuffer ();
}
timerStreamThread = IOCreateThread (timerStreamMain, this);
}
Exit:
debug2IOLog("-AppleUSBAudioEngine[%p]::startTimerStream()\n", this);
}
bool AppleUSBAudioEngine::startTimerStreamIfNecessary() {
bool timerStreamStarted;
timerStreamStarted = FALSE;
if (usbAudioDevice && !usbAudioDevice->allStreamsStopped ()) {
timerStreamStarted = TRUE;
debug2IOLog("++AppleUSBAudioEngine[%p]::startTimerStreamIfNecessary () - not all streams are stopped and this is the only audio device.\n", this);
if (usbStreamRunning) {
stopUSBStream ();
startTimerStream ();
}
}
return timerStreamStarted;
}
IOReturn AppleUSBAudioEngine::startTimerStreamIfNecessaryAction(OSObject *owner, void *arg1, void *arg2, void *arg3, void *arg4) {
IOReturn result;
result = kIOReturnBadArgument;
if (owner && arg1) {
AppleUSBAudioEngine *audioEngine = OSDynamicCast(AppleUSBAudioEngine, owner);
if (audioEngine) {
*(bool *)arg1 = audioEngine->startTimerStreamIfNecessary();
result = kIOReturnSuccess;
}
}
return result;
}
#endif
IOReturn AppleUSBAudioEngine::startUSBStream () {
IOReturn resultCode;
AbsoluteTime uptime;
AbsoluteTime initialTimestampOffset;
UInt32 frameListNum;
UInt32 numQueued;
UInt32 numRetries;
debug2IOLog ("+AppleUSBAudioEngine[%p]::startUSBStream ()\n", this);
resultCode = kIOReturnError;
numQueued = 0;
if (status->fLastLoopTime.hi == 0 && status->fLastLoopTime.lo == 0) {
if (getDirection() == kIOAudioStreamDirectionOutput) {
nanoseconds_to_absolutetime ((kMinimumFrameOffset) * 1000 * 1000, &initialTimestampOffset);
} else if (getDirection() == kIOAudioStreamDirectionInput) {
nanoseconds_to_absolutetime ((kMinimumFrameOffset) * 1000 * 1000, &initialTimestampOffset);
}
clock_get_uptime (&uptime);
ADD_ABSOLUTETIME (&uptime, &initialTimestampOffset);
status->fLastLoopTime.hi = uptime.hi;
status->fLastLoopTime.lo = uptime.lo;
currentFrameList = 0;
bufferOffset = 0;
previous = 0;
startingEngine = TRUE;
}
shouldStop = 0;
FailIf ((numFrameLists < numFrameListsToQueue), Exit);
FailIf (NULL == streamInterface, Exit);
theFirstFrame = streamInterface->GetDevice()->GetBus()->GetFrameNumber() + kMinimumFrameOffset;
numRetries = 0;
if (NULL != theAssociatedPipe) {
nextSynchReadFrame = theFirstFrame;
retain (); (void)theAssociatedPipe->Read (neededSampleRate, nextSynchReadFrame, 1, &theSampleRateFrame, &sampleRateCompletion);
}
for (frameListNum = currentFrameList; (frameListNum < numFrameLists) && (numQueued < numFrameListsToQueue); frameListNum++) {
while ((getDirection () == kIOAudioStreamDirectionOutput ? (writeFrameList (frameListNum) != kIOReturnSuccess) : (readFrameList (frameListNum) != kIOReturnSuccess)) && (numRetries < MAX_WRITE_RETRIES)) {
numRetries++;
}
FailIf ((numRetries == MAX_WRITE_RETRIES), Exit);
numQueued++;
}
numRetries = 0;
for (frameListNum = 0; numQueued < numFrameListsToQueue; frameListNum++) {
while ((getDirection () == kIOAudioStreamDirectionOutput ? (writeFrameList (frameListNum) != kIOReturnSuccess) : (readFrameList (frameListNum) != kIOReturnSuccess)) && (numRetries < MAX_WRITE_RETRIES)) {
numRetries++;
}
FailIf ((numRetries == MAX_WRITE_RETRIES), Exit);
numQueued++;
}
usbStreamRunning = TRUE;
resultCode = kIOReturnSuccess;
Exit:
debug2IOLog("-AppleUSBAudioEngine[%p]::startUSBStream ()\n", this);
return resultCode;
}
#if TIMERSTREAM
void AppleUSBAudioEngine::stopTimerStream() {
debug2IOLog("+AppleUSBAudioEngine[%p]::stopTimerStream()\n", this);
if (timerStreamThread) {
timerStreamThread = NULL;
signal->wait(FALSE);
signal->reinit();
}
debug2IOLog("-AppleUSBAudioEngine[%p]::stopTimerStream()\n", this);
}
#endif
IOReturn AppleUSBAudioEngine::stopUSBStream () {
debug2IOLog ("+AppleUSBAudioEngine[%p]::stopUSBStream ()\n", this);
if (streamInterface) { shouldStop = 1;
}
signal->wait (FALSE);
signal->reinit ();
usbStreamRunning = FALSE;
debug2IOLog ("-AppleUSBAudioEngine[%p]::stopUSBStream ()\n", this);
return kIOReturnSuccess;
}
#if TIMERSTREAM
void AppleUSBAudioEngine::timerStreamMain(void *audioEngine) {
AppleUSBAudioEngine * self;
debugIOLog("+AppleUSBAudioEngine::timerStreamMain ()\n");
self = (AppleUSBAudioEngine *)audioEngine;
while (self->timerStreamThread) {
IOSleep(self->numFramesPerList);
if (self->timerStreamThread) {
if (((UInt32)self->numFrameLists - 1) == self->currentFrameList) {
self->takeTimeStamp ();
self->currentFrameList = 0;
} else {
self->currentFrameList++;
}
}
}
self->signal->signal(kIOReturnSuccess, FALSE);
IOExitThread();
debugIOLog("-AppleUSBAudioEngine::timerStreamMain ()\n");
}
void AppleUSBAudioEngine::unregisterUnattachedStream() {
debugIOLog ("+AppleUSBAudioEngine::unregisterUnattachedStream ()\n");
if (streamNotifier) {
streamNotifier->remove ();
streamNotifier = 0;
} else {
debug2IOLog ("++AppleUSBAudioEngine[%p]::unregisterUnattachedStream () - error - don't have a stream notifier - inconsistent state.\n", this);
}
debugIOLog ("-AppleUSBAudioEngine::unregisterUnattachedStream ()\n");
}
#endif
IOReturn AppleUSBAudioEngine::writeFrameList (UInt32 frameListNum) {
const IOAudioStreamFormat * theFormat;
UInt32 i,
firstFrame;
#if FIXEDSIZEPACKETS || DEBUGLOG
UInt16 averageFrameSamples;
UInt16 averageFrameSize;
UInt16 alternateFrameSize;
UInt16 additionalSampleFrameFreq;
#endif
IOReturn result;
#if RETRY_WRITES
AbsoluteTime uptime;
UInt64 nanos;
#endif
#if !FIXEDSIZEPACKETS
UInt32 sampleRate;
UInt32 bytesPerSample;
UInt32 bytesThisFrameList;
IOFixed fixedSampleRate;
#endif
result = kIOReturnError;
#if RETRY_WRITES
if (retrySync) { FailIf (NULL == pendingFrameListCall, Exit);
FailIf (NULL == pendingFrameListWriteInfo, Exit);
if (pendingFrameListWriteInfo->frameListNum != frameListNum) { retrySync->wait (); retrySync = 0;
thread_call_free (pendingFrameListCall); pendingFrameListCall = NULL;
IOFree (pendingFrameListWriteInfo, sizeof (FrameListWriteInfo));
pendingFrameListWriteInfo = NULL;
} else { debug4IOLog ("++AppleUSBAudioEngine[%p]::writeFrameList (%d) - retry %d\n", this, frameListNum, ++pendingFrameListWriteInfo->retryCount);
}
}
#endif
firstFrame = (frameListNum % numFrameListsToQueue) * numFramesPerList;
theFormat = mainStream->getFormat ();
#if FIXEDSIZEPACKETS || DEBUGLOG
CalculateSamplesPerFrame (curSampleRate.whole, &averageFrameSamples, &additionalSampleFrameFreq);
averageFrameSize = averageFrameSamples * (theFormat->fNumChannels * (theFormat->fBitWidth / 8));
#endif
#if FIXEDSIZEPACKETS
alternateFrameSize = (averageFrameSamples + 1) * (theFormat->fNumChannels * (theFormat->fBitWidth / 8));
if (additionalSampleFrameFreq) {
if (additionalSampleFrameFreq == numFramesPerList) {
for (i = 0; i < numFramesPerList; i++) {
theFrames[firstFrame + i].frStatus = -1;
if ((i % additionalSampleFrameFreq) == (UInt16)(additionalSampleFrameFreq - 1)) {
theFrames[firstFrame + i].frReqCount = alternateFrameSize;
} else {
theFrames[firstFrame + i].frReqCount = averageFrameSize;
}
}
} else {
for (i = 0; i < numFramesPerList; i++) {
if (((i + previous++) % additionalSampleFrameFreq) == (UInt16)(additionalSampleFrameFreq - 1)) {
theFrames[firstFrame + i].frReqCount = alternateFrameSize;
} else {
theFrames[firstFrame + i].frReqCount = averageFrameSize;
}
if (previous == additionalSampleFrameFreq) {
previous = 0;
}
}
theFrames[firstFrame + i].frActCount = 0;
}
} else {
for (i = 0; i < numFramesPerList; i++) {
theFrames[firstFrame + i].frStatus = -1;
theFrames[firstFrame + i].frReqCount = averageFrameSize;
theFrames[firstFrame + i].frActCount = 0;
}
}
#else
sampleRate = averageSampleRate;
bytesPerSample = theFormat->fNumChannels * (theFormat->fBitWidth / 8);
fixedSampleRate = IOUFixedDivide (sampleRate << 16, 1000 << 16); if (1000 == sampleNum || 0 == sampleNum) {
samplesThisFrame = fixedSampleRate >> 16;
sampleNum = 2;
sum = samplesThisFrame;
}
for (i = 0; i < numFramesPerList; i++) {
theFrames[firstFrame + i].frStatus = -1;
theFrames[firstFrame + i].frActCount = 0;
theFrames[firstFrame + i].frReqCount = samplesThisFrame * bytesPerSample;
bytesThisFrameList += theFrames[firstFrame + i].frReqCount;
bytesQueued += bytesThisFrameList;
samplesThisFrame = (IOUFixedMultiply (fixedSampleRate, sampleNum << 16) >> 16) - sum;
#if DEBUGLOG
if (samplesThisFrame < averageFrameSamples || samplesThisFrame > (averageFrameSamples + 1)) {
IOLog ("error !!! samplesThisFrame = %d\n", samplesThisFrame);
IOLog ("sum = %d\n", sum);
IOLog ("sampleNum = %d\n", sampleNum);
}
#endif
sum += samplesThisFrame;
sampleNum++;
if (1000 == sampleNum) {
samplesThisFrame = fixedSampleRate >> 16;
sampleNum = 2;
sum = samplesThisFrame;
}
}
#endif
FailIf (NULL == thePipe, Exit);
retain (); result = thePipe->Write (soundBuffer[frameListNum], theFirstFrame, numFramesPerList, &theFrames[firstFrame], &usbCompletion[frameListNum]);
if (result != kIOReturnSuccess) {
debug6IOLog ("++AppleUSBAudioEngine[%p]::writeFrameList(%d) - error writing to pipe at frame %lu - current = %lu: 0x%x\n", this, frameListNum, (UInt32)theFirstFrame, (UInt32)streamInterface->GetDevice()->GetBus()->GetFrameNumber(), result);
#if RETRY_WRITES
if (!retrySync) { FailIf (pendingFrameListWriteInfo, Exit);
FailIf (pendingFrameListCall, Exit);
retrySync = IOSyncer::create (TRUE);
if (!retrySync) {
return kIOReturnNoMemory;
}
pendingFrameListWriteInfo = (FrameListWriteInfo *)IOMalloc (sizeof (FrameListWriteInfo));
if (!pendingFrameListWriteInfo) {
return kIOReturnNoMemory;
}
pendingFrameListWriteInfo->audioEngine = this;
pendingFrameListWriteInfo->frameListNum = frameListNum;
pendingFrameListWriteInfo->retryCount = 0;
pendingFrameListCall = thread_call_allocate ((thread_call_func_t)retryWriteFrameList, (thread_call_param_t)pendingFrameListWriteInfo);
if (!pendingFrameListCall) {
return kIOReturnNoMemory;
}
} else {
FailIf (NULL == pendingFrameListWriteInfo, Exit);
FailIf (NULL == pendingFrameListCall, Exit);
FailIf (pendingFrameListWriteInfo->frameListNum != frameListNum, Exit);
}
clock_get_uptime (&uptime);
absolutetime_to_nanoseconds (uptime, &nanos);
nanos += 1000000; nanoseconds_to_absolutetime (nanos, &uptime);
thread_call_enter_delayed (pendingFrameListCall, uptime);
#endif
} else {
theFirstFrame += numFramesPerList;
#if RETRY_WRITES
if (retrySync) {
retrySync->signal ();
debug3IOLog ("++AppleUSBAudioEngine[%p]::writeFrameList (%d) - retry successful.\n", this, frameListNum);
}
#endif
}
Exit:
return result;
}
void AppleUSBAudioEngine::writeHandler (AppleUSBAudioEngine * self, void * parameter, IOReturn result, IOUSBIsocFrame * pFrames) {
UInt32 frameListToWrite;
UInt64 currentUSBFrame;
#if DEBUGTIMESTAMPS
static AbsoluteTime lastTimeCalled = {0, 0};
AbsoluteTime timeAdded;
#endif
#if DEBUGTIMESTAMPS || DEBUGZEROTIME
AbsoluteTime uptime;
AbsoluteTime diff;
UInt64 nanos;
#endif
#if DEBUGLOG
UInt64 USBFrameNumber;
UInt32 i;
#endif
#if DEBUGTIMESTAMPS
clock_get_uptime (&diff);
if (lastTimeCalled.hi == 0 && lastTimeCalled.lo == 0) {
lastTimeCalled.hi = self->status->fLastLoopTime.hi;
lastTimeCalled.lo = self->status->fLastLoopTime.lo;
nanoseconds_to_absolutetime ((self->numFramesPerList) * (1000 * 1000), &timeAdded);
SUB_ABSOLUTETIME (&lastTimeCalled, &timeAdded);
}
SUB_ABSOLUTETIME (&diff, &lastTimeCalled);
absolutetime_to_nanoseconds (diff, &nanos);
IOLog ("%ld\n", (UInt32)(nanos / (1000 * 1000)));
clock_get_uptime (&diff);
lastTimeCalled = diff;
#endif
if (result != kIOReturnSuccess) {
#if DEBUGLOG
USBFrameNumber = self->streamInterface->GetDevice()->GetBus()->GetFrameNumber ();
IOLog ("++AppleUSBAudioEngine[%p]::writeHandler () - error 0x%x on USB frame 0x%lx%lx\n", self, result, (UInt32)(USBFrameNumber >> 32), (UInt32)USBFrameNumber);
IOLog ("current frame list = %d\n", self->currentFrameList);
for (i = 0; i < self->numFramesPerList; i++) {
if (kIOReturnSuccess != pFrames->frStatus) {
IOLog ("fr %d: 0x%lx ", i, pFrames->frStatus);
}
}
IOLog ("\n");
#endif
currentUSBFrame = self->streamInterface->GetDevice()->GetBus()->GetFrameNumber ();
switch (result) {
case kIOReturnOverrun:
FailIf (NULL == self->streamInterface, Exit);
if (self->theFirstFrame <= currentUSBFrame) {
self->theFirstFrame = currentUSBFrame + kMinimumFrameOffset;
}
break;
default:
;
}
}
if (((UInt32)self->numFrameLists - 1) == self->currentFrameList) {
#if DEBUGZEROTIME
clock_get_uptime (&uptime);
diff = uptime;
SUB_ABSOLUTETIME (&diff, &self->status->fLastLoopTime);
absolutetime_to_nanoseconds (diff, &nanos);
IOLog ("delta=%ld\n", (UInt32)(nanos / (1000 * 1000)));
#endif
self->takeTimeStamp ();
self->currentFrameList = 0;
} else {
self->currentFrameList++;
}
if (self->shouldStop > 0) {
debug2IOLog ("++AppleUSBAudioEngine::writeHandler() - stopping: %d\n", self->shouldStop);
self->shouldStop++;
if (self->shouldStop > self->numFrameListsToQueue) {
FailIf (NULL == self->signal, Exit);
self->signal->signal (kIOReturnSuccess, FALSE);
}
} else {
frameListToWrite = self->currentFrameList + self->numFrameListsToQueue - 1;
if (frameListToWrite >= self->numFrameLists) {
frameListToWrite -= self->numFrameLists;
}
self->writeFrameList (frameListToWrite);
}
Exit:
self->release (); return;
}
Generated by GNU enscript 1.6.4.