[plain text]
#define DEBUGZEROTIME FALSE
#include "AppleUSBAudioCommon.h"
#include "AppleUSBAudioDevice.h"
#include "AppleUSBAudioLevelControl.h"
#include "AppleUSBAudioMuteControl.h"
#include "AppleUSBAudioClip.h"
#include "AppleiSubEngine.h"
#include "AppleUSBAudioEngine.h"
#include <IOKit/IOLib.h>
#include <IOKit/IOSyncer.h>
#include <IOKit/IOService.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);
if (neededSampleRate) {
neededSampleRate->release ();
neededSampleRate = NULL;
}
if (aveSampleRateBuf) {
IOFree (aveSampleRateBuf, 4);
aveSampleRateBuf = NULL;
}
if (signal) {
signal->release ();
}
if (theStartBufferDescriptor) {
theStartBufferDescriptor->release ();
theStartBufferDescriptor = NULL;
}
if (theStartBuffer) {
IOFree (theStartBuffer, theStartBufferSize);
theStartBuffer = NULL;
}
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, readUSBFrameListSize * numUSBFrameLists);
readBuffer = NULL;
}
if (NULL != soundBufferDescriptors) {
for (i = 0; i < numUSBFrameLists; i++) {
if (NULL != soundBufferDescriptors[i]) {
soundBufferDescriptors[i]->release ();
soundBufferDescriptors[i] = NULL;
}
}
IOFree (soundBufferDescriptors, numUSBFrameLists * sizeof (IOMemoryDescriptor *));
soundBufferDescriptors = NULL;
}
if (NULL != theUSBIsocFrames) {
#if NEWUSB
IOFree (theUSBIsocFrames, numUSBFrameLists * numUSBFramesPerList * sizeof (IOUSBLowLatencyIsocFrame));
#else
IOFree (theUSBIsocFrames, numUSBFrameLists * numUSBFramesPerList * sizeof (IOUSBIsocFrame));
#endif
theUSBIsocFrames = NULL;
}
if (NULL != usbCompletion) {
#if NEWUSB
IOFree (usbCompletion, numUSBFrameLists * sizeof (IOUSBLowLatencyIsocCompletion));
#else
IOFree (usbCompletion, numUSBFrameLists * sizeof (IOUSBIsocCompletion));
#endif
usbCompletion = NULL;
}
if (NULL != getSampleBuffer ()) {
IOFree (getSampleBuffer (), getSampleBufferSize ());
}
if (NULL != lowFreqSamples) {
IOFree (lowFreqSamples, getSampleBufferSize () * 2);
}
if (NULL != highFreqSamples) {
IOFree (highFreqSamples, getSampleBufferSize () * 2);
}
if (NULL != iSubEngineNotifier) {
iSubEngineNotifier->remove ();
iSubEngineNotifier = NULL;
}
if (NULL != iSubAttach) {
iSubAttach->release ();
iSubAttach = NULL;
}
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;
srcPhase = 1.0; srcState = 0.0; justResetClipPosition = FALSE;
Exit:
debug2IOLog("-AppleUSBAudioEngine[%p]::init ()\n", this);
return result;
}
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;
}
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) {
debug3IOLog("+AppleUSBAudioEngine[%p]::stop (%p)\n", this, provider);
if (NULL != iSubEngineNotifier) {
iSubEngineNotifier->remove ();
iSubEngineNotifier = NULL;
}
if (NULL != iSubEngine) {
iSubTeardownConnection ();
}
if (usbAudioDevice) {
usbAudioDevice->release ();
usbAudioDevice = 0;
}
if (thePipe) {
thePipe->release ();
thePipe = NULL;
}
if (theAssociatedPipe) {
theAssociatedPipe->release ();
theAssociatedPipe = NULL;
}
if (streamInterface) {
streamInterface->close (this);
streamInterface = NULL;
}
super::stop (provider);
debug4IOLog ("-AppleUSBAudioEngine[%p]::stop (%p) - rc=%ld\n", this, provider, getRetainCount());
}
bool AppleUSBAudioEngine::terminate (IOOptionBits options) {
bool shouldTerminate;
bool result;
result = TRUE;
shouldTerminate = TRUE;
debug2IOLog ("+AppleUSBAudioEngine[%p]::terminate ()\n", this);
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;
IOAudioStreamFormatExtension streamFormatExtension;
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);
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;
streamFormatExtension.fVersion = kFormatExtensionCurrentVersion;
streamFormatExtension.fFlags = 0;
streamFormatExtension.fFramesPerPacket = 1;
streamFormatExtension.fBytesPerPacket = usbAudio->GetNumChannels (ourInterfaceNumber, altInterfaceIndx) * usbAudio->GetSubframeSize (ourInterfaceNumber, altInterfaceIndx);
switch (usbAudio->GetFormat (ourInterfaceNumber, altInterfaceIndx)) {
case PCM:
streamFormat.fSampleFormat = kIOAudioStreamSampleFormatLinearPCM;
streamFormat.fNumericRepresentation = kIOAudioStreamNumericRepresentationSignedInt;
streamFormat.fIsMixable = TRUE;
break;
case AC3: debugIOLog ("variable bit rate AC-3 audio format type!\n");
streamFormat.fSampleFormat = kIOAudioStreamSampleFormatAC3;
streamFormat.fIsMixable = FALSE;
streamFormat.fNumChannels = 6;
streamFormat.fNumericRepresentation = kIOAudioStreamNumericRepresentationSignedInt;
streamFormat.fBitDepth = 16;
streamFormat.fBitWidth = 16;
streamFormat.fByteOrder = kIOAudioStreamByteOrderBigEndian;
streamFormatExtension.fFlags = USBToHostLong (usbAudio->GetAC3BSID (ourInterfaceNumber, altInterfaceIndx));
streamFormatExtension.fFramesPerPacket = 1536;
streamFormatExtension.fBytesPerPacket = streamFormatExtension.fFramesPerPacket * streamFormat.fNumChannels * usbAudio->GetSubframeSize (ourInterfaceNumber, altInterfaceIndx);
break;
case IEC1937_AC3:
debugIOLog ("IEC1937 AC-3 audio format type!\n");
streamFormat.fSampleFormat = kIOAudioStreamSampleFormat1937AC3;
streamFormat.fNumericRepresentation = kIOAudioStreamNumericRepresentationSignedInt;
streamFormat.fIsMixable = FALSE;
streamFormatExtension.fFramesPerPacket = 1536;
streamFormatExtension.fBytesPerPacket = streamFormatExtension.fFramesPerPacket * streamFormat.fNumChannels * usbAudio->GetSubframeSize (ourInterfaceNumber, altInterfaceIndx);
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; }
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, &streamFormatExtension, &lowSampleRate, &lowSampleRate);
if (kIOAudioStreamSampleFormatLinearPCM == streamFormat.fSampleFormat) {
streamFormat.fIsMixable = FALSE;
mainStream->addAvailableFormat (&streamFormat, &streamFormatExtension, &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, &streamFormatExtension, &lowSampleRate, &highSampleRate);
if (kIOAudioStreamSampleFormatLinearPCM == streamFormat.fSampleFormat) {
streamFormat.fIsMixable = FALSE;
mainStream->addAvailableFormat (&streamFormat, &streamFormatExtension, &lowSampleRate, &lowSampleRate);
}
}
}
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;
}
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 << refreshInterval; if (framesUntilRefresh < numUSBFramesPerList) {
if (NULL != theUSBIsocFrames) {
IOFree (theUSBIsocFrames, numUSBFrameLists * numUSBFramesPerList * sizeof (IOUSBLowLatencyIsocFrame));
theUSBIsocFrames = NULL;
}
numUSBFramesPerList = framesUntilRefresh; #if NEWUSB
theUSBIsocFrames = (IOUSBLowLatencyIsocFrame *)IOMalloc (numUSBFrameLists * numUSBFramesPerList * sizeof (IOUSBLowLatencyIsocFrame));
#else
theUSBIsocFrames = (IOUSBIsocFrame *)IOMalloc (numUSBFrameLists * numUSBFramesPerList * sizeof (IOUSBIsocFrame));
#endif
}
associatedEndpoint.type = kUSBIsoc;
associatedEndpoint.direction = direction == kUSBIn ? kUSBOut : kUSBIn; associatedEndpoint.maxPacketSize = 3; associatedEndpoint.interval = 0xFF; theAssociatedPipe = streamInterface->FindNextPipe (NULL, &associatedEndpoint);
FailWithAction (NULL == theAssociatedPipe, result = kIOReturnError, Exit);
if (NULL == neededSampleRate) {
aveSampleRateBuf = (UInt32 *)IOMalloc (sizeof (UInt32));
FailIf (NULL == aveSampleRateBuf, Exit);
bzero (aveSampleRateBuf, 4);
neededSampleRate = IOMemoryDescriptor::withAddress (aveSampleRateBuf, 4, kIODirectionIn);
FailIf (NULL == neededSampleRate, Exit);
}
theSampleRateFrame.frStatus = -1;
theSampleRateFrame.frReqCount = 3;
theSampleRateFrame.frActCount = 0;
sampleRateCompletion.target = (void *)this;
sampleRateCompletion.action = sampleRateHandler;
sampleRateCompletion.parameter = 0;
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) {
UInt64 curUSBFrameNumber;
UInt64 framesLeftInQueue;
void * iSubBuffer = NULL;
UInt32 iSubBufferLen = 0;
UInt32 sampleRate;
SInt32 offsetDelta;
SInt32 safetyOffset;
IOReturn result;
iSubAudioFormatType iSubFormat;
result = kIOReturnError;
if (0 == shouldStop && TRUE != inCompletion) {
curUSBFrameNumber = streamInterface->GetDevice()->GetBus()->GetFrameNumber ();
framesLeftInQueue = usbFrameToQueueAt - curUSBFrameNumber;
if (framesLeftInQueue < (numUSBFramesPerList * (numUSBFrameListsToQueue / 2)) / 2) {
#ifdef DEBUGLOG
IOLog ("queue a write from clipOutputSamples: framesLeftInQueue = %ld\n", (UInt32)framesLeftInQueue);
#endif
writeHandler (this, usbCompletion[currentFrameList].parameter, kIOReturnSuccess, &theUSBIsocFrames[currentFrameList * numUSBFramesPerList]);
}
}
#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 (NULL != iSubBufferMemory && NULL != iSubEngine) {
iSubBufferLen = iSubBufferMemory->getLength ();
iSubBuffer = (void*)iSubBufferMemory->getVirtualSegment (0, &iSubBufferLen);
iSubBufferLen = iSubBufferLen / 2;
sampleRate = getSampleRate()->whole;
iSubFormat.altInterface = iSubEngine->GetAltInterface();
iSubFormat.numChannels = iSubEngine->GetNumChannels();
iSubFormat.bytesPerSample = iSubEngine->GetBytesPerSample();
iSubFormat.outputSampleRate = iSubEngine->GetSampleRate();
#if ABORT_PIPE_ON_START
if (needToSync == FALSE && previousClippedToFrame == firstSampleFrame && 0x0 != iSubEngine->GetCurrentLoopCount ()) {
#else
if (needToSync == FALSE && previousClippedToFrame == firstSampleFrame && 0xFFFFFFFF != iSubEngine->GetCurrentLoopCount ()) {
#endif
safetyOffset = iSubBufferOffset - ((iSubFormat.outputSampleRate) / 1000); if (safetyOffset < 0) {
safetyOffset += iSubBufferLen;
}
if (iSubLoopCount == iSubEngine->GetCurrentLoopCount () && safetyOffset < (SInt32)(iSubEngine->GetCurrentByteCount () / 2)) {
#if DEBUGLOG
IOLog ("****iSub is in front of write head iSubBufferOffset = %ld, iSubEngine->GetCurrentByteCount () / 2 = %ld\n", iSubBufferOffset, iSubEngine->GetCurrentByteCount () / 2);
#endif
needToSync = TRUE;
startiSub = TRUE;
} else if (iSubLoopCount > (iSubEngine->GetCurrentLoopCount () + 1)) {
#if DEBUGLOG
IOLog ("****looped more than the iSub iSubLoopCount = %ld, iSubEngine->GetCurrentLoopCount () = %ld\n", iSubLoopCount, iSubEngine->GetCurrentLoopCount ());
#endif
needToSync = TRUE;
startiSub = TRUE;
} else if (iSubLoopCount < iSubEngine->GetCurrentLoopCount ()) {
#if DEBUGLOG
IOLog ("****iSub is ahead of us iSubLoopCount = %ld, iSubEngine->GetCurrentLoopCount () = %ld\n", iSubLoopCount, iSubEngine->GetCurrentLoopCount ());
#endif
needToSync = TRUE;
startiSub = TRUE;
} else if (iSubLoopCount == iSubEngine->GetCurrentLoopCount () && iSubBufferOffset > ((SInt32)((iSubEngine->GetCurrentByteCount() + (((iSubFormat.outputSampleRate)/1000 * NUM_ISUB_FRAME_LISTS_TO_QUEUE * NUM_ISUB_FRAMES_PER_LIST) * iSubFormat.bytesPerSample * iSubFormat.numChannels)) / 2))) { #if DEBUGLOG
IOLog ("****iSub is too far behind write head iSubBufferOffset = %ld, (iSubEngine->GetCurrentByteCount () / 2 + iSubBufferLen) = %ld\n", iSubBufferOffset, (iSubEngine->GetCurrentByteCount() / 2 + iSubBufferLen));
#endif
needToSync = TRUE;
startiSub = TRUE;
}
}
if (FALSE == needToSync && previousClippedToFrame != firstSampleFrame && !(previousClippedToFrame == getNumSampleFramesPerBuffer () && firstSampleFrame == 0)) {
#if DEBUGLOG
IOLog ("iSubBufferOffset was %ld\n", iSubBufferOffset);
#endif
if (firstSampleFrame < previousClippedToFrame) {
offsetDelta = (getNumSampleFramesPerBuffer () - firstSampleFrame + previousClippedToFrame) * iSubEngine->GetNumChannels();
} else {
offsetDelta = (firstSampleFrame - previousClippedToFrame) * iSubEngine->GetNumChannels();
}
offsetDelta = (offsetDelta * 1000) / ((sampleRate * 1000) / iSubFormat.outputSampleRate);
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
}
}
if (TRUE == justResetClipPosition) {
justResetClipPosition = FALSE;
needToSync = FALSE;
startiSub = FALSE;
}
if (TRUE == needToSync) {
needToSync = FALSE;
srcPhase = 1.0; srcState = 0.0;
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;
filterState2.xl_1 = 0.0;
filterState2.xr_1 = 0.0;
filterState2.xl_2 = 0.0;
filterState2.xr_2 = 0.0;
filterState2.yl_1 = 0.0;
filterState2.yr_1 = 0.0;
filterState2.yl_2 = 0.0;
filterState2.yr_2 = 0.0;
phaseCompState.xl_1 = 0.0;
phaseCompState.xr_1 = 0.0;
phaseCompState.xl_2 = 0.0;
phaseCompState.xr_2 = 0.0;
phaseCompState.yl_1 = 0.0;
phaseCompState.yr_1 = 0.0;
phaseCompState.yl_2 = 0.0;
phaseCompState.yr_2 = 0.0;
#if ABORT_PIPE_ON_START
bzero(iSubBuffer, iSubBufferLen);
#endif
UInt32 curSampleFrame = getCurrentSampleFrame ();
if (firstSampleFrame < curSampleFrame) {
offsetDelta = (getNumSampleFramesPerBuffer () - curSampleFrame + firstSampleFrame) * iSubEngine->GetNumChannels();
} else {
offsetDelta = (firstSampleFrame - curSampleFrame) * iSubEngine->GetNumChannels();
}
offsetDelta = (offsetDelta * 1000) / ((sampleRate * 1000) / iSubFormat.outputSampleRate);
iSubBufferOffset = offsetDelta;
#if DEBUGLOG
IOLog ("USBEngine: need sync: starting iSubBufferOffset = %ld, iSubLoopCount = %ld\n", iSubBufferOffset, iSubLoopCount);
#endif
}
if (iSubBufferOffset > (SInt32)iSubBufferLen) {
needToSync = TRUE;
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, &filterState2, &phaseCompState, lowFreqSamples, highFreqSamples, firstSampleFrame, numSampleFrames, sampleRate, streamFormat, (SInt16*)iSubBuffer, &iSubLoopCount, &iSubBufferOffset, iSubBufferLen, &iSubFormat, &srcPhase, &srcState);
if (TRUE == startiSub) {
iSubEngine->StartiSub ();
startiSub = FALSE;
iSubLoopCount = 0;
}
previousClippedToFrame = firstSampleFrame + numSampleFrames;
} else {
result = clipAppleUSBAudioToOutputStream (mixBuf, sampleBuf, firstSampleFrame, numSampleFrames, streamFormat);
}
} else {
UInt32 offset;
offset = firstSampleFrame * streamFormat->fNumChannels * (streamFormat->fBitWidth / 8);
memcpy ((UInt8 *)sampleBuf + offset, (UInt8 *)mixBuf, numSampleFrames * streamFormat->fNumChannels * (streamFormat->fBitWidth / 8));
previousClippedToFrame = firstSampleFrame + numSampleFrames;
result = kIOReturnSuccess;
}
return result;
}
#if NEWUSB
void AppleUSBAudioEngine::CoalesceInputSamples (UInt32 numBytesToCoalesce, IOUSBLowLatencyIsocFrame * pFrames) {
#else
void AppleUSBAudioEngine::CoalesceInputSamples (UInt32 numBytesToCoalesce, IOUSBIsocFrame * pFrames) {
#endif
#if DEBUGZEROTIME
AbsoluteTime timeNow;
#endif
AbsoluteTime time;
AbsoluteTime timeOffset;
UInt64 nanos;
#if !NEWUSB
AbsoluteTime delay;
AbsoluteTime frameOffset;
UInt64 a;
UInt64 b;
#else
#endif
UInt32 usbFrameIndex;
UInt32 numFramesChecked;
UInt32 numBytesToCopy;
UInt32 numBytesToEnd;
UInt32 numBytesCopied;
UInt32 originalBufferOffset;
SInt32 numBytesLeft;
UInt8 * source;
UInt8 * dest;
Boolean done;
if (0 != numBytesToCoalesce) {
originalBufferOffset = bufferOffset; }
dest = (UInt8 *)getSampleBuffer () + bufferOffset;
source = (UInt8 *)readBuffer + (currentFrameList * readUSBFrameListSize);
usbFrameIndex = 0;
numFramesChecked = 0;
numBytesCopied = 0;
numBytesLeft = numBytesToCoalesce;
done = FALSE;
if (NULL == pFrames) {
pFrames = &theUSBIsocFrames[currentFrameList * numUSBFramesPerList];
}
while (FALSE == done) {
#if DEBUGLOG
if (pFrames[usbFrameIndex].frActCount < (pFrames[usbFrameIndex].frReqCount - (2 * bytesPerSampleFrame))) {
IOLog ("ERROR! short read packet %d req = %d\n", pFrames[usbFrameIndex].frActCount, pFrames[usbFrameIndex].frReqCount);
}
if (kIOReturnSuccess != pFrames[usbFrameIndex].frStatus && kIOReturnUnderrun != pFrames[usbFrameIndex].frStatus) {
IOLog ("Err:0x%lx fl:%ld, fr:%ld\n", pFrames[usbFrameIndex].frStatus, currentFrameList, usbFrameIndex);
}
#endif
numBytesToEnd = getSampleBufferSize () - bufferOffset;
if ((UInt32)(pFrames[usbFrameIndex].frActCount) > numBytesToEnd) {
numBytesToCopy = numBytesToEnd;
} else {
numBytesToCopy = pFrames[usbFrameIndex].frActCount;
}
memcpy (dest, source, numBytesToCopy);
bufferOffset += numBytesToCopy;
numBytesCopied = numBytesToCopy;
numBytesLeft -= numBytesToCopy;
if ((UInt32)(pFrames[usbFrameIndex].frActCount) > numBytesToEnd) {
numBytesToCopy = (pFrames[usbFrameIndex].frActCount) - numBytesToEnd;
dest = (UInt8 *)getSampleBuffer ();
memcpy (dest, source + numBytesCopied, numBytesToCopy);
bufferOffset = numBytesToCopy;
numBytesLeft -= numBytesToCopy;
if (0 == numBytesToCoalesce) {
#if NEWUSB
time = pFrames[usbFrameIndex].frTimeStamp;
nanos = (numBytesToCopy * 1000000) / pFrames[usbFrameIndex].frActCount;
nanoseconds_to_absolutetime (nanos, &timeOffset);
SUB_ABSOLUTETIME (&time, &timeOffset); #else
do {
a = streamInterface->GetDevice()->GetBus()->GetFrameNumber ();
clock_get_uptime (&time);
b = streamInterface->GetDevice()->GetBus()->GetFrameNumber ();
} while (a != b);
nanoseconds_to_absolutetime (((UInt32)(a - expectedBusFrame) - (numUSBFramesPerList - usbFrameIndex)) * 1000 * 1000, &delay);
SUB_ABSOLUTETIME (&time, &delay);
nanoseconds_to_absolutetime ((numUSBFramesPerList - usbFrameIndex) * 1000 * 1000, &frameOffset);
SUB_ABSOLUTETIME (&time, &frameOffset);
nanos = (pFrames[usbFrameIndex].frActCount - numBytesToCopy * 1000000) / getSampleBufferSize ();
nanoseconds_to_absolutetime (nanos, &timeOffset);
ADD_ABSOLUTETIME (&time, &timeOffset);
#endif
#if DEBUGZEROTIME
timeNow = time;
SUB_ABSOLUTETIME (&timeNow, &status->fLastLoopTime);
absolutetime_to_nanoseconds (timeNow, &nanos);
IOLog ("d=%ld\n", (UInt32)(nanos / (1000 * 1000)));
#endif
takeTimeStamp (TRUE, &time);
}
}
#if !NEWUSB
if (0 == numBytesToCoalesce) {
expectedBusFrame++;
}
#endif
dest += numBytesToCopy;
source += pFrames[usbFrameIndex].frReqCount;
usbFrameIndex++;
numFramesChecked++;
if (0 != numBytesToCoalesce && (usbFrameIndex + (currentFrameList * numUSBFramesPerList)) == (numUSBFrameLists * numUSBFramesPerList)) {
pFrames = &theUSBIsocFrames[0]; usbFrameIndex = 0;
source = (UInt8 *)readBuffer;
}
if (((0 == numBytesToCoalesce) && (numUSBFramesPerList == usbFrameIndex)) || ((0 != numBytesToCoalesce) && (0 >= numBytesLeft)) || ((0 != numBytesToCoalesce) && (numFramesChecked >= (numUSBFramesPerList * numUSBFrameListsToQueue)))) { done = TRUE;
}
}
if (0 != numBytesToCoalesce) {
bufferOffset = originalBufferOffset;
}
return;
}
IOReturn AppleUSBAudioEngine::convertInputSamples (const void *sampleBuf,
void *destBuf,
UInt32 firstSampleFrame,
UInt32 numSampleFrames,
const IOAudioStreamFormat *streamFormat,
IOAudioStream *audioStream) {
#if 1
UInt64 curUSBFrameNumber;
SInt64 framesLeftInQueue;
#if NEWUSB || DEBUGLOG
UInt32 lastSampleByte;
UInt32 windowStartByte;
UInt32 windowEndByte;
#endif
#endif
#if DEBUGLOG
#if 0
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
#if 1 // enabled for [3091812]
#if NEWUSB
if (0 == shouldStop && TRUE != inCompletion) {
curUSBFrameNumber = streamInterface->GetDevice()->GetBus()->GetFrameNumber ();
framesLeftInQueue = usbFrameToQueueAt - curUSBFrameNumber;
if (framesLeftInQueue < (numUSBFramesPerList * (numUSBFrameListsToQueue / 2)) / 2) {
while (framesLeftInQueue < numUSBFramesPerList * (numUSBFrameListsToQueue - 1)) {
#ifdef DEBUGLOG
IOLog ("queue a read from convertInputSamples: framesLeftInQueue = %ld\n", (UInt32)framesLeftInQueue);
#endif
readHandler (this, usbCompletion[currentFrameList].parameter, kIOReturnSuccess, &theUSBIsocFrames[(currentFrameList) * numUSBFramesPerList]);
curUSBFrameNumber = streamInterface->GetDevice()->GetBus()->GetFrameNumber ();
framesLeftInQueue = usbFrameToQueueAt - curUSBFrameNumber;
}
}
}
#endif
#endif
#if 1 // enabled for [3091812]
#if NEWUSB || DEBUGLOG
lastSampleByte = (firstSampleFrame + numSampleFrames) * streamFormat->fNumChannels * (streamFormat->fBitWidth / 8);
if (bufferOffset + 1 > getSampleBufferSize ()) {
windowStartByte = 0;
} else {
windowStartByte = bufferOffset + 1;
}
windowEndByte = windowStartByte + (numUSBFrameListsToQueue * readUSBFrameListSize);
if (windowEndByte > getSampleBufferSize ()) {
windowEndByte -= getSampleBufferSize ();
}
if ((windowStartByte < lastSampleByte && windowEndByte > lastSampleByte) ||
(windowEndByte > lastSampleByte && windowStartByte > windowEndByte) ||
(windowStartByte < lastSampleByte && windowStartByte > windowEndByte && windowEndByte < lastSampleByte)) {
#if NEWUSB
if (bufferOffset < lastSampleByte) {
CoalesceInputSamples (lastSampleByte - bufferOffset, NULL);
} else {
UInt32 numBytesToCoalesce = getSampleBufferSize () - bufferOffset + lastSampleByte;
CoalesceInputSamples (numBytesToCoalesce, NULL);
}
}
#endif
#endif
#endif
return convertFromAppleUSBAudioInputStream_NoWrap (sampleBuf, destBuf, firstSampleFrame, numSampleFrames, streamFormat);
}
UInt32 AppleUSBAudioEngine::getCurrentSampleFrame () {
const IOAudioStreamFormat *theFormat;
UInt32 currentSampleFrame;
currentSampleFrame = 0;
FailIf (NULL == mainStream, Exit);
theFormat = mainStream->getFormat ();
if (getDirection () == kIOAudioStreamDirectionOutput) {
currentSampleFrame = safeToEraseTo;
} else {
currentSampleFrame = (bufferOffset == bufferSize ? 0 : bufferOffset);
}
currentSampleFrame /= (theFormat->fNumChannels * (theFormat->fBitWidth / 8));
Exit:
#if 0 // 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 = OSDynamicCast (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);
debug2IOLog ("getGlobalUniqueID = %s\n", uniqueIDStr);
IOFree (uniqueIDStr, uniqueIDSize);
}
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;
UInt32 index;
UInt16 terminalType;
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;
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");
index = 0;
do {
terminalType = usbAudio->GetIndexedInputTerminalType (usbAudioDevice->controlInterface->GetInterfaceNumber (), 0, index++);
} while (terminalType == INPUT_UNDEFINED && index < 256);
numUSBFrameLists = RECORD_NUM_USB_FRAME_LISTS;
numUSBFramesPerList = RECORD_NUM_USB_FRAMES_PER_LIST;
numUSBFrameListsToQueue = RECORD_NUM_USB_FRAME_LISTS_TO_QUEUE;
} else if (kUSBOut == direction) {
debugIOLog ("This is an output type endpoint (speaker, etc.)\n");
index = 0;
do {
terminalType = usbAudio->GetIndexedOutputTerminalType (usbAudioDevice->controlInterface->GetInterfaceNumber (), 0, index++);
} while (terminalType == OUTPUT_UNDEFINED && index < 256);
numUSBFrameLists = PLAY_NUM_USB_FRAME_LISTS;
numUSBFramesPerList = PLAY_NUM_USB_FRAMES_PER_LIST;
numUSBFrameListsToQueue = PLAY_NUM_USB_FRAME_LISTS_TO_QUEUE;
} else {
FailMessage ("Couldn't get the endpoint direction!\n", Exit);
}
mainStream->setTerminalType (terminalType);
#if NEWUSB
theUSBIsocFrames = (IOUSBLowLatencyIsocFrame *)IOMalloc (numUSBFrameLists * numUSBFramesPerList * sizeof (IOUSBLowLatencyIsocFrame));
usbCompletion = (IOUSBLowLatencyIsocCompletion *)IOMalloc (numUSBFrameLists * sizeof (IOUSBLowLatencyIsocCompletion));
#else
theUSBIsocFrames = (IOUSBIsocFrame *)IOMalloc (numUSBFrameLists * numUSBFramesPerList * sizeof (IOUSBIsocFrame));
usbCompletion = (IOUSBIsocCompletion *)IOMalloc (numUSBFrameLists * sizeof (IOUSBIsocCompletion));
#endif
soundBufferDescriptors = (IOMemoryDescriptor **)IOMalloc (numUSBFrameLists * sizeof (IOMemoryDescriptor *));
bzero (soundBufferDescriptors, numUSBFrameLists * sizeof (IOMemoryDescriptor *));
FailIf (NULL == theUSBIsocFrames, Exit);
FailIf (NULL == usbCompletion, Exit);
FailIf (NULL == soundBufferDescriptors, Exit);
FailIf (kIOReturnSuccess != AddAvailableFormatsFromDevice (usbAudio), Exit);
curSampleRate = sampleRate;
setSampleRate (&sampleRate);
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;
switch (usbAudio->GetFormat (ourInterfaceNumber, alternateInterfaceID)) {
case PCM:
streamFormat.fSampleFormat = kIOAudioStreamSampleFormatLinearPCM;
streamFormat.fNumericRepresentation = kIOAudioStreamNumericRepresentationSignedInt;
streamFormat.fIsMixable = TRUE;
break;
case AC3: streamFormat.fSampleFormat = kIOAudioStreamSampleFormatAC3;
streamFormat.fNumericRepresentation = kIOAudioStreamNumericRepresentationSignedInt;
streamFormat.fIsMixable = FALSE;
streamFormat.fNumChannels = 6;
streamFormat.fBitDepth = 16;
streamFormat.fBitWidth = 16;
streamFormat.fByteOrder = kIOAudioStreamByteOrderBigEndian;
break;
case IEC1937_AC3:
streamFormat.fSampleFormat = kIOAudioStreamSampleFormat1937AC3;
streamFormat.fNumericRepresentation = kIOAudioStreamNumericRepresentationSignedInt;
streamFormat.fIsMixable = FALSE;
break;
default:
FailMessage ("!!!!interface doesn't support a format that we can deal with!!!!\n", Exit);
}
FailIf (FALSE == streamInterface->open (this), Exit); resultCode = streamInterface->SetAlternateInterface (this, kRootAlternateSetting); FailIf (kIOReturnSuccess != resultCode, Exit);
resultCode = mainStream->setFormat (&streamFormat);
FailIf (kIOReturnSuccess != resultCode, Exit);
resultCode = addAudioStream (mainStream);
FailIf (kIOReturnSuccess != resultCode, Exit);
FailIf (kUSBAudioClass != usbAudio->GetInterfaceClass (ourInterfaceNumber, alternateInterfaceID), Exit);
FailIf (kUSBAudioStreamInterfaceSubclass != usbAudio->GetInterfaceSubClass (ourInterfaceNumber, alternateInterfaceID), Exit);
GetDeviceInfo ();
if (kUSBOut == direction) {
iSubBufferMemory = NULL;
iSubEngine = NULL;
iSubAttach = IOAudioToggleControl::create (FALSE,
kIOAudioControlChannelIDAll,
kIOAudioControlChannelNameAll,
0,
kIOAudioToggleControlSubTypeiSubAttach,
kIOAudioControlUsageOutput);
if (NULL != iSubAttach) {
addDefaultAudioControl (iSubAttach);
iSubAttach->setValueChangeHandler ((IOAudioControl::IntValueChangeHandler)iSubAttachChangeHandler, this);
}
}
usbAudioDevice->activateAudioEngine (this, FALSE, ourInterfaceNumber, alternateInterfaceID);
resultCode = TRUE;
if (resultCode) {
usbAudioDevice->retain ();
}
Exit:
debug4IOLog("-%d = AppleUSBAudioEngine[%p]::initHardware(%p)\n", resultCode, this, provider);
return resultCode;
}
IOReturn AppleUSBAudioEngine::iSubAttachChangeHandler (IOService *target, IOAudioControl *theControl, SInt32 oldValue, SInt32 newValue) {
IOReturn result;
AppleUSBAudioEngine * audioEngine;
debug5IOLog ("+ AppleUSBAudioEngine::iSubAttachChangeHandler (%p, %p, %ld, %ld)\n", target, theControl, oldValue, newValue);
result = kIOReturnSuccess;
FailIf (oldValue == newValue, Exit);
audioEngine = OSDynamicCast (AppleUSBAudioEngine, target);
FailIf (NULL == audioEngine, Exit);
if (newValue) {
audioEngine->iSubEngineNotifier = addNotification (gIOPublishNotification, serviceMatching ("AppleiSubEngine"), (IOServiceNotificationHandler)&iSubEnginePublished, audioEngine);
if (NULL != audioEngine->iSubBufferMemory) {
audioEngine->iSubEngineNotifier->remove ();
audioEngine->iSubEngineNotifier = NULL;
}
} else {
if (NULL != audioEngine->iSubBufferMemory && NULL != audioEngine->iSubEngine) {
audioEngine->iSubTeardownConnection ();
}
if (NULL != audioEngine->iSubEngineNotifier) {
audioEngine->iSubEngineNotifier->remove ();
audioEngine->iSubEngineNotifier = NULL;
}
}
Exit:
debugIOLog("- AppleUSBAudioEngine::iSubAttachChangeHandler\n");
return result;
}
IOReturn AppleUSBAudioEngine::iSubCloseAction (OSObject *owner, void *arg1, void *arg2, void *arg3, void *arg4) {
debugIOLog("+AppleUSBAudioEngine::iSubCloseAction\n");
AppleUSBAudioEngine *audioEngine = OSDynamicCast (AppleUSBAudioEngine, owner);
FailIf (NULL == audioEngine, Exit);
if (TRUE == audioEngine->iSubIsOpen && NULL != audioEngine->oldiSubEngine) {
audioEngine->oldiSubEngine->closeiSub (audioEngine);
debugIOLog ("iSub closed\n");
audioEngine->detach (audioEngine->oldiSubEngine);
audioEngine->iSubIsOpen = FALSE;
audioEngine->iSubEngine = NULL;
audioEngine->iSubBufferMemory = NULL;
#if DEBUGLOG
} else {
if (TRUE != audioEngine->iSubIsOpen) {IOLog ("TRUE != audioEngine->iSubIsOpen\n");}
if (NULL == audioEngine->oldiSubEngine) {IOLog ("NULL == audioEngine->oldiSubEngine\n");}
#endif
}
if (NULL != audioEngine->lowFreqSamples) {
IOFree (audioEngine->lowFreqSamples, audioEngine->getSampleBufferSize () * 2);
}
if (NULL != audioEngine->highFreqSamples) {
IOFree (audioEngine->highFreqSamples, audioEngine->getSampleBufferSize () * 2);
}
Exit:
debugIOLog("-AppleUSBAudioEngine::iSubCloseAction\n");
return kIOReturnSuccess;
}
bool AppleUSBAudioEngine::iSubEnginePublished (AppleUSBAudioEngine * usbAudioEngineObject, void * refCon, IOService * newService) {
debug4IOLog ("AppleUSBAudioEngine::iSubEnginePublished (%p, %p, %p)\n", usbAudioEngineObject, refCon, newService);
FailIf (NULL == usbAudioEngineObject, Exit);
FailIf (NULL == newService, Exit);
if (FALSE == usbAudioEngineObject->iSubIsOpen) {
usbAudioEngineObject->iSubEngine = (AppleiSubEngine *)newService;
usbAudioEngineObject->iSubOpenThreadCall = thread_call_allocate ((thread_call_func_t)usbAudioEngineObject->iSubOpen, (thread_call_param_t)usbAudioEngineObject);
if (NULL != usbAudioEngineObject->iSubOpenThreadCall) {
thread_call_enter (usbAudioEngineObject->iSubOpenThreadCall);
} else {
}
} else {
debugIOLog ("iSub is already open\n");
}
Exit:
return TRUE;
}
void AppleUSBAudioEngine::iSubOpen (AppleUSBAudioEngine * usbAudioEngineObject) {
IOReturn result;
IOCommandGate * cg;
debug2IOLog ("+AppleUSBAudioEngine::iSubOpen (%p)\n", usbAudioEngineObject);
FailIf (NULL == usbAudioEngineObject, Exit);
cg = usbAudioEngineObject->getCommandGate ();
if (NULL != cg) {
result = cg->runAction (iSubOpenAction);
}
Exit:
if (NULL != usbAudioEngineObject && NULL != usbAudioEngineObject->iSubOpenThreadCall) {
thread_call_free(usbAudioEngineObject->iSubOpenThreadCall);
}
debug2IOLog ("-AppleUSBAudioEngine::iSubOpen (%p)\n", usbAudioEngineObject);
return;
}
IOReturn AppleUSBAudioEngine::iSubOpenAction (OSObject *owner, void *arg1, void *arg2, void *arg3, void *arg4) {
AppleUSBAudioEngine * usbAudioEngineObject;
IOReturn result;
bool resultBool;
UInt32 sampleRateWhole;
UInt32 numTries;
debug2IOLog ("+AppleUSBAudioEngine::iSubOpenAction (%p)\n", owner);
result = kIOReturnError;
usbAudioEngineObject = OSDynamicCast (AppleUSBAudioEngine, owner);
FailIf (NULL == usbAudioEngineObject, Exit);
FailIf (NULL == usbAudioEngineObject->iSubEngine, Exit);
sampleRateWhole = usbAudioEngineObject->curSampleRate.whole;
if ((8000 != sampleRateWhole) && (11025 != sampleRateWhole) && (22050 != sampleRateWhole) &&
(44100 != sampleRateWhole) && (48000 != sampleRateWhole) && (96000 != sampleRateWhole)) {
goto Exit;
}
usbAudioEngineObject->lowFreqSamples = (float *)IOMallocAligned (usbAudioEngineObject->getSampleBufferSize () * 2, PAGE_SIZE);
FailIf (NULL == usbAudioEngineObject->lowFreqSamples, Cleanup);
usbAudioEngineObject->highFreqSamples = (float *)IOMallocAligned (usbAudioEngineObject->getSampleBufferSize () * 2, PAGE_SIZE);
FailIf (NULL == usbAudioEngineObject->highFreqSamples, Cleanup);
usbAudioEngineObject->attach (usbAudioEngineObject->iSubEngine);
numTries = 0;
do {
IOSleep (102);
resultBool = usbAudioEngineObject->iSubEngine->openiSub (usbAudioEngineObject);
numTries++;
} while (FALSE == resultBool && numTries < 5);
FailWithAction (FALSE == resultBool, usbAudioEngineObject->detach (usbAudioEngineObject->iSubEngine), Cleanup);
result = kIOReturnSuccess;
Cleanup:
if (NULL != usbAudioEngineObject->iSubEngineNotifier) {
usbAudioEngineObject->iSubEngineNotifier->remove ();
usbAudioEngineObject->iSubEngineNotifier = NULL;
}
if (kIOReturnSuccess == result) {
debugIOLog ("successfully opened the iSub\n");
usbAudioEngineObject->iSubBufferMemory = usbAudioEngineObject->iSubEngine->GetSampleBuffer ();
usbAudioEngineObject->iSubIsOpen = TRUE;
} else {
usbAudioEngineObject->iSubBufferMemory = NULL;
usbAudioEngineObject->iSubEngine = NULL;
usbAudioEngineObject->iSubIsOpen = FALSE;
if (NULL != usbAudioEngineObject->lowFreqSamples) {
IOFree (usbAudioEngineObject->lowFreqSamples, usbAudioEngineObject->getSampleBufferSize () * 2);
}
if (NULL != usbAudioEngineObject->highFreqSamples) {
IOFree (usbAudioEngineObject->highFreqSamples, usbAudioEngineObject->getSampleBufferSize () * 2);
}
}
Exit:
debug3IOLog ("-AppleUSBAudioEngine::iSubOpenAction (%p) = 0x%lx\n", owner, result);
return result;
}
void AppleUSBAudioEngine::iSubTeardown (AppleUSBAudioEngine * usbAudioEngine, thread_call_t iSubTeardownThreadCall) {
IOCommandGate * cg;
debugIOLog ("+AppleUSBAudioEngine::iSubTeardown ()\n");
if (NULL != usbAudioEngine) {
usbAudioEngine->pauseAudioEngine ();
usbAudioEngine->beginConfigurationChange ();
cg = usbAudioEngine->getCommandGate ();
if (NULL != cg) {
cg->runAction (iSubCloseAction);
}
usbAudioEngine->completeConfigurationChange ();
usbAudioEngine->resumeAudioEngine ();
}
if (NULL != iSubTeardownThreadCall) {
thread_call_free(iSubTeardownThreadCall);
}
debugIOLog ("-AppleUSBAudioEngine::iSubTeardown ()\n");
}
void AppleUSBAudioEngine::iSubTeardownConnection (void) {
debugIOLog ("+AppleUSBAudioEngine::iSubTeardownConnection ()\n");
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 {
}
debugIOLog ("-AppleUSBAudioEngine::iSubTeardownConnection ()\n");
return;
}
IOReturn AppleUSBAudioEngine::performAudioEngineStart () {
IOReturn resultCode;
debug2IOLog ("+AppleUSBAudioEngine[%p]::performAudioEngineStart ()\n", this);
resultCode = kIOReturnSuccess;
if (NULL != iSubEngine) {
startiSub = TRUE;
needToSync = TRUE;
}
if (!usbStreamRunning) {
resultCode = startUSBStream ();
}
if (resultCode != kIOReturnSuccess) {
debug2IOLog ("++AppleUSBAudioEngine[%p]::performAudioEngineStart () -- NOT started, error = 0x%x\n", resultCode);
} else {
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 (usbStreamRunning) {
stopUSBStream ();
}
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;
IOReturn result;
void * sampleBuffer;
UInt32 i;
UInt32 oldBufferSize;
UInt32 numSamplesInBuffer;
UInt16 averageFrameSamples;
UInt16 averageFrameSize;
UInt16 alternateFrameSize;
UInt16 additionalSampleFrameFreq;
UInt16 oldReadUSBFrameListSize;
UInt8 ourInterfaceNumber;
UInt8 newAlternateInterfaceID;
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);
newAlternateInterfaceID = (UInt8)(newFormat->fDriverTag);
if (newSampleRate) {
FailWithAction (FALSE == usbAudio->VerifySampleRateIsSupported (ourInterfaceNumber, newAlternateInterfaceID, newSampleRate->whole), result = kIOReturnError, Exit);
}
newDirection = usbAudio->GetIsocEndpointDirection (ourInterfaceNumber, newAlternateInterfaceID);
FailIf (newDirection != direction, Exit);
debug3IOLog ("++about to set: ourInterfaceNumber = %d & newAlternateInterfaceID = %d\n", ourInterfaceNumber, newAlternateInterfaceID);
alternateInterfaceID = newAlternateInterfaceID;
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);
}
(void)SetSampleRate (usbAudio, curSampleRate.whole);
averageSampleRate = curSampleRate.whole; debug2IOLog ("averageSampleRate = %d\n", averageSampleRate);
CalculateSamplesPerFrame (curSampleRate.whole, &averageFrameSamples, &additionalSampleFrameFreq);
debug3IOLog ("averageFrameSamples = %d, additionalSampleFrameFreq = %d\n", averageFrameSamples, additionalSampleFrameFreq);
oldReadUSBFrameListSize = readUSBFrameListSize;
averageFrameSize = averageFrameSamples * (newFormat->fNumChannels * (newFormat->fBitWidth / 8));
if (kUSBIn == direction) {
alternateFrameSize = (averageFrameSamples + 2) * (newFormat->fNumChannels * (newFormat->fBitWidth / 8));
} else {
alternateFrameSize = (averageFrameSamples + 1) * (newFormat->fNumChannels * (newFormat->fBitWidth / 8));
}
debug3IOLog ("averageFrameSize = %d, alternateFrameSize = %d\n", averageFrameSize, alternateFrameSize);
if (kUSBIn == direction) {
readUSBFrameListSize = alternateFrameSize * numUSBFramesPerList;
}
numSamplesInBuffer = averageSampleRate / 4;
numSamplesInBuffer += (PAGE_SIZE - 1);
numSamplesInBuffer /= PAGE_SIZE;
numSamplesInBuffer *= PAGE_SIZE;
bufferSize = numSamplesInBuffer * newFormat->fNumChannels * (newFormat->fBitWidth / 8);
if (NULL != iSubBufferMemory) {
if ((2 != newFormat->fNumChannels) || ((8000 != curSampleRate.whole) && (11025 != curSampleRate.whole) && (22050 != curSampleRate.whole) &&
(44100 != curSampleRate.whole) && (48000 != curSampleRate.whole) && (96000 != curSampleRate.whole))) {
if (NULL != lowFreqSamples) {
IOFree (lowFreqSamples, getSampleBufferSize () * 2);
}
if (NULL != highFreqSamples) {
IOFree (highFreqSamples, getSampleBufferSize () * 2);
}
iSubTeardownConnection ();
}
}
if (NULL != theStartBuffer) {
IOFree (theStartBuffer, theStartBufferSize);
}
theStartBuffer = IOMalloc (alternateFrameSize);
FailIf (NULL == theStartBuffer, Exit);
bzero (theStartBuffer, alternateFrameSize);
theStartBufferSize = alternateFrameSize;
theStartBufferDescriptor = IOMemoryDescriptor::withAddress (theStartBuffer, theStartBufferSize, kIODirectionOut);
FailIf (NULL == theStartBufferDescriptor, Exit);
theStartFrame.frStatus = -1;
theStartFrame.frReqCount = theStartBufferSize;
theStartFrame.frActCount = 0;
if (NULL != soundBufferDescriptors) {
for (i = 0; i < numUSBFrameLists; i++) {
if (NULL != soundBufferDescriptors[i]) {
soundBufferDescriptors[i]->release ();
soundBufferDescriptors[i] = NULL;
}
}
}
if (kUSBIn == direction) {
if (NULL != readBuffer) {
IOFree (readBuffer, numUSBFrameLists * oldReadUSBFrameListSize);
}
readBuffer = IOMallocAligned (numUSBFrameLists * readUSBFrameListSize, PAGE_SIZE);
FailIf (NULL == readBuffer, Exit);
for (i = 0; i < numUSBFrameLists; i++) {
soundBufferDescriptors[i] = IOMemoryDescriptor::withAddress ((UInt8 *)readBuffer + (i * readUSBFrameListSize), readUSBFrameListSize, kIODirectionIn);
FailIf (NULL == soundBufferDescriptors[i], Exit);
}
} else {
if (NULL != iSubBufferMemory) {
if (NULL != lowFreqSamples) {
IOFree (lowFreqSamples, getSampleBufferSize () * 2);
}
if (NULL != highFreqSamples) {
IOFree (highFreqSamples, getSampleBufferSize () * 2);
}
if ((2 == newFormat->fNumChannels) && ((8000 == curSampleRate.whole) || (11025 == curSampleRate.whole) || (22050 == curSampleRate.whole) ||
(44100 == curSampleRate.whole) || (48000 == curSampleRate.whole) || (96000 == curSampleRate.whole))) {
lowFreqSamples = (float *)IOMallocAligned (bufferSize * 2, PAGE_SIZE);
FailIf (NULL == lowFreqSamples, Exit);
highFreqSamples = (float *)IOMallocAligned (bufferSize * 2, PAGE_SIZE);
FailIf (NULL == highFreqSamples, Exit);
}
}
for (i = 0; i < numUSBFrameLists; i++) {
soundBufferDescriptors[i] = IOMemoryDescriptor::withAddress (sampleBuffer, bufferSize, kIODirectionOut);
FailIf (NULL == soundBufferDescriptors[i], Exit);
}
}
if (NULL != getSampleBuffer ()) {
IOFree (getSampleBuffer (), getSampleBufferSize ());
}
debug2IOLog ("sampleBufferSize = %ld\n", bufferSize);
sampleBuffer = IOMallocAligned (bufferSize, PAGE_SIZE);
FailIf (NULL == sampleBuffer, Exit);
mainStream->setSampleBuffer (sampleBuffer, bufferSize);
setNumSampleFramesPerBuffer (numSamplesInBuffer);
if (kUSBIn == direction) {
#if NEWUSB
setSampleOffset ((numUSBFramesPerList + 1) * (averageFrameSamples + 2));
#else
setSampleOffset ((numUSBFramesPerList + 1) * (averageFrameSamples + 2));
#endif
setSampleLatency (averageFrameSamples * (kMinimumFrameOffset + 1));
} else {
setSampleOffset (3 * (additionalSampleFrameFreq ? averageFrameSamples + 1 : averageFrameSamples));
setSampleLatency (averageFrameSamples * kMinimumFrameOffset);
}
debug2IOLog ("called setNumSampleFramesPerBuffer with %d\n", bufferSize / (newFormat->fNumChannels * (newFormat->fBitWidth / 8)));
debug3IOLog ("newFormat->fNumChannels = %d, newFormat->fBitWidth %d\n", newFormat->fNumChannels, newFormat->fBitWidth);
debug2IOLog ("called setSampleOffset with %d\n", numUSBFramesPerList);
result = kIOReturnSuccess;
FailIf (kIOReturnSuccess != result, Exit);
Exit:
debug2IOLog ("-AppleUSBAudioEngine::performFormatChange, result = %x\n", result);
return result;
}
IOReturn AppleUSBAudioEngine::PrepareWriteFrameList (UInt32 arrayIndex) {
const IOAudioStreamFormat * theFormat;
IOReturn result;
UInt32 thisFrameListSize;
UInt32 thisFrameSize;
UInt32 firstFrame;
UInt32 numBytesToBufferEnd;
UInt32 lastPreparedByte;
UInt32 updateFreq;
UInt32 numUSBFramesPrepared;
UInt16 integerSamplesInFrame;
Boolean haveWrapped;
result = kIOReturnError; updateFreq = 0;
haveWrapped = FALSE;
firstFrame = arrayIndex * numUSBFramesPerList;
usbCompletion[arrayIndex].target = (void *)this;
usbCompletion[arrayIndex].action = writeHandler;
usbCompletion[arrayIndex].parameter = 0;
theFormat = mainStream->getFormat ();
numBytesToBufferEnd = getSampleBufferSize () - previouslyPreparedBufferOffset;
lastPreparedByte = previouslyPreparedBufferOffset;
thisFrameListSize = 0;
for (numUSBFramesPrepared = 0; numUSBFramesPrepared < numUSBFramesPerList; numUSBFramesPrepared++) {
integerSamplesInFrame = averageSampleRate / 1000;
fractionalSamplesRemaining += averageSampleRate - (integerSamplesInFrame * 1000);
if (fractionalSamplesRemaining >= 1000) {
integerSamplesInFrame++;
fractionalSamplesRemaining -= 1000;
}
thisFrameSize = integerSamplesInFrame * (theFormat->fBitWidth / 8) * theFormat->fNumChannels;
if (thisFrameSize >= numBytesToBufferEnd) {
usbCompletion[arrayIndex].parameter = (void *)(((numUSBFramesPrepared + 1) << 16) | (thisFrameSize - numBytesToBufferEnd));
theWrapRanges[0].address = (IOVirtualAddress)((UInt8 *)getSampleBuffer () + previouslyPreparedBufferOffset);
theWrapRanges[0].length = getSampleBufferSize () - previouslyPreparedBufferOffset;
lastPreparedByte = thisFrameSize - numBytesToBufferEnd;
numBytesToBufferEnd = getSampleBufferSize () - lastPreparedByte;
haveWrapped = TRUE;
#if !NEWUSB
expectedBusFrame = usbFrameToQueueAt + numUSBFramesPrepared;
#endif
} else {
thisFrameListSize += thisFrameSize;
lastPreparedByte += thisFrameSize;
numBytesToBufferEnd -= thisFrameSize;
}
theUSBIsocFrames[firstFrame + numUSBFramesPrepared].frStatus = -1;
theUSBIsocFrames[firstFrame + numUSBFramesPrepared].frActCount = 0;
theUSBIsocFrames[firstFrame + numUSBFramesPrepared].frReqCount = thisFrameSize;
}
if (TRUE == haveWrapped) {
updateFreq = 1;
theWrapRanges[1].address = (IOVirtualAddress)getSampleBuffer ();
theWrapRanges[1].length = lastPreparedByte;
soundBufferDescriptors[arrayIndex]->initWithRanges (theWrapRanges, 2, kIODirectionOut, kernel_task, TRUE);
} else {
soundBufferDescriptors[arrayIndex]->initWithAddress (((UInt8 *)getSampleBuffer ()) + previouslyPreparedBufferOffset, thisFrameListSize, kIODirectionOut);
FailIf (NULL == soundBufferDescriptors[arrayIndex], Exit);
}
safeToEraseTo = lastSafeErasePoint;
lastSafeErasePoint = previouslyPreparedBufferOffset;
previouslyPreparedBufferOffset = lastPreparedByte;
result = kIOReturnSuccess;
Exit:
return result;
}
IOReturn AppleUSBAudioEngine::PrepareAndReadFrameLists (UInt8 sampleSize, UInt8 numChannels, UInt32 usbFrameListIndex) {
IOReturn result;
UInt32 firstFrame;
UInt32 arrayIndex;
UInt32 numUSBFramesPrepared;
UInt16 averageFrameSamples;
UInt16 additionalSampleFrameFreq;
UInt16 bytesToRead;
result = kIOReturnError; arrayIndex = usbFrameListIndex;
firstFrame = arrayIndex * numUSBFramesPerList;
usbCompletion[arrayIndex].target = (void *)this;
usbCompletion[arrayIndex].action = readHandler;
usbCompletion[arrayIndex].parameter = (void *)arrayIndex;
CalculateSamplesPerFrame (curSampleRate.whole, &averageFrameSamples, &additionalSampleFrameFreq);
bytesPerSampleFrame = sampleSize * numChannels;
bytesToRead = (averageFrameSamples + 2) * bytesPerSampleFrame;
for (numUSBFramesPrepared = 0; numUSBFramesPrepared < numUSBFramesPerList; numUSBFramesPrepared++) {
theUSBIsocFrames[firstFrame + numUSBFramesPrepared].frStatus = -1;
theUSBIsocFrames[firstFrame + numUSBFramesPrepared].frActCount = 0;
theUSBIsocFrames[firstFrame + numUSBFramesPrepared].frReqCount = bytesToRead;
theUSBIsocFrames[firstFrame + numUSBFramesPrepared].frTimeStamp.hi = 0;
theUSBIsocFrames[firstFrame + numUSBFramesPrepared].frTimeStamp.lo = 0;
}
FailIf (NULL == thePipe, Exit);
#if NEWUSB
result = thePipe->Read (soundBufferDescriptors[arrayIndex], usbFrameToQueueAt, numUSBFramesPerList, &theUSBIsocFrames[firstFrame], &usbCompletion[arrayIndex], 1); #else
result = thePipe->Read (soundBufferDescriptors[arrayIndex], usbFrameToQueueAt, numUSBFramesPerList, &theUSBIsocFrames[firstFrame], &usbCompletion[arrayIndex]);
#endif
usbFrameToQueueAt += numUSBFramesPerList;
Exit:
return result;
}
IOReturn AppleUSBAudioEngine::readFrameList (UInt32 frameListNum) {
const IOAudioStreamFormat * theFormat;
IOReturn result;
theFormat = mainStream->getFormat ();
result = PrepareAndReadFrameLists (theFormat->fBitWidth / 8, theFormat->fNumChannels, frameListNum);
return result;
}
#if NEWUSB
void AppleUSBAudioEngine::readHandler (void * object, void * parameter, IOReturn result, IOUSBLowLatencyIsocFrame * pFrames) {
#else
void AppleUSBAudioEngine::readHandler (void * object, void * parameter, IOReturn result, IOUSBIsocFrame * pFrames) {
#endif
AppleUSBAudioEngine * self;
#if !NEWUSB
#endif
UInt64 currentUSBFrameNumber;
UInt32 frameListToRead;
self = (AppleUSBAudioEngine *)object;
FailIf (TRUE == self->inCompletion, Exit);
self->inCompletion = TRUE;
FailIf (NULL == self->streamInterface, Exit);
if (TRUE == self->startingEngine) {
self->startingEngine = FALSE; #if 0
#if NEWUSB
time = pFrames[0].frTimeStamp;
nanoseconds_to_absolutetime (1000000, &timeOffset);
SUB_ABSOLUTETIME (&time, &timeOffset); #else
do {
a = streamInterface->GetDevice()->GetBus()->GetFrameNumber ();
clock_get_uptime (&time);
b = streamInterface->GetDevice()->GetBus()->GetFrameNumber ();
} while (a != b);
nanoseconds_to_absolutetime (((UInt32)(a - expectedBusFrame) - numUSBFramesPerList) * 1000 * 1000, &delay);
SUB_ABSOLUTETIME (&time, &delay);
nanoseconds_to_absolutetime (numUSBFramesPerList * 1000 * 1000, &frameOffset);
SUB_ABSOLUTETIME (&time, &frameOffset);
nanos = (pFrames[0].frActCount - numBytesToCopy * 1000000) / getSampleBufferSize ();
nanoseconds_to_absolutetime (nanos, &timeOffset);
ADD_ABSOLUTETIME (&time, &timeOffset); #endif
self->takeTimeStamp (FALSE, &time);
#endif
}
#if 0 // logs differences in time between completion routine calls, to use add member variable mLastTime of type AbsoluteTime
AbsoluteTime t_now;
AbsoluteTime t_old;
UInt64 nanos_del;
t_old.lo = self->mLastTime.lo;
t_old.hi = self->mLastTime.hi;
clock_get_uptime (&t_now);
self->mLastTime.lo = t_now.lo;
self->mLastTime.hi = t_now.hi;
SUB_ABSOLUTETIME (&t_now, &t_old); absolutetime_to_nanoseconds (t_now, &nanos_del);
nanos_del = nanos_del / (1000);
if (nanos_del > 3000) {
IOLog ("Read handler delta = %ld microseconds\n", (UInt32)(nanos_del));
}
#endif
if (kIOReturnSuccess != result && kIOReturnAborted != result) {
#if DEBUGLOG
IOLog ("Error 0x%X from USB read\n", result);
#endif
if (self->usbFrameToQueueAt <= currentUSBFrameNumber) {
self->usbFrameToQueueAt = currentUSBFrameNumber + kMinimumFrameOffset;
#if !NEWUSB
self->expectedBusFrame += self->usbFrameToQueueAt;
#endif
}
}
#if 1 // enabled for [3091812]
#if NEWUSB
currentUSBFrameNumber = self->streamInterface->GetDevice()->GetBus()->GetFrameNumber ();
if ((SInt32)(self->usbFrameToQueueAt - currentUSBFrameNumber) > (SInt32)(self->numUSBFramesPerList * (self->numUSBFrameListsToQueue + 1))) {
#if DEBUGLOG
IOLog ("Not queuing a frame list in readHandler\n");
#endif
goto Exit;
}
#endif
#endif
self->CoalesceInputSamples (0, pFrames);
if (self->shouldStop > 0) {
debug2IOLog("++AppleUSBAudioEngine::readHandler() - stopping: %d\n", self->shouldStop);
self->shouldStop++;
if (self->shouldStop > self->numUSBFrameListsToQueue && TRUE == self->terminatingDriver) {
self->streamInterface->close (self);
self->streamInterface = NULL;
}
} else {
if (self->currentFrameList == self->numUSBFrameLists - 1) {
self->currentFrameList = 0;
} else {
self->currentFrameList++;
}
frameListToRead = self->currentFrameList + self->numUSBFrameListsToQueue - 1;
if (frameListToRead >= self->numUSBFrameLists) {
frameListToRead -= self->numUSBFrameLists;
}
self->readFrameList (frameListToRead);
}
Exit:
self->inCompletion = FALSE;
return;
}
void AppleUSBAudioEngine::resetClipPosition (IOAudioStream *audioStream, UInt32 clipSampleFrame) {
if ((NULL != iSubBufferMemory) && (NULL != iSubEngine)) {
srcPhase = 1.0; srcState = 0.0;
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;
filterState2.xl_1 = 0.0;
filterState2.xr_1 = 0.0;
filterState2.xl_2 = 0.0;
filterState2.xr_2 = 0.0;
filterState2.yl_1 = 0.0;
filterState2.yr_1 = 0.0;
filterState2.yl_2 = 0.0;
filterState2.yr_2 = 0.0;
phaseCompState.xl_1 = 0.0;
phaseCompState.xr_1 = 0.0;
phaseCompState.xl_2 = 0.0;
phaseCompState.xr_2 = 0.0;
phaseCompState.yl_1 = 0.0;
phaseCompState.yr_1 = 0.0;
phaseCompState.yl_2 = 0.0;
phaseCompState.yr_2 = 0.0;
#if DEBUGLOG
IOLog ("+resetClipPosition, iSubBufferOffset=%ld, previousClippedToFrame=%ld, clipSampleFrame=%ld\n", iSubBufferOffset, previousClippedToFrame, clipSampleFrame);
#endif
UInt32 clipAdjustment;
if (previousClippedToFrame < clipSampleFrame) {
clipAdjustment = (previousClippedToFrame + ((getSampleBufferSize () / (2 * iSubEngine->GetNumChannels())) - clipSampleFrame)) * iSubEngine->GetNumChannels();
} else {
clipAdjustment = (previousClippedToFrame - clipSampleFrame) * iSubEngine->GetNumChannels();
}
clipAdjustment = (clipAdjustment * 1000) / ((1000 * getSampleRate()->whole) / iSubEngine->GetSampleRate());
iSubBufferOffset -= clipAdjustment;
if (iSubBufferOffset < 0) {
iSubBufferOffset += (iSubBufferMemory->getLength () / 2);
iSubLoopCount--; }
previousClippedToFrame = clipSampleFrame;
justResetClipPosition = TRUE; #if DEBUGLOG
IOLog ("-resetClipPosition, iSubBufferOffset=%ld, previousClippedToFrame=%ld\n", iSubBufferOffset, previousClippedToFrame);
#endif
}
}
void AppleUSBAudioEngine::sampleRateHandler (void * target, void * parameter, IOReturn result, IOUSBIsocFrame * pFrames) {
AppleUSBAudioEngine * self;
IOFixed sampleRate;
UInt16 fixed;
IOFixed fract;
UInt32 oldSampleRate;
UInt32 newSampleRate;
self = (AppleUSBAudioEngine *)target;
newSampleRate = *(self->aveSampleRateBuf);
sampleRate = USBToHostLong (newSampleRate);
oldSampleRate = self->averageSampleRate;
sampleRate = sampleRate << 2;
fixed = sampleRate >> 16;
newSampleRate = fixed * 1000;
fract = IOFixedMultiply (sampleRate & 0x0000FFFF, 1000 << 16);
newSampleRate += (fract & 0xFFFF0000) >> 16;
if (newSampleRate && newSampleRate != oldSampleRate) {
self->averageSampleRate = newSampleRate;
debug2IOLog ("!!!!sample rate changed, requestedFrameRate = %d\n", self->averageSampleRate);
}
if (0 == self->shouldStop) {
self->theSampleRateFrame.frStatus = -1;
self->theSampleRateFrame.frReqCount = 3;
self->theSampleRateFrame.frActCount = 0;
self->nextSynchReadFrame = self->nextSynchReadFrame + (1 << self->refreshInterval);
if (NULL != self->theAssociatedPipe) {
result = self->theAssociatedPipe->Read (self->neededSampleRate, self->nextSynchReadFrame, 1, &(self->theSampleRateFrame), &(self->sampleRateCompletion));
}
}
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;
}
IOReturn AppleUSBAudioEngine::startUSBStream () {
const IOAudioStreamFormat * theFormat;
IOReturn resultCode;
IOUSBFindEndpointRequest audioIsochEndpoint;
USBAudioConfigObject * usbAudio;
AbsoluteTime uptime;
AbsoluteTime initialTimestampOffset;
UInt32 frameListNum;
UInt32 numQueued;
UInt16 averageFrameSamples;
UInt16 additionalSampleFrameFreq;
UInt16 maxFrameSize;
debug2IOLog ("+AppleUSBAudioEngine[%p]::startUSBStream ()\n", this);
resultCode = kIOReturnError;
numQueued = 0;
currentFrameList = 0;
safeToEraseTo = 0;
lastSafeErasePoint = 0;
bufferOffset = 0;
previous = 0;
startingEngine = TRUE;
previouslyPreparedBufferOffset = 0; fractionalSamplesRemaining = 0;
shouldStop = 0;
FailIf ((numUSBFrameLists < numUSBFrameListsToQueue), Exit);
usbAudio = usbAudioDevice->GetUSBAudioConfigObject ();
FailIf (NULL == usbAudio, Exit);
FailIf (NULL == streamInterface, Exit);
resultCode = streamInterface->SetAlternateInterface (this, alternateInterfaceID);
debug3IOLog ("streamInterface->SetAlternateInterface (this, %d) = 0x%X\n", alternateInterfaceID, resultCode);
FailIf (kIOReturnSuccess != resultCode, Exit);
SetSampleRate (usbAudio, curSampleRate.whole);
audioIsochEndpoint.type = kUSBIsoc;
audioIsochEndpoint.direction = direction;
thePipe = streamInterface->FindNextPipe (NULL, &audioIsochEndpoint);
FailIf (NULL == thePipe, Exit);
thePipe->retain ();
if (getDirection () == kIOAudioStreamDirectionOutput) {
(void)CheckForAssociatedEndpoint (usbAudio);
}
CalculateSamplesPerFrame (curSampleRate.whole, &averageFrameSamples, &additionalSampleFrameFreq);
theFormat = mainStream->getFormat ();
if (kUSBIn == direction) {
if (additionalSampleFrameFreq) {
maxFrameSize = (averageFrameSamples + 2) * (theFormat->fNumChannels * (theFormat->fBitWidth / 8));
} else {
maxFrameSize = (averageFrameSamples + 1) * (theFormat->fNumChannels * (theFormat->fBitWidth / 8));
}
} else {
maxFrameSize = (averageFrameSamples + 1) * (theFormat->fNumChannels * (theFormat->fBitWidth / 8));
}
if (maxFrameSize > thePipe->GetEndpoint()->maxPacketSize) {
maxFrameSize = thePipe->GetEndpoint()->maxPacketSize;
}
resultCode = thePipe->SetPipePolicy (maxFrameSize, 0);
FailIf (kIOReturnSuccess != resultCode, Exit);
theMaxPacket = thePipe->GetEndpoint()->maxPacketSize;
FailIf (0 == theMaxPacket, Exit);
usbFrameToQueueAt = streamInterface->GetDevice()->GetBus()->GetFrameNumber() + kMinimumFrameOffset; if (NULL != theAssociatedPipe) {
nextSynchReadFrame = usbFrameToQueueAt;
(void)theAssociatedPipe->Read (neededSampleRate, nextSynchReadFrame, 1, &theSampleRateFrame, &sampleRateCompletion);
}
if (getDirection () == kIOAudioStreamDirectionInput) {
clock_get_uptime (&uptime);
nanoseconds_to_absolutetime (kMinimumFrameOffset * 1000 * 1000, &initialTimestampOffset);
ADD_ABSOLUTETIME (&uptime, &initialTimestampOffset);
takeTimeStamp (FALSE, &uptime);
#if !NEWUSB
expectedBusFrame = usbFrameToQueueAt;
#endif
for (frameListNum = 0; frameListNum < numUSBFrameListsToQueue; frameListNum++) {
readFrameList (frameListNum);
}
} else {
thePipe->Write (theStartBufferDescriptor, usbFrameToQueueAt++, 1, &theStartFrame, NULL);
takeTimeStamp (FALSE);
startingEngine = FALSE;
for (frameListNum = 0; frameListNum < numUSBFrameListsToQueue; frameListNum++) {
writeFrameList (frameListNum);
}
}
usbStreamRunning = TRUE;
resultCode = kIOReturnSuccess;
Exit:
debug2IOLog ("-AppleUSBAudioEngine[%p]::startUSBStream ()\n", this);
return resultCode;
}
IOReturn AppleUSBAudioEngine::stopUSBStream () {
debug2IOLog ("+AppleUSBAudioEngine[%p]::stopUSBStream ()\n", this);
if (NULL != streamInterface) { shouldStop = 1;
}
if (NULL != thePipe) {
thePipe->SetPipePolicy (0, 0);
thePipe->release ();
thePipe = NULL;
}
if (NULL != theAssociatedPipe) {
theAssociatedPipe->release ();
theAssociatedPipe = NULL;
}
usbStreamRunning = FALSE;
if (NULL != streamInterface) { (void)streamInterface->SetAlternateInterface (this, kRootAlternateSetting);
}
debug2IOLog ("-AppleUSBAudioEngine[%p]::stopUSBStream ()\n", this);
return kIOReturnSuccess;
}
bool AppleUSBAudioEngine::willTerminate (IOService * provider, IOOptionBits options) {
debug3IOLog ("+AppleUSBAudioEngine[%p]::willTerminate (%p)\n", this, provider);
if (iSubEngine == (AppleiSubEngine *)provider) {
debugIOLog ("iSub requesting termination\n");
iSubTeardownConnection ();
if (iSubAttach->getIntValue ()) {
iSubEngineNotifier = addNotification (gIOPublishNotification, serviceMatching ("AppleiSubEngine"), (IOServiceNotificationHandler)&iSubEnginePublished, this);
}
}
if (streamInterface == provider) {
terminatingDriver = TRUE;
if (FALSE == usbStreamRunning) {
debugIOLog ("willTerminate closing down\n");
streamInterface->close (this);
streamInterface = NULL;
} else {
debug2IOLog ("willTerminate checking shouldStop = 0x%x\n", shouldStop);
if (0 == shouldStop) {
shouldStop++;
}
}
iSubCloseAction (this, NULL, NULL, NULL, NULL);
}
debug2IOLog ("-AppleUSBAudioEngine[%p]::willTerminate\n", this);
return super::willTerminate (provider, options);
}
IOReturn AppleUSBAudioEngine::writeFrameList (UInt32 frameListNum) {
IOReturn result;
UInt32 arrayIndex;
arrayIndex = frameListNum;
result = PrepareWriteFrameList (arrayIndex);
FailIf (kIOReturnSuccess != result, Exit);
result = kIOReturnError;
FailIf (NULL == thePipe, Exit);
#if NEWUSB
result = thePipe->Write (soundBufferDescriptors[arrayIndex], usbFrameToQueueAt, numUSBFramesPerList, &theUSBIsocFrames[arrayIndex * numUSBFramesPerList], &usbCompletion[arrayIndex], 0 == usbCompletion[arrayIndex].parameter ? 0 : 1);
#else
result = thePipe->Write (soundBufferDescriptors[arrayIndex], usbFrameToQueueAt, numUSBFramesPerList, &theUSBIsocFrames[arrayIndex * numUSBFramesPerList], &usbCompletion[arrayIndex]);
#endif
FailIf (result != kIOReturnSuccess, Exit);
usbFrameToQueueAt += numUSBFramesPerList;
Exit:
return result;
}
#if NEWUSB
void AppleUSBAudioEngine::writeHandler (void * object, void * parameter, IOReturn result, IOUSBLowLatencyIsocFrame * pFrames) {
#else
void AppleUSBAudioEngine::writeHandler (void * object, void * parameter, IOReturn result, IOUSBIsocFrame * pFrames) {
#endif
AppleUSBAudioEngine * self;
AbsoluteTime time;
AbsoluteTime timeOffset;
#if !NEWUSB
AbsoluteTime delay;
AbsoluteTime tempTime;
AbsoluteTime timeOther;
UInt64 a;
UInt64 b;
#endif
UInt64 curUSBFrameNumber;
UInt64 nanos;
UInt32 frameListToWrite;
UInt32 byteOffset;
#if DEBUGZEROTIME
UInt32 ms;
AbsoluteTime diff;
#endif
#if DEBUGLOG
UInt32 i;
#endif
self = (AppleUSBAudioEngine *)object;
FailIf (TRUE == self->inCompletion, Exit);
self->inCompletion = TRUE;
FailIf (NULL == self->streamInterface, Exit);
curUSBFrameNumber = self->streamInterface->GetDevice()->GetBus()->GetFrameNumber ();
if ((SInt64)(self->usbFrameToQueueAt - curUSBFrameNumber) > (SInt32)(self->numUSBFramesPerList * (self->numUSBFrameListsToQueue / 2) + 1)) {
#if DEBUGLOG
IOLog ("Not queuing a frame list in writeHandler\n");
if (parameter) {
IOLog ("parameter = 0x%x\n", parameter);
IOLog ("0x%x%x - 0x%x%x = 0x%x\n", (UInt32)(self->usbFrameToQueueAt >> 32), (UInt32)(self->usbFrameToQueueAt), (UInt32)(curUSBFrameNumber >> 32), (UInt32)(curUSBFrameNumber), (UInt32)(self->usbFrameToQueueAt - curUSBFrameNumber));
}
#endif
goto Exit;
}
if (kIOReturnSuccess != result && kIOReturnAborted != result) {
#if DEBUGLOG
IOLog ("++AppleUSBAudioEngine[%p]::writeHandler () - error 0x%x on USB frame 0x%lx%lx\n", self, result, (UInt32)(curUSBFrameNumber >> 32), (UInt32)curUSBFrameNumber);
IOLog ("current frame list = %d\n", self->currentFrameList);
for (i = 0; i < self->numUSBFramesPerList; i++) {
if (kIOReturnSuccess != pFrames[i].frStatus) {
IOLog ("fr %d: 0x%lx ", i, pFrames[i].frStatus);
}
}
IOLog ("\n");
#endif
if (self->usbFrameToQueueAt <= curUSBFrameNumber) {
self->usbFrameToQueueAt = curUSBFrameNumber + kMinimumFrameOffset;
}
}
#if DEBUGLOG
if (self->usbFrameToQueueAt < curUSBFrameNumber) {
IOLog ("fell behind 0x%x%x < 0x%x%x\n", (UInt32)(self->usbFrameToQueueAt >> 32), (UInt32)(self->usbFrameToQueueAt), (UInt32)(curUSBFrameNumber >> 32), (UInt32)(curUSBFrameNumber));
self->usbFrameToQueueAt = curUSBFrameNumber + kMinimumFrameOffset;
}
#endif
if (0 != parameter) {
#if DEBUGZEROTIME
#endif
#if NEWUSB
byteOffset = (UInt32)parameter & 0x00FF;
time = pFrames[((UInt32)parameter >> 16) - 1].frTimeStamp;
#if DEBUGZEROTIME
IOLog ("to = %lx %lx, n = %lx\n", timeOther.hi, timeOther.lo, (UInt32)nanos);
#endif
nanos = (byteOffset * 1000000) / pFrames[((UInt32)parameter >> 16) - 1].frActCount;
#if DEBUGZEROTIME
IOLog ("so = %ld, n = %lx\n", byteOffset, (UInt32)nanos);
#endif
nanoseconds_to_absolutetime (nanos, &timeOffset);
SUB_ABSOLUTETIME (&time, &timeOffset); #else
byteOffset = (UInt32)parameter & 0x00FF;
do {
a = self->streamInterface->GetDevice()->GetBus()->GetFrameNumber ();
clock_get_uptime (&time);
b = self->streamInterface->GetDevice()->GetBus()->GetFrameNumber ();
} while (a != b);
nanoseconds_to_absolutetime ((a - self->expectedBusFrame) * 1000 * 1000, &delay);
SUB_ABSOLUTETIME (&time, &delay);
tempTime = time;
timeOther.hi = self->status->fLastLoopTime.hi;
timeOther.lo = self->status->fLastLoopTime.lo;
SUB_ABSOLUTETIME (&tempTime, &timeOther);
absolutetime_to_nanoseconds (tempTime, &nanos);
nanos = (byteOffset * nanos) / self->getSampleBufferSize ();
nanoseconds_to_absolutetime (nanos, &timeOffset);
SUB_ABSOLUTETIME (&time, &timeOffset); #endif
#if DEBUGZEROTIME
diff = time;
SUB_ABSOLUTETIME (&diff, &self->status->fLastLoopTime); absolutetime_to_nanoseconds (diff, &nanos);
ms = nanos / (1000 * 1000);
if (ms > 280 || ms < 275) {
IOLog ("%ldms, parameter=0x%x\n", ms, parameter);
IOLog ("last loop = 0x%x%x, now = 0x%x%x, e=0x%x%x c=0x%x%x, delay=0x%x%x\n", self->status->fLastLoopTime.hi, self->status->fLastLoopTime.lo, time.hi, time.lo, (UInt32)(self->expectedBusFrame >> 32), (UInt32)(self->expectedBusFrame), (UInt32)(curUSBFrameNumber >> 32), (UInt32)(curUSBFrameNumber), delay.hi, delay.lo);
}
#if NEWUSB
if (ms < 277 || ms > 279) {
if (((UInt32)parameter >> 16) == self->numUSBFramesPerList) {
IOLog ("bad delta %lx %lx, %lx %lx\n", pFrames[(UInt32)parameter >> 16 - 2].frTimeStamp, pFrames[(UInt32)parameter >> 16 - 1].frTimeStamp);
} else {
IOLog ("bad delta %lx %lx, %lx %lx\n", pFrames[(UInt32)parameter >> 16 - 1].frTimeStamp, pFrames[(UInt32)parameter >> 16].frTimeStamp);
}
}
#endif
#endif
self->takeTimeStamp (TRUE, &time);
}
if (self->currentFrameList == self->numUSBFrameLists - 1) {
self->currentFrameList = 0;
} else {
self->currentFrameList++;
}
if (self->shouldStop > 0) {
debug2IOLog ("++AppleUSBAudioEngine::writeHandler() - stopping: %d\n", self->shouldStop);
self->shouldStop++;
if (self->shouldStop > self->numUSBFrameListsToQueue && TRUE == self->terminatingDriver) {
self->streamInterface->close (self);
self->streamInterface = NULL;
}
} else {
frameListToWrite = self->currentFrameList + self->numUSBFrameListsToQueue - 1;
if (frameListToWrite >= self->numUSBFrameLists) {
frameListToWrite -= self->numUSBFrameLists;
}
self->writeFrameList (frameListToWrite);
}
Exit:
self->inCompletion = FALSE;
return;
}
Generated by GNU enscript 1.6.4.