[plain text]
#define DEBUGZEROTIME FALSE
#define DEBUGUSB FALSE
#define DEBUGISUB FALSE
#define DEBUGLOADING FALSE
#include "AppleUSBAudioEngine.h"
#include "AppleUSBAudioPlugin.h"
#define super IOAudioEngine
OSDefineMetaClassAndStructors(AppleUSBAudioEngine, IOAudioEngine)
#pragma mark -IOKit Routines-
void AppleUSBAudioEngine::free () {
UInt32 i;
debugIOLog ("+AppleUSBAudioEngine[%p]::free ()", this);
if (NULL != startTimer) {
startTimer->cancelTimeout ();
startTimer->release ();
startTimer = NULL;
}
if (neededSampleRateDescriptor) {
neededSampleRateDescriptor->release ();
neededSampleRateDescriptor = NULL;
}
if (aveSampleRateBuf) {
IOFree (aveSampleRateBuf, 4);
aveSampleRateBuf = NULL;
}
if (signal) {
signal->release ();
}
if (mUSBBufferDescriptor) {
mUSBBufferDescriptor->release ();
mUSBBufferDescriptor = NULL;
}
if (theWrapRangeDescriptor) {
theWrapRangeDescriptor->release ();
theWrapDescriptors[0]->release ();
theWrapDescriptors[1]->release ();
theWrapRangeDescriptor = NULL;
}
if (sampleBufferMemoryDescriptor) {
sampleBufferMemoryDescriptor->release ();
sampleBufferMemoryDescriptor = NULL;
}
if (streamNotifier) {
streamNotifier->remove ();
streamNotifier = 0;
}
if (NULL != soundBufferDescriptors) {
for (i = 0; i < numUSBFrameLists; i++) {
if (NULL != soundBufferDescriptors[i]) {
soundBufferDescriptors[i]->release ();
soundBufferDescriptors[i] = NULL;
}
}
IOFree (soundBufferDescriptors, numUSBFrameLists * sizeof (IOSubMemoryDescriptor *));
soundBufferDescriptors = NULL;
}
if (NULL != theUSBIsocFrames) {
IOFree (theUSBIsocFrames, numUSBFrameLists * numUSBFramesPerList * sizeof (IOUSBLowLatencyIsocFrame));
theUSBIsocFrames = NULL;
}
if (NULL != usbCompletion) {
IOFree (usbCompletion, numUSBFrameLists * sizeof (IOUSBLowLatencyIsocCompletion));
usbCompletion = NULL;
}
if (NULL != getSampleBuffer ()) {
IOFree (getSampleBuffer (), getSampleBufferSize ());
}
if (NULL != lowFreqSamples) {
IOFreeAligned (lowFreqSamples, getSampleBufferSize () * 2);
}
if (NULL != highFreqSamples) {
IOFreeAligned (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 ();
debugIOLog ("-AppleUSBAudioEngine[%p]::free()", this);
}
bool AppleUSBAudioEngine::init (OSDictionary *properties) {
Boolean result;
debugIOLog("+AppleUSBAudioEngine[%p]::init ()", 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:
debugIOLog("-AppleUSBAudioEngine[%p]::init ()", this);
return result;
}
bool AppleUSBAudioEngine::requestTerminate (IOService * provider, IOOptionBits options) {
bool result;
debugIOLog ("+AppleUSBAudioEngine[%p]::requestTerminate (%p, %x)", this, provider, options);
if (usbAudioDevice == provider || streamInterface == provider) {
result = TRUE; } else {
result = FALSE; }
debugIOLog ("-AppleUSBAudioEngine[%p]::requestTerminate (%p, %x)", this, provider, options);
return result;
}
bool AppleUSBAudioEngine::start (IOService * provider) {
IONotifier * audioDeviceNotifier;
bool resultCode;
USBAudioConfigObject * usbAudio;
debugIOLog ("+AppleUSBAudioEngine[%p]::start (%p)", this, provider);
resultCode = FALSE;
streamInterface = OSDynamicCast (IOUSBInterface, provider);
FailIf (NULL == streamInterface, Exit);
ourInterfaceNumber = streamInterface->GetInterfaceNumber ();
debugIOLog ("ourInterfaceNumber = %d", ourInterfaceNumber);
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);
debugIOLog ("-%d = AppleUSBAudioEngine[%p]::start (%p)", resultCode, this, provider);
Exit:
return resultCode;
}
void AppleUSBAudioEngine::stop (IOService * provider) {
debugIOLog("+AppleUSBAudioEngine[%p]::stop (%p)", this, provider);
if (provider == iSubEngine) {
goto Exit;
}
if (NULL != mPluginNotification) {
mPluginNotification->remove ();
mPluginNotification = NULL;
}
if (NULL != iSubEngineNotifier) {
iSubEngineNotifier->remove ();
iSubEngineNotifier = NULL;
}
if (mPlugin) {
mPlugin->close (this);
mPlugin = NULL;
}
if (NULL != iSubEngine) {
iSubTeardownConnection ();
}
if (usbAudioDevice) {
usbAudioDevice->release ();
usbAudioDevice = NULL;
}
if (thePipe) {
thePipe->release ();
thePipe = NULL;
}
if (theAssociatedPipe) {
theAssociatedPipe->release ();
theAssociatedPipe = NULL;
}
if (streamInterface) {
streamInterface->close (this);
streamInterface = NULL;
}
Exit:
super::stop (provider);
debugIOLog ("-AppleUSBAudioEngine[%p]::stop (%p) - rc=%ld", this, provider, getRetainCount());
}
bool AppleUSBAudioEngine::terminate (IOOptionBits options) {
bool shouldTerminate;
bool result;
result = TRUE;
shouldTerminate = TRUE;
debugIOLog ("+AppleUSBAudioEngine[%p]::terminate ()", this);
if (shouldTerminate) {
result = super::terminate (options);
}
debugIOLog ("-AppleUSBAudioEngine[%p]::terminate ()", this);
return result;
}
#pragma mark -USB Audio driver-
IOReturn AppleUSBAudioEngine::AddAvailableFormatsFromDevice (USBAudioConfigObject *usbAudio) {
IOAudioStreamFormat streamFormat;
IOAudioStreamFormatExtension streamFormatExtension;
IOAudioSampleRate lowSampleRate;
IOAudioSampleRate highSampleRate;
UInt32 * sampleRates;
IOReturn result;
UInt16 numAltInterfaces;
UInt8 numSampleRates;
UInt8 altSettingIndx;
UInt8 rateIndx;
UInt8 candidateAC3AltSetting;
Boolean hasNativeAC3Format;
Boolean hasDigitalOutput;
result = kIOReturnError;
FailIf (NULL == usbAudio, Exit);
FailIf (NULL == mainStream, Exit);
numAltInterfaces = usbAudio->GetNumAltStreamInterfaces (ourInterfaceNumber);
debugIOLog ("There are %d alternate stream interfaces on interface %d", numAltInterfaces, ourInterfaceNumber);
hasNativeAC3Format = FALSE;
candidateAC3AltSetting = 0;
for (altSettingIndx = 1; altSettingIndx < numAltInterfaces; altSettingIndx++) {
numSampleRates = usbAudio->GetNumSampleRates (ourInterfaceNumber, altSettingIndx);
sampleRates = usbAudio->GetSampleRates (ourInterfaceNumber, altSettingIndx);
streamFormat.fNumChannels = usbAudio->GetNumChannels (ourInterfaceNumber, altSettingIndx);
streamFormat.fBitDepth = usbAudio->GetSampleSize (ourInterfaceNumber, altSettingIndx);
streamFormat.fBitWidth = usbAudio->GetSubframeSize (ourInterfaceNumber, altSettingIndx) * 8;
streamFormat.fAlignment = kIOAudioStreamAlignmentLowByte;
streamFormat.fByteOrder = kIOAudioStreamByteOrderLittleEndian;
streamFormat.fDriverTag = (ourInterfaceNumber << 16) | altSettingIndx;
streamFormatExtension.fVersion = kFormatExtensionCurrentVersion;
streamFormatExtension.fFlags = 0;
streamFormatExtension.fFramesPerPacket = 1;
streamFormatExtension.fBytesPerPacket = usbAudio->GetNumChannels (ourInterfaceNumber, altSettingIndx) * usbAudio->GetSubframeSize (ourInterfaceNumber, altSettingIndx);
switch (usbAudio->GetFormat (ourInterfaceNumber, altSettingIndx)) {
case PCM:
streamFormat.fSampleFormat = kIOAudioStreamSampleFormatLinearPCM;
streamFormat.fNumericRepresentation = kIOAudioStreamNumericRepresentationSignedInt;
streamFormat.fIsMixable = TRUE;
if (2 == streamFormat.fNumChannels && 16 == streamFormat.fBitDepth && 16 == streamFormat.fBitWidth) {
candidateAC3AltSetting = altSettingIndx;
}
break;
case AC3: debugIOLog ("variable bit rate AC-3 audio format type!");
continue; 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, altSettingIndx));
streamFormatExtension.fFramesPerPacket = 1536;
streamFormatExtension.fBytesPerPacket = streamFormatExtension.fFramesPerPacket * streamFormat.fNumChannels * usbAudio->GetSubframeSize (ourInterfaceNumber, altSettingIndx);
break;
case IEC1937_AC3:
debugIOLog ("IEC1937 AC-3 audio format type!");
hasNativeAC3Format = TRUE;
streamFormat.fSampleFormat = kIOAudioStreamSampleFormat1937AC3;
streamFormat.fNumericRepresentation = kIOAudioStreamNumericRepresentationSignedInt;
streamFormat.fIsMixable = FALSE;
streamFormatExtension.fFramesPerPacket = 1536;
streamFormatExtension.fBytesPerPacket = streamFormatExtension.fFramesPerPacket * streamFormat.fNumChannels * usbAudio->GetSubframeSize (ourInterfaceNumber, altSettingIndx);
break;
default:
debugIOLog ("interface format = %x", usbAudio->GetFormat (ourInterfaceNumber, altSettingIndx));
debugIOLog ("interface doesn't support a format that we can deal with, so we're not making it available");
continue; }
debugIOLog ("Interface %d, Alt %d has a ", ourInterfaceNumber, altSettingIndx);
debugIOLog ("%d bit interface, ", streamFormat.fBitDepth);
debugIOLog ("%d channels, and ", streamFormat.fNumChannels);
debugIOLog ("%d sample rates, which are:", numSampleRates);
if (numSampleRates) {
for (rateIndx = 0; rateIndx < numSampleRates; rateIndx++) {
debugIOLog (" %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);
streamFormat.fIsMixable = TRUE; }
}
debugIOLog ("");
} else if (sampleRates) {
debugIOLog (" %d to %d", 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, &highSampleRate);
}
}
}
switch (usbAudio->GetOutputTerminalType (usbAudioDevice->mControlInterface->GetInterfaceNumber (), 0, altSettingIndx)) {
case EXTERNAL_DIGITAL_AUDIO_INTERFACE:
case EXTERNAL_SPDIF_INTERFACE:
case EMBEDDED_DVD_AUDIO:
hasDigitalOutput = TRUE;
break;
default:
hasDigitalOutput = FALSE;
}
if (TRUE == hasDigitalOutput && FALSE == hasNativeAC3Format && 0 != candidateAC3AltSetting && kIOAudioStreamDirectionOutput == getDirection ()) {
numSampleRates = usbAudio->GetNumSampleRates (ourInterfaceNumber, candidateAC3AltSetting);
sampleRates = usbAudio->GetSampleRates (ourInterfaceNumber, candidateAC3AltSetting);
streamFormat.fNumChannels = usbAudio->GetNumChannels (ourInterfaceNumber, candidateAC3AltSetting);
streamFormat.fBitDepth = usbAudio->GetSampleSize (ourInterfaceNumber, candidateAC3AltSetting);
streamFormat.fBitWidth = usbAudio->GetSubframeSize (ourInterfaceNumber, candidateAC3AltSetting) * 8;
streamFormat.fAlignment = kIOAudioStreamAlignmentLowByte;
streamFormat.fByteOrder = kIOAudioStreamByteOrderLittleEndian;
streamFormat.fDriverTag = (ourInterfaceNumber << 16) | candidateAC3AltSetting;
streamFormat.fSampleFormat = kIOAudioStreamSampleFormat1937AC3;
streamFormat.fNumericRepresentation = kIOAudioStreamNumericRepresentationSignedInt;
streamFormat.fIsMixable = FALSE;
streamFormatExtension.fVersion = kFormatExtensionCurrentVersion;
streamFormatExtension.fFlags = 0;
streamFormatExtension.fFramesPerPacket = 1536;
streamFormatExtension.fBytesPerPacket = streamFormatExtension.fFramesPerPacket * streamFormat.fNumChannels * usbAudio->GetSubframeSize (ourInterfaceNumber, candidateAC3AltSetting);
if (numSampleRates) {
for (rateIndx = 0; rateIndx < numSampleRates; rateIndx++) {
lowSampleRate.whole = sampleRates[rateIndx];
lowSampleRate.fraction = 0;
mainStream->addAvailableFormat (&streamFormat, &streamFormatExtension, &lowSampleRate, &lowSampleRate);
}
} else if (sampleRates) {
lowSampleRate.whole = sampleRates[0];
lowSampleRate.fraction = 0;
highSampleRate.whole = sampleRates[1];
highSampleRate.fraction = 0;
mainStream->addAvailableFormat (&streamFormat, &streamFormatExtension, &lowSampleRate, &highSampleRate);
}
}
result = kIOReturnSuccess;
Exit:
return result;
}
bool AppleUSBAudioEngine::audioDevicePublished (AppleUSBAudioEngine * audioEngine, void * ref, IOService * newService) {
AppleUSBAudioDevice * audioDevice;
IOUSBInterface * thisControlInterface;
IOUSBInterface * thisStreamInterface;
bool resultCode;
debugIOLog ("+AppleUSBAudioEngine::audioDevicePublished (%p, %p, %p)", 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 ()) {
if (audioDevice->ControlsStreamNumber (audioEngine->ourInterfaceNumber)) {
debugIOLog ("++AppleUSBAudioEngine[%p]: found device (%p) for Audio Engine (%p)", audioEngine, audioDevice, audioEngine);
audioEngine->usbAudioDevice = audioDevice;
audioEngine->signal->signal (kIOReturnSuccess, FALSE);
resultCode = TRUE; }
}
Exit:
debugIOLog ("-AppleUSBAudioEngine::audioDevicePublished (%p, %p, %p)", 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, alternateSettingID, direction);
syncType = usbAudio->GetIsocEndpointSyncType (ourInterfaceNumber, alternateSettingID, address);
if (kAsynchSyncType == syncType) {
debugIOLog ("checking endpoint %d for an associated endpoint", address);
assocEndpoint = usbAudio->GetIsocAssociatedEndpointAddress (ourInterfaceNumber, alternateSettingID, address);
if (assocEndpoint != 0) {
debugIOLog ("This endpoint has an associated synch endpoint!");
refreshInterval = usbAudio->GetIsocAssociatedEndpointRefreshInt (ourInterfaceNumber, alternateSettingID, assocEndpoint);
debugIOLog ("The refresh interval is %d", refreshInterval);
framesUntilRefresh = 1 << refreshInterval; if (framesUntilRefresh < numUSBFramesPerList) {
debugIOLog ("Need to adjust numUSBFramesPerList, %ld < %ld", framesUntilRefresh, numUSBFramesPerList);
if (NULL != theUSBIsocFrames) {
debugIOLog ("Disposing of current theUSBIsocFrames [%p]", theUSBIsocFrames);
IOFree (theUSBIsocFrames, numUSBFrameLists * numUSBFramesPerList * sizeof (IOUSBLowLatencyIsocFrame));
theUSBIsocFrames = NULL;
}
numUSBFramesPerList = framesUntilRefresh; theUSBIsocFrames = (IOUSBLowLatencyIsocFrame *)IOMalloc (numUSBFrameLists * numUSBFramesPerList * sizeof (IOUSBLowLatencyIsocFrame));
debugIOLog ("theUSBIsocFrames is now %p", theUSBIsocFrames);
FailIf (NULL == theUSBIsocFrames, Exit);
}
associatedEndpoint.type = kUSBIsoc;
associatedEndpoint.direction = kUSBIn; associatedEndpoint.maxPacketSize = 3; associatedEndpoint.interval = 0xFF; theAssociatedPipe = streamInterface->FindNextPipe (NULL, &associatedEndpoint);
FailWithAction (NULL == theAssociatedPipe, result = kIOReturnError, Exit);
if (NULL == neededSampleRateDescriptor) {
aveSampleRateBuf = (UInt32 *)IOMalloc (sizeof (UInt32));
FailIf (NULL == aveSampleRateBuf, Exit);
bzero (aveSampleRateBuf, 4);
neededSampleRateDescriptor = IOMemoryDescriptor::withAddress (aveSampleRateBuf, 4, kIODirectionIn);
FailIf (NULL == neededSampleRateDescriptor, 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!");
}
} else {
debugIOLog ("This endpoint does not have an associated synch endpoint");
}
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) {
debugIOLog ("queue a write from clipOutputSamples: framesLeftInQueue = %ld", (UInt32)framesLeftInQueue);
writeHandler (this, usbCompletion[currentFrameList].parameter, kIOReturnSuccess, &theUSBIsocFrames[currentFrameList * numUSBFramesPerList]);
}
}
#if 0
#if DEBUGLOGGING
UInt32 currentLocation = getCurrentSampleFrame ();
if (firstSampleFrame <= currentLocation && (firstSampleFrame + numSampleFrames) > currentLocation) {
debugIOLog ("!!!!!!!!!!Buffer problems!!!!!!!!!");
debugIOLog ("currentLocation = 0x%lX, firstSampleFrame = 0x%lX, numSampleFrames = 0x%lX", currentLocation, firstSampleFrame, numSampleFrames);
} else if (((currentLocation + 96) - firstSampleFrame) < numSampleFrames) {
debugIOLog("!!!!!! Possible buffer problem !!!!!!");
debugIOLog ("currentLocation = 0x%lX, firstSampleFrame = 0x%lX, numSampleFrames = 0x%lX", currentLocation, firstSampleFrame, numSampleFrames);
debugIOLog ("overlap = 0x%X [%d]", (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 DEBUGISUB
debugIOLog ("****iSub is in front of write head iSubBufferOffset = %ld, iSubEngine->GetCurrentByteCount () / 2 = %ld", iSubBufferOffset, iSubEngine->GetCurrentByteCount () / 2);
#endif
needToSync = TRUE;
startiSub = TRUE;
} else if (iSubLoopCount > (iSubEngine->GetCurrentLoopCount () + 1)) {
#if DEBUGISUB
debugIOLog ("****looped more than the iSub iSubLoopCount = %ld, iSubEngine->GetCurrentLoopCount () = %ld", iSubLoopCount, iSubEngine->GetCurrentLoopCount ());
#endif
needToSync = TRUE;
startiSub = TRUE;
} else if (iSubLoopCount < iSubEngine->GetCurrentLoopCount ()) {
#if DEBUGISUB
debugIOLog ("****iSub is ahead of us iSubLoopCount = %ld, iSubEngine->GetCurrentLoopCount () = %ld", 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 DEBUGISUB
debugIOLog ("****iSub is too far behind write head iSubBufferOffset = %ld, (iSubEngine->GetCurrentByteCount () / 2 + iSubBufferLen) = %ld", iSubBufferOffset, (iSubEngine->GetCurrentByteCount() / 2 + iSubBufferLen));
#endif
needToSync = TRUE;
startiSub = TRUE;
}
}
if (FALSE == needToSync && previousClippedToFrame != firstSampleFrame && !(previousClippedToFrame == getNumSampleFramesPerBuffer () && firstSampleFrame == 0)) {
#if DEBUGISUB
debugIOLog ("iSubBufferOffset was %ld", 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 DEBUGISUB
debugIOLog ("clip to point was %ld, now %ld (delta = %ld)", previousClippedToFrame, firstSampleFrame, offsetDelta);
debugIOLog ("iSubBufferOffset is now %ld", iSubBufferOffset);
#endif
if (iSubBufferOffset > (SInt32)iSubBufferLen) {
iSubLoopCount += iSubBufferOffset / iSubBufferLen;
iSubBufferOffset = iSubBufferOffset % iSubBufferLen;
#if DEBUGISUB
debugIOLog ("iSubBufferOffset > iSubBufferLen, iSubBufferOffset is now %ld", iSubBufferOffset);
#endif
} else if (iSubBufferOffset < 0) {
iSubBufferOffset += iSubBufferLen;
#if DEBUGISUB
debugIOLog ("iSubBufferOffset < 0, iSubBufferOffset is now %ld", iSubBufferOffset);
#endif
}
}
if (TRUE == justResetClipPosition) {
justResetClipPosition = FALSE;
needToSync = FALSE;
startiSub = FALSE;
}
if ((TRUE == needToSync) || (iSubEngine->GetNeedToSync())) {
needToSync = FALSE;
iSubEngine->SetNeedToSync(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 DEBUGISUB
debugIOLog ("USBEngine: need sync: starting iSubBufferOffset = %ld, iSubLoopCount = %ld", iSubBufferOffset, iSubLoopCount);
#endif
}
if (iSubBufferOffset > (SInt32)iSubBufferLen) {
needToSync = TRUE;
iSubLoopCount += iSubBufferOffset / iSubBufferLen;
iSubBufferOffset = iSubBufferOffset % iSubBufferLen;
#if DEBUGISUB
debugIOLog ("iSubBufferOffset > iSubBufferLen, iSubBufferOffset is now %ld", iSubBufferOffset);
#endif
} else if (iSubBufferOffset < 0) {
iSubBufferOffset += iSubBufferLen;
#if DEBUGISUB
debugIOLog ("iSubBufferOffset < 0, iSubBufferOffset is now %ld", iSubBufferOffset);
#endif
}
if (mPlugin) {
mPlugin->pluginProcess ((Float32*)mixBuf + (firstSampleFrame * streamFormat->fNumChannels), numSampleFrames, streamFormat->fNumChannels);
}
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 {
if (mPlugin) {
mPlugin->pluginProcess ((Float32*)mixBuf + (firstSampleFrame * streamFormat->fNumChannels), numSampleFrames, streamFormat->fNumChannels);
}
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;
}
void AppleUSBAudioEngine::CoalesceInputSamples (UInt32 numBytesToCoalesce, IOUSBLowLatencyIsocFrame * pFrames) {
#if DEBUGZEROTIME
AbsoluteTime timeNow;
#endif
AbsoluteTime time;
AbsoluteTime timeOffset;
UInt64 nanos;
UInt32 usbFrameIndex;
UInt32 numFramesChecked;
UInt32 numBytesToCopy;
UInt32 numBytesToEnd;
UInt32 numBytesCopied;
UInt32 originalBufferOffset;
SInt32 numBytesLeft;
UInt8 * source;
UInt8 * dest;
Boolean done;
#if DEBUGUSB
#endif
originalBufferOffset = 0;
if (0 != numBytesToCoalesce) {
originalBufferOffset = bufferOffset; debugIOLog ("coalesce from %ld %ld bytes", originalBufferOffset, numBytesToCoalesce);
debugIOLog ("%ld %ld", currentFrameList, numBytesToCoalesce);
}
if (NULL == pFrames) {
pFrames = &theUSBIsocFrames[currentFrameList * numUSBFramesPerList];
}
dest = (UInt8 *)getSampleBuffer () + bufferOffset;
source = (UInt8 *)readBuffer + (currentFrameList * readUSBFrameListSize);
usbFrameIndex = 0;
numFramesChecked = 0;
numBytesCopied = 0;
numBytesLeft = numBytesToCoalesce;
done = FALSE;
while (FALSE == done && 'llit' != pFrames[usbFrameIndex].frStatus) {
#if DEBUGUSB
if (pFrames[usbFrameIndex].frActCount < (pFrames[usbFrameIndex].frReqCount - bytesPerSampleFrame)) {
debugIOLog ("ERROR! short read packet %d req = %d", pFrames[usbFrameIndex].frActCount, pFrames[usbFrameIndex].frReqCount);
}
if (kIOReturnSuccess != pFrames[usbFrameIndex].frStatus && kIOReturnUnderrun != pFrames[usbFrameIndex].frStatus) {
debugIOLog ("Err:0x%lx req:%ld, act:%ld", pFrames[usbFrameIndex].frStatus, pFrames[usbFrameIndex].frReqCount, pFrames[usbFrameIndex].frActCount);
}
#endif
numBytesToEnd = getSampleBufferSize () - bufferOffset;
if ((UInt32)(pFrames[usbFrameIndex].frActCount) > numBytesToEnd) {
numBytesToCopy = numBytesToEnd;
} else {
numBytesToCopy = pFrames[usbFrameIndex].frActCount;
#if !DEBUGUSB
if (0 == numBytesToCoalesce) {
pFrames[usbFrameIndex].frActCount = 0;
}
#endif
}
#if DEBUGUSB
memcpy (dest, source, numBytesToCopy);
if ((UInt32)(pFrames[usbFrameIndex].frActCount) <= numBytesToEnd) {
if (0 == numBytesToCoalesce) {
pFrames[usbFrameIndex].frActCount = 0;
}
}
#else
memcpy (dest, source, numBytesToCopy);
#endif
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) {
time = pFrames[usbFrameIndex].frTimeStamp;
nanos = (numBytesToCopy * 1000000) / pFrames[usbFrameIndex].frActCount;
pFrames[usbFrameIndex].frActCount = 0;
nanoseconds_to_absolutetime (nanos, &timeOffset);
SUB_ABSOLUTETIME (&time, &timeOffset); #if DEBUGZEROTIME
timeNow = time;
SUB_ABSOLUTETIME (&timeNow, &status->fLastLoopTime);
absolutetime_to_nanoseconds (timeNow, &nanos);
debugIOLog ("d=%ld", (UInt32)(nanos / (1000 * 1000)));
#endif
takeTimeStamp (TRUE, &time);
}
}
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 * numUSBFrameLists)))) { done = TRUE;
}
}
#if DEBUGUSB
if (0 != numBytesToCoalesce && numBytesLeft > 0) {
debugIOLog ("!!!!Not enough data yet!!!!");
} else {
debugIOLog ("did %ld bytes", numBytesToCoalesce - numBytesLeft);
}
#endif
if (0 != numBytesToCoalesce) {
bufferOffset = originalBufferOffset;
}
return;
}
IOReturn AppleUSBAudioEngine::convertInputSamples (const void *sampleBuf,
void *destBuf,
UInt32 firstSampleFrame,
UInt32 numSampleFrames,
const IOAudioStreamFormat *streamFormat,
IOAudioStream *audioStream) {
UInt64 curUSBFrameNumber;
SInt64 framesLeftInQueue;
UInt32 lastSampleByte;
UInt32 windowStartByte;
UInt32 windowEndByte;
IOReturn result;
#if DEBUGLOGGING
#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)) {
debugIOLog ("input error - samples not input yet! (%lx, %lx, curr = %lx)", firstSampleFrame, numSampleFrames, currentSampleFrame);
}
} else {
if ((currentSampleFrame > firstSampleFrame) || (currentSampleFrame < lastSampleFrame)) {
debugIOLog ("input error - samples not input yet! (%lx, %lx, curr = %lx)", firstSampleFrame, numSampleFrames, currentSampleFrame);
}
}
#endif
#endif
#if 1 // enabled for [3091812]
if (0 == shouldStop && TRUE != inCompletion) {
curUSBFrameNumber = streamInterface->GetDevice()->GetBus()->GetFrameNumber ();
framesLeftInQueue = usbFrameToQueueAt - curUSBFrameNumber;
if (framesLeftInQueue < (numUSBFramesPerList * (numUSBFrameListsToQueue / 2)) / 2) {
while (framesLeftInQueue < numUSBFramesPerList * (numUSBFrameListsToQueue - 1) && 0 == shouldStop) {
#if DEBUGLOADING
debugIOLog ("queue a read from convertInputSamples: framesLeftInQueue = %ld", (UInt32)framesLeftInQueue);
#endif
readHandler (this, usbCompletion[currentFrameList].parameter, kIOReturnSuccess, &theUSBIsocFrames[currentFrameList * numUSBFramesPerList]);
curUSBFrameNumber = streamInterface->GetDevice()->GetBus()->GetFrameNumber ();
framesLeftInQueue = usbFrameToQueueAt - curUSBFrameNumber;
}
}
}
#endif
#if 1 // enabled for [3091812]
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)) {
debugIOLog ("%ld, %ld, %ld, %ld, %ld, %ld, %ld", firstSampleFrame * 4, numSampleFrames, lastSampleByte, currentFrameList, bufferOffset, windowStartByte, windowEndByte);
if (bufferOffset < lastSampleByte) {
CoalesceInputSamples (lastSampleByte - bufferOffset, NULL);
#if DEBUGLOADING
debugIOLog ("Coalesce from convert %d bytes", lastSampleByte - bufferOffset);
#endif
} else {
UInt32 numBytesToCoalesce = getSampleBufferSize () - bufferOffset + lastSampleByte;
CoalesceInputSamples (numBytesToCoalesce, NULL);
#if DEBUGLOADING
debugIOLog ("Coalesce from convert %d bytes (wrapping)", numBytesToCoalesce);
#endif
}
}
#endif
result = convertFromAppleUSBAudioInputStream_NoWrap (sampleBuf, destBuf, firstSampleFrame, numSampleFrames, streamFormat);
if (mPlugin) {
mPlugin->pluginProcessInput ((float *)destBuf + (firstSampleFrame * streamFormat->fNumChannels), numSampleFrames, streamFormat->fNumChannels);
}
return result;
}
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 // DEBUGLOGGING
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;
}
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 ();
stringIndex = 0;
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 {
debugIOLog ("device has a serial number = %s", 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);
debugIOLog ("getGlobalUniqueID = %s", 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) {
char vendorIDCString[7];
char productIDCString[7];
USBAudioConfigObject * usbAudio;
IOAudioStreamFormat streamFormat;
IOReturn resultCode;
Boolean resultBool;
UInt32 index;
UInt16 terminalType;
debugIOLog ("+AppleUSBAudioEngine[%p]::initHardware (%p)", this, provider);
resultBool = FALSE;
terminatingDriver = FALSE;
FailIf (FALSE == super::initHardware (provider), Exit);
streamInterface = OSDynamicCast (IOUSBInterface, provider);
FailIf (NULL == streamInterface, Exit);
usbAudio = usbAudioDevice->GetUSBAudioConfigObject ();
FailIf (NULL == usbAudio, Exit);
mainStream = new IOAudioStream;
FailIf (NULL == mainStream, Exit);
sampleRate.whole = kDefaultSamplingRate;
sampleRate.fraction = 0;
alternateSettingID = usbAudio->FindAltInterfaceWithSettings (ourInterfaceNumber, kChannelDepth_STEREO, kBitDepth_16bits, sampleRate.whole);
if (255 == alternateSettingID) {
alternateSettingID = usbAudio->FindAltInterfaceWithSettings (ourInterfaceNumber, kChannelDepth_MONO, kBitDepth_16bits, sampleRate.whole);
}
if (255 == alternateSettingID) {
alternateSettingID = usbAudio->FindAltInterfaceWithSettings (ourInterfaceNumber, kChannelDepth_STEREO, kBitDepth_16bits);
sampleRate.whole = usbAudio->GetHighestSampleRate (ourInterfaceNumber, alternateSettingID); }
if (255 == alternateSettingID) {
alternateSettingID = usbAudio->FindAltInterfaceWithSettings (ourInterfaceNumber, kChannelDepth_MONO, kBitDepth_16bits);
sampleRate.whole = usbAudio->GetHighestSampleRate (ourInterfaceNumber, alternateSettingID); }
if (255 == alternateSettingID) {
alternateSettingID = 1;
sampleRate.whole = usbAudio->GetHighestSampleRate (ourInterfaceNumber, alternateSettingID);
}
debugIOLog ("default sample rate is %d", sampleRate.whole);
debugIOLog ("starting with alternateSettingID of %d", alternateSettingID);
FailIf (0 == sampleRate.whole, Exit);
direction = usbAudio->GetIsocEndpointDirection (ourInterfaceNumber, alternateSettingID);
FailIf (!mainStream->initWithAudioEngine (this, (IOAudioStreamDirection)direction, 1), Exit);
if (kUSBIn == direction) {
debugIOLog ("This is an input type endpoint (mic, etc.)");
index = 0;
do {
terminalType = usbAudio->GetIndexedInputTerminalType (usbAudioDevice->mControlInterface->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.)");
index = 0;
do {
terminalType = usbAudio->GetIndexedOutputTerminalType (usbAudioDevice->mControlInterface->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!", Exit);
}
mainStream->setTerminalType (terminalType);
theUSBIsocFrames = (IOUSBLowLatencyIsocFrame *)IOMalloc (numUSBFrameLists * numUSBFramesPerList * sizeof (IOUSBLowLatencyIsocFrame));
usbCompletion = (IOUSBLowLatencyIsocCompletion *)IOMalloc (numUSBFrameLists * sizeof (IOUSBLowLatencyIsocCompletion));
soundBufferDescriptors = (IOSubMemoryDescriptor **)IOMalloc (numUSBFrameLists * sizeof (IOSubMemoryDescriptor *));
bzero (soundBufferDescriptors, numUSBFrameLists * sizeof (IOSubMemoryDescriptor *));
theWrapDescriptors[0] = OSTypeAlloc (IOSubMemoryDescriptor);
theWrapDescriptors[1] = OSTypeAlloc (IOSubMemoryDescriptor);
FailIf (NULL == theWrapDescriptors[0], Exit);
FailIf (NULL == theWrapDescriptors[1], Exit);
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, alternateSettingID);
streamFormat.fBitDepth = usbAudio->GetSampleSize (ourInterfaceNumber, alternateSettingID);
streamFormat.fBitWidth = usbAudio->GetSubframeSize (ourInterfaceNumber, alternateSettingID) * 8;
streamFormat.fAlignment = kIOAudioStreamAlignmentLowByte;
streamFormat.fByteOrder = kIOAudioStreamByteOrderLittleEndian;
streamFormat.fDriverTag = (ourInterfaceNumber << 16) | alternateSettingID;
switch (usbAudio->GetFormat (ourInterfaceNumber, alternateSettingID)) {
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, alternateSettingID), Exit);
FailIf (kUSBAudioStreamInterfaceSubclass != usbAudio->GetInterfaceSubClass (ourInterfaceNumber, alternateSettingID), Exit);
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);
}
}
startTimer = IOTimerEventSource::timerEventSource (this, waitForFirstUSBFrameCompletion);
FailIf (NULL == startTimer, Exit);
workLoop->addEventSource (startTimer);
usbAudioDevice->activateAudioEngine (this, FALSE);
resultBool = TRUE;
if (resultBool) {
usbAudioDevice->retain ();
}
sprintf (vendorIDCString, "0x%04X", streamInterface->GetDevice()->GetVendorID ());
sprintf (productIDCString, "0x%04X", streamInterface->GetDevice()->GetProductID ());
setProperty (vendorIDCString, productIDCString); IOService::registerService ();
Exit:
debugIOLog("-%d = AppleUSBAudioEngine[%p]::initHardware(%p), resultCode = %x", resultBool, this, provider, resultCode);
return resultBool;
}
void AppleUSBAudioEngine::registerPlugin (AppleUSBAudioPlugin * thePlugin) {
mPlugin = thePlugin;
mPluginInitThread = thread_call_allocate ((thread_call_func_t)pluginLoaded, (thread_call_param_t)this);
if (NULL != mPluginInitThread) {
thread_call_enter (mPluginInitThread);
}
}
void AppleUSBAudioEngine::pluginLoaded (AppleUSBAudioEngine * usbAudioEngineObject) {
IOReturn result;
if (usbAudioEngineObject->mPlugin) {
usbAudioEngineObject->mPlugin->open (usbAudioEngineObject);
result = usbAudioEngineObject->mPlugin->pluginInit (usbAudioEngineObject, usbAudioEngineObject->streamInterface->GetDevice()->GetVendorID (), usbAudioEngineObject->streamInterface->GetDevice()->GetProductID ());
if (result == kIOReturnSuccess) {
debugIOLog ("success initing the plugin");
usbAudioEngineObject->mPlugin->pluginSetDirection ((IOAudioStreamDirection) usbAudioEngineObject->direction);
usbAudioEngineObject->mPlugin->pluginSetFormat (usbAudioEngineObject->mainStream->getFormat (), &usbAudioEngineObject->sampleRate);
} else {
debugIOLog ("Error initing the plugin");
usbAudioEngineObject->mPlugin->close (usbAudioEngineObject);
usbAudioEngineObject->mPlugin = NULL;
}
if (NULL != usbAudioEngineObject->mPluginNotification) {
usbAudioEngineObject->mPluginNotification->remove ();
usbAudioEngineObject->mPluginNotification = NULL;
}
}
}
IOReturn AppleUSBAudioEngine::pluginDeviceRequest (IOUSBDevRequest * request, IOUSBCompletion * completion) {
IOReturn result;
result = kIOReturnBadArgument;
if (request) {
result = usbAudioDevice->deviceRequest (request, usbAudioDevice, completion);
}
return result;
}
void AppleUSBAudioEngine::pluginSetConfigurationApp (const char * bundleID) {
if (bundleID) {
usbAudioDevice->setConfigurationApp (bundleID);
}
}
IOReturn AppleUSBAudioEngine::iSubAttachChangeHandler (IOService *target, IOAudioControl *theControl, SInt32 oldValue, SInt32 newValue) {
IOReturn result;
AppleUSBAudioEngine * audioEngine;
debugIOLog ("+ AppleUSBAudioEngine::iSubAttachChangeHandler (%p, %p, %ld, %ld)", target, theControl, oldValue, newValue);
result = kIOReturnSuccess;
FailIf (oldValue == newValue, Exit);
audioEngine = OSDynamicCast (AppleUSBAudioEngine, target);
FailIf (NULL == audioEngine, Exit);
if (newValue) {
if (NULL != audioEngine->iSubEngineNotifier) {
audioEngine->iSubEngineNotifier->remove ();
}
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");
return result;
}
IOReturn AppleUSBAudioEngine::iSubCloseAction (OSObject *owner, void *arg1, void *arg2, void *arg3, void *arg4) {
debugIOLog("+AppleUSBAudioEngine::iSubCloseAction");
AppleUSBAudioEngine *audioEngine = OSDynamicCast (AppleUSBAudioEngine, owner);
FailIf (NULL == audioEngine, Exit);
if (TRUE == audioEngine->iSubIsOpen && NULL != audioEngine->oldiSubEngine) {
audioEngine->oldiSubEngine->closeiSub (audioEngine);
debugIOLog ("iSub closed");
audioEngine->detach (audioEngine->oldiSubEngine);
audioEngine->iSubIsOpen = FALSE;
audioEngine->iSubEngine = NULL;
audioEngine->iSubBufferMemory = NULL;
#if DEBUGISUB
} else {
if (TRUE != audioEngine->iSubIsOpen) {debugIOLog ("TRUE != audioEngine->iSubIsOpen");}
if (NULL == audioEngine->oldiSubEngine) {debugIOLog ("NULL == audioEngine->oldiSubEngine");}
#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");
return kIOReturnSuccess;
}
bool AppleUSBAudioEngine::iSubEnginePublished (AppleUSBAudioEngine * usbAudioEngineObject, void * refCon, IOService * newService) {
debugIOLog ("AppleUSBAudioEngine::iSubEnginePublished (%p, %p, %p)", 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) {
AbsoluteTime callTime;
AbsoluteTime delayAmount;
clock_get_uptime (&callTime);
nanoseconds_to_absolutetime (750ULL * 1000 * 1000, &delayAmount);
ADD_ABSOLUTETIME (&callTime, &delayAmount);
thread_call_enter_delayed (usbAudioEngineObject->iSubOpenThreadCall, callTime);
} else {
}
} else {
debugIOLog ("iSub is already open");
}
Exit:
return TRUE;
}
void AppleUSBAudioEngine::iSubOpen (AppleUSBAudioEngine * usbAudioEngineObject) {
IOReturn result;
IOCommandGate * cg;
debugIOLog ("+AppleUSBAudioEngine::iSubOpen (%p)", 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);
}
debugIOLog ("-AppleUSBAudioEngine::iSubOpen (%p)", usbAudioEngineObject);
return;
}
IOReturn AppleUSBAudioEngine::iSubOpenAction (OSObject *owner, void *arg1, void *arg2, void *arg3, void *arg4) {
AppleUSBAudioEngine * usbAudioEngineObject;
const IOAudioStreamFormat * streamFormat;
IOReturn result;
bool resultBool;
UInt32 sampleRateWhole;
UInt32 numTries;
debugIOLog ("+AppleUSBAudioEngine::iSubOpenAction (%p)", owner);
result = kIOReturnError;
usbAudioEngineObject = OSDynamicCast (AppleUSBAudioEngine, owner);
FailIf (NULL == usbAudioEngineObject, Exit);
FailIf (NULL == usbAudioEngineObject->iSubEngine, Exit);
streamFormat = usbAudioEngineObject->mainStream->getFormat ();
sampleRateWhole = usbAudioEngineObject->curSampleRate.whole;
if ((2 != streamFormat->fNumChannels) || ((8000 != usbAudioEngineObject->curSampleRate.whole) && (11025 != usbAudioEngineObject->curSampleRate.whole) &&
(22050 != usbAudioEngineObject->curSampleRate.whole) && (44100 != usbAudioEngineObject->curSampleRate.whole) &&
(48000 != usbAudioEngineObject->curSampleRate.whole) && (96000 != usbAudioEngineObject->curSampleRate.whole))) {
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 {
resultBool = usbAudioEngineObject->iSubEngine->openiSub (usbAudioEngineObject, &requestiSubClose);
numTries++;
if (!resultBool) IOSleep (102);
} 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");
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:
debugIOLog ("-AppleUSBAudioEngine::iSubOpenAction (%p) = 0x%lx", owner, result);
return result;
}
void AppleUSBAudioEngine::iSubTeardown (AppleUSBAudioEngine * usbAudioEngine, thread_call_t iSubTeardownThreadCall) {
IOCommandGate * cg;
Boolean streamWasRunning;
debugIOLog ("+AppleUSBAudioEngine::iSubTeardown ()");
if (NULL != usbAudioEngine) {
streamWasRunning = usbAudioEngine->usbStreamRunning;
usbAudioEngine->usbStreamRunning = FALSE;
usbAudioEngine->pauseAudioEngine ();
usbAudioEngine->beginConfigurationChange ();
cg = usbAudioEngine->getCommandGate ();
if (NULL != cg) {
cg->runAction (iSubCloseAction);
}
usbAudioEngine->completeConfigurationChange ();
usbAudioEngine->resumeAudioEngine ();
usbAudioEngine->usbStreamRunning = streamWasRunning;
}
if (NULL != iSubTeardownThreadCall) {
thread_call_free(iSubTeardownThreadCall);
}
if (NULL != usbAudioEngine->iSubEngineNotifier) {
usbAudioEngine->iSubEngineNotifier->remove ();
usbAudioEngine->iSubEngineNotifier = NULL;
}
debugIOLog ("-AppleUSBAudioEngine::iSubTeardown ()");
}
void AppleUSBAudioEngine::iSubTeardownConnection (void) {
debugIOLog ("+AppleUSBAudioEngine::iSubTeardownConnection ()");
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 ()");
return;
}
IOReturn AppleUSBAudioEngine::performAudioEngineStart () {
IOReturn resultCode;
debugIOLog ("+AppleUSBAudioEngine[%p]::performAudioEngineStart ()", this);
resultCode = kIOReturnSuccess;
if (mPlugin) {
mPlugin->pluginStart ();
}
if (NULL != iSubEngine) {
startiSub = TRUE;
needToSync = TRUE;
}
if (!usbStreamRunning) {
resultCode = startUSBStream ();
}
if (resultCode != kIOReturnSuccess) {
debugIOLog ("++AppleUSBAudioEngine[%p]::performAudioEngineStart () -- NOT started, error = 0x%x", resultCode);
} else {
debugIOLog ("++AppleUSBAudioEngine[%p]::performAudioEngineStart () - started.", this);
}
debugIOLog ("-AppleUSBAudioEngine[%p]::performAudioEngineStart ()", this);
return resultCode;
}
IOReturn AppleUSBAudioEngine::performAudioEngineStop() {
debugIOLog("+AppleUSBAudioEngine[%p]::performAudioEngineStop ()", this);
if (mPlugin) {
mPlugin->pluginStop ();
}
if (NULL != iSubEngine) {
iSubEngine->StopiSub ();
needToSync = TRUE;
}
if (usbStreamRunning) {
stopUSBStream ();
}
debugIOLog("++AppleUSBAudioEngine[%p]::performAudioEngineStop() - stopped", this);
debugIOLog("-AppleUSBAudioEngine[%p]::performAudioEngineStop()", 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 newAlternateSettingID;
UInt8 newDirection;
bool needToChangeChannels;
debugIOLog ("+AppleUSBAudioEngine::performFormatChange");
result = kIOReturnError;
oldBufferSize = bufferSize;
FailIf (NULL == streamInterface, Exit);
FailIf (NULL == usbAudioDevice, Exit);
usbAudio = usbAudioDevice->GetUSBAudioConfigObject ();
FailIf (NULL == usbAudio, Exit);
if (newFormat == NULL) {
result = kIOReturnSuccess;
goto Exit;
}
ourInterfaceNumber = (UInt8)(newFormat->fDriverTag >> 16);
newAlternateSettingID = (UInt8)(newFormat->fDriverTag);
debugIOLog ("fDriverTag = 0x%x", newFormat->fDriverTag);
if (newFormat->fNumChannels != audioStream->format.fNumChannels) {
needToChangeChannels = TRUE;
debugIOLog ("Need to adjust channel controls, cur = %d, new = %d", audioStream->format.fNumChannels, newFormat->fNumChannels);
} else {
needToChangeChannels = FALSE;
debugIOLog ("No need to adjust channel controls");
}
if (newSampleRate) {
debugIOLog ("changing sampling rate to %d", newSampleRate->whole);
curSampleRate = *newSampleRate;
} else {
debugIOLog ("keeping the existing sampling rate of %d", curSampleRate.whole);
}
if (FALSE == usbAudio->VerifySampleRateIsSupported (ourInterfaceNumber, newAlternateSettingID, curSampleRate.whole)) {
newAlternateSettingID = usbAudio->FindAltInterfaceWithSettings (ourInterfaceNumber, newFormat->fNumChannels, newFormat->fBitDepth, curSampleRate.whole);
FailIf (255 == newAlternateSettingID, Exit);
}
newDirection = usbAudio->GetIsocEndpointDirection (ourInterfaceNumber, newAlternateSettingID);
FailIf (newDirection != direction, Exit);
debugIOLog ("++about to set: ourInterfaceNumber = %d & newAlternateSettingID = %d", ourInterfaceNumber, newAlternateSettingID);
alternateSettingID = newAlternateSettingID;
if (mPlugin) {
mPlugin->pluginSetFormat (newFormat, &curSampleRate);
}
(void)SetSampleRate (usbAudio, curSampleRate.whole);
averageSampleRate = curSampleRate.whole; debugIOLog ("averageSampleRate = %d", averageSampleRate);
CalculateSamplesPerFrame (curSampleRate.whole, &averageFrameSamples, &additionalSampleFrameFreq);
debugIOLog ("averageFrameSamples = %d, additionalSampleFrameFreq = %d", averageFrameSamples, additionalSampleFrameFreq);
oldReadUSBFrameListSize = readUSBFrameListSize;
averageFrameSize = averageFrameSamples * (newFormat->fNumChannels * (newFormat->fBitWidth / 8));
alternateFrameSize = (averageFrameSamples + 1) * (newFormat->fNumChannels * (newFormat->fBitWidth / 8));
debugIOLog ("averageFrameSize = %d, alternateFrameSize = %d", 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) {
debugIOLog ("Checking to see if we should close connection to iSub");
if ((2 != newFormat->fNumChannels) || ((8000 != curSampleRate.whole) && (11025 != curSampleRate.whole) && (22050 != curSampleRate.whole) &&
(44100 != curSampleRate.whole) && (48000 != curSampleRate.whole) && (96000 != curSampleRate.whole))) {
debugIOLog ("closing connection to iSub due to incompatible format");
iSubTeardownConnection ();
}
} else {
debugIOLog ("Checking to see if we should open a connection to iSub");
debugIOLog ("iSubAttach = %p", iSubAttach);
if (iSubAttach) {
debugIOLog ("iSubAttach value = %d", iSubAttach->getIntValue ());
}
if (NULL != iSubAttach && 1 == iSubAttach->getIntValue ()) {
debugIOLog ("iSubAttach says we should open connection to iSub");
if ((2 == newFormat->fNumChannels) && ((8000 == curSampleRate.whole) || (11025 == curSampleRate.whole) || (22050 == curSampleRate.whole) ||
(44100 == curSampleRate.whole) || (48000 == curSampleRate.whole) || (96000 == curSampleRate.whole))) {
debugIOLog ("opening connection to iSub");
iSubAttachChangeHandler (this, iSubAttach, 0, 1);
}
}
}
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) {
mUSBBufferDescriptor->release ();
}
mUSBBufferDescriptor = IOBufferMemoryDescriptor::withOptions (kIODirectionInOut, numUSBFrameLists * readUSBFrameListSize, PAGE_SIZE);
FailIf (NULL == mUSBBufferDescriptor, Exit);
readBuffer = mUSBBufferDescriptor->getBytesNoCopy ();
FailIf (NULL == readBuffer, Exit);
for (i = 0; i < numUSBFrameLists; i++) {
soundBufferDescriptors[i] = OSTypeAlloc (IOSubMemoryDescriptor);
soundBufferDescriptors[i]->initSubRange (mUSBBufferDescriptor, i * readUSBFrameListSize, readUSBFrameListSize, kIODirectionInOut);
FailIf (NULL == soundBufferDescriptors[i], Exit);
}
if (NULL != sampleBufferMemoryDescriptor) {
mainStream->setSampleBuffer (NULL, 0);
setNumSampleFramesPerBuffer (0);
sampleBufferMemoryDescriptor->release ();
}
sampleBufferMemoryDescriptor = IOBufferMemoryDescriptor::withOptions (kIODirectionInOut, bufferSize, PAGE_SIZE);
FailIf (NULL == sampleBufferMemoryDescriptor, Exit);
sampleBuffer = sampleBufferMemoryDescriptor->getBytesNoCopy ();
} 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);
}
}
if (NULL != mUSBBufferDescriptor) {
mainStream->setSampleBuffer (NULL, 0);
setNumSampleFramesPerBuffer (0);
mUSBBufferDescriptor->release ();
}
mUSBBufferDescriptor = IOBufferMemoryDescriptor::withOptions (kIODirectionInOut, bufferSize, PAGE_SIZE);
FailIf (NULL == mUSBBufferDescriptor, Exit);
for (i = 0; i < numUSBFrameLists; i++) {
if (NULL != soundBufferDescriptors[i]) {
soundBufferDescriptors[i]->release ();
}
soundBufferDescriptors[i] = OSTypeAlloc (IOSubMemoryDescriptor);
soundBufferDescriptors[i]->initSubRange (mUSBBufferDescriptor, 0, bufferSize, kIODirectionInOut);
FailIf (NULL == soundBufferDescriptors[i], Exit);
result = soundBufferDescriptors[i]->prepare();
FailIf (kIOReturnSuccess != result, Exit);
}
sampleBuffer = mUSBBufferDescriptor->getBytesNoCopy();
FailIf (NULL == sampleBuffer, Exit);
}
mainStream->setSampleBuffer (sampleBuffer, bufferSize);
setNumSampleFramesPerBuffer (numSamplesInBuffer);
if (kUSBIn == direction) {
setSampleOffset ((numUSBFramesPerList + 1) * (averageFrameSamples + 2));
setSampleLatency (averageFrameSamples * (kMinimumFrameOffset + 1));
} else {
setSampleOffset (3 * (additionalSampleFrameFreq ? averageFrameSamples + 1 : averageFrameSamples));
setSampleLatency (averageFrameSamples * kMinimumFrameOffset);
}
if (TRUE == needToChangeChannels) {
beginConfigurationChange ();
removeAllDefaultAudioControls ();
usbAudioDevice->createControlsForInterface (this, ourInterfaceNumber, alternateSettingID);
completeConfigurationChange ();
}
debugIOLog ("called setNumSampleFramesPerBuffer with %d", bufferSize / (newFormat->fNumChannels * (newFormat->fBitWidth / 8)));
debugIOLog ("newFormat->fNumChannels = %d, newFormat->fBitWidth %d", newFormat->fNumChannels, newFormat->fBitWidth);
debugIOLog ("called setSampleOffset with %d", numUSBFramesPerList);
result = kIOReturnSuccess;
Exit:
debugIOLog ("-AppleUSBAudioEngine::performFormatChange, result = %x", result);
return result;
}
IOReturn AppleUSBAudioEngine::PrepareWriteFrameList (UInt32 arrayIndex) {
const IOAudioStreamFormat * theFormat;
IOReturn result;
UInt32 thisFrameListSize;
UInt32 thisFrameSize;
UInt32 firstFrame;
UInt32 numBytesToBufferEnd;
UInt32 lastPreparedByte;
UInt32 numUSBFramesPrepared;
UInt16 integerSamplesInFrame;
Boolean haveWrapped;
result = kIOReturnError; 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));
theWrapDescriptors[0]->initSubRange (mUSBBufferDescriptor, previouslyPreparedBufferOffset, getSampleBufferSize () - previouslyPreparedBufferOffset, kIODirectionInOut);
lastPreparedByte = thisFrameSize - numBytesToBufferEnd;
numBytesToBufferEnd = getSampleBufferSize () - lastPreparedByte;
haveWrapped = TRUE;
} 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) {
needTimeStamps = TRUE;
theWrapDescriptors[1]->initSubRange (mUSBBufferDescriptor, 0, lastPreparedByte, kIODirectionInOut);
if (NULL != theWrapRangeDescriptor) {
theWrapRangeDescriptor->release ();
theWrapRangeDescriptor = NULL;
}
theWrapRangeDescriptor = IOMultiMemoryDescriptor::withDescriptors ((IOMemoryDescriptor **)theWrapDescriptors, 2, kIODirectionInOut, true);
} else {
soundBufferDescriptors[arrayIndex]->initSubRange (mUSBBufferDescriptor, previouslyPreparedBufferOffset, thisFrameListSize, kIODirectionInOut);
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 numUSBFramesPrepared;
UInt16 averageFrameSamples;
UInt16 additionalSampleFrameFreq;
UInt16 bytesToRead;
result = kIOReturnError; firstFrame = usbFrameListIndex * numUSBFramesPerList;
usbCompletion[usbFrameListIndex].target = (void *)this;
usbCompletion[usbFrameListIndex].action = readHandler;
usbCompletion[usbFrameListIndex].parameter = (void *)usbFrameListIndex;
CalculateSamplesPerFrame (curSampleRate.whole, &averageFrameSamples, &additionalSampleFrameFreq);
bytesPerSampleFrame = sampleSize * numChannels;
bytesToRead = (averageFrameSamples + 1) * 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;
}
if (NULL != thePipe) {
result = thePipe->Read (soundBufferDescriptors[usbFrameListIndex], usbFrameToQueueAt, numUSBFramesPerList, &theUSBIsocFrames[firstFrame], &usbCompletion[usbFrameListIndex], 1); usbFrameToQueueAt += numUSBFramesPerList;
}
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;
}
void AppleUSBAudioEngine::readHandler (void * object, void * parameter, IOReturn result, IOUSBLowLatencyIsocFrame * pFrames) {
AppleUSBAudioEngine * self;
UInt64 currentUSBFrameNumber;
UInt32 frameListToRead;
self = (AppleUSBAudioEngine *)object;
FailIf (TRUE == self->inCompletion, Exit);
self->inCompletion = TRUE;
#if DEBUGUSB
if (0 == self->shouldStop && (UInt32)parameter != self->currentFrameList) {
debugIOLog ("%ld != %ld", (UInt32)parameter, self->currentFrameList);
}
#endif
FailIf (NULL == self->streamInterface, Exit);
if (TRUE == self->startingEngine) {
self->startingEngine = FALSE; #if 0
time = pFrames[0].frTimeStamp;
nanoseconds_to_absolutetime (1000000, &timeOffset);
SUB_ABSOLUTETIME (&time, &timeOffset); 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) {
debugIOLog ("Read handler delta = %ld microseconds", (UInt32)(nanos_del));
}
#endif
#if 1 // enabled for [3091812]
currentUSBFrameNumber = self->streamInterface->GetDevice()->GetBus()->GetFrameNumber ();
if (0 == self->shouldStop && (SInt32)(self->usbFrameToQueueAt - currentUSBFrameNumber) > (SInt32)(self->numUSBFramesPerList * (self->numUSBFrameListsToQueue - 1))) {
#if DEBUGLOADING
debugIOLog ("Not queuing a frame list in readHandler (%ld)", (SInt32)(self->usbFrameToQueueAt - currentUSBFrameNumber));
#endif
goto Exit;
}
#endif
if (kIOReturnSuccess != result && kIOReturnAborted != result && kIOReturnUnderrun != result) {
#if DEBUGUSB
debugIOLog ("Error 0x%X from USB read", result);
#endif
if (self->usbFrameToQueueAt <= currentUSBFrameNumber) {
#if DEBUGUSB
debugIOLog ("skipping ahead %ld frames", currentUSBFrameNumber - self->usbFrameToQueueAt);
#endif
self->usbFrameToQueueAt = currentUSBFrameNumber + kMinimumFrameOffset;
}
}
if (kIOReturnAborted != result) {
self->CoalesceInputSamples (0, pFrames);
}
#if DEBUGUSB
bzero ((UInt8 *)self->readBuffer + (self->currentFrameList * self->readUSBFrameListSize), self->readUSBFrameListSize);
#endif
if (self->shouldStop > 0) {
debugIOLog("++AppleUSBAudioEngine::readHandler() - stopping: %d", self->shouldStop);
self->shouldStop++;
if (self->shouldStop == (self->numUSBFrameListsToQueue + 1) && 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 - 1) + self->numUSBFrameListsToQueue;
if (frameListToRead >= self->numUSBFrameLists) {
frameListToRead -= self->numUSBFrameLists;
}
self->readFrameList (frameListToRead);
}
Exit:
self->inCompletion = FALSE;
return;
}
void AppleUSBAudioEngine::resetClipPosition (IOAudioStream *audioStream, UInt32 clipSampleFrame) {
if (mPlugin) {
mPlugin->pluginReset ();
}
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 DEBUGISUB
debugIOLog ("+resetClipPosition, iSubBufferOffset=%ld, previousClippedToFrame=%ld, clipSampleFrame=%ld", 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 DEBUGISUB
debugIOLog ("-resetClipPosition, iSubBufferOffset=%ld, previousClippedToFrame=%ld", iSubBufferOffset, previousClippedToFrame);
#endif
}
}
void AppleUSBAudioEngine::requestiSubClose (IOAudioEngine * audioEngine) {
}
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;
if (kIOReturnSuccess == result) {
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;
debugIOLog ("!!!!sample rate changed, requestedFrameRate = %d", 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->neededSampleRateDescriptor, 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, alternateSettingID)) {
devReq.bmRequestType = USBmakebmRequestType (kUSBOut, kUSBClass, kUSBEndpoint);
devReq.bRequest = SET_CUR;
devReq.wValue = (SAMPLING_FREQ_CONTROL << 8) | 0;
devReq.wIndex = usbAudio->GetIsocEndpointAddress (ourInterfaceNumber, alternateSettingID, direction);
devReq.wLength = 3;
theSampleRate = OSSwapHostToLittleInt32 (sampleRate);
devReq.pData = &theSampleRate;
debugIOLog ("Set freq control interface %d, alt interface %d, endpoint address 0x%X, sample rate (little endian) 0x%X", ourInterfaceNumber, alternateSettingID, devReq.wIndex, theSampleRate);
result = streamInterface->GetDevice()->DeviceRequest (&devReq);
FailIf (kIOReturnSuccess != result, Exit);
} else {
result = kIOReturnSuccess;
debugIOLog ("Device doesn't have a sample freq control!");
}
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;
debugIOLog ("+AppleUSBAudioEngine[%p]::startUSBStream ()", this);
resultCode = kIOReturnError;
numQueued = 0;
currentFrameList = 0;
safeToEraseTo = 0;
lastSafeErasePoint = 0;
bufferOffset = 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, alternateSettingID);
debugIOLog ("streamInterface->SetAlternateInterface (this, %d) = 0x%X", alternateSettingID, 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) {
maxFrameSize = (averageFrameSamples + 1) * (theFormat->fNumChannels * (theFormat->fBitWidth / 8));
resultCode = thePipe->SetPipePolicy (maxFrameSize, 0);
if (kIOReturnSuccess != resultCode) {
maxFrameSize = averageFrameSamples * (theFormat->fNumChannels * (theFormat->fBitWidth / 8));
}
} else {
if (0 == additionalSampleFrameFreq) {
maxFrameSize = averageFrameSamples * (theFormat->fNumChannels * (theFormat->fBitWidth / 8));
} else {
maxFrameSize = (averageFrameSamples + 1) * (theFormat->fNumChannels * (theFormat->fBitWidth / 8));
}
}
debugIOLog ("calling SetPipePolicy (%d)", maxFrameSize);
resultCode = thePipe->SetPipePolicy (maxFrameSize, 0);
FailIf (kIOReturnSuccess != resultCode, Exit);
usbFrameToQueueAt = streamInterface->GetDevice()->GetBus()->GetFrameNumber() + kMinimumFrameOffset; if (NULL != theAssociatedPipe) {
nextSynchReadFrame = usbFrameToQueueAt;
(void)theAssociatedPipe->Read (neededSampleRateDescriptor, 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);
for (frameListNum = currentFrameList; frameListNum < numUSBFrameListsToQueue; frameListNum++) {
readFrameList (frameListNum);
}
} else {
theUSBIsocFrames[0].frTimeStamp.hi = 0xFFFFFFFF;
theUSBIsocFrames[0].frTimeStamp.lo = 0xFFFFFFFF;
for (frameListNum = currentFrameList; frameListNum < numUSBFrameListsToQueue; frameListNum++) {
writeFrameList (frameListNum);
}
startTimer->enable ();
startTimer->setTimeoutMS (kMinimumFrameOffset); }
usbStreamRunning = TRUE;
resultCode = kIOReturnSuccess;
Exit:
debugIOLog ("-AppleUSBAudioEngine[%p]::startUSBStream () = %x", this, resultCode);
return resultCode;
}
IOReturn AppleUSBAudioEngine::stopUSBStream () {
debugIOLog ("+AppleUSBAudioEngine[%p]::stopUSBStream ()", this);
if (0 == shouldStop) {
shouldStop = 1;
}
if (NULL != thePipe) {
if (FALSE == terminatingDriver) {
thePipe->SetPipePolicy (0, 0);
}
thePipe->release ();
thePipe = NULL;
}
if (NULL != theAssociatedPipe) {
theAssociatedPipe->release ();
theAssociatedPipe = NULL;
}
if (FALSE == terminatingDriver) {
if (NULL != streamInterface) { (void)streamInterface->SetAlternateInterface (this, kRootAlternateSetting);
}
}
usbStreamRunning = FALSE;
debugIOLog ("-AppleUSBAudioEngine[%p]::stopUSBStream ()", this);
return kIOReturnSuccess;
}
void AppleUSBAudioEngine::waitForFirstUSBFrameCompletion (OSObject * owner, IOTimerEventSource * sender) {
AppleUSBAudioEngine * usbAudioEngineObject;
AbsoluteTime timeOffset;
static UInt32 timeout = 60;
usbAudioEngineObject = OSDynamicCast (AppleUSBAudioEngine, owner);
FailIf (NULL == usbAudioEngineObject, Exit);
FailIf (usbAudioEngineObject->isInactive (), Exit);
FailIf (0 != usbAudioEngineObject->shouldStop, Exit);
if (0 == timeout || usbAudioEngineObject->theUSBIsocFrames[0].frTimeStamp.lo != 0xFFFFFFFF) {
nanoseconds_to_absolutetime (1 * 1000 * 1000, &timeOffset);
SUB_ABSOLUTETIME (&usbAudioEngineObject->theUSBIsocFrames[0].frTimeStamp, &timeOffset); if (0 == timeout) {
usbAudioEngineObject->takeTimeStamp (FALSE);
} else {
usbAudioEngineObject->takeTimeStamp (FALSE, &usbAudioEngineObject->theUSBIsocFrames[0].frTimeStamp);
}
timeout = 60;
usbAudioEngineObject->startingEngine = FALSE; usbAudioEngineObject->startTimer->disable ();
debugIOLog ("audio engine starting playing now");
} else {
usbAudioEngineObject->startTimer->setTimeoutUS (50); timeout--;
debugIOLog ("audio not running, requeuing timer (%ld)", timeout);
}
Exit:
return;
}
bool AppleUSBAudioEngine::willTerminate (IOService * provider, IOOptionBits options) {
debugIOLog ("+AppleUSBAudioEngine[%p]::willTerminate (%p)", this, provider);
if (iSubEngine == (AppleiSubEngine *)provider) {
debugIOLog ("iSub requesting termination");
iSubTeardownConnection ();
if (iSubAttach->getIntValue ()) {
iSubEngineNotifier = addNotification (gIOPublishNotification, serviceMatching ("AppleiSubEngine"), (IOServiceNotificationHandler)&iSubEnginePublished, this);
}
}
if (streamInterface == provider) {
terminatingDriver = TRUE;
if (FALSE == usbStreamRunning) {
debugIOLog ("willTerminate closing down");
streamInterface->close (this);
streamInterface = NULL;
} else {
debugIOLog ("willTerminate checking shouldStop = 0x%x", shouldStop);
if (0 == shouldStop) {
shouldStop++;
}
}
oldiSubEngine = iSubEngine;
iSubCloseAction (this, NULL, NULL, NULL, NULL);
}
debugIOLog ("-AppleUSBAudioEngine[%p]::willTerminate", 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 (needTimeStamps) {
result = thePipe->Write (theWrapRangeDescriptor, usbFrameToQueueAt, numUSBFramesPerList, &theUSBIsocFrames[arrayIndex * numUSBFramesPerList], &usbCompletion[arrayIndex], 1);
needTimeStamps = FALSE;
} else {
if (TRUE == startingEngine) {
result = thePipe->Write (soundBufferDescriptors[arrayIndex], usbFrameToQueueAt, numUSBFramesPerList, &theUSBIsocFrames[arrayIndex * numUSBFramesPerList], &usbCompletion[arrayIndex], 1);
} else {
result = thePipe->Write (soundBufferDescriptors[arrayIndex], usbFrameToQueueAt, numUSBFramesPerList, &theUSBIsocFrames[arrayIndex * numUSBFramesPerList], &usbCompletion[arrayIndex], 0);
}
}
FailIf (result != kIOReturnSuccess, Exit);
usbFrameToQueueAt += numUSBFramesPerList;
Exit:
return result;
}
void AppleUSBAudioEngine::writeHandler (void * object, void * parameter, IOReturn result, IOUSBLowLatencyIsocFrame * pFrames) {
AppleUSBAudioEngine * self;
AbsoluteTime time;
AbsoluteTime timeOffset;
UInt64 curUSBFrameNumber;
UInt64 nanos;
UInt32 frameListToWrite;
UInt32 byteOffset;
#if DEBUGZEROTIME
UInt32 ms;
AbsoluteTime diff;
#endif
#if DEBUGUSB
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 DEBUGLOADING
debugIOLog ("Not queuing a frame list in writeHandler");
if (parameter) {
debugIOLog ("parameter = 0x%x", parameter);
debugIOLog ("0x%x%x - 0x%x%x = 0x%x", (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 DEBUGUSB
debugIOLog ("++AppleUSBAudioEngine[%p]::writeHandler () - error 0x%x on USB frame 0x%lx%lx", self, result, (UInt32)(curUSBFrameNumber >> 32), (UInt32)curUSBFrameNumber);
debugIOLog ("current frame list = %d", self->currentFrameList);
for (i = 0; i < self->numUSBFramesPerList; i++) {
if (kIOReturnSuccess != pFrames[i].frStatus) {
debugIOLog ("fr %d: 0x%lx ", i, pFrames[i].frStatus);
}
}
debugIOLog ("");
#endif
if (self->usbFrameToQueueAt <= curUSBFrameNumber) {
self->usbFrameToQueueAt = curUSBFrameNumber + kMinimumFrameOffset;
}
}
#if DEBUGUSB
if (self->usbFrameToQueueAt < curUSBFrameNumber) {
debugIOLog ("fell behind 0x%x%x < 0x%x%x", (UInt32)(self->usbFrameToQueueAt >> 32), (UInt32)(self->usbFrameToQueueAt), (UInt32)(curUSBFrameNumber >> 32), (UInt32)(curUSBFrameNumber));
self->usbFrameToQueueAt = curUSBFrameNumber + kMinimumFrameOffset;
}
#endif
if (0 != parameter) {
#if DEBUGZEROTIME
#endif
byteOffset = (UInt32)parameter & 0x00FF;
time = pFrames[((UInt32)parameter >> 16) - 1].frTimeStamp;
#if DEBUGZEROTIME
#endif
nanos = (byteOffset * 1000000) / pFrames[((UInt32)parameter >> 16) - 1].frActCount;
#if DEBUGZEROTIME
debugIOLog ("so = %ld, n = %lx", byteOffset, (UInt32)nanos);
#endif
nanoseconds_to_absolutetime (nanos, &timeOffset);
SUB_ABSOLUTETIME (&time, &timeOffset);
#if DEBUGZEROTIME
diff = time;
SUB_ABSOLUTETIME (&diff, &self->status->fLastLoopTime); absolutetime_to_nanoseconds (diff, &nanos);
ms = nanos / (1000 * 1000);
debugIOLog ("%ld", ms);
if (ms > 280 || ms < 275) {
debugIOLog ("%ldms, parameter=0x%x", ms, parameter);
}
if (ms < 277 || ms > 279) {
if (((UInt32)parameter >> 16) == self->numUSBFramesPerList) {
debugIOLog ("bad delta %lx %lx, %lx %lx", pFrames[(UInt32)parameter >> 16 - 2].frTimeStamp.hi, pFrames[(UInt32)parameter >> 16 - 2].frTimeStamp.lo, pFrames[(UInt32)parameter >> 16 - 1].frTimeStamp.hi, pFrames[(UInt32)parameter >> 16 - 1].frTimeStamp.lo);
} else {
debugIOLog ("bad delta %lx %lx, %lx %lx", pFrames[(UInt32)parameter >> 16 - 1].frTimeStamp.hi, pFrames[(UInt32)parameter >> 16 - 1].frTimeStamp.lo, pFrames[(UInt32)parameter >> 16].frTimeStamp.hi, pFrames[(UInt32)parameter >> 16].frTimeStamp.lo);
}
}
#endif
self->takeTimeStamp (TRUE, &time);
}
if (self->currentFrameList == self->numUSBFrameLists - 1) {
self->currentFrameList = 0;
} else {
self->currentFrameList++;
}
if (self->shouldStop > 0) {
debugIOLog ("++AppleUSBAudioEngine::writeHandler() - stopping: %d", self->shouldStop);
self->shouldStop++;
if (self->shouldStop == (self->numUSBFrameListsToQueue + 1) && TRUE == self->terminatingDriver) {
self->streamInterface->close (self);
self->streamInterface = NULL;
}
} else {
frameListToWrite = (self->currentFrameList - 1) + self->numUSBFrameListsToQueue;
if (frameListToWrite >= self->numUSBFrameLists) {
frameListToWrite -= self->numUSBFrameLists;
}
self->writeFrameList (frameListToWrite);
}
Exit:
self->inCompletion = FALSE;
return;
}
Generated by GNU enscript 1.6.4.