[plain text]
#define DEBUGZEROTIME FALSE
#define DEBUGUSB FALSE
#define DEBUGISUB FALSE
#define DEBUGLOADING FALSE
#define DEBUGTIMESTAMPS FALSE
#define DEBUGINPUT FALSE
#define DEBUGUHCI FALSE
#define THREAD_ISUB_OPEN 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 != mCoalescenceMutex)
{
IOLockFree (mCoalescenceMutex);
mCoalescenceMutex = NULL;
}
if (NULL != mFrameQueuedForList)
{
delete [] mFrameQueuedForList;
mFrameQueuedForList = NULL;
}
if (mAssociatedEndpointMemoryDescriptor)
{
mAssociatedEndpointMemoryDescriptor->release ();
mAssociatedEndpointMemoryDescriptor = NULL;
}
if (mAverageSampleRateBuffer)
{
IOFreeContiguous (mAverageSampleRateBuffer, sizeof (UInt32));
mAverageSampleRateBuffer = NULL;
}
if (mDeviceAndEngineSyncer)
{
mDeviceAndEngineSyncer->release ();
}
if (mUSBBufferDescriptor)
{
mUSBBufferDescriptor->release ();
mUSBBufferDescriptor = NULL;
}
if (mWrapRangeDescriptor)
{
mWrapRangeDescriptor->release ();
mWrapDescriptors[0]->release ();
mWrapDescriptors[1]->release ();
mWrapRangeDescriptor = NULL;
}
if (mSampleBufferMemoryDescriptor)
{
mSampleBufferMemoryDescriptor->release ();
mSampleBufferMemoryDescriptor = NULL;
}
if (NULL != mSampleBufferDescriptors)
{
for (i = 0; i < mNumUSBFrameLists; i++)
{
if (NULL != mSampleBufferDescriptors[i])
{
mSampleBufferDescriptors[i]->release ();
mSampleBufferDescriptors[i] = NULL;
}
}
IOFree (mSampleBufferDescriptors, mNumUSBFrameLists * sizeof (IOSubMemoryDescriptor *));
mSampleBufferDescriptors = NULL;
}
if (NULL != mUSBIsocFrames)
{
IOFree (mUSBIsocFrames, mNumUSBFrameLists * mNumTransactionsPerList * sizeof (IOUSBLowLatencyIsocFrame));
mUSBIsocFrames = NULL;
}
if (NULL != mUSBCompletion)
{
IOFree (mUSBCompletion, mNumUSBFrameLists * sizeof (IOUSBLowLatencyIsocCompletion));
mUSBCompletion = NULL;
}
if (NULL != getSampleBuffer ())
{
IOFree (getSampleBuffer (), mSampleBufferSizeExtended);
}
if (NULL != mLowFreqSamples)
{
IOFreeAligned (mLowFreqSamples, getSampleBufferSize () * 2);
}
if (NULL != mHighFreqSamples)
{
IOFreeAligned (mHighFreqSamples, getSampleBufferSize () * 2);
}
if (NULL != miSubEngineNotifier)
{
debugIOLog ("? AppleUSBAudioEngine[%p]::free () - Removing miSubEngineNotifier ...", this);
miSubEngineNotifier->remove ();
miSubEngineNotifier = NULL;
}
if (NULL != miSubAttachToggle)
{
miSubAttachToggle->release ();
miSubAttachToggle = NULL;
}
if (mMainStream)
{
mMainStream->release ();
mMainStream = 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");
mDeviceAndEngineSyncer = IOSyncer::create (FALSE);
result = TRUE;
mSrcPhase = 1.0; mSrcState = 0.0; mJustResetClipPosition = 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 (mUSBAudioDevice == provider || mStreamInterface == provider)
{
result = TRUE; }
else
{
result = FALSE; }
debugIOLog ("- AppleUSBAudioEngine[%p]::requestTerminate (%p, %x) = %d", this, provider, options, result);
return result;
}
bool AppleUSBAudioEngine::start (IOService * provider) {
IONotifier * audioDeviceNotifier;
bool resultCode;
AUAConfigurationDictionary * configDictionary = NULL;
OSDictionary * matchingDictionary;
OSString * name;
debugIOLog ("+ AppleUSBAudioEngine[%p]::start (%p)", this, provider);
resultCode = FALSE;
mStreamInterface = OSDynamicCast (IOUSBInterface, provider);
FailIf (NULL == mStreamInterface, Exit);
mInterfaceNumber = mStreamInterface->GetInterfaceNumber ();
debugIOLog ("? AppleUSBAudioEngine[%p]::start () - mInterfaceNumber = %d", this, mInterfaceNumber);
FailIf ((INTERFACE_PROTOCOL_UNDEFINED != mStreamInterface->GetInterfaceProtocol()) && (IP_VERSION_02_00 != mStreamInterface->GetInterfaceProtocol()), Exit);
matchingDictionary = serviceMatching ("AppleUSBAudioDevice");
name = OSString::withCString ("*");
matchingDictionary->setObject (kIOAudioDeviceNameKey, name);
name->release ();
debugIOLog ("? AppleUSBAudioEngine[%p]::start () - Adding notification with custom matching dictionary", this);
audioDeviceNotifier = addNotification (gIOMatchedNotification,
matchingDictionary,
(IOServiceNotificationHandler)&audioDevicePublished,
this,
NULL);
mDeviceAndEngineSyncer->wait (FALSE);
audioDeviceNotifier->remove ();
mDeviceAndEngineSyncer->reinit ();
FailIf (NULL == mUSBAudioDevice, Exit);
FailIf ( NULL == mUSBAudioDevice->mControlInterface, Exit );
if ( 0 == mUSBAudioDevice->mControlInterface->GetInterfaceNumber() )
{
FailIf (NULL == (configDictionary = mUSBAudioDevice->getConfigDictionary()), Exit);
FailIf (configDictionary->isiSub(), Exit);
}
resultCode = super::start (provider, mUSBAudioDevice);
Exit:
debugIOLog ("- AppleUSBAudioEngine[%p]::start (%p) = %d", this, provider, resultCode);
return resultCode;
}
void AppleUSBAudioEngine::stop (IOService * provider) {
debugIOLog("+ AppleUSBAudioEngine[%p]::stop (%p)", this, provider);
if (provider == miSubEngine)
{
goto Exit;
}
if (NULL != mPluginNotification)
{
mPluginNotification->remove ();
mPluginNotification = NULL;
}
if (NULL != mPluginInitThread)
{
thread_call_cancel (mPluginInitThread);
thread_call_free (mPluginInitThread);
mPluginInitThread = NULL;
}
if (NULL != miSubEngineNotifier)
{
debugIOLog ("? AppleUSBAudioEngine[%p]::stop () - Removing miSubEngineNotifier ...", this);
miSubEngineNotifier->remove ();
miSubEngineNotifier = NULL;
}
if (mPlugin)
{
mPlugin->close (this);
mPlugin = NULL;
}
if (NULL != miSubEngine)
{
iSubTeardownConnection ();
}
if (mUSBAudioDevice)
{
mUSBAudioDevice->release ();
mUSBAudioDevice = NULL;
}
if (mPipe)
{
mPipe->release ();
mPipe = NULL;
}
if (mAssociatedPipe)
{
mAssociatedPipe->release ();
mAssociatedPipe = NULL;
}
if ( (mStreamInterface)
&& (provider == mStreamInterface)
&& (mStreamInterface->isOpen()))
{
debugIOLog ("! AppleUSBAudioEngine[%p]::stop () - mStreamInterface was still open when stop() was called. Closing ...", this);
mStreamInterface->close (this);
mStreamInterface = 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::addAvailableFormats (AUAConfigurationDictionary * configDictionary)
{
IOAudioStreamFormat streamFormat;
IOAudioStreamFormatExtension streamFormatExtension;
IOAudioSampleRate lowSampleRate;
IOAudioSampleRate highSampleRate;
OSArray * sampleRates = NULL;
OSObject * arrayObject = NULL;
OSNumber * arrayNumber = NULL;
IOReturn result = kIOReturnError;
UInt32 thisSampleRate;
UInt32 otherSampleRate;
UInt16 format;
UInt8 numAltInterfaces;
UInt8 numSampleRates;
UInt8 altSettingIndex;
UInt8 numChannels;
UInt8 rateIndex;
UInt8 candidateAC3AltSetting;
Boolean hasNativeAC3Format;
Boolean hasDigitalOutput = FALSE;
debugIOLog ("+ AppleUSBAudioEngine[%p]::addAvailableFormats (%p)", this, configDictionary);
FailIf (NULL == configDictionary, Exit);
FailIf (NULL == mMainStream, Exit);
FailIf (kIOReturnSuccess != configDictionary->getNumAltSettings (&numAltInterfaces, mInterfaceNumber), Exit);
debugIOLog ("? AppleUSBAudioEngine[%p]::addAvailableFormats () - There are %d alternate interfaces @ interface %d", this, numAltInterfaces, mInterfaceNumber);
hasNativeAC3Format = FALSE;
candidateAC3AltSetting = 0;
altSettingIndex = configDictionary->alternateSettingZeroCanStream (mInterfaceNumber) ? 0 : 1;
for ( ; altSettingIndex < numAltInterfaces; altSettingIndex++)
{
if ( kIOReturnSuccess != configDictionary->getNumSampleRates (&numSampleRates, mInterfaceNumber, altSettingIndex) )
{
continue;
}
sampleRates = configDictionary->getSampleRates (mInterfaceNumber, altSettingIndex);
FailIf (kIOReturnSuccess != configDictionary->getFormat (&format, mInterfaceNumber, altSettingIndex), Exit);
if ( ( PCM == format )
|| ( IEC1937_AC3 == format ) )
{
FailIf (kIOReturnSuccess != configDictionary->getNumChannels (&numChannels, mInterfaceNumber, altSettingIndex), Exit);
FailIf (kIOReturnSuccess != configDictionary->getBitResolution (&(streamFormat.fBitDepth), mInterfaceNumber, altSettingIndex), Exit);
FailIf (kIOReturnSuccess != configDictionary->getSubframeSize (&(streamFormat.fBitWidth), mInterfaceNumber, altSettingIndex), Exit);
}
else
{
numChannels = 0;
}
streamFormat.fNumChannels = numChannels;
streamFormat.fBitWidth *= 8;
streamFormat.fAlignment = kIOAudioStreamAlignmentLowByte;
streamFormat.fByteOrder = kIOAudioStreamByteOrderLittleEndian;
streamFormat.fDriverTag = (mInterfaceNumber << 16) | altSettingIndex;
streamFormatExtension.fVersion = kFormatExtensionCurrentVersion;
streamFormatExtension.fFlags = 0;
streamFormatExtension.fFramesPerPacket = 1;
streamFormatExtension.fBytesPerPacket = numChannels * (streamFormat.fBitWidth / 8);
switch (format)
{
case PCM:
streamFormat.fSampleFormat = kIOAudioStreamSampleFormatLinearPCM;
streamFormat.fNumericRepresentation = kIOAudioStreamNumericRepresentationSignedInt;
streamFormat.fIsMixable = TRUE;
if (2 == streamFormat.fNumChannels && 16 == streamFormat.fBitDepth && 16 == streamFormat.fBitWidth)
{
candidateAC3AltSetting = altSettingIndex;
}
break;
case AC3: debugIOLog ("? AppleUSBAudioEngine[%p]::addAvailableFormats () - Variable bit rate AC-3 audio format type", this);
continue; streamFormat.fSampleFormat = kIOAudioStreamSampleFormatAC3;
streamFormat.fIsMixable = FALSE;
streamFormat.fNumChannels = 6;
streamFormat.fNumericRepresentation = kIOAudioStreamNumericRepresentationSignedInt;
streamFormat.fBitDepth = 16;
streamFormat.fBitWidth = 16;
streamFormat.fByteOrder = kIOAudioStreamByteOrderBigEndian;
FailIf (kIOReturnSuccess != configDictionary->getAC3BSID (&(streamFormatExtension.fFlags), mInterfaceNumber, altSettingIndex), Exit);
streamFormatExtension.fFramesPerPacket = 1536;
streamFormatExtension.fBytesPerPacket = streamFormatExtension.fFramesPerPacket * streamFormat.fNumChannels * (streamFormat.fBitWidth / 8);
break;
case IEC1937_AC3:
debugIOLog ("? AppleUSBAudioEngine[%p]::addAvailableFormats () - IEC1937 AC-3 audio format type", this);
hasNativeAC3Format = TRUE;
streamFormat.fSampleFormat = kIOAudioStreamSampleFormat1937AC3;
streamFormat.fNumericRepresentation = kIOAudioStreamNumericRepresentationSignedInt;
streamFormat.fIsMixable = FALSE;
streamFormatExtension.fFramesPerPacket = 1536;
streamFormatExtension.fBytesPerPacket = streamFormatExtension.fFramesPerPacket * streamFormat.fNumChannels * (streamFormat.fBitWidth / 8);
break;
default:
debugIOLog ("? AppleUSBAudioEngine[%p]::addAvailableFormats () - Interface format = 0x%x not published.", this, format);
continue; }
debugIOLog ("? AppleUSBAudioEngine[%p]::addAvailableFormats () - Interface %d, Alt %d has a ", this, mInterfaceNumber, altSettingIndex);
debugIOLog (" %d bit interface, ", streamFormat.fBitDepth);
debugIOLog (" %d channel(s), and ", streamFormat.fNumChannels);
debugIOLog (" %d sample rate(s), which is/are:", numSampleRates);
if (numSampleRates && sampleRates)
{
for (rateIndex = 0; rateIndex < numSampleRates; rateIndex++)
{
FailIf (NULL == (arrayObject = sampleRates->getObject (rateIndex)), Exit);
FailIf (NULL == (arrayNumber = OSDynamicCast (OSNumber, arrayObject)), Exit);
thisSampleRate = arrayNumber->unsigned32BitValue();
debugIOLog (" %d", thisSampleRate);
lowSampleRate.whole = thisSampleRate;
lowSampleRate.fraction = 0;
mMainStream->addAvailableFormat (&streamFormat, &streamFormatExtension, &lowSampleRate, &lowSampleRate);
if (kIOAudioStreamSampleFormatLinearPCM == streamFormat.fSampleFormat)
{
streamFormat.fIsMixable = FALSE;
mMainStream->addAvailableFormat (&streamFormat, &streamFormatExtension, &lowSampleRate, &lowSampleRate);
streamFormat.fIsMixable = TRUE; }
}
debugIOLog ("");
}
else if (sampleRates)
{
FailIf (NULL == (arrayObject = sampleRates->getObject (0)), Exit);
FailIf (NULL == (arrayNumber = OSDynamicCast (OSNumber, arrayObject)), Exit);
thisSampleRate = arrayNumber->unsigned32BitValue();
FailIf (NULL == (arrayObject = sampleRates->getObject (1)), Exit);
FailIf (NULL == (arrayNumber = OSDynamicCast (OSNumber, arrayObject)), Exit);
otherSampleRate = arrayNumber->unsigned32BitValue();
debugIOLog (" %d to %d", thisSampleRate, otherSampleRate);
lowSampleRate.whole = thisSampleRate;
lowSampleRate.fraction = 0;
highSampleRate.whole = otherSampleRate;
highSampleRate.fraction = 0;
mMainStream->addAvailableFormat (&streamFormat, &streamFormatExtension, &lowSampleRate, &highSampleRate);
if (kIOAudioStreamSampleFormatLinearPCM == streamFormat.fSampleFormat)
{
streamFormat.fIsMixable = FALSE;
mMainStream->addAvailableFormat (&streamFormat, &streamFormatExtension, &lowSampleRate, &highSampleRate);
}
}
}
if (TRUE == hasDigitalOutput && FALSE == hasNativeAC3Format && 0 != candidateAC3AltSetting && kIOAudioStreamDirectionOutput == getDirection ())
{
FailIf (kIOReturnSuccess != configDictionary->getNumSampleRates (&numSampleRates, mInterfaceNumber, candidateAC3AltSetting), Exit);
sampleRates = configDictionary->getSampleRates (mInterfaceNumber, candidateAC3AltSetting);
FailIf (kIOReturnSuccess != configDictionary->getNumChannels (&numChannels, mInterfaceNumber, candidateAC3AltSetting), Exit);
streamFormat.fNumChannels = numChannels;
FailIf (kIOReturnSuccess != configDictionary->getBitResolution (&(streamFormat.fBitDepth), mInterfaceNumber, candidateAC3AltSetting), Exit);
FailIf (kIOReturnSuccess != configDictionary->getSubframeSize (&(streamFormat.fBitWidth), mInterfaceNumber, candidateAC3AltSetting), Exit);
streamFormat.fBitWidth *= 8;
streamFormat.fAlignment = kIOAudioStreamAlignmentLowByte;
streamFormat.fByteOrder = kIOAudioStreamByteOrderLittleEndian;
streamFormat.fDriverTag = (mInterfaceNumber << 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 * (streamFormat.fBitWidth / 8);
if (numSampleRates && sampleRates)
{
for (rateIndex = 0; rateIndex < numSampleRates; rateIndex++)
{
FailIf (NULL == (arrayObject = sampleRates->getObject (rateIndex)), Exit);
FailIf (NULL == (arrayNumber = OSDynamicCast (OSNumber, arrayObject)), Exit);
thisSampleRate = arrayNumber->unsigned32BitValue();
lowSampleRate.whole = thisSampleRate;
lowSampleRate.fraction = 0;
mMainStream->addAvailableFormat (&streamFormat, &streamFormatExtension, &lowSampleRate, &lowSampleRate);
}
}
else if (sampleRates)
{
FailIf (NULL == (arrayObject = sampleRates->getObject (0)), Exit);
FailIf (NULL == (arrayNumber = OSDynamicCast (OSNumber, arrayObject)), Exit);
thisSampleRate = arrayNumber->unsigned32BitValue();
FailIf (NULL == (arrayObject = sampleRates->getObject (1)), Exit);
FailIf (NULL == (arrayNumber = OSDynamicCast (OSNumber, arrayObject)), Exit);
otherSampleRate = arrayNumber->unsigned32BitValue();
lowSampleRate.whole = thisSampleRate;
lowSampleRate.fraction = 0;
highSampleRate.whole = otherSampleRate;
highSampleRate.fraction = 0;
mMainStream->addAvailableFormat (&streamFormat, &streamFormatExtension, &lowSampleRate, &highSampleRate);
}
}
result = kIOReturnSuccess;
Exit:
debugIOLog ("- AppleUSBAudioEngine[%p]::addAvailableFormats (%p) = 0x%x", this, configDictionary, result);
return result;
}
IOBufferMemoryDescriptor * AppleUSBAudioEngine::allocateBufferDescriptor (IOOptionBits options, vm_size_t capacity, vm_offset_t alignment)
{
IOBufferMemoryDescriptor * bufferDescriptorPtr = NULL;
#ifdef IOMEMORYDESCRIPTOR_SUPPORTS_DMACOMMAND
mach_vm_address_t physicalMask;
IOOptionBits usbOptions;
IOUSBControllerV2 * usbController;
#endif
debugIOLog ("+ AppleUSBAudioEngine[%p]::allocateBufferDescriptor ()", this);
FailIf (NULL == mStreamInterface, Exit);
#ifdef IOMEMORYDESCRIPTOR_SUPPORTS_DMACOMMAND
FailIf (NULL == (usbController = OSDynamicCast (IOUSBControllerV2, mStreamInterface->GetDevice()->GetBus ())), Exit);
FailIf (kIOReturnSuccess != usbController->GetLowLatencyOptionsAndPhysicalMask (&usbOptions, &physicalMask), Exit);
options |= usbOptions;
debugIOLog ("? AppleUSBAudioEngine[%p]::allocateBufferDescriptor () - allocating a buffer with mask 0x%x", this, physicalMask);
bufferDescriptorPtr = IOBufferMemoryDescriptor::inTaskWithPhysicalMask(kernel_task, options, capacity, physicalMask);
#else
if ( mUHCISupport )
{
options |= kIOMemoryPhysicallyContiguous;
}
bufferDescriptorPtr = IOBufferMemoryDescriptor::withOptions ( options, capacity, alignment );
#endif
Exit:
debugIOLog ("- AppleUSBAudioEngine[%p]::allocateBufferDescriptor () = %p", this, bufferDescriptorPtr);
return bufferDescriptorPtr;
}
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->mInterfaceNumber))
{
debugIOLog ("? AppleUSBAudioEngine[%p]::audioDevicePublished () - Found device (%p) for Audio Engine (%p)", audioEngine, audioDevice, audioEngine);
audioEngine->mUSBAudioDevice = audioDevice;
audioEngine->mDeviceAndEngineSyncer->signal (kIOReturnSuccess, FALSE);
resultCode = TRUE; }
}
Exit:
debugIOLog ("- AppleUSBAudioEngine::audioDevicePublished (%p, %p, %p)", audioEngine, (UInt32 *)ref, newService);
return resultCode;
}
void AppleUSBAudioEngine::calculateSamplesPerPacket (UInt32 sampleRate, UInt16 * averageFrameSamples, UInt16 * additionalSampleFrameFreq)
{
UInt32 divisor;
UInt32 modulus;
if ( mTransactionsPerUSBFrame )
{
modulus = 1000 * mTransactionsPerUSBFrame;
}
else
{
modulus = 1000;
}
* averageFrameSamples = sampleRate / modulus;
divisor = (sampleRate % modulus);
if ( divisor )
{
* additionalSampleFrameFreq = modulus / divisor;
}
else
{
* additionalSampleFrameFreq = 0;
}
}
IOReturn AppleUSBAudioEngine::checkForFeedbackEndpoint (AUAConfigurationDictionary * configDictionary)
{
IOUSBFindEndpointRequest associatedEndpoint;
IOReturn result;
UInt16 maxPacketSize;
UInt8 assocEndpoint;
UInt8 address;
UInt8 syncType;
result = kIOReturnSuccess;
mAssociatedPipe = NULL;
FailIf (NULL == mUSBAudioDevice, Exit);
FailIf (configDictionary->getIsocEndpointAddress (&address, mInterfaceNumber, mAlternateSettingID, mDirection), Exit);
FailIf (configDictionary->getIsocEndpointSyncType (&syncType, mInterfaceNumber, mAlternateSettingID, address), Exit);
if (kAsynchSyncType == syncType)
{
FailIf (kIOReturnSuccess != configDictionary->getIsocAssociatedEndpointAddress (&assocEndpoint, mInterfaceNumber, mAlternateSettingID, address), Exit);
if (assocEndpoint != 0)
{
debugIOLog ("? AppleUSBAudioEngine[%p]::checkForFeedbackEndpoint () - assocEndpoint = 0x%x", this, assocEndpoint);
FailIf (kIOReturnSuccess != configDictionary->getIsocAssociatedEndpointRefreshInt (&mRefreshInterval, mInterfaceNumber, mAlternateSettingID, assocEndpoint), Exit);
FailIf (kIOReturnSuccess != configDictionary->getIsocAssociatedEndpointMaxPacketSize (&maxPacketSize, mInterfaceNumber, mAlternateSettingID, assocEndpoint), Exit);
if (kUSBDeviceSpeedHigh == mUSBAudioDevice->getDeviceSpeed())
{
mFeedbackPacketSize = (maxPacketSize < kFixedPoint16_16ByteSize) ? maxPacketSize : kFixedPoint16_16ByteSize;
}
else
{
mFeedbackPacketSize = kFixedPoint10_14ByteSize;
}
debugIOLog ("? AppleUSBAudioEngine[%p]::checkForFeedbackEndpoint () - Synch endpoint has refresh interval %d, feedback packet size %d", this, mRefreshInterval, mFeedbackPacketSize);
mRefreshInterval = mRefreshInterval ? mRefreshInterval : kMinimumSyncRefreshInterval;
mFramesUntilRefresh = 1 << mRefreshInterval;
if (mFramesUntilRefresh < mNumUSBFramesPerList)
{
debugIOLog ("? AppleUSBAudioEngine[%p]::checkForFeedbackEndpoint () - Need to adjust mNumUSBFramesPerList: %ld < %ld", mFramesUntilRefresh, mNumUSBFramesPerList);
if (NULL != mUSBIsocFrames)
{
debugIOLog ("? AppleUSBAudioEngine[%p]::checkForFeedbackEndpoint () - Disposing of current mUSBIsocFrames [%p]", this, mUSBIsocFrames);
IOFree (mUSBIsocFrames, mNumUSBFrameLists * mNumTransactionsPerList * sizeof (IOUSBLowLatencyIsocFrame));
mUSBIsocFrames = NULL;
}
mNumUSBFramesPerList = PLAY_NUM_USB_FRAMES_PER_LIST_SYNC;
mNumTransactionsPerList = mNumUSBFramesPerList * mTransactionsPerUSBFrame;
mNumUSBFrameLists = mNumUSBFrameListsToQueue * 2;
debugIOLog ("? AppleUSBAudioEngine[%p]::checkForFeedbackEndpoint () - mNumUSBFramesPerList = %d, mNumUSBFrameListsToQueue = %d, mNumUSBFrameLists = %d", this, mNumUSBFramesPerList, mNumUSBFrameListsToQueue, mNumUSBFrameLists);
mUSBIsocFrames = (IOUSBLowLatencyIsocFrame *)IOMalloc (mNumUSBFrameLists * mNumTransactionsPerList * sizeof (IOUSBLowLatencyIsocFrame));
debugIOLog ("? AppleUSBAudioEngine[%p]::checkForFeedbackEndpoint () - mUSBIsocFrames is now %p", this, mUSBIsocFrames);
FailIf (NULL == mUSBIsocFrames, Exit);
}
associatedEndpoint.type = kUSBIsoc;
associatedEndpoint.direction = kUSBIn; associatedEndpoint.maxPacketSize = mFeedbackPacketSize;
associatedEndpoint.interval = 0xFF;
mAssociatedPipe = mStreamInterface->FindNextPipe (NULL, &associatedEndpoint);
FailWithAction (NULL == mAssociatedPipe, result = kIOReturnError, Exit);
if (NULL == mAssociatedEndpointMemoryDescriptor)
{
mAverageSampleRateBuffer = (UInt32 *)IOMallocContiguous (sizeof (UInt32), sizeof (UInt32), NULL);
FailIf (NULL == mAverageSampleRateBuffer, Exit);
bzero (mAverageSampleRateBuffer, sizeof (UInt32));
mAssociatedEndpointMemoryDescriptor = IOMemoryDescriptor::withAddress (mAverageSampleRateBuffer, sizeof (UInt32), kIODirectionIn);
FailIf (NULL == mAssociatedEndpointMemoryDescriptor, Exit);
}
mSampleRateFrame.frStatus = -1;
mSampleRateFrame.frReqCount = mFeedbackPacketSize;
mSampleRateFrame.frActCount = 0;
mSampleRateCompletion.target = (void *)this;
mSampleRateCompletion.action = sampleRateHandler;
mSampleRateCompletion.parameter = 0;
mAssociatedPipe->retain ();
} else
{
debugIOLog ("! AppleUSBAudioEngine[%p]::checkForFeedbackEndpoint () - No associated synch endpoint found.", this);
}
} else
{
debugIOLog ("? AppleUSBAudioEngine[%p]::checkForFeedbackEndpoint () - No associated synch endpoint.", this);
}
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 == mShouldStop && TRUE != mInCompletion)
{
curUSBFrameNumber = mStreamInterface->GetDevice()->GetBus()->GetFrameNumber ();
framesLeftInQueue = mUSBFrameToQueue - curUSBFrameNumber;
if (framesLeftInQueue < (mNumTransactionsPerList * (mNumUSBFrameListsToQueue / 2)) / 2)
{
debugIOLog ("! AppleUSBAudioEngine::clipOutputSamples () - Queue a write from clipOutputSamples: framesLeftInQueue = %ld", (UInt32)framesLeftInQueue);
writeHandler (this, mUSBCompletion[mCurrentFrameList].parameter, kIOReturnSuccess, &mUSBIsocFrames[mCurrentFrameList * mNumUSBFramesPerList]);
}
}
if (TRUE == streamFormat->fIsMixable)
{
if (NULL != miSubBufferMemory && NULL != miSubEngine)
{
iSubBufferLen = miSubBufferMemory->getLength ();
iSubBuffer = (void*)miSubBufferMemory->getVirtualSegment (0, &iSubBufferLen);
iSubBufferLen = iSubBufferLen / 2;
sampleRate = getSampleRate()->whole;
iSubFormat.altInterface = miSubEngine->GetAltInterface();
iSubFormat.numChannels = miSubEngine->GetNumChannels();
iSubFormat.bytesPerSample = miSubEngine->GetBytesPerSample();
iSubFormat.outputSampleRate = miSubEngine->GetSampleRate();
#if ABORT_PIPE_ON_START
if (mNeedToSync == FALSE && mLastClippedFrame == firstSampleFrame && 0x0 != miSubEngine->GetCurrentLoopCount ())
#else
if (mNeedToSync == FALSE && mLastClippedFrame == firstSampleFrame && 0xFFFFFFFF != miSubEngine->GetCurrentLoopCount ())
#endif
{
safetyOffset = miSubBufferOffset - ((iSubFormat.outputSampleRate) / 1000); if (safetyOffset < 0)
{
safetyOffset += iSubBufferLen;
}
if (miSubLoopCount == miSubEngine->GetCurrentLoopCount () && safetyOffset < (SInt32)(miSubEngine->GetCurrentByteCount () / 2))
{
#if DEBUGISUB
debugIOLog ("****iSub is in front of write head miSubBufferOffset = %ld, miSubEngine->GetCurrentByteCount () / 2 = %ld", miSubBufferOffset, miSubEngine->GetCurrentByteCount () / 2);
#endif
mNeedToSync = TRUE;
mStartiSub = TRUE;
}
else if (miSubLoopCount > (miSubEngine->GetCurrentLoopCount () + 1))
{
#if DEBUGISUB
debugIOLog ("****looped more than the iSub miSubLoopCount = %ld, miSubEngine->GetCurrentLoopCount () = %ld", miSubLoopCount, miSubEngine->GetCurrentLoopCount ());
#endif
mNeedToSync = TRUE;
mStartiSub = TRUE;
}
else if (miSubLoopCount < miSubEngine->GetCurrentLoopCount ())
{
#if DEBUGISUB
debugIOLog ("****iSub is ahead of us miSubLoopCount = %ld, miSubEngine->GetCurrentLoopCount () = %ld", miSubLoopCount, miSubEngine->GetCurrentLoopCount ());
#endif
mNeedToSync = TRUE;
mStartiSub = TRUE;
}
else if (miSubLoopCount == miSubEngine->GetCurrentLoopCount () && miSubBufferOffset > ((SInt32)((miSubEngine->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 miSubBufferOffset = %ld, (miSubEngine->GetCurrentByteCount () / 2 + iSubBufferLen) = %ld", miSubBufferOffset, (miSubEngine->GetCurrentByteCount() / 2 + iSubBufferLen));
#endif
mNeedToSync = TRUE;
mStartiSub = TRUE;
}
}
if (FALSE == mNeedToSync && mLastClippedFrame != firstSampleFrame && !(mLastClippedFrame == getNumSampleFramesPerBuffer () && firstSampleFrame == 0))
{
#if DEBUGISUB
debugIOLog ("miSubBufferOffset was %ld", miSubBufferOffset);
#endif
if (firstSampleFrame < mLastClippedFrame)
{
offsetDelta = (getNumSampleFramesPerBuffer () - firstSampleFrame + mLastClippedFrame) * miSubEngine->GetNumChannels();
}
else
{
offsetDelta = (firstSampleFrame - mLastClippedFrame) * miSubEngine->GetNumChannels();
}
offsetDelta = (offsetDelta * 1000) / ((sampleRate * 1000) / iSubFormat.outputSampleRate);
miSubBufferOffset += offsetDelta;
#if DEBUGISUB
debugIOLog ("clip to point was %ld, now %ld (delta = %ld)", mLastClippedFrame, firstSampleFrame, offsetDelta);
debugIOLog ("miSubBufferOffset is now %ld", miSubBufferOffset);
#endif
if (miSubBufferOffset > (SInt32)iSubBufferLen)
{
miSubLoopCount += miSubBufferOffset / iSubBufferLen;
miSubBufferOffset = miSubBufferOffset % iSubBufferLen;
#if DEBUGISUB
debugIOLog ("miSubBufferOffset > iSubBufferLen, miSubBufferOffset is now %ld", miSubBufferOffset);
#endif
}
else if (miSubBufferOffset < 0)
{
miSubBufferOffset += iSubBufferLen;
#if DEBUGISUB
debugIOLog ("miSubBufferOffset < 0, miSubBufferOffset is now %ld", miSubBufferOffset);
#endif
}
}
if (TRUE == mJustResetClipPosition)
{
mJustResetClipPosition = FALSE;
mNeedToSync = FALSE;
mStartiSub = FALSE;
}
if ( (TRUE == mNeedToSync)
|| (miSubEngine->GetNeedToSync()))
{
mNeedToSync = FALSE;
miSubEngine->SetNeedToSync(false);
mSrcPhase = 1.0; mSrcState = 0.0;
mFilterState.xl_1 = 0.0;
mFilterState.xr_1 = 0.0;
mFilterState.xl_2 = 0.0;
mFilterState.xr_2 = 0.0;
mFilterState.yl_1 = 0.0;
mFilterState.yr_1 = 0.0;
mFilterState.yl_2 = 0.0;
mFilterState.yr_2 = 0.0;
mFilterState2.xl_1 = 0.0;
mFilterState2.xr_1 = 0.0;
mFilterState2.xl_2 = 0.0;
mFilterState2.xr_2 = 0.0;
mFilterState2.yl_1 = 0.0;
mFilterState2.yr_1 = 0.0;
mFilterState2.yl_2 = 0.0;
mFilterState2.yr_2 = 0.0;
mPhaseCompState.xl_1 = 0.0;
mPhaseCompState.xr_1 = 0.0;
mPhaseCompState.xl_2 = 0.0;
mPhaseCompState.xr_2 = 0.0;
mPhaseCompState.yl_1 = 0.0;
mPhaseCompState.yr_1 = 0.0;
mPhaseCompState.yl_2 = 0.0;
mPhaseCompState.yr_2 = 0.0;
#if ABORT_PIPE_ON_START
bzero(iSubBuffer, iSubBufferLen);
#endif
UInt32 curSampleFrame = getCurrentSampleFrame ();
if (firstSampleFrame < curSampleFrame)
{
offsetDelta = (getNumSampleFramesPerBuffer () - curSampleFrame + firstSampleFrame) * miSubEngine->GetNumChannels();
}
else
{
offsetDelta = (firstSampleFrame - curSampleFrame) * miSubEngine->GetNumChannels();
}
offsetDelta = (offsetDelta * 1000) / ((sampleRate * 1000) / iSubFormat.outputSampleRate);
miSubBufferOffset = offsetDelta;
#if DEBUGISUB
debugIOLog ("USBEngine: need sync: starting miSubBufferOffset = %ld, miSubLoopCount = %ld", miSubBufferOffset, miSubLoopCount);
#endif
}
if (miSubBufferOffset > (SInt32)iSubBufferLen)
{
mNeedToSync = TRUE;
miSubLoopCount += miSubBufferOffset / iSubBufferLen;
miSubBufferOffset = miSubBufferOffset % iSubBufferLen;
#if DEBUGISUB
debugIOLog ("miSubBufferOffset > iSubBufferLen, miSubBufferOffset is now %ld", miSubBufferOffset);
#endif
}
else if (miSubBufferOffset < 0)
{
miSubBufferOffset += iSubBufferLen;
#if DEBUGISUB
debugIOLog ("miSubBufferOffset < 0, miSubBufferOffset is now %ld", miSubBufferOffset);
#endif
}
if (mPlugin)
{
mPlugin->pluginProcess ((Float32*)mixBuf + (firstSampleFrame * streamFormat->fNumChannels), numSampleFrames, streamFormat->fNumChannels);
}
result = clipAppleUSBAudioToOutputStreamiSub (mixBuf, sampleBuf, &mFilterState, &mFilterState2, &mPhaseCompState, mLowFreqSamples, mHighFreqSamples, firstSampleFrame, numSampleFrames, sampleRate, streamFormat, (SInt16*)iSubBuffer, &miSubLoopCount, &miSubBufferOffset, iSubBufferLen, &iSubFormat, &mSrcPhase, &mSrcState);
if (TRUE == mStartiSub)
{
miSubEngine->StartiSub ();
mStartiSub = FALSE;
miSubLoopCount = 0;
}
mLastClippedFrame = firstSampleFrame + numSampleFrames;
}
else
{
if (mPlugin)
{
mPlugin->pluginProcess ((Float32*)mixBuf + (firstSampleFrame * streamFormat->fNumChannels), numSampleFrames, streamFormat->fNumChannels);
}
result = clipAppleUSBAudioToOutputStream (mixBuf, sampleBuf, firstSampleFrame, numSampleFrames, streamFormat);
#if DEBUGLATENCY
if (!mHaveClipped)
{
mHaveClipped = true;
}
else if ((0 == firstSampleFrame) || true)
{
}
#endif
}
if (mUHCISupport)
{
UInt32 start = firstSampleFrame * streamFormat->fNumChannels * (streamFormat->fBitWidth / 8); if ( start < mAlternateFrameSize )
{
UInt32 size = mAlternateFrameSize - start;
memcpy( &( ( ( char * )sampleBuf )[ mSampleBufferSize + start ] ), & ( ( ( char * )sampleBuf )[ start ] ), size );
#if DEBUGUHCI
debugIOLog( "? AppleUSBAudioEngine::clipOutputSamples () - firstSampleFrame = %d. Just copied %d bytes from %d to %d \n", firstSampleFrame, size, start, start + mSampleBufferSize );
#endif
}
}
}
else
{
UInt32 offset;
offset = firstSampleFrame * streamFormat->fNumChannels * (streamFormat->fBitWidth / 8);
memcpy ((UInt8 *)sampleBuf + offset, (UInt8 *)mixBuf, numSampleFrames * streamFormat->fNumChannels * (streamFormat->fBitWidth / 8));
mLastClippedFrame = firstSampleFrame + numSampleFrames;
result = kIOReturnSuccess;
}
return result;
}
IOReturn AppleUSBAudioEngine::CoalesceInputSamples (UInt32 numBytesToCoalesce, IOUSBLowLatencyIsocFrame * pFrames) {
IOReturn result = kIOReturnSuccess;
AbsoluteTime time;
UInt32 usbFrameIndex;
UInt32 numFramesChecked;
UInt32 numBytesToCopy;
UInt32 numBytesToEnd;
UInt32 numBytesCopied;
UInt32 originalBufferOffset;
SInt32 numBytesLeft;
UInt32 preWrapBytes = 0;
UInt32 byteCount = 0;
UInt8 * source;
UInt8 * dest;
Boolean done;
bool onCoreAudioThread;
if (mCoalescenceMutex)
{
IOLockLock (mCoalescenceMutex);
}
#if DEBUGINPUT
debugIOLog ("+ AppleUSBAudioEngine[%p]::CoalesceInputSamples (%lu, %p)", this, numBytesToCoalesce, pFrames);
#endif
originalBufferOffset = 0;
if (0 != numBytesToCoalesce)
{
onCoreAudioThread = true;
originalBufferOffset = mBufferOffset; #if DEBUGINPUT
debugIOLog ("! AppleUSBAudioEngine[%p]::CoalesceInputSamples () - Coalesce from %ld %ld bytes (framelist %ld) on CoreAudio thread", this, originalBufferOffset, numBytesToCoalesce, mCurrentFrameList);
#endif
if ( !mHaveTakenFirstTimeStamp )
{
debugIOLog ("! AppleUSBAudioEngine[%p]::CoalesceInputSamples () - CoreAudio thread is asking for samples without having been sent a timestamp!", this );
}
}
else
{
onCoreAudioThread = false;
}
if (NULL == pFrames)
{
pFrames = &mUSBIsocFrames[mCurrentFrameList * mNumTransactionsPerList];
}
dest = (UInt8 *)getSampleBuffer () + mBufferOffset;
source = (UInt8 *)mReadBuffer + (mCurrentFrameList * mReadUSBFrameListSize);
usbFrameIndex = 0;
numFramesChecked = 0;
numBytesCopied = 0;
numBytesLeft = numBytesToCoalesce;
done = FALSE;
while ( (FALSE == done)
&& ('llit' != pFrames[usbFrameIndex].frStatus) && (-1 != pFrames[usbFrameIndex].frStatus)) {
if ( (!(mShouldStop))
&& ( (kIOReturnSuccess != pFrames[usbFrameIndex].frStatus)
&& ( (kIOReturnUnderrun != pFrames[usbFrameIndex].frStatus)
|| (pFrames[usbFrameIndex].frActCount < mAverageFrameSize - mSampleSize))))
{
debugIOLog ("! AppleUSBAudioEngine[%p]::CoalesceInputSamples () - encountered unusual frame with status 0x%x in frame list %lu", this, pFrames[usbFrameIndex].frStatus, usbFrameIndex);
debugIOLog (" pFrames[%lu].frStatus = 0x%x", usbFrameIndex, pFrames[usbFrameIndex].frStatus);
debugIOLog (" pFrames[%lu].frReqCount = %lu", usbFrameIndex, pFrames[usbFrameIndex].frReqCount);
debugIOLog (" pFrames[%lu].frActCount = %lu", usbFrameIndex, pFrames[usbFrameIndex].frActCount);
debugIOLog (" pFrames[%lu].frTimeStamp = 0x%x", usbFrameIndex, (* (UInt64 *) &(pFrames[usbFrameIndex].frTimeStamp)));
}
numBytesToEnd = getSampleBufferSize () - mBufferOffset;
if ( (!mHaveTakenFirstTimeStamp)
&& (0 == mBufferOffset)
&& (pFrames[usbFrameIndex].frActCount > 0))
{
debugIOLog ("? AppleUSBAudioEngine::CoalesceInputSamples () - Taking first time stamp.");
time = generateTimeStamp (usbFrameIndex, 0, 0);
takeTimeStamp (false, &time);
}
if ((UInt32)(pFrames[usbFrameIndex].frActCount) > numBytesToEnd)
{
numBytesToCopy = numBytesToEnd;
preWrapBytes = numBytesToEnd;
byteCount = pFrames[usbFrameIndex].frActCount;
}
else
{
numBytesToCopy = pFrames[usbFrameIndex].frActCount;
if (0 == numBytesToCoalesce)
{
pFrames[usbFrameIndex].frActCount = 0;
#ifdef DEBUG
if (kIOReturnUnderrun == pFrames[usbFrameIndex].frStatus)
{
pFrames[usbFrameIndex].frStatus = kIOReturnSuccess;
}
#endif DEBUG
}
}
if (0 != numBytesToCopy)
{
memcpy (dest, source, numBytesToCopy);
mBufferOffset += numBytesToCopy;
numBytesLeft -= numBytesToCopy;
}
numBytesCopied = numBytesToCopy;
if (pFrames[usbFrameIndex].frActCount > numBytesToEnd)
{
numBytesToCopy = pFrames[usbFrameIndex].frActCount - numBytesToEnd;
dest = (UInt8 *)getSampleBuffer ();
memcpy (dest, source + numBytesCopied, numBytesToCopy);
mBufferOffset = numBytesToCopy;
numBytesLeft -= numBytesToCopy;
if (0 == numBytesToCoalesce)
{
time = generateTimeStamp (usbFrameIndex, preWrapBytes, byteCount);
takeTimeStamp (TRUE, &time);
}
}
dest += numBytesToCopy;
source += pFrames[usbFrameIndex].frReqCount;
usbFrameIndex++;
numFramesChecked++;
if (0 != numBytesToCoalesce && (usbFrameIndex + (mCurrentFrameList * mNumTransactionsPerList)) == (mNumUSBFrameLists * mNumTransactionsPerList))
{
pFrames = &mUSBIsocFrames[0]; usbFrameIndex = 0;
source = (UInt8 *)mReadBuffer;
}
if (((0 == numBytesToCoalesce) && (mNumTransactionsPerList == usbFrameIndex)) || ((0 != numBytesToCoalesce) && (0 >= numBytesLeft)) || ((0 != numBytesToCoalesce) && (numFramesChecked >= (mNumTransactionsPerList * mNumUSBFrameLists)))) {
done = TRUE;
}
}
if (0 != numBytesToCoalesce)
{
mBufferOffset = originalBufferOffset;
}
if ( ( 0 != numBytesToCoalesce )
&& ( numBytesLeft > 0 ) )
{
debugIOLog ("! AppleUSBAudioEngine[%p]::CoalesceInputSamples () - Requested: %lu, Remaining: %lu on frame list %lu", this, numBytesToCoalesce, numBytesLeft, mCurrentFrameList);
}
#if DEBUGINPUT
debugIOLog ("- AppleUSBAudioEngine[%p]::CoalesceInputSamples (%lu, %p)", this, numBytesToCoalesce, pFrames);
#endif
if (mCoalescenceMutex)
{
IOLockUnlock (mCoalescenceMutex);
}
if ( kIOReturnSuccess != result )
{
debugIOLog ( "! AppleUSBAudioEngine[%p]::CoalesceInputSamples (%lu, %p) = 0x%x", this, numBytesToCoalesce, pFrames, result );
}
return result;
}
IOReturn AppleUSBAudioEngine::controlledFormatChange (IOAudioStream *audioStream, const IOAudioStreamFormat *newFormat, const IOAudioSampleRate *newSampleRate)
{
IOReturn result;
AUAConfigurationDictionary * configDictionary = NULL;
void * sampleBuffer;
UInt32 i;
UInt32 numSamplesInBuffer;
UInt32 minimumSafeSampleOffset;
UInt32 cautiousSafeSampleOffset;
UInt16 averageFrameSamples;
UInt16 additionalSampleFrameFreq;
UInt16 maxPacketSize;
UInt8 endpointAddress;
UInt8 interval;
UInt8 newAlternateSettingID;
UInt8 newDirection;
UInt8 oldTransactionsPerFrame;
bool highSpeedCompensation;
bool needToChangeChannels;
bool forcedFormatChange = false;
debugIOLog ("+ AppleUSBAudioEngine[%p]::controlledFormatChange (%p, %p, %p)", this, audioStream, newFormat, newSampleRate);
result = kIOReturnError;
FailIf (NULL == mStreamInterface, Exit);
FailIf (NULL == mUSBAudioDevice, Exit);
FailIf (NULL == (configDictionary = mUSBAudioDevice->getConfigDictionary()), Exit);
if ( (newFormat == NULL)
&& (audioStream != NULL))
{
result = kIOReturnSuccess;
goto Exit;
}
if (NULL == audioStream)
{
forcedFormatChange = true;
audioStream = mMainStream;
if (NULL == newFormat)
{
newFormat = &(audioStream->format);
}
}
FailIf (NULL == audioStream, Exit);
FailIf (NULL == newFormat, Exit);
mInterfaceNumber = (UInt8)(newFormat->fDriverTag >> 16);
newAlternateSettingID = (UInt8)(newFormat->fDriverTag);
if (newFormat->fNumChannels != audioStream->format.fNumChannels)
{
needToChangeChannels = TRUE;
debugIOLog ("? AppleUSBAudioEngine[%p]::controlledFormatChange () - Need to adjust channel controls (cur = %d, new = %d)", this, audioStream->format.fNumChannels, newFormat->fNumChannels);
if (kIOAudioStreamDirectionOutput == mDirection)
{
if (1 == newFormat->fNumChannels)
{
mUSBAudioDevice->setMonoState (TRUE);
}
else
{
mUSBAudioDevice->setMonoState (FALSE);
}
}
}
else
{
needToChangeChannels = FALSE;
}
if (newSampleRate)
{
debugIOLog ("? AppleUSBAudioEngine[%p]::controlledFormatChange () - Changing sampling rate to %d", this, newSampleRate->whole);
mCurSampleRate = *newSampleRate;
}
else
{
}
if (false == configDictionary->verifySampleRateIsSupported (mInterfaceNumber, newAlternateSettingID, mCurSampleRate.whole))
{
debugIOLog ("? AppleUSBAudioEngine[%p]::controlledFormatChange () - %d channel %d bit @ %d Hz is not supported by alternate setting %d.", this,
newFormat->fNumChannels, newFormat->fBitDepth, mCurSampleRate.whole, newAlternateSettingID);
FailIf (kIOReturnSuccess != configDictionary->getAltSettingWithSettings (&newAlternateSettingID, mInterfaceNumber, newFormat->fNumChannels, newFormat->fBitDepth, mCurSampleRate.whole), Exit);
}
FailIf (kIOReturnSuccess != configDictionary->getIsocEndpointDirection (&newDirection, mInterfaceNumber, newAlternateSettingID), Exit);
FailIf (newDirection != mDirection, Exit);
debugIOLog ("? AppleUSBAudioEngine[%p]::controlledFormatChange () - about to set: mInterfaceNumber = %d & newAlternateSettingID = %d", this, mInterfaceNumber, newAlternateSettingID);
mAlternateSettingID = newAlternateSettingID;
oldTransactionsPerFrame = mTransactionsPerUSBFrame;
if ( ( IP_VERSION_02_00 == mStreamInterface->GetInterfaceProtocol () )
&& ( kUSBDeviceSpeedHigh == mUSBAudioDevice->getDeviceSpeed () ) )
{
FailIf ( kIOReturnSuccess != configDictionary->getIsocEndpointInterval ( &interval, mInterfaceNumber, mAlternateSettingID, mDirection ), Exit );
if ( 0 == interval )
{
debugIOLog ( "! AppleUSBAudioEngine[%p]::controlledFormatChange () - ERROR! Isoc endpoint has a refresh interval of 0! Treating as 4 ...", this );
mTransactionsPerUSBFrame = 1;
}
else
{
FailIf ( interval > 4, Exit );
mTransactionsPerUSBFrame = 8 >> ( interval - 1 );
}
}
else
{
mTransactionsPerUSBFrame = 1;
}
mNumTransactionsPerList = mNumUSBFramesPerList * mTransactionsPerUSBFrame;
if ( ( NULL != mUSBIsocFrames )
&& ( oldTransactionsPerFrame != mTransactionsPerUSBFrame ) )
{
IOFree ( mUSBIsocFrames, mNumUSBFrameLists * mNumUSBFramesPerList * oldTransactionsPerFrame * sizeof ( IOUSBLowLatencyIsocFrame ) );
mUSBIsocFrames = NULL;
}
if ( NULL == mUSBIsocFrames )
{
mUSBIsocFrames = ( IOUSBLowLatencyIsocFrame * ) IOMalloc ( mNumUSBFrameLists * mNumTransactionsPerList * sizeof ( IOUSBLowLatencyIsocFrame ) );
}
if (mPlugin)
{
mPlugin->pluginSetFormat (newFormat, &mCurSampleRate);
}
if (IP_VERSION_02_00 == mStreamInterface->GetInterfaceProtocol())
{
OSArray * pathArray = mUSBAudioDevice->getOptimalClockPath ( this, mInterfaceNumber, mAlternateSettingID, mCurSampleRate.whole, NULL );
FailIf ( NULL == pathArray, Exit );
mUSBAudioDevice->setClockPathCurSampleRate ( mCurSampleRate.whole, pathArray );
mActiveClockPath = pathArray;
}
if (configDictionary->asEndpointHasSampleFreqControl (mInterfaceNumber, mAlternateSettingID))
{
FailIf (kIOReturnSuccess != configDictionary->getIsocEndpointAddress (&endpointAddress, mInterfaceNumber, mAlternateSettingID, mDirection), Exit);
(void) setSampleRateControl (endpointAddress, mCurSampleRate.whole); }
mAverageSampleRate = mCurSampleRate.whole; calculateSamplesPerPacket (mCurSampleRate.whole, &averageFrameSamples, &additionalSampleFrameFreq);
debugIOLog ("? AppleUSBAudioEngine[%p]::controlledFormatChange () - averageFrameSamples = %d, additionalSampleFrameFreq = %d", this, averageFrameSamples, additionalSampleFrameFreq);
mSampleSize = newFormat->fNumChannels * (newFormat->fBitWidth / 8);
mAverageFrameSize = averageFrameSamples * mSampleSize;
mAlternateFrameSize = (averageFrameSamples + 1) * mSampleSize;
debugIOLog ("? AppleUSBAudioEngine[%p]::controlledFormatChange () - mAverageFrameSize = %d, mAlternateFrameSize = %d", this, mAverageFrameSize, mAlternateFrameSize);
if (kUSBIn == mDirection)
{
FailIf ( kIOReturnSuccess != configDictionary->getIsocEndpointMaxPacketSize ( &maxPacketSize, mInterfaceNumber, mAlternateSettingID, mDirection ), Exit );
mReadUSBFrameListSize = ( ( mAlternateFrameSize + mSampleSize ) < maxPacketSize ) ? ( mAlternateFrameSize + mSampleSize ) : maxPacketSize;
mReadUSBFrameListSize *= mNumTransactionsPerList;
}
numSamplesInBuffer = mAverageSampleRate / 4;
numSamplesInBuffer += (PAGE_SIZE*2 - 1);
numSamplesInBuffer /= PAGE_SIZE*2;
numSamplesInBuffer *= PAGE_SIZE*2;
mSampleBufferSize = numSamplesInBuffer * mSampleSize;
if (mUHCISupport)
{
mSampleBufferSizeExtended = mSampleBufferSize + PAGE_SIZE;
}
else
{
mSampleBufferSizeExtended = mSampleBufferSize;
}
debugIOLog("? AppleUSBAudioEngine[%p]::controlledFormatChange () - New mSampleBufferSize = %d numSamplesInBuffer = %d", this, mSampleBufferSize, numSamplesInBuffer );
if (NULL != miSubBufferMemory)
{
if (FALSE == isiSubCompatibleFormat (newFormat, mCurSampleRate))
{
debugIOLog ("! AppleUSBAudioEngine[%p]::controlledFormatChange () - Closing connection to iSub due to incompatible format", this);
iSubTeardownConnection ();
}
} else
{
if (miSubAttachToggle)
{
}
if (NULL != miSubAttachToggle && 1 == miSubAttachToggle->getIntValue ())
{
iSubAttachChangeCall (isiSubCompatibleFormat (newFormat, mCurSampleRate));
}
}
if (NULL != mSampleBufferDescriptors)
{
for (i = 0; i < mNumUSBFrameLists; i++)
{
if (NULL != mSampleBufferDescriptors[i])
{
mSampleBufferDescriptors[i]->release ();
mSampleBufferDescriptors[i] = NULL;
}
}
}
if (kUSBIn == mDirection)
{
if (NULL != mReadBuffer)
{
mUSBBufferDescriptor->release ();
}
mUSBBufferDescriptor = allocateBufferDescriptor (kIODirectionIn, mNumUSBFrameLists * mReadUSBFrameListSize, PAGE_SIZE);
FailIf (NULL == mUSBBufferDescriptor, Exit);
mReadBuffer = mUSBBufferDescriptor->getBytesNoCopy ();
FailIf (NULL == mReadBuffer, Exit);
for (i = 0; i < mNumUSBFrameLists; i++)
{
mSampleBufferDescriptors[i] = OSTypeAlloc (IOSubMemoryDescriptor);
mSampleBufferDescriptors[i]->initSubRange (mUSBBufferDescriptor, i * mReadUSBFrameListSize, mReadUSBFrameListSize, kIODirectionIn);
FailIf (NULL == mSampleBufferDescriptors[i], Exit);
}
if (NULL != mSampleBufferMemoryDescriptor)
{
mMainStream->setSampleBuffer (NULL, 0);
setNumSampleFramesPerBuffer (0);
mSampleBufferMemoryDescriptor->release ();
}
mSampleBufferMemoryDescriptor = IOBufferMemoryDescriptor::withOptions (kIODirectionInOut, mSampleBufferSize, PAGE_SIZE);
FailIf (NULL == mSampleBufferMemoryDescriptor, Exit);
sampleBuffer = mSampleBufferMemoryDescriptor->getBytesNoCopy ();
}
else
{
if (NULL != miSubBufferMemory)
{
if (NULL != mLowFreqSamples)
{
IOFree (mLowFreqSamples, getSampleBufferSize () * 2);
}
if (NULL != mHighFreqSamples)
{
IOFree (mHighFreqSamples, getSampleBufferSize () * 2);
}
if ((2 == newFormat->fNumChannels) && ((8000 == mCurSampleRate.whole) || (11025 == mCurSampleRate.whole) || (22050 == mCurSampleRate.whole) ||
(44100 == mCurSampleRate.whole) || (48000 == mCurSampleRate.whole) || (96000 == mCurSampleRate.whole)))
{
mLowFreqSamples = (float *)IOMallocAligned (mSampleBufferSize * 2, PAGE_SIZE);
FailIf (NULL == mLowFreqSamples, Exit);
mHighFreqSamples = (float *)IOMallocAligned (mSampleBufferSize * 2, PAGE_SIZE);
FailIf (NULL == mHighFreqSamples, Exit);
}
}
if (NULL != mUSBBufferDescriptor)
{
mMainStream->setSampleBuffer (NULL, 0);
setNumSampleFramesPerBuffer (0);
mUSBBufferDescriptor->release ();
}
if (mUHCISupport)
{
mUSBBufferDescriptor = allocateBufferDescriptor (kIODirectionOut, mSampleBufferSizeExtended, PAGE_SIZE);
}
else
{
mUSBBufferDescriptor = allocateBufferDescriptor (kIODirectionOut, mSampleBufferSize, PAGE_SIZE);
}
FailIf (NULL == mUSBBufferDescriptor, Exit);
for (i = 0; i < mNumUSBFrameLists; i++)
{
if (NULL != mSampleBufferDescriptors[i])
{
mSampleBufferDescriptors[i]->release ();
}
mSampleBufferDescriptors[i] = OSTypeAlloc (IOSubMemoryDescriptor);
mSampleBufferDescriptors[i]->initSubRange (mUSBBufferDescriptor, 0, mSampleBufferSize, kIODirectionOut);
FailIf (NULL == mSampleBufferDescriptors[i], Exit);
result = mSampleBufferDescriptors[i]->prepare();
FailIf (kIOReturnSuccess != result, Exit);
}
sampleBuffer = mUSBBufferDescriptor->getBytesNoCopy();
FailIf (NULL == sampleBuffer, Exit);
}
mMainStream->setSampleBuffer (sampleBuffer, mSampleBufferSize);
setNumSampleFramesPerBuffer (numSamplesInBuffer);
if (kUSBIn == mDirection)
{
if (mSplitTransactions)
{
debugIOLog ("? AppleUSBAudioEngine[%p]::controlledFormatChange () - Compensating for high speed timing difference in sample offset", this);
highSpeedCompensation = true;
}
else
{
highSpeedCompensation = false;
}
minimumSafeSampleOffset = averageFrameSamples + 1;
cautiousSafeSampleOffset = minimumSafeSampleOffset + (minimumSafeSampleOffset / kUSBInputRecoveryTimeFraction) + (highSpeedCompensation ? (5 * minimumSafeSampleOffset / 3) : 0);
setSampleOffset (cautiousSafeSampleOffset);
debugIOLog ("? AppleUSBAudioEngine[%p]::controlledFormatChange () - setting input sample offset to %lu sample frames", this, minimumSafeSampleOffset);
setSampleLatency (averageFrameSamples * ( 1));
}
else
{
cautiousSafeSampleOffset = averageFrameSamples + 1;
minimumSafeSampleOffset = cautiousSafeSampleOffset / 2;
setSampleOffset (minimumSafeSampleOffset);
debugIOLog ("? AppleUSBAudioEngine[%p]::controlledFormatChange () - setting output sample offset to %lu sample frames", this, minimumSafeSampleOffset);
setSampleLatency (additionalSampleFrameFreq ? averageFrameSamples + 1 : averageFrameSamples);
}
if (TRUE == needToChangeChannels)
{
beginConfigurationChange ();
removeAllDefaultAudioControls ();
mUSBAudioDevice->createControlsForInterface (this, mInterfaceNumber, mAlternateSettingID);
completeConfigurationChange ();
}
debugIOLog ("? AppleUSBAudioEngine[%p]::controlledFormatChange () - Called setNumSampleFramesPerBuffer with %d", this, mSampleBufferSize / (mSampleSize ? mSampleSize : 1));
debugIOLog ("? AppleUSBAudioEngine[%p]::controlledFormatChange () - newFormat->fNumChannels = %d, newFormat->fBitWidth %d", this, newFormat->fNumChannels, newFormat->fBitWidth);
result = kIOReturnSuccess;
Exit:
debugIOLog ("- AppleUSBAudioEngine[%p]::controlledFormatChange () = 0x%x", this, result);
return result;
}
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 coalescenceErrorCode = kIOReturnSuccess;
IOReturn result = kIOReturnSuccess;
#if DEBUGCONVERT
debugIOLog ("+ AppleUSBAudioEngine::convertInputSamples (%p, %p, %lu, %lu, %p, %p)", sampleBuf, destBuf, firstSampleFrame, numSampleFrames, streamFormat, audioStream);
#endif
if (!mHaveTakenFirstTimeStamp)
{
debugIOLog ("! AppleUSBAudioEngine::convertInputSamples () - called before first time stamp!");
}
#if 1 if (0 == mShouldStop && TRUE != mInCompletion)
{
curUSBFrameNumber = mStreamInterface->GetDevice()->GetBus()->GetFrameNumber ();
framesLeftInQueue = mUSBFrameToQueue - curUSBFrameNumber;
if (framesLeftInQueue < (mNumTransactionsPerList * (mNumUSBFrameListsToQueue / 2)) / 2)
{
while (framesLeftInQueue < mNumTransactionsPerList* (mNumUSBFrameListsToQueue - 1) && 0 == mShouldStop)
{
#if DEBUGLOADING
debugIOLog ("! AppleUSBAudioEngine::convertInputSamples () - Queue a read from convertInputSamples: framesLeftInQueue = %ld", (UInt32)framesLeftInQueue);
#endif
readHandler (this, mUSBCompletion[mCurrentFrameList].parameter, kIOReturnSuccess, &mUSBIsocFrames[mCurrentFrameList * mNumUSBFramesPerList]);
curUSBFrameNumber = mStreamInterface->GetDevice()->GetBus()->GetFrameNumber ();
framesLeftInQueue = mUSBFrameToQueue - curUSBFrameNumber;
}
}
}
#endif
#if 1 lastSampleByte = (firstSampleFrame + numSampleFrames) * streamFormat->fNumChannels * (streamFormat->fBitWidth / 8);
if (mBufferOffset + 1 > getSampleBufferSize ())
{
windowStartByte = 0;
}
else
{
windowStartByte = mBufferOffset + 1;
}
windowEndByte = windowStartByte + (mNumUSBFrameListsToQueue * mReadUSBFrameListSize);
if (windowEndByte > getSampleBufferSize ())
{
windowEndByte -= getSampleBufferSize ();
}
if ((windowStartByte < lastSampleByte && windowEndByte > lastSampleByte) ||
(windowEndByte > lastSampleByte && windowStartByte > windowEndByte) ||
(windowStartByte < lastSampleByte && windowStartByte > windowEndByte && windowEndByte < lastSampleByte))
{
if (mBufferOffset < lastSampleByte)
{
coalescenceErrorCode = CoalesceInputSamples (lastSampleByte - mBufferOffset, NULL);
#if DEBUGLOADING
debugIOLog ("! AppleUSBAudioEngine::convertInputSamples () - Coalesce from convert %d bytes", lastSampleByte - mBufferOffset);
#endif
}
else
{
UInt32 numBytesToCoalesce = getSampleBufferSize () - mBufferOffset + lastSampleByte;
coalescenceErrorCode = CoalesceInputSamples (numBytesToCoalesce, NULL);
#if DEBUGLOADING
debugIOLog ("! AppleUSBAudioEngine::convertInputSamples () - Coalesce from convert %d bytes (wrapping)", numBytesToCoalesce);
#endif
}
}
#endif
result = convertFromAppleUSBAudioInputStream_NoWrap (sampleBuf, destBuf, firstSampleFrame, numSampleFrames, streamFormat);
if (mPlugin)
{
mPlugin->pluginProcessInput ((float *)destBuf, numSampleFrames, streamFormat->fNumChannels);
}
#if 0
if (0 == firstSampleFrame) {
debugIOLog("sample 0 converted on USB frame %llu", mStreamInterface->GetDevice()->GetBus()->GetFrameNumber());
}
#endif
if ( kIOReturnSuccess != coalescenceErrorCode )
{
result = coalescenceErrorCode;
}
if ( kIOReturnSuccess != result )
{
debugIOLog ( "! AppleUSBAudioEngine::convertInputSamples () = 0x%x", result );
}
return result;
}
IOReturn AppleUSBAudioEngine::copyAnchor (UInt64 * anchorFrame, AbsoluteTime * anchorTime)
{
IOReturn result = kIOReturnError;
UInt64 frame = 0ull;
AbsoluteTime time;
UInt8 triesLeft;
FailIf (NULL == mUSBAudioDevice, Exit);
triesLeft = 3;
do
{
frame = mUSBAudioDevice->mNewReferenceUSBFrame;
time = mUSBAudioDevice->mNewReferenceWallTime;
triesLeft--;
} while ( (frame != mUSBAudioDevice->mNewReferenceUSBFrame)
&& (0 != triesLeft));
FailIf (frame != mUSBAudioDevice->mNewReferenceUSBFrame, Exit);
*anchorFrame = frame;
*anchorTime = time;
result = kIOReturnSuccess;
Exit:
return result;
}
IOReturn AppleUSBAudioEngine::eraseOutputSamples(const void *mixBuf, void *sampleBuf, UInt32 firstSampleFrame, UInt32 numSampleFrames, const IOAudioStreamFormat *streamFormat, IOAudioStream *audioStream)
{
super::eraseOutputSamples (mixBuf, sampleBuf, firstSampleFrame, numSampleFrames, streamFormat, audioStream);
if ( (mUHCISupport)
&& (getDirection () == kIOAudioStreamDirectionOutput))
{
UInt32 start = firstSampleFrame * streamFormat->fNumChannels * (streamFormat->fBitWidth / 8); if ( start < mAlternateFrameSize )
{
UInt32 size = mAlternateFrameSize - start;
bzero( &( ( ( char * )sampleBuf )[ mSampleBufferSize + start ] ), size );
}
}
return kIOReturnSuccess;
}
AbsoluteTime AppleUSBAudioEngine::generateTimeStamp (UInt32 usbFrameIndex, UInt32 preWrapBytes, UInt32 byteCount)
{
UInt64 transactionDifference = 0ull;
UInt64 usbFrameDifference = 0ull;
UInt64 time_nanos = 0ull;
UInt64 referenceWallTime_nanos = 0ull;
UInt64 anchorFrame;
AbsoluteTime anchorTime;
AbsoluteTime time;
#if DEBUGTIMESTAMPS
SInt64 stampDifference = 0;
UInt64 frameDifference = 0;
UInt64 sampleRate = 0;
SInt64 stampJitter = 0;
#endif
UInt64 thisFrameNum;
UInt32 divisor;
UInt32 remainingTransfers = 0ul;
UInt32 partialFrame = 0;
bool anchorInFuture;
FailIf ( NULL == mFrameQueuedForList, Exit );
FailIf ( NULL == mUSBAudioDevice, Exit );
FailIf ( 0 == mTransactionsPerUSBFrame, Exit );
FailIf ( kIOReturnSuccess != copyAnchor ( &anchorFrame, &anchorTime ), Exit );
remainingTransfers = usbFrameIndex ? ( usbFrameIndex % mTransactionsPerUSBFrame ) : 0;
remainingTransfers = remainingTransfers ? ( remainingTransfers - 1 ) : 0;
thisFrameNum = mFrameQueuedForList[mCurrentFrameList] + ( ( usbFrameIndex - remainingTransfers ) / mTransactionsPerUSBFrame );
#if 0
if ( 1 != mTransactionsPerUSBFrame )
{
debugIOLog ( "? AppleUSBAudioEngine[%p]::generateTimeStamp () - thisFrameNum = %llu, anchorFrame = %llu", this, thisFrameNum, anchorFrame );
}
#endif
anchorInFuture = ( anchorFrame > thisFrameNum );
partialFrame = ( ( mTransactionsPerUSBFrame != 1 ) && ( byteCount ) ) ? ( byteCount * remainingTransfers ) : 0;
if ( anchorInFuture )
{
usbFrameDifference = byteCount ? ( byteCount * ( anchorFrame - thisFrameNum ) ) : ( anchorFrame - thisFrameNum );
}
else
{
usbFrameDifference = byteCount ? ( byteCount * ( thisFrameNum - anchorFrame ) ) : ( thisFrameNum - anchorFrame );
}
if ( anchorInFuture )
{
transactionDifference = usbFrameDifference * mTransactionsPerUSBFrame - partialFrame;
}
else
{
transactionDifference = usbFrameDifference * mTransactionsPerUSBFrame + partialFrame;
}
divisor = byteCount ? ( byteCount * mTransactionsPerUSBFrame ) : mTransactionsPerUSBFrame;
time_nanos = transactionDifference ;
if ( anchorInFuture )
{
time_nanos -= preWrapBytes;
}
else
{
time_nanos += preWrapBytes;
}
time_nanos *= mUSBAudioDevice->mWallTimePerUSBCycle / divisor;
time_nanos /= kWallTimeExtraPrecision;
absolutetime_to_nanoseconds (anchorTime, &referenceWallTime_nanos);
if ( anchorInFuture )
{
time_nanos = referenceWallTime_nanos - time_nanos;
}
else
{
time_nanos += referenceWallTime_nanos;
}
if (getDirection () == kIOAudioStreamDirectionInput)
{
time_nanos += mUSBAudioDevice->mWallTimePerUSBCycle / kWallTimeExtraPrecision;
}
#if DEBUGTIMESTAMPS
#define MAGNITUDEOF( x ) ( ( ( x ) > 0 ) ? ( x ) : ( - ( x ) ) )
if (0ull != mLastTimeStamp_nanos)
{
if ( 0ull != mLastWrapFrame )
{
frameDifference = thisFrameNum - mLastWrapFrame;
}
stampDifference = time_nanos - mLastTimeStamp_nanos;
if ( 0ull != mLastStampDifference )
{
stampJitter = stampDifference - mLastStampDifference;
}
sampleRate = ( 1000000000ull * ( mSampleBufferSize / mSampleSize ) ) / stampDifference;
mStampDrift += stampJitter;
debugIOLog ( " usbFrameIndex = %lu, remainingTransfers = %lu, preWrapBytes = %u, byteCount = %u", usbFrameIndex, remainingTransfers, preWrapBytes, byteCount );
debugIOLog ( " frameDifference = %llu, referenceWallTime_nanos = %llu, mWallTimePerUSBCycle = %llu, time = %llu",
frameDifference, referenceWallTime_nanos, mUSBAudioDevice->mWallTimePerUSBCycle, time_nanos );
debugIOLog ( " stampDifference = %lld, stampJitter = %lld, mStampDrift = %lld, sampleRate = %llu ", stampDifference, stampJitter, mStampDrift, sampleRate );
if ( ( MAGNITUDEOF( stampJitter ) > 1000000 )
&& ( TRUE ) )
{
debugIOLog( "\nthisFrameNum = %llu, mFrameQueuedForList = %llu, remainingTransfers = %lu", thisFrameNum, mFrameQueuedForList[mCurrentFrameList], remainingTransfers );
}
}
mLastTimeStamp_nanos = time_nanos;
if (0ull != stampDifference)
{
mLastStampDifference = stampDifference;
}
mLastWrapFrame = thisFrameNum;
#endif
Exit:
nanoseconds_to_absolutetime (time_nanos, &time);
return time;
}
UInt32 AppleUSBAudioEngine::getCurrentSampleFrame () {
const IOAudioStreamFormat *theFormat;
UInt32 currentSampleFrame;
currentSampleFrame = 0;
FailIf (NULL == mMainStream, Exit);
theFormat = mMainStream->getFormat ();
if (getDirection () == kIOAudioStreamDirectionOutput)
{
currentSampleFrame = mSafeErasePoint;
}
else
{
currentSampleFrame = (mBufferOffset == mSampleBufferSize ? 0 : mBufferOffset);
}
currentSampleFrame /= (theFormat->fNumChannels * (theFormat->fBitWidth / 8));
Exit:
return currentSampleFrame;
}
IOReturn AppleUSBAudioEngine::GetDefaultSettings (UInt8 * altSettingID, IOAudioSampleRate * sampleRate) {
IOReturn result;
UInt16 format;
UInt8 newAltSettingID;
IOAudioSampleRate newSampleRate;
AUAConfigurationDictionary * configDictionary = NULL;
debugIOLog ("+ AppleUSBAudioEngine[%p]::GetDefaultSettings ()", this);
result = kIOReturnError;
newSampleRate.whole = kDefaultSamplingRate;
newSampleRate.fraction = 0;
configDictionary = mUSBAudioDevice->getConfigDictionary ();
result = configDictionary->getAltSettingWithSettings (&newAltSettingID, mInterfaceNumber, kChannelDepth_STEREO, kBitDepth_16bits, newSampleRate.whole);
if ( ( kIOReturnSuccess != result )
|| ( ( kIOReturnSuccess == configDictionary->getFormat( &format, mInterfaceNumber, newAltSettingID )
&& ( PCM != format ) ) ) )
{
result = configDictionary->getAltSettingWithSettings (&newAltSettingID, mInterfaceNumber, kChannelDepth_MONO, kBitDepth_16bits, newSampleRate.whole);
}
if ( ( kIOReturnSuccess != result )
|| ( ( kIOReturnSuccess == configDictionary->getFormat( &format, mInterfaceNumber, newAltSettingID )
&& ( PCM != format ) ) ) )
{
if ( ( kIOReturnSuccess == (result = configDictionary->getAltSettingWithSettings (&newAltSettingID, mInterfaceNumber, kChannelDepth_STEREO, kBitDepth_16bits ) ) )
&& ( kIOReturnSuccess == configDictionary->getFormat( &format, mInterfaceNumber, newAltSettingID )
&& ( PCM == format ) ) )
{
configDictionary->getHighestSampleRate (&(newSampleRate.whole), mInterfaceNumber, newAltSettingID);
}
}
if ( ( kIOReturnSuccess != result )
|| ( ( kIOReturnSuccess == configDictionary->getFormat( &format, mInterfaceNumber, newAltSettingID )
&& ( PCM != format ) ) ) )
{
if ( ( kIOReturnSuccess == (result = configDictionary->getAltSettingWithSettings (&newAltSettingID, mInterfaceNumber, kChannelDepth_MONO, kBitDepth_16bits ) ) )
&& ( kIOReturnSuccess == configDictionary->getFormat( &format, mInterfaceNumber, newAltSettingID )
&& ( PCM == format ) ) )
{
configDictionary->getHighestSampleRate (&(newSampleRate.whole), mInterfaceNumber, newAltSettingID);
}
}
if ( ( kIOReturnSuccess != result )
|| ( ( kIOReturnSuccess == configDictionary->getFormat( &format, mInterfaceNumber, newAltSettingID )
&& ( PCM != format ) ) ) )
{
newAltSettingID = configDictionary->alternateSettingZeroCanStream (mInterfaceNumber) ? 0 : 1;
debugIOLog ("? AppleUSBAudioEngine[%p]::GetDefaultSettings () - Taking first available alternate setting (%d)", this, newAltSettingID);
FailIf (kIOReturnSuccess != (result = configDictionary->getHighestSampleRate (&(newSampleRate.whole), mInterfaceNumber, newAltSettingID)), Exit);;
}
debugIOLog ("? AppleUSBAudioEngine[%p]::GetDefaultSettings () - Default sample rate is %d", this, newSampleRate.whole);
debugIOLog ("? AppleUSBAudioEngine[%p]::GetDefaultSettings () - Default alternate setting ID is %d", this, newAltSettingID);
FailIf (0 == newSampleRate.whole, Exit);
*sampleRate = newSampleRate;
*altSettingID = newAltSettingID;
result = kIOReturnSuccess;
Exit:
debugIOLog ("- AppleUSBAudioEngine[%p]::GetDefaultSettings (%d, %lu) = 0x%x", this, *altSettingID, sampleRate->whole, result);
return result;
}
IOAudioStreamDirection AppleUSBAudioEngine::getDirection () {
IOAudioStreamDirection direction;
direction = kIOAudioStreamDirectionOutput;
FailIf (NULL == mMainStream, Exit);
direction = mMainStream->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 = mStreamInterface->GetDevice()->GetManufacturerStringIndex ();
if (0 != stringIndex)
{
err = mStreamInterface->GetDevice()->GetStringDescriptor (stringIndex, manufacturerString, kStringBufferSize);
}
if (0 == manufacturerString[0] || kIOReturnSuccess != err)
{
strncpy (manufacturerString, "Unknown Manufacturer", kStringBufferSize);
}
uniqueIDSize += strlen (manufacturerString);
err = kIOReturnSuccess;
productString[0] = 0;
stringIndex = mStreamInterface->GetDevice()->GetProductStringIndex ();
if (0 != stringIndex)
{
err = mStreamInterface->GetDevice()->GetStringDescriptor (stringIndex, productString, kStringBufferSize);
}
if (0 == productString[0] || kIOReturnSuccess != err)
{
strncpy (productString, "Unknown USB Audio Device", kStringBufferSize);
}
uniqueIDSize += strlen (productString);
err = kIOReturnSuccess;
serialNumberString[0] = 0;
stringIndex = mStreamInterface->GetDevice()->GetSerialNumberStringIndex ();
stringIndex = 0;
if (0 != stringIndex)
{
err = mStreamInterface->GetDevice()->GetStringDescriptor (stringIndex, serialNumberString, kStringBufferSize);
}
if (0 == serialNumberString[0] || kIOReturnSuccess != err)
{
usbLocation = OSDynamicCast (OSNumber, mStreamInterface->GetDevice()->getProperty (kUSBDevicePropertyLocationID));
if (NULL != usbLocation)
{
locationID = usbLocation->unsigned32BitValue ();
snprintf (locationIDString, kStringBufferSize, "%x", locationID);
}
else
{
strncpy (locationIDString, "Unknown location", kStringBufferSize);
}
uniqueIDSize += strlen (locationIDString);
}
else
{
debugIOLog ("? AppleUSBAudioEngine[%p]::getGlobalUniqueID () - Device has a serial number = %s", this, serialNumberString);
uniqueIDSize += strlen (serialNumberString);
}
interfaceNumber = mStreamInterface->GetInterfaceNumber ();
snprintf (interfaceNumberString, 4, "%d", interfaceNumber);
uniqueIDSize += strlen (interfaceNumberString);
uniqueIDStr = (char *)IOMalloc (uniqueIDSize);
if (NULL != uniqueIDStr)
{
uniqueIDStr[0] = 0;
if (0 == serialNumberString[0])
{
snprintf (uniqueIDStr, uniqueIDSize, "AppleUSBAudioEngine:%s:%s:%s:%s", manufacturerString, productString, locationIDString, interfaceNumberString);
}
else
{
snprintf (uniqueIDStr,uniqueIDSize, "AppleUSBAudioEngine:%s:%s:%s:%s", manufacturerString, productString, serialNumberString, interfaceNumberString);
}
uniqueID = OSString::withCString (uniqueIDStr);
debugIOLog ("AppleUSBAudioEngine[%p]::getGlobalUniqueID () - getGlobalUniqueID = %s", this, uniqueIDStr);
IOFree (uniqueIDStr, uniqueIDSize);
}
return uniqueID;
}
void * AppleUSBAudioEngine::getSampleBuffer (void) {
void * sampleBuffer;
sampleBuffer = NULL;
if (NULL != mMainStream)
{
sampleBuffer = mMainStream->getSampleBuffer ();
}
return sampleBuffer;
}
UInt32 AppleUSBAudioEngine::getSampleBufferSize (void) {
UInt32 sampleBufferSize;
sampleBufferSize = 0;
FailIf (NULL == mMainStream, Exit);
sampleBufferSize = mMainStream->getSampleBufferSize ();
Exit:
return sampleBufferSize;
}
#if DEBUGLATENCY
UInt64 AppleUSBAudioEngine::getQueuedFrameForSample (UInt32 sampleFrame)
{
UInt64 usbFrame = 0ull;
UInt32 sampleByteOffset;
UInt32 bufferByteOffset;
UInt32 bytesToQueuePoint;
UInt8 frameListNumber;
UInt8 i;
FailIf (NULL == mFrameQueuedForList, Exit);
FailIf (0 == mSampleSize, Exit);
sampleByteOffset = sampleFrame * mSampleSize;
bytesToQueuePoint = (mLastPreparedBufferOffset > sampleByteOffset ? 0 : getSampleBufferSize()) + mLastPreparedBufferOffset - sampleByteOffset;
if (bytesToQueuePoint > mThisFrameListSize + mLastFrameListSize)
{
debugIOLog ("? AppleUSBAudioEngine::getQueuedFrameForSample (%lu) - sample frame is not queued in the previous two frame lists", sampleFrame);
}
else
{
if (bytesToQueuePoint <= mThisFrameListSize)
{
bufferByteOffset = mThisFrameListSize;
frameListNumber = (mCurrentFrameList + 1) % mNumUSBFrameLists;
}
else
{
bufferByteOffset = mThisFrameListSize + mLastFrameListSize;
frameListNumber = mCurrentFrameList;
}
bufferByteOffset = (getSampleBufferSize() + mLastPreparedBufferOffset - bufferByteOffset) % getSampleBufferSize();
if (bufferByteOffset > sampleByteOffset)
{
sampleByteOffset += getSampleBufferSize ();
}
for (i = 0; i < mNumTransactionsPerList; i++)
{
bufferByteOffset += mUSBIsocFrames[frameListNumber * mNumTransactionsPerList].frReqCount;
if (sampleByteOffset < bufferByteOffset)
{
usbFrame = mFrameQueuedForList[frameListNumber] + i;
break;
}
}
FailIf (0 == usbFrame, Exit);
}
Exit:
return usbFrame;
}
#endif
bool AppleUSBAudioEngine::initHardware (IOService *provider) {
char vendorIDCString[7];
char productIDCString[7];
AUAConfigurationDictionary * configDictionary;
UInt8 deviceClass;
UInt8 deviceSubclass;
IOAudioStreamFormat streamFormat;
IOReturn resultCode;
Boolean resultBool;
UInt32 index;
UInt16 terminalType;
UInt16 format;
UInt8 numChannels;
#if STAGGERINTERFACES
if ( mInterfaceNumber % 2 != 1 )
{
IOSleep (1000);
}
#endif
debugIOLog ("+ AppleUSBAudioEngine[%p]::initHardware (%p)", this, provider);
resultBool = FALSE;
mTerminatingDriver = FALSE;
mCoalescenceMutex = NULL;
FailIf (FALSE == super::initHardware (provider), Exit);
mStreamInterface = OSDynamicCast (IOUSBInterface, provider);
FailIf (NULL == mStreamInterface, Exit);
FailIf (NULL == (configDictionary = mUSBAudioDevice->getConfigDictionary ()), Exit);
mMainStream = new IOAudioStream;
FailIf (NULL == mMainStream, Exit);
FailIf (kIOReturnSuccess != GetDefaultSettings (&mAlternateSettingID, &sampleRate), Exit);
FailIf (kIOReturnSuccess != configDictionary->getIsocEndpointDirection (&mDirection, mInterfaceNumber, mAlternateSettingID), Exit);
FailIf (!mMainStream->initWithAudioEngine (this, (IOAudioStreamDirection)mDirection, 1), Exit);
if (kUSBIn == mDirection)
{
debugIOLog ("? AppleUSBAudioEngine[%p]::initHardware () - This is an input type endpoint (mic, etc.)", this);
index = 0;
do
{
resultCode = configDictionary->getIndexedInputTerminalType (&terminalType, mUSBAudioDevice->mControlInterface->GetInterfaceNumber (), 0, index++);
} while (terminalType == INPUT_UNDEFINED && index < 256 && kIOReturnSuccess == resultCode);
mNumUSBFrameLists = RECORD_NUM_USB_FRAME_LISTS;
mNumUSBFramesPerList = RECORD_NUM_USB_FRAMES_PER_LIST;
mNumUSBFrameListsToQueue = RECORD_NUM_USB_FRAME_LISTS_TO_QUEUE;
mCoalescenceMutex = IOLockAlloc ();
FailIf (NULL == mCoalescenceMutex, Exit);
}
else if (kUSBOut == mDirection)
{
debugIOLog ("? AppleUSBAudioEngine[%p]::initHardware () - This is an output type endpoint (speaker, etc.)", this);
index = 0;
do
{
resultCode = configDictionary->getIndexedOutputTerminalType (&terminalType, mUSBAudioDevice->mControlInterface->GetInterfaceNumber (), 0, index++);
} while (terminalType == OUTPUT_UNDEFINED && index < 256 && kIOReturnSuccess == resultCode);
mNumUSBFrameLists = PLAY_NUM_USB_FRAME_LISTS;
mNumUSBFramesPerList = PLAY_NUM_USB_FRAMES_PER_LIST;
mNumUSBFrameListsToQueue = PLAY_NUM_USB_FRAME_LISTS_TO_QUEUE;
}
else
{
FailMessage ("Couldn't get the endpoint direction!", Exit);
}
mUHCISupport = mUSBAudioDevice->checkForUHCI ();
mSplitTransactions = mUSBAudioDevice->detectSplitTransactions ();
mFrameQueuedForList = NULL;
mFrameQueuedForList = new UInt64[mNumUSBFrameLists];
FailIf (NULL == mFrameQueuedForList, Exit);
mMainStream->setTerminalType (terminalType);
mUSBCompletion = (IOUSBLowLatencyIsocCompletion *)IOMalloc (mNumUSBFrameLists * sizeof (IOUSBLowLatencyIsocCompletion));
mSampleBufferDescriptors = (IOSubMemoryDescriptor **)IOMalloc (mNumUSBFrameLists * sizeof (IOSubMemoryDescriptor *));
bzero (mSampleBufferDescriptors, mNumUSBFrameLists * sizeof (IOSubMemoryDescriptor *));
mWrapDescriptors[0] = OSTypeAlloc (IOSubMemoryDescriptor);
mWrapDescriptors[1] = OSTypeAlloc (IOSubMemoryDescriptor);
FailIf (NULL == mWrapDescriptors[0], Exit);
FailIf (NULL == mWrapDescriptors[1], Exit);
FailIf (NULL == mUSBCompletion, Exit);
FailIf (NULL == mSampleBufferDescriptors, Exit);
FailIf (kIOReturnSuccess != addAvailableFormats (configDictionary), Exit);
mCurSampleRate = sampleRate;
setSampleRate (&sampleRate);
FailIf (kIOReturnSuccess != configDictionary->getNumChannels (&numChannels, mInterfaceNumber, mAlternateSettingID), Exit);
streamFormat.fNumChannels = numChannels;
FailIf (kIOReturnSuccess != configDictionary->getBitResolution (&(streamFormat.fBitDepth), mInterfaceNumber, mAlternateSettingID), Exit);
FailIf (kIOReturnSuccess != configDictionary->getSubframeSize (&(streamFormat.fBitWidth), mInterfaceNumber, mAlternateSettingID), Exit);
streamFormat.fBitWidth *= 8;
streamFormat.fAlignment = kIOAudioStreamAlignmentLowByte;
streamFormat.fByteOrder = kIOAudioStreamByteOrderLittleEndian;
streamFormat.fDriverTag = (mInterfaceNumber << 16) | mAlternateSettingID;
FailIf (kIOReturnSuccess != configDictionary->getFormat (&format, mInterfaceNumber, mAlternateSettingID), Exit);
switch (format)
{
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 have any supported formats!\n", Exit);
}
mDefaultAudioStreamFormat = streamFormat;
mDefaultAudioSampleRate = sampleRate;
FailIf (FALSE == mStreamInterface->open (this), Exit); FailIf (kIOReturnSuccess != (resultCode = mStreamInterface->SetAlternateInterface (this, kRootAlternateSetting)), Exit); FailIf (kIOReturnSuccess != (resultCode = mMainStream->setFormat (&streamFormat)), Exit);
FailIf (kIOReturnSuccess != (resultCode = addAudioStream (mMainStream)), Exit);
FailIf (kIOReturnSuccess != configDictionary->getInterfaceClass (&deviceClass, mInterfaceNumber, mAlternateSettingID), Exit);
FailIf (kUSBAudioClass != deviceClass, Exit);
FailIf (kIOReturnSuccess != configDictionary->getInterfaceSubClass (&deviceSubclass, mInterfaceNumber, mAlternateSettingID), Exit);
FailIf (kUSBAudioStreamInterfaceSubclass != deviceSubclass, Exit);
if (kUSBOut == mDirection)
{
miSubBufferMemory = NULL;
miSubEngine = NULL;
miSubAttachToggle = IOAudioToggleControl::create (FALSE,
kIOAudioControlChannelIDAll,
kIOAudioControlChannelNameAll,
0,
kIOAudioToggleControlSubTypeiSubAttach,
kIOAudioControlUsageOutput);
if (NULL != miSubAttachToggle)
{
addDefaultAudioControl (miSubAttachToggle);
miSubAttachToggle->setValueChangeHandler ((IOAudioControl::IntValueChangeHandler)iSubAttachChangeHandler, this);
}
}
mUSBAudioDevice->activateAudioEngine (this, FALSE);
resultBool = TRUE;
if (resultBool)
{
mUSBAudioDevice->retain ();
}
snprintf (vendorIDCString, 7, "0x%04X", mStreamInterface->GetDevice()->GetVendorID ());
snprintf (productIDCString, 7, "0x%04X", mStreamInterface->GetDevice()->GetProductID ());
setProperty (vendorIDCString, productIDCString); IOService::registerService ();
Exit:
debugIOLog("- AppleUSBAudioEngine[%p]::initHardware(%p), resultCode = %x, resultBool = %d", this, provider, resultCode, resultBool);
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->mStreamInterface->GetDevice()->GetVendorID (), usbAudioEngineObject->mStreamInterface->GetDevice()->GetProductID ());
if (result == kIOReturnSuccess)
{
debugIOLog ("success initing the plugin");
usbAudioEngineObject->mPlugin->pluginSetDirection ((IOAudioStreamDirection) usbAudioEngineObject->mDirection);
usbAudioEngineObject->mPlugin->pluginSetFormat (usbAudioEngineObject->mMainStream->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 = mUSBAudioDevice->deviceRequest (request, mUSBAudioDevice, completion);
}
return result;
}
void AppleUSBAudioEngine::pluginSetConfigurationApp (const char * bundleID) {
if (bundleID)
{
mUSBAudioDevice->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;
audioEngine = OSDynamicCast (AppleUSBAudioEngine, target);
FailIf (NULL == audioEngine, Exit);
if ( (newValue)
&& (!oldValue) && (audioEngine->isiSubCompatibleFormat (audioEngine->mMainStream->getFormat (), audioEngine->sampleRate))) {
if (NULL == audioEngine->miSubEngineNotifier)
{
debugIOLog ("? AppleUSBAudioEngine::iSubAttachChangeHandler () - Adding miSubEngineNotifier ...");
audioEngine->miSubEngineNotifier = addNotification (gIOPublishNotification, serviceMatching ("AppleiSubEngine"), (IOServiceNotificationHandler)&iSubEnginePublished, audioEngine);
if (NULL != audioEngine->miSubBufferMemory)
{
debugIOLog ("? AppleUSBAudioEngine::iSubAttachChangeHandler () - Removing miSubEngineNotifier because notifier was already called ...");
audioEngine->miSubEngineNotifier->remove ();
audioEngine->miSubEngineNotifier = NULL;
}
}
else
{
debugIOLog ("! AppleUSBAudioEngine::iSubAttachChangeHandler () - There is already a notifier @ 0x%x!", audioEngine->miSubEngineNotifier);
}
}
else if (oldValue != newValue) {
if (NULL != audioEngine->miSubBufferMemory && NULL != audioEngine->miSubEngine)
{
audioEngine->iSubTeardownConnection ();
}
if (NULL != audioEngine->miSubEngineNotifier)
{
debugIOLog ("? AppleUSBAudioEngine::iSubAttachChangeHandler () - Removing miSubEngineNotifier because iSub was detached ...");
audioEngine->miSubEngineNotifier->remove ();
audioEngine->miSubEngineNotifier = NULL;
}
}
Exit:
debugIOLog("- AppleUSBAudioEngine::iSubAttachChangeHandler ()");
return result;
}
IOReturn AppleUSBAudioEngine::iSubAttachChangeCall (Boolean isiSubCompatible) {
IOReturn result;
debugIOLog ("+ AppleUSBAudioEngine[%p]::iSubAttachChangeCall (%d)", this, isiSubCompatible);
result = kIOReturnSuccess;
if (isiSubCompatible)
{
if (NULL == miSubEngineNotifier)
{
debugIOLog ("? AppleUSBAudioEngine::iSubAttachChangeCall () - Adding miSubEngineNotifier ...");
miSubEngineNotifier = addNotification (gIOPublishNotification, serviceMatching ("AppleiSubEngine"), (IOServiceNotificationHandler)&iSubEnginePublished, this);
if (NULL != miSubBufferMemory)
{
debugIOLog ("? AppleUSBAudioEngine::iSubAttachChangeCall () - Removing miSubEngineNotifier because notifier was already called ...");
miSubEngineNotifier->remove ();
miSubEngineNotifier = NULL;
}
}
else
{
debugIOLog ("! AppleUSBAudioEngine::iSubAttachChangeHandler () - There is already a notifier @ 0x%x!", miSubEngineNotifier);
}
}
else
{
if (NULL != miSubEngineNotifier)
{
debugIOLog ("? AppleUSBAudioEngine::iSubAttachChangeCall () - Removing miSubEngineNotifier because this is not an iSub-compatible format ...");
miSubEngineNotifier->remove ();
miSubEngineNotifier = NULL;
}
}
debugIOLog("- AppleUSBAudioEngine::iSubAttachChangeCall");
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->miSubIsOpen && NULL != audioEngine->mOldiSubEngine)
{
audioEngine->mOldiSubEngine->closeiSub (audioEngine);
audioEngine->detach (audioEngine->mOldiSubEngine);
audioEngine->miSubIsOpen = FALSE;
audioEngine->miSubEngine = NULL;
audioEngine->miSubBufferMemory = NULL;
#if DEBUGISUB
}
else
{
if (TRUE != audioEngine->miSubIsOpen) {debugIOLog ("TRUE != audioEngine->miSubIsOpen");}
if (NULL == audioEngine->mOldiSubEngine) {debugIOLog ("NULL == audioEngine->mOldiSubEngine");}
#endif
}
if (NULL != audioEngine->mLowFreqSamples)
{
IOFree (audioEngine->mLowFreqSamples, audioEngine->getSampleBufferSize () * 2);
}
if (NULL != audioEngine->mHighFreqSamples)
{
IOFree (audioEngine->mHighFreqSamples, 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->miSubIsOpen)
{
usbAudioEngineObject->miSubEngine = (AppleiSubEngine *)newService;
#if THREAD_ISUB_OPEN
usbAudioEngineObject->miSubOpenThreadCall = thread_call_allocate ((thread_call_func_t)usbAudioEngineObject->iSubOpen, (thread_call_param_t)usbAudioEngineObject);
if (NULL != usbAudioEngineObject->miSubOpenThreadCall)
{
AbsoluteTime callTime;
AbsoluteTime delayAmount;
clock_get_uptime (&callTime);
nanoseconds_to_absolutetime (750ULL * 1000 * 1000, &delayAmount);
ADD_ABSOLUTETIME (&callTime, &delayAmount);
thread_call_enter_delayed (usbAudioEngineObject->miSubOpenThreadCall, callTime);
}
else
{
}
#else
iSubOpen(usbAudioEngineObject);
#endif
}
else
{
debugIOLog ("? AppleUSBAudioEngine::iSubEnginePublished () - 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->miSubOpenThreadCall)
{
thread_call_free(usbAudioEngineObject->miSubOpenThreadCall);
}
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->miSubEngine, Exit);
FailIf (NULL == usbAudioEngineObject->mMainStream, Exit);
streamFormat = usbAudioEngineObject->mMainStream->getFormat ();
sampleRateWhole = usbAudioEngineObject->mCurSampleRate.whole;
if ((2 != streamFormat->fNumChannels) || ((8000 != usbAudioEngineObject->mCurSampleRate.whole) && (11025 != usbAudioEngineObject->mCurSampleRate.whole) &&
(22050 != usbAudioEngineObject->mCurSampleRate.whole) && (44100 != usbAudioEngineObject->mCurSampleRate.whole) &&
(48000 != usbAudioEngineObject->mCurSampleRate.whole) && (96000 != usbAudioEngineObject->mCurSampleRate.whole)))
{
goto Exit;
}
usbAudioEngineObject->mLowFreqSamples = (float *)IOMallocAligned (usbAudioEngineObject->getSampleBufferSize () * 2, PAGE_SIZE);
FailIf (NULL == usbAudioEngineObject->mLowFreqSamples, Cleanup);
usbAudioEngineObject->mHighFreqSamples = (float *)IOMallocAligned (usbAudioEngineObject->getSampleBufferSize () * 2, PAGE_SIZE);
FailIf (NULL == usbAudioEngineObject->mHighFreqSamples, Cleanup);
usbAudioEngineObject->attach (usbAudioEngineObject->miSubEngine);
numTries = 0;
do
{
resultBool = usbAudioEngineObject->miSubEngine->openiSub (usbAudioEngineObject, &requestiSubClose);
numTries++;
if (!resultBool) IOSleep (102);
} while (FALSE == resultBool && numTries < 5);
FailWithAction (FALSE == resultBool, usbAudioEngineObject->detach (usbAudioEngineObject->miSubEngine), Cleanup);
result = kIOReturnSuccess;
Cleanup:
if (NULL != usbAudioEngineObject->miSubEngineNotifier)
{
debugIOLog ("? AppleUSBAudioEngine::iSubOpenAction () - Removing miSubEngineNotifier because we found an iSub ...");
usbAudioEngineObject->miSubEngineNotifier->remove ();
usbAudioEngineObject->miSubEngineNotifier = NULL;
}
if (kIOReturnSuccess == result)
{
debugIOLog ("? AppleUSBAudioEngine::iSubOpenAction () - Successfully opened the iSub");
usbAudioEngineObject->miSubBufferMemory = usbAudioEngineObject->miSubEngine->GetSampleBuffer ();
usbAudioEngineObject->miSubIsOpen = TRUE;
}
else
{
usbAudioEngineObject->miSubBufferMemory = NULL;
usbAudioEngineObject->miSubEngine = NULL;
usbAudioEngineObject->miSubIsOpen = FALSE;
if (NULL != usbAudioEngineObject->mLowFreqSamples)
{
IOFree (usbAudioEngineObject->mLowFreqSamples, usbAudioEngineObject->getSampleBufferSize () * 2);
}
if (NULL != usbAudioEngineObject->mHighFreqSamples)
{
IOFree (usbAudioEngineObject->mHighFreqSamples, 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->mUSBStreamRunning;
usbAudioEngine->mUSBStreamRunning = FALSE;
usbAudioEngine->pauseAudioEngine ();
usbAudioEngine->beginConfigurationChange ();
cg = usbAudioEngine->getCommandGate ();
if (NULL != cg)
{
cg->runAction (iSubCloseAction);
}
usbAudioEngine->completeConfigurationChange ();
usbAudioEngine->resumeAudioEngine ();
usbAudioEngine->mUSBStreamRunning = streamWasRunning;
}
if (NULL != iSubTeardownThreadCall)
{
thread_call_free(iSubTeardownThreadCall);
}
debugIOLog ("- AppleUSBAudioEngine::iSubTeardown ()");
}
void AppleUSBAudioEngine::iSubTeardownConnection (void) {
debugIOLog ("+ AppleUSBAudioEngine::iSubTeardownConnection ()");
mOldiSubEngine = miSubEngine;
miSubTeardownThreadCall = thread_call_allocate ((thread_call_func_t)iSubTeardown, (thread_call_param_t)this);
if (NULL != miSubTeardownThreadCall)
{
thread_call_enter1 (miSubTeardownThreadCall, miSubTeardownThreadCall);
}
else
{
}
debugIOLog ("- AppleUSBAudioEngine::iSubTeardownConnection ()");
return;
}
bool AppleUSBAudioEngine::isiSubCompatibleFormat (const IOAudioStreamFormat *format, IOAudioSampleRate sampleRate)
{
if ( (NULL != format)
&& (2 == format->fNumChannels)
&& (16 == format->fBitDepth)
&& ( (8000 == sampleRate.whole)
|| (11025 == sampleRate.whole)
|| (22050 == sampleRate.whole)
|| (44100 == sampleRate.whole)
|| (48000 == sampleRate.whole)
|| (96000 == sampleRate.whole)))
{
debugIOLog ("? AppleUSBAudioEngine::isiSubCompatibleFormat () - TRUE");
return TRUE;
}
else
{
debugIOLog ("? AppleUSBAudioEngine::isiSubCompatibleFormat () - FALSE");
return FALSE;
}
}
IOReturn AppleUSBAudioEngine::performAudioEngineStart () {
IOReturn resultCode;
debugIOLog ("+ AppleUSBAudioEngine[%p]::performAudioEngineStart ()", this);
resultCode = kIOReturnError;
FailIf (NULL == mUSBAudioDevice, Exit);
#if DEBUGTIMESTAMPS
mLastTimeStamp_nanos = 0ull;
mLastStampDifference = 0ull;
mStampDrift = 0ll;
mLastWrapFrame = 0ull;
#endif
if (mUSBAudioDevice->mNewReferenceUSBFrame == 0ull)
{
debugIOLog ("! AppleUSBAudioEngine[%p]::performAudioEngineStart () - Getting an anchor for the first timestamp.", this);
FailIf (kIOReturnSuccess != mUSBAudioDevice->getAnchorFrameAndTimeStamp (NULL, NULL), Exit);
}
resultCode = kIOReturnSuccess;
if (mPlugin)
{
mPlugin->pluginStart ();
}
if (NULL != miSubEngine)
{
mStartiSub = TRUE;
mNeedToSync = TRUE;
}
if (!mUSBStreamRunning)
{
#if DEBUGLATENCY
mHaveClipped = false;
mLastFrameListSize = 0;
mThisFrameListSize = 0;
#endif
resultCode = startUSBStream ();
}
Exit:
if (resultCode != kIOReturnSuccess)
{
debugIOLog ("! AppleUSBAudioEngine[%p]::performAudioEngineStart () - NOT started, error = 0x%x", this, resultCode);
performAudioEngineStop ();
if ( ( (kIOReturnNotResponding == resultCode)
|| (kIOReturnExclusiveAccess == resultCode))
&& ( ! mUSBAudioDevice->recoveryRequested ()))
{
if (mUSBAudioDevice)
{
debugIOLog ("! AppleUSBAudioEngine[%p]::startUSBStream () - Device not responding! Requesting a recovery attempt.");
mUSBAudioDevice->requestDeviceRecovery ();
}
}
}
else
{
debugIOLog ("\n");
debugIOLog (" -------------------- Starting Stream (interface %d, alternate setting %d) --------------------", mInterfaceNumber, mAlternateSettingID);
debugIOLog (" format = %p", mMainStream->getFormat ());
debugIOLog (" fNumChannels = %d", mMainStream->getFormat ()->fNumChannels);
debugIOLog (" fBitDepth = %d", mMainStream->getFormat ()->fBitDepth);
debugIOLog (" fDriverTag = 0x%x", mMainStream->getFormat ()->fDriverTag);
debugIOLog (" sampleRate->whole = %lu", getSampleRate()->whole);
debugIOLog ("\n");
}
debugIOLog ("- AppleUSBAudioEngine[%p]::performAudioEngineStart ()", this);
return resultCode;
}
IOReturn AppleUSBAudioEngine::performAudioEngineStop() {
debugIOLog("+ AppleUSBAudioEngine[%p]::performAudioEngineStop ()", this);
if (mPlugin)
{
mPlugin->pluginStop ();
}
if (NULL != miSubEngine)
{
miSubEngine->StopiSub ();
mNeedToSync = TRUE;
}
if (mUSBStreamRunning)
{
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) {
IOReturn result;
UInt32 controllerResult;
bool streamIsRunning = false;
debugIOLog ("+ AppleUSBAudioEngine[%p]::performFormatChange (%p, %p, %p)", this, audioStream, newFormat, newSampleRate);
result = kIOReturnError;
FailIf (NULL == mUSBAudioDevice, Exit);
streamIsRunning = mUSBStreamRunning;
if (streamIsRunning)
{
pauseAudioEngine ();
}
controllerResult = mUSBAudioDevice->formatChangeController (this, audioStream, newFormat, newSampleRate);
switch (controllerResult)
{
case kAUAFormatChangeNormal:
result = kIOReturnSuccess;
break;
case kAUAFormatChangeForced:
debugIOLog ("? AppleUSBAudioEngine[%p]::performFormatChange () - This request was forced.");
result = kIOReturnSuccess;
break;
case kAUAFormatChangeForceFailure:
debugIOLog ("! AppleUSBAudioEngine[%p]::performFormatChange () - Force of this request was attempted but failed.");
result = kIOReturnSuccess;
break;
case kAUAFormatChangeError:
default:
debugIOLog ("! AppleUSBAudioEngine[%p]::performFormatChange () - Error encountered.");
result = kIOReturnError;
}
Exit:
if (streamIsRunning)
{
resumeAudioEngine ();
}
debugIOLog ("- AppleUSBAudioEngine[%p]::performFormatChange () = 0x%x", this, result);
return result;
}
IOReturn AppleUSBAudioEngine::PrepareWriteFrameList (UInt32 arrayIndex) {
const IOAudioStreamFormat * theFormat;
IOReturn result;
UInt32 thisFrameListSize;
#if DEBUGLATENCY
UInt32 frameListByteCount; #endif
UInt32 thisFrameSize;
UInt32 firstFrame;
UInt32 numBytesToBufferEnd;
UInt32 lastPreparedByte;
UInt32 numUSBFramesPrepared;
UInt16 integerSamplesInFrame;
UInt16 bytesAfterWrap = 0; Boolean haveWrapped;
result = kIOReturnError; haveWrapped = FALSE;
firstFrame = arrayIndex * mNumTransactionsPerList;
mUSBCompletion[arrayIndex].target = (void *)this;
mUSBCompletion[arrayIndex].action = writeHandler;
mUSBCompletion[arrayIndex].parameter = 0;
theFormat = mMainStream->getFormat ();
numBytesToBufferEnd = getSampleBufferSize () - mLastPreparedBufferOffset;
lastPreparedByte = mLastPreparedBufferOffset;
thisFrameListSize = 0;
#if DEBUGLATENCY
frameListByteCount = 0;
#endif
for (numUSBFramesPrepared = 0; numUSBFramesPrepared < mNumTransactionsPerList; numUSBFramesPrepared++)
{
integerSamplesInFrame = mAverageSampleRate / ( 1000 * mTransactionsPerUSBFrame );
mFractionalSamplesLeft += ( mAverageSampleRate - (integerSamplesInFrame * 1000 * mTransactionsPerUSBFrame) ) / mTransactionsPerUSBFrame;
if (mFractionalSamplesLeft >= 1000)
{
integerSamplesInFrame++;
mFractionalSamplesLeft -= 1000;
}
thisFrameSize = integerSamplesInFrame * mSampleSize;
#if DEBUGLATENCY
frameListByteCount += thisFrameSize;
#endif
if (thisFrameSize >= numBytesToBufferEnd)
{
bytesAfterWrap = thisFrameSize - numBytesToBufferEnd;
mNumFramesInFirstList = numUSBFramesPrepared + 1;
mUSBCompletion[arrayIndex].parameter = (void *)((mNumFramesInFirstList << 16) | bytesAfterWrap);
if (mUHCISupport)
{
#if DEBUGUHCI
debugIOLog ("PrepareWriteFrameList: Wrapping because (thisFrameSize = ) %d >= (numBytesToBufferEnd = ) %d", thisFrameSize, numBytesToBufferEnd);
debugIOLog ("PrepareWriteFrameList: bytesAfterWrap = %d, numUSBFramesPrepared = %d, numTransactionsPerList %d", bytesAfterWrap, numUSBFramesPrepared, mNumTransactionsPerList);
#endif
mWrapDescriptors[0]->initSubRange (mUSBBufferDescriptor,
mLastPreparedBufferOffset,
getSampleBufferSize () + bytesAfterWrap - mLastPreparedBufferOffset,
kIODirectionOut);
#if DEBUGUHCI
debugIOLog ("PrepareWriteFrameList: initSubRange 0: %d to %d", mLastPreparedBufferOffset, getSampleBufferSize () + bytesAfterWrap);
debugIOLog ("PrepareWriteFrameList: %d frames in first list", mNumFramesInFirstList);
#endif
}
else
{
mWrapDescriptors[0]->initSubRange (mUSBBufferDescriptor, mLastPreparedBufferOffset, getSampleBufferSize () - mLastPreparedBufferOffset, kIODirectionOut);
}
numBytesToBufferEnd = getSampleBufferSize () - bytesAfterWrap;
lastPreparedByte = bytesAfterWrap;
haveWrapped = TRUE;
} else
{
thisFrameListSize += thisFrameSize;
lastPreparedByte += thisFrameSize;
numBytesToBufferEnd -= thisFrameSize;
}
mUSBIsocFrames[firstFrame + numUSBFramesPrepared].frStatus = -1;
mUSBIsocFrames[firstFrame + numUSBFramesPrepared].frActCount = 0;
mUSBIsocFrames[firstFrame + numUSBFramesPrepared].frReqCount = thisFrameSize;
}
if (TRUE == haveWrapped)
{
mNeedTimeStamps = TRUE;
if (mUHCISupport)
{
mWrapDescriptors[1]->initSubRange (mUSBBufferDescriptor, bytesAfterWrap, lastPreparedByte - bytesAfterWrap, kIODirectionOut);
#if DEBUGUHCI
debugIOLog ("PrepareWriteFrameList: initSubRange 1: %d to %d", bytesAfterWrap, lastPreparedByte);
#endif
if (lastPreparedByte != bytesAfterWrap)
{
mExtraUSBCompletion.target = (void *)this;
mExtraUSBCompletion.action = writeHandlerForUHCI;
}
}
else
{
mWrapDescriptors[1]->initSubRange (mUSBBufferDescriptor, 0, lastPreparedByte, kIODirectionOut);
if (NULL != mWrapRangeDescriptor)
{
mWrapRangeDescriptor->release ();
mWrapRangeDescriptor = NULL;
}
mWrapRangeDescriptor = IOMultiMemoryDescriptor::withDescriptors ((IOMemoryDescriptor **)mWrapDescriptors, 2, kIODirectionOut, true);
}
}
else
{
mSampleBufferDescriptors[arrayIndex]->initSubRange (mUSBBufferDescriptor, mLastPreparedBufferOffset, thisFrameListSize, kIODirectionOut);
FailIf (NULL == mSampleBufferDescriptors[arrayIndex], Exit);
}
mSafeErasePoint = mLastSafeErasePoint;
mLastSafeErasePoint = mLastPreparedBufferOffset;
mLastPreparedBufferOffset = lastPreparedByte;
#if DEBUGLATENCY
mLastFrameListSize = mThisFrameListSize;
mThisFrameListSize = frameListByteCount;
#endif
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;
#if DEBUGINPUT
debugIOLog ("+ AppleUSBAudioEngine::PrepareAndReadFrameLists (%d, %d, %ld)", sampleSize, numChannels, usbFrameListIndex);
#endif
result = kIOReturnError; firstFrame = usbFrameListIndex * mNumTransactionsPerList;
mUSBCompletion[usbFrameListIndex].target = (void *)this;
mUSBCompletion[usbFrameListIndex].action = readHandler;
mUSBCompletion[usbFrameListIndex].parameter = (void *)usbFrameListIndex;
calculateSamplesPerPacket (mCurSampleRate.whole, &averageFrameSamples, &additionalSampleFrameFreq);
mBytesPerSampleFrame = sampleSize * numChannels;
bytesToRead = mReadUSBFrameSize;
for (numUSBFramesPrepared = 0; numUSBFramesPrepared < mNumTransactionsPerList; numUSBFramesPrepared++)
{
mUSBIsocFrames[firstFrame + numUSBFramesPrepared].frStatus = -1;
mUSBIsocFrames[firstFrame + numUSBFramesPrepared].frActCount = 0;
mUSBIsocFrames[firstFrame + numUSBFramesPrepared].frReqCount = bytesToRead;
* (UInt64 *) ( & ( mUSBIsocFrames[firstFrame + numUSBFramesPrepared].frTimeStamp)) = 0ull;
}
if (NULL != mPipe)
{
result = mPipe->Read (mSampleBufferDescriptors[usbFrameListIndex], mUSBFrameToQueue, mNumTransactionsPerList, &mUSBIsocFrames[firstFrame], &mUSBCompletion[usbFrameListIndex], 1); if (result != kIOReturnSuccess)
{
debugIOLog ("! AppleUSBAudioEngine[%p]::PrepareAndReadFrameLists () - Error 0x%x reading from pipe", this, result);
}
if (NULL != mFrameQueuedForList)
{
mFrameQueuedForList[usbFrameListIndex] = mUSBFrameToQueue;
}
mUSBFrameToQueue += mNumUSBFramesPerList;
}
else
{
debugIOLog ("! AppleUSBAudioEngine[%p]::PrepareAndReadFrameLists () - mPipe is NULL!", this);
}
#if DEBUGINPUT
debugIOLog ("- AppleUSBAudioEngine::PrepareAndReadFrameLists ()");
#endif
return result;
}
#if PRIMEISOCINPUT
void AppleUSBAudioEngine::primeInputPipe (IOUSBPipe * pipeToPrime, UInt32 bytesPerUSBFrame, UInt32 usbFramesToDelay)
{
IOReturn result;
UInt32 i;
bool dataWrittenToPipe = false;
FailIf (NULL == pipeToPrime, Exit);
FailIf (0 == bytesPerUSBFrame, Exit);
FailIf ( (bytesPerUSBFrame * usbFramesToDelay) > mSampleBufferSize, Exit );
mPrimeInputIsocFrames = (IOUSBLowLatencyIsocFrame *)IOMalloc (usbFramesToDelay * sizeof (IOUSBLowLatencyIsocFrame));
FailIf (NULL == mPrimeInputIsocFrames, Exit);
mPrimeInputCompletion.target = (void *) this;
mPrimeInputCompletion.action = primeInputPipeHandler;
mPrimeInputCompletion.parameter = (void *) usbFramesToDelay;
for (i = 0; i < usbFramesToDelay; i++)
{
(mPrimeInputIsocFrames + i)->frStatus = -1;
(mPrimeInputIsocFrames + i)->frReqCount = bytesPerUSBFrame;
(mPrimeInputIsocFrames + i)->frActCount = 0;
}
result = pipeToPrime->Read (mUSBBufferDescriptor, mUSBFrameToQueue, usbFramesToDelay, mPrimeInputIsocFrames, &mPrimeInputCompletion, 0);
if (result == kIOReturnSuccess)
{
dataWrittenToPipe = true;
mUSBFrameToQueue += usbFramesToDelay;
debugIOLog ("? AppleUSBAudioEngine::primeInputPipe (%p, %lu) - %d frames primed. mUSBFrameToQueue = %llu", pipeToPrime, bytesPerUSBFrame, usbFramesToDelay, mUSBFrameToQueue);
}
Exit:
if (false == dataWrittenToPipe)
{
if (mPrimeInputIsocFrames)
{
IOFree (mPrimeInputIsocFrames, usbFramesToDelay * sizeof (IOUSBLowLatencyIsocFrame));
mPrimeInputIsocFrames = NULL;
}
}
}
void AppleUSBAudioEngine::primeInputPipeHandler (void * object, void * parameter, IOReturn result, IOUSBLowLatencyIsocFrame * pFrames)
{
AppleUSBAudioEngine * self;
UInt32 usbFramesToDelay;
debugIOLog ("+ AppleUSBAudioEngine::primeInputPipeHandler (%p, %lu, 0x%x, %p)", object, (UInt32) parameter, result, pFrames);
self = (AppleUSBAudioEngine *)object;
FailIf (NULL == self, Exit);
Exit:
if (self->mPrimeInputIsocFrames)
{
usbFramesToDelay = UInt32( parameter );
IOFree (self->mPrimeInputIsocFrames, usbFramesToDelay * sizeof (IOUSBLowLatencyIsocFrame));
self->mPrimeInputIsocFrames = NULL;
}
debugIOLog ("- AppleUSBAudioEngine::primeInputPipeHandler (%p, %lu, 0x%x, %p)", object, (UInt32) parameter, result, pFrames);
}
#endif
IOReturn AppleUSBAudioEngine::readFrameList (UInt32 frameListNum) {
const IOAudioStreamFormat * theFormat;
IOReturn result;
#if DEBUGINPUT
debugIOLog ("+ AppleUSBAudioEngine::readFrameList ()");
#endif
theFormat = mMainStream->getFormat ();
result = PrepareAndReadFrameLists (theFormat->fBitWidth / 8, theFormat->fNumChannels, frameListNum);
#if DEBUGINPUT
debugIOLog ("- AppleUSBAudioEngine::readFrameList ()");
#endif
return result;
}
void AppleUSBAudioEngine::readHandler (void * object, void * parameter, IOReturn result, IOUSBLowLatencyIsocFrame * pFrames) {
AppleUSBAudioEngine * self;
UInt64 currentUSBFrameNumber;
UInt32 frameListToRead;
UInt32 thisActCount = 0;
UInt32 minimumUSBFrameSize = 0;
UInt8 frameIndex;
IOReturn thisStatus = 0;
bool flagOverrun;
#if DEBUGINPUT
debugIOLog ("+ AppleUSBAudioEngine::readHandler ()");
#endif
self = (AppleUSBAudioEngine *)object;
FailIf (TRUE == self->mInCompletion, Exit);
self->mInCompletion = TRUE;
if ( (self->mUSBAudioDevice)
&& (false == self->mUSBAudioDevice->getSingleSampleRateDevice ()) && (kIOReturnOverrun == result)) {
debugIOLog ("! AppleUSBAudioEngine::readHandler () - Encountered fatal error 0x%x on frame list %d (frReqCount = %d).", result, self->mCurrentFrameList, pFrames->frReqCount );
if ( false == self->mGeneratesOverruns )
{
IOLog ( "WARNING: AppleUSBAudio has detected that a connected USB audio device is sending too much audio data.\n" );
IOLog ( "WARNING: This USB audio device may not function properly. Please notify the device manufacturer.\n" );
self->mGeneratesOverruns = true;
}
flagOverrun = true;
for ( UInt16 frameIndex = 0; frameIndex < self->mNumTransactionsPerList && pFrames; frameIndex++ )
{
if ( kIOReturnOverrun != pFrames[frameIndex].frStatus )
{
flagOverrun = false;
break;
}
}
if ( flagOverrun )
{
self->mUSBAudioDevice->setShouldSyncSampleRates (self);
}
goto Exit;
}
FailIf (NULL == self->mStreamInterface, Exit);
currentUSBFrameNumber = self->mStreamInterface->GetDevice()->GetBus()->GetFrameNumber();
if (kIOReturnAborted != result)
{
#if 1 if (0 == self->mShouldStop && (SInt32)(self->mUSBFrameToQueue - currentUSBFrameNumber) > (SInt32)(self->mNumUSBFramesPerList * (self->mNumUSBFrameListsToQueue - 1)))
{
#if DEBUGLOADING
debugIOLog ("Not queuing a frame list in readHandler (%ld)", (SInt32)(self->mUSBFrameToQueue - currentUSBFrameNumber));
#endif
goto Exit;
}
#endif
for (frameIndex = 0; frameIndex < self->mNumTransactionsPerList && pFrames; frameIndex++)
{
thisStatus = (pFrames + frameIndex)->frStatus;
thisActCount = (pFrames + frameIndex)->frActCount;
minimumUSBFrameSize = self->mAverageFrameSize - self->mSampleSize;
#ifdef DEBUG
if ( (!(self->mShouldStop))
&& (thisStatus != kIOReturnSuccess)
&& ( (thisStatus != kIOReturnUnderrun)
|| ( (thisStatus == kIOReturnUnderrun)
&& (thisActCount < minimumUSBFrameSize))))
{
debugIOLog ("! AppleUSBAudioEngine::readHandler () - Frame list %d frame index %d returned error 0x%x (frActCount = %lu, result = 0x%x)", self->mCurrentFrameList, frameIndex, thisStatus, thisActCount, result);
}
#endif
if (thisActCount < minimumUSBFrameSize)
{
}
if (kIOReturnNotResponding == thisStatus)
{
if ( (self->mUSBAudioDevice)
&& (false == self->mUSBAudioDevice->recoveryRequested ()))
{
self->mUSBAudioDevice->requestDeviceRecovery ();
}
}
}
}
if (kIOReturnSuccess != result && kIOReturnAborted != result && kIOReturnUnderrun != result)
{
if (self->mUSBFrameToQueue <= currentUSBFrameNumber)
{
self->mUSBFrameToQueue = currentUSBFrameNumber + kMinimumFrameOffset;
}
}
if (kIOReturnAborted != result)
{
self->CoalesceInputSamples (0, pFrames);
}
if (self->mShouldStop > 0)
{
if ( (self->mShouldStop == 1)
|| (self->mShouldStop == self->mNumUSBFrameListsToQueue))
{
debugIOLog("? AppleUSBAudioEngine::readHandler() - stopping: %d", self->mShouldStop);
}
self->mShouldStop++;
}
else if (kIOReturnAborted != result)
{
if (self->mCurrentFrameList == self->mNumUSBFrameLists - 1)
{
self->mCurrentFrameList = 0;
}
else
{
self->mCurrentFrameList++;
}
frameListToRead = (self->mCurrentFrameList - 1) + self->mNumUSBFrameListsToQueue;
if (frameListToRead >= self->mNumUSBFrameLists)
{
frameListToRead -= self->mNumUSBFrameLists;
}
self->readFrameList (frameListToRead);
}
Exit:
self->mInCompletion = FALSE;
#if DEBUGINPUT
debugIOLog ("- AppleUSBAudioEngine::readHandler ()");
#endif
return;
}
void AppleUSBAudioEngine::resetClipPosition (IOAudioStream *audioStream, UInt32 clipSampleFrame) {
if (mPlugin)
{
mPlugin->pluginReset ();
}
if ( (NULL != miSubBufferMemory)
&& (NULL != miSubEngine))
{
mSrcPhase = 1.0; mSrcState = 0.0;
mFilterState.xl_1 = 0.0;
mFilterState.xr_1 = 0.0;
mFilterState.xl_2 = 0.0;
mFilterState.xr_2 = 0.0;
mFilterState.yl_1 = 0.0;
mFilterState.yr_1 = 0.0;
mFilterState.yl_2 = 0.0;
mFilterState.yr_2 = 0.0;
mFilterState2.xl_1 = 0.0;
mFilterState2.xr_1 = 0.0;
mFilterState2.xl_2 = 0.0;
mFilterState2.xr_2 = 0.0;
mFilterState2.yl_1 = 0.0;
mFilterState2.yr_1 = 0.0;
mFilterState2.yl_2 = 0.0;
mFilterState2.yr_2 = 0.0;
mPhaseCompState.xl_1 = 0.0;
mPhaseCompState.xr_1 = 0.0;
mPhaseCompState.xl_2 = 0.0;
mPhaseCompState.xr_2 = 0.0;
mPhaseCompState.yl_1 = 0.0;
mPhaseCompState.yr_1 = 0.0;
mPhaseCompState.yl_2 = 0.0;
mPhaseCompState.yr_2 = 0.0;
#if DEBUGISUB
debugIOLog ("+resetClipPosition, miSubBufferOffset=%ld, mLastClippedFrame=%ld, clipSampleFrame=%ld", miSubBufferOffset, mLastClippedFrame, clipSampleFrame);
#endif
UInt32 clipAdjustment;
if (mLastClippedFrame < clipSampleFrame)
{
clipAdjustment = (mLastClippedFrame + ((getSampleBufferSize () / (2 * miSubEngine->GetNumChannels())) - clipSampleFrame)) * miSubEngine->GetNumChannels();
}
else
{
clipAdjustment = (mLastClippedFrame - clipSampleFrame) * miSubEngine->GetNumChannels();
}
clipAdjustment = (clipAdjustment * 1000) / ((1000 * getSampleRate()->whole) / miSubEngine->GetSampleRate());
miSubBufferOffset -= clipAdjustment;
if (miSubBufferOffset < 0)
{
miSubBufferOffset += (miSubBufferMemory->getLength () / 2);
miSubLoopCount--; }
mLastClippedFrame = clipSampleFrame;
mJustResetClipPosition = TRUE; #if DEBUGISUB
debugIOLog ("-resetClipPosition, miSubBufferOffset=%ld, mLastClippedFrame=%ld", miSubBufferOffset, mLastClippedFrame);
#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 = 0;
UInt32 newSampleRate = 0;
UInt32 framesToAdvance = 0;
IOReturn readStatus = kIOReturnError;
self = (AppleUSBAudioEngine *)target;
if ( (pFrames)
&& ( (kIOReturnSuccess == result)
|| (kIOReturnUnderrun == result)))
{
newSampleRate = *(self->mAverageSampleRateBuffer);
sampleRate = USBToHostLong (newSampleRate);
oldSampleRate = self->mAverageSampleRate;
switch (pFrames->frActCount)
{
case kFixedPoint10_14ByteSize:
sampleRate = sampleRate << 2;
fixed = sampleRate >> 16;
newSampleRate = fixed * 1000;
fract = IOFixedMultiply (sampleRate & 0x0000FFFF, 1000 << 16);
newSampleRate += (fract & 0xFFFF0000) >> 16;
break;
case kFixedPoint16_16ByteSize:
fixed = sampleRate >> 16;
newSampleRate = fixed * 1000;
fract = IOFixedMultiply (sampleRate & 0x0000FFFF, 1000 << 16);
newSampleRate += (fract & 0xFFFF0000) >> 16;
break;
default:
newSampleRate = 0;
}
if (newSampleRate && newSampleRate != oldSampleRate)
{
if ( ( newSampleRate > ( oldSampleRate + 1000 ) )
|| ( newSampleRate < ( oldSampleRate - 1000 ) ) )
{
}
else
{
self->mAverageSampleRate = newSampleRate;
debugIOLog ("? AppleUSBAudioEngine::sampleRateHandler () - Sample rate changed, requestedFrameRate = %d", self->mAverageSampleRate);
}
}
}
else
{
debugIOLog ("! AppleUSBAudioEngine::sampleRateHandler () - ignoring isoc result due to error 0x%x", result);
if ( pFrames )
{
debugIOLog (" pFrames->frReqCount = %d", pFrames->frReqCount);
debugIOLog (" pFrames->frActCount = %d", pFrames->frActCount);
debugIOLog (" pFrames->frStatus = 0x%x", pFrames->frStatus);
}
else
{
debugIOLog (" pFrames = NULL");
}
}
if (0 == self->mShouldStop)
{
self->mSampleRateFrame.frStatus = -1;
self->mSampleRateFrame.frReqCount = self->mFeedbackPacketSize;
self->mSampleRateFrame.frActCount = 0;
framesToAdvance = (1 << self->mRefreshInterval);
while ( framesToAdvance < kMinimumFrameOffset )
{
framesToAdvance *= 2;
}
if (NULL != self->mAssociatedPipe)
{
while ( (readStatus != kIOReturnSuccess)
&& (framesToAdvance <= kMaxFeedbackPollingInterval))
{
self->mNextSyncReadFrame += framesToAdvance;
readStatus = self->mAssociatedPipe->Read (self->mAssociatedEndpointMemoryDescriptor, self->mNextSyncReadFrame, 1, &(self->mSampleRateFrame), &(self->mSampleRateCompletion));
if ( kIOReturnSuccess != readStatus )
{
debugIOLog ( "! AppleUSBAudioEngine::sampleRateHandler () - framesToAdvance = %d, mNextSyncReadFrame = %llu, readStatus = 0x%x", framesToAdvance, self->mNextSyncReadFrame, readStatus );
self->mNextSyncReadFrame -= framesToAdvance;
framesToAdvance *= 2;
}
}
if ( kIOReturnSuccess != readStatus )
{
debugIOLog ( "! AppleUSBAudioEngine::sampleRateHandler () - Could not queue feedback endpoint isoc request. Feedback request chain is halted!" );
debugIOLog ( " mRefreshInterval = %d, framesToAdvance = %d, mNextSyncReadFrame = %llu, readStatus = 0x%x", self->mRefreshInterval, framesToAdvance, self->mNextSyncReadFrame, readStatus );
}
}
}
else
{
debugIOLog ( "? AppleUSBAudioEngine::sampleRateHandler () - Stopping feedback chain because stream is stopping." );
}
return;
}
IOReturn AppleUSBAudioEngine::setSampleRateControl (UInt8 address, UInt32 sampleRate) {
IOUSBDevRequest devReq;
UInt32 theSampleRate;
IOReturn result;
result = kIOReturnError;
devReq.bmRequestType = USBmakebmRequestType (kUSBOut, kUSBClass, kUSBEndpoint);
devReq.bRequest = SET_CUR;
devReq.wValue = (SAMPLING_FREQ_CONTROL << 8) | 0;
devReq.wIndex = address;
devReq.wLength = 3;
theSampleRate = OSSwapHostToLittleInt32 (sampleRate);
devReq.pData = &theSampleRate;
debugIOLog ("? AppleUSBAudioEngine[%p]::SetSampleRate () - Control interface %d, alt setting %d, endpoint address 0x%x, sample rate (little endian) 0x%x", this, mInterfaceNumber, mAlternateSettingID, devReq.wIndex, theSampleRate);
result = mStreamInterface->GetDevice()->DeviceRequest (&devReq);
FailIf (kIOReturnSuccess != result, Exit);
Exit:
if (kIOReturnSuccess != result)
{
debugIOLog ("! AppleUSBAudioEngine[%p]::setSampleRateControl () = 0x%x", this, result);
}
return result;
}
IOReturn AppleUSBAudioEngine::startUSBStream () {
const IOAudioStreamFormat * theFormat;
IOReturn resultCode;
IOReturn interimResult;
IOUSBFindEndpointRequest audioIsochEndpoint;
AUAConfigurationDictionary * configDictionary;
UInt64 currentUSBFrame;
UInt32 frameListNum;
UInt32 numQueued;
UInt32 usbFramesToDelay = 0;
UInt16 averageFrameSamples;
UInt16 additionalSampleFrameFreq;
UInt16 maxFrameSize;
UInt16 maxConsecutiveFramesToPrime;
UInt16 transactionsToQueue;
UInt16 remainingFrames;
UInt16 maxPacketSize = 0;
UInt8 endpointAddress;
UInt8 lockDelay = 0;
UInt8 lockDelayUnits = 0;
bool encounteredQueuingError = false;
debugIOLog ("+ AppleUSBAudioEngine[%p]::startUSBStream ()", this);
resultCode = kIOReturnError;
numQueued = 0;
mCurrentFrameList = 0;
mSafeErasePoint = 0;
mLastSafeErasePoint = 0;
mBufferOffset = 0;
mLastPreparedBufferOffset = 0; mFractionalSamplesLeft = 0;
mShouldStop = 0;
FailIf ((mNumUSBFrameLists < mNumUSBFrameListsToQueue), Exit);
FailIf (NULL == (configDictionary = mUSBAudioDevice->getConfigDictionary()), Exit);
FailIf (NULL == mStreamInterface, Exit);
resultCode = mStreamInterface->SetAlternateInterface (this, mAlternateSettingID);
debugIOLog ("? AppleUSBAudioEngine[%p]::startUSBStream () - mStreamInterface->SetAlternateInterface (this, %d) = 0x%x", this, mAlternateSettingID, resultCode);
FailIf (kIOReturnSuccess != resultCode, Exit);
if (configDictionary->asEndpointHasSampleFreqControl (mInterfaceNumber, mAlternateSettingID))
{
FailIf (kIOReturnSuccess != configDictionary->getIsocEndpointAddress (&endpointAddress, mInterfaceNumber, mAlternateSettingID, mDirection), Exit);
(void) setSampleRateControl (endpointAddress, mCurSampleRate.whole); }
audioIsochEndpoint.type = kUSBIsoc;
audioIsochEndpoint.direction = mDirection;
mPipe = mStreamInterface->FindNextPipe (NULL, &audioIsochEndpoint);
FailIf (NULL == mPipe, Exit);
mPipe->retain ();
if (getDirection () == kIOAudioStreamDirectionOutput)
{
(void)checkForFeedbackEndpoint ( configDictionary );
}
calculateSamplesPerPacket (mCurSampleRate.whole, &averageFrameSamples, &additionalSampleFrameFreq);
theFormat = mMainStream->getFormat ();
FailIf ( kIOReturnSuccess != configDictionary->getIsocEndpointMaxPacketSize ( &maxPacketSize, mInterfaceNumber, mAlternateSettingID, mDirection ), Exit );
FailIf ( 0 == maxPacketSize, Exit );
if (kUSBIn == mDirection)
{
maxFrameSize = ( averageFrameSamples + 2 ) * ( theFormat->fNumChannels * ( theFormat->fBitWidth / 8 ) );
maxFrameSize = ( maxFrameSize > maxPacketSize ) ? maxPacketSize : maxFrameSize;
debugIOLog ( "? AppleUSBAudioEngine[%p]::startUSBStream () - maxPacketSize = %d, maxFrameSize = %d", this, maxPacketSize, maxFrameSize );
mReadUSBFrameSize = maxFrameSize;
}
else
{
if ( ( 0 == additionalSampleFrameFreq )
&& ( NULL == mAssociatedPipe ) ) {
maxFrameSize = averageFrameSamples * ( theFormat->fNumChannels * ( theFormat->fBitWidth / 8 ) );
}
else
{
maxFrameSize = ( averageFrameSamples + 1 ) * ( theFormat->fNumChannels * ( theFormat->fBitWidth / 8 ) );
}
}
debugIOLog ("? AppleUSBAudioEngine[%p]::startUSBStream () - calling SetPipePolicy (%d)", this, maxFrameSize);
resultCode = mPipe->SetPipePolicy (maxFrameSize, 0);
FailIf (kIOReturnSuccess != resultCode, Exit);
currentUSBFrame = mStreamInterface->GetDevice()->GetBus()->GetFrameNumber();
mUSBFrameToQueue = currentUSBFrame + kMinimumFrameOffset;
debugIOLog ("? AppleUSBAudioEngine[%p]::startUSBStream () - mUSBFrameToQueue = %llu", this, mUSBFrameToQueue);
if (NULL != mAssociatedPipe)
{
mNextSyncReadFrame = mUSBFrameToQueue;
debugIOLog ("? AppleUSBAudioEngine[%p]::startUSBStream () - Starting feedback endpoint stream at frame %llu", this, mNextSyncReadFrame);
(void)mAssociatedPipe->Read (mAssociatedEndpointMemoryDescriptor, mNextSyncReadFrame, 1, &mSampleRateFrame, &mSampleRateCompletion);
debugIOLog ("? AppleUSBAudioEngine[%p]::startUSBStream () - Feedback endpoint stream started.", this);
}
mHaveTakenFirstTimeStamp = false;
if (getDirection () == kIOAudioStreamDirectionInput)
{
#if PRIMEISOCINPUT
FailIf ( kIOReturnSuccess != configDictionary->asEndpointGetLockDelay( &lockDelay, mInterfaceNumber, mAlternateSettingID ), Exit );
FailIf ( kIOReturnSuccess != configDictionary->asEndpointGetLockDelayUnits( &lockDelayUnits, mInterfaceNumber, mAlternateSettingID ), Exit );
if ( ( lockDelay )
&& ( lockDelayUnits ) )
{
switch ( lockDelayUnits )
{
case kLockDelayUnitMilliseconds:
usbFramesToDelay = lockDelay;
break;
case kLockDelayUnitsDecodedPCMSamples:
usbFramesToDelay = ( lockDelay / ( averageFrameSamples + 1 ) ) + ( ( lockDelay % ( averageFrameSamples + 1) ) ? 1 : 0 );
break;
default:
usbFramesToDelay = kNumUSBFramesToPrime;
}
}
else
{
usbFramesToDelay = kNumUSBFramesToPrime;
}
maxConsecutiveFramesToPrime = mSampleBufferSize / maxFrameSize;
FailIf ( 0 == maxConsecutiveFramesToPrime, Exit );
transactionsToQueue = ( usbFramesToDelay / maxConsecutiveFramesToPrime ) + ( ( usbFramesToDelay % maxConsecutiveFramesToPrime ) ? 1 : 0 );
debugIOLog ("? AppleUSBAudioEngine[%p]::startUSBStream () - Priming input stream at frame %llu ( %d USB frames ) in %d transaction(s)", this, mUSBFrameToQueue, usbFramesToDelay, transactionsToQueue );
remainingFrames = usbFramesToDelay;
currentUSBFrame = mStreamInterface->GetDevice()->GetBus()->GetFrameNumber();
mUSBFrameToQueue = currentUSBFrame + kMinimumFrameOffset;
for ( UInt16 currentTransaction = 0; currentTransaction < transactionsToQueue; currentTransaction++ )
{
if ( remainingFrames < maxConsecutiveFramesToPrime )
{
primeInputPipe ( mPipe, maxFrameSize, remainingFrames );
remainingFrames = 0;
}
else
{
primeInputPipe ( mPipe, maxFrameSize, maxConsecutiveFramesToPrime );
remainingFrames -= maxConsecutiveFramesToPrime;
}
}
#endif
debugIOLog ("? AppleUSBAudioEngine[%p]::startUSBStream () - Starting input stream at frame %llu", this, mUSBFrameToQueue);
for (frameListNum = mCurrentFrameList; frameListNum < mNumUSBFrameListsToQueue; frameListNum++)
{
interimResult = readFrameList (frameListNum);
if (kIOReturnSuccess != interimResult)
{
debugIOLog ("! AppleUSBAudioEngine[%p]::startUSBStream () - readFrameList (%d) failed with error 0x%x!", this, frameListNum, interimResult);
encounteredQueuingError = true;
}
}
IOSleep ( usbFramesToDelay );
}
else
{
* (UInt64 *) ( & (mUSBIsocFrames[0].frTimeStamp)) = 0xFFFFFFFFFFFFFFFFull;
mUSBIsocFrames[0].frStatus = kUSBLowLatencyIsochTransferKey;
for (frameListNum = mCurrentFrameList; frameListNum < mNumUSBFrameListsToQueue; frameListNum++)
{
interimResult = writeFrameList (frameListNum);
if (kIOReturnSuccess != interimResult)
{
debugIOLog ("! AppleUSBAudioEngine[%p]::startUSBStream () - writeFrameList (%d) failed with error 0x%x!", this, frameListNum, interimResult);
encounteredQueuingError = true;
}
}
}
if (encounteredQueuingError)
{
debugIOLog ("! AppleUSBAudioEngine[%p]::startUSBStream () - Stream will *NOT* start because of queuing errors", this);
resultCode = kIOReturnError;
}
else
{
mUSBStreamRunning = TRUE;
resultCode = kIOReturnSuccess;
}
Exit:
debugIOLog ("- AppleUSBAudioEngine[%p]::startUSBStream () = %x", this, resultCode);
return resultCode;
}
IOReturn AppleUSBAudioEngine::stopUSBStream () {
debugIOLog ("+ AppleUSBAudioEngine[%p]::stopUSBStream ()", this);
if (0 == mShouldStop)
{
mShouldStop = 1;
}
if (NULL != mPipe)
{
if (FALSE == mTerminatingDriver)
{
mPipe->SetPipePolicy (0, 0);
}
mPipe->release ();
mPipe = NULL;
}
if (NULL != mAssociatedPipe)
{
mAssociatedPipe->release ();
mAssociatedPipe = NULL;
}
if (FALSE == mTerminatingDriver)
{
if (NULL != mStreamInterface)
{ (void)mStreamInterface->SetAlternateInterface (this, kRootAlternateSetting);
}
}
mUSBStreamRunning = FALSE;
debugIOLog ("- AppleUSBAudioEngine[%p]::stopUSBStream ()", this);
return kIOReturnSuccess;
}
void AppleUSBAudioEngine::takeTimeStamp (bool incrementLoopCount, AbsoluteTime *timestamp)
{
#if LOGTIMESTAMPS
UInt64 time_nanos;
absolutetime_to_nanoseconds (*timestamp, &time_nanos);
if (true)
{
debugIOLog ("? AppleUSBAudioEngine[%p]::takeTimeStamp (%d, %p) = %llu ns", this, mHaveTakenFirstTimeStamp, timestamp, time_nanos);
}
#endif
if (false == mHaveTakenFirstTimeStamp)
{
super::takeTimeStamp (false, timestamp);
debugIOLog ("? AppleUSBAudioEngine[%p]::takeTimeStamp (0, %p) - First timestamp taken", this, timestamp);
mHaveTakenFirstTimeStamp = true;
}
else
{
super::takeTimeStamp (incrementLoopCount, timestamp);
}
}
bool AppleUSBAudioEngine::willTerminate (IOService * provider, IOOptionBits options) {
debugIOLog ("+ AppleUSBAudioEngine[%p]::willTerminate (%p)", this, provider);
if (miSubEngine == (AppleiSubEngine *)provider)
{
debugIOLog ("? AppleUSBAudioEngine[%p]::willTerminate () - iSub requesting termination", this);
iSubTeardownConnection ();
if ( (miSubAttachToggle->getIntValue ())
&& (NULL == miSubEngineNotifier)) {
debugIOLog ("? AppleUSBAudioEngine[%p]::willTerminate () - Adding miSubEngineNotifier because of iSub termination ...", this);
miSubEngineNotifier = addNotification (gIOPublishNotification, serviceMatching ("AppleiSubEngine"), (IOServiceNotificationHandler)&iSubEnginePublished, this);
}
}
if (mStreamInterface == provider)
{
mTerminatingDriver = TRUE;
debugIOLog ("? AppleUSBAudioEngine[%p]::willTerminate () - Closing stream interface", this);
if ( ( mUSBStreamRunning )
&& ( NULL != mPipe ) )
{
mPipe->Abort ();
if ( 0 == mShouldStop )
{
mShouldStop++;
}
}
mStreamInterface->close (this);
mOldiSubEngine = miSubEngine;
iSubCloseAction (this, NULL, NULL, NULL, NULL);
}
debugIOLog ("- AppleUSBAudioEngine[%p]::willTerminate ()", this);
return super::willTerminate (provider, options);
}
IOReturn AppleUSBAudioEngine::writeFrameList (UInt32 frameListNum) {
IOReturn result;
result = PrepareWriteFrameList (frameListNum);
FailIf (kIOReturnSuccess != result, Exit);
FailIf (NULL == mStreamInterface, Exit);
result = kIOReturnError;
FailIf (NULL == mPipe, Exit);
if (mNeedTimeStamps)
{
if (mUHCISupport)
{
#if DEBUGUHCI
debugIOLog ("? AppleUSBAudioEngine::writeFrameList () - Writing mSampleBufferWrapDescriptors[0]");
#endif
result = mPipe->Write (mWrapDescriptors[0], mUSBFrameToQueue, mNumFramesInFirstList, &mUSBIsocFrames[frameListNum * mNumTransactionsPerList], &mUSBCompletion[frameListNum], 1);
if ( mNumFramesInFirstList < mNumTransactionsPerList )
{
#if DEBUGUHCI
debugIOLog ("? AppleUSBAudioEngine::writeFrameList () - writeFrameList: Writing mSampleBufferWrapDescriptors[1] to frame %ld", mUSBFrameToQueue + mNumFramesInFirstList);
#endif
result = mPipe->Write (mWrapDescriptors[1], mUSBFrameToQueue + mNumFramesInFirstList, mNumTransactionsPerList - mNumFramesInFirstList, &mUSBIsocFrames[frameListNum * mNumTransactionsPerList + mNumFramesInFirstList], &mExtraUSBCompletion, 1);
}
}
else
{
result = mPipe->Write (mWrapRangeDescriptor, mUSBFrameToQueue, mNumTransactionsPerList, &mUSBIsocFrames[frameListNum * mNumTransactionsPerList], &mUSBCompletion[frameListNum], 1);
}
mNeedTimeStamps = FALSE;
}
else
{
result = mPipe->Write (mSampleBufferDescriptors[frameListNum], mUSBFrameToQueue, mNumTransactionsPerList, &mUSBIsocFrames[frameListNum * mNumTransactionsPerList], &mUSBCompletion[frameListNum], 0);
}
FailIf (result != kIOReturnSuccess, Exit);
if (NULL != mFrameQueuedForList)
{
mFrameQueuedForList[frameListNum] = mUSBFrameToQueue;
}
mUSBFrameToQueue += mNumUSBFramesPerList;
Exit:
if (kIOReturnSuccess != result)
{
debugIOLog ("? AppleUSBAudioEngine[%p]::writeFrameList () - failed with error 0x%x", this, result);
}
return result;
}
void AppleUSBAudioEngine::writeHandler (void * object, void * parameter, IOReturn result, IOUSBLowLatencyIsocFrame * pFrames) {
AppleUSBAudioEngine * self;
AbsoluteTime time;
UInt64 curUSBFrameNumber;
UInt32 frameListToWrite;
UInt32 byteOffset;
UInt32 frameIndex;
UInt32 byteCount;
UInt32 preWrapBytes;
UInt32 numberOfFramesToCheck;
SInt64 frameDifference;
SInt32 expectedFrames;
self = (AppleUSBAudioEngine *)object;
FailIf (TRUE == self->mInCompletion, Exit);
self->mInCompletion = TRUE;
FailIf (NULL == self->mStreamInterface, Exit);
curUSBFrameNumber = self->mStreamInterface->GetDevice()->GetBus()->GetFrameNumber ();
frameDifference = (SInt64)(self->mUSBFrameToQueue - curUSBFrameNumber);
expectedFrames = (SInt32)(self->mNumUSBFramesPerList * (self->mNumUSBFrameListsToQueue / 2)) + 1;
numberOfFramesToCheck = 0;
#if DEBUGUHCI
debugIOLog ("? AppleUSBAudioEngine::writeHandler () - writeHandler: curUSBFrameNumber = %llu parameter = 0x%x mUSBFrameToQueue = %llu", curUSBFrameNumber, (UInt32)parameter, self->mUSBFrameToQueue);
debugIOLog ("? AppleUSBAudioEngine::writeHandler () - %llu ?> %lu", frameDifference, expectedFrames);
#endif
if ( (frameDifference > expectedFrames)
&& ( (!(self->mUHCISupport)) || (0 == parameter))) {
debugIOLog ("? AppleUSBAudioEngine::writeHandler () - Not advancing frame list");
goto Exit;
}
if (kIOReturnAborted != result)
{
if (kIOReturnSuccess != result)
{
debugIOLog ("! AppleUSBAudioEngine::writeHandler () - Frame list %d write returned with error 0x%x", self->mCurrentFrameList, result);
}
numberOfFramesToCheck = ((self->mUHCISupport && (UInt32) parameter) ? self->mNumFramesInFirstList : self->mNumTransactionsPerList);
if ( (!(self->mHaveTakenFirstTimeStamp))
&& (0 == self->mBufferOffset))
{
for (UInt16 i = 0; i < numberOfFramesToCheck && pFrames; i++)
{
if (pFrames[i].frActCount)
{
debugIOLog ("? AppleUSBAudioEngine::writeHandler () - Taking first time stamp on frame list %lu frame index %d", self->mCurrentFrameList, i);
debugIOLog (" pFrames[%d].frStatus = %lu", i, pFrames[i].frStatus);
debugIOLog (" pFrames[%d].frReqCount = %lu", i, pFrames[i].frReqCount);
debugIOLog (" pFrames[%d].frActCount = %lu", i, pFrames[i].frActCount);
debugIOLog (" pFrames[%d].frTimeStamp = 0x%x", i, * (UInt64 *) &(pFrames[i].frTimeStamp));
time = self->generateTimeStamp (i, 0, 0);
self->takeTimeStamp (FALSE, &time);
break;
}
}
}
#ifdef DEBUG
for (UInt16 i = 0; i < numberOfFramesToCheck && pFrames; i++)
{
if ( (kIOReturnSuccess != pFrames[i].frStatus)
|| (pFrames[i].frActCount != pFrames[i].frReqCount))
{
debugIOLog ("! AppleUSBAudioEngine::writeHandler () - pFrames[%d].frStatus = 0x%x", i, pFrames[i].frStatus);
debugIOLog (" pFrames[%d].frReqCount = %lu", i, pFrames[i].frReqCount);
debugIOLog (" pFrames[%d].frActCount = %lu", i, pFrames[i].frActCount);
debugIOLog (" pFrames[%d].frTimeStamp = 0x%x", i, * (UInt64 *) &(pFrames[i].frTimeStamp));
}
}
#endif
if (self->mUSBFrameToQueue <= curUSBFrameNumber)
{
debugIOLog ("! AppleUSBAudioEngine::writeHandler - Fell behind! mUSBFrameToQueue = %llu, curUSBFrameNumber = %llu", self->mUSBFrameToQueue, curUSBFrameNumber);
self->mUSBFrameToQueue = curUSBFrameNumber + kMinimumFrameOffset;
}
}
if (0 != parameter)
{
byteOffset = (UInt32)parameter & 0x00FF;
frameIndex = ((UInt32)parameter >> 16) - 1; byteCount = pFrames[frameIndex].frActCount; preWrapBytes = byteCount - byteOffset; time = self->generateTimeStamp (frameIndex, preWrapBytes, byteCount);
self->takeTimeStamp (TRUE, &time);
if ( (self->mUHCISupport)
&& (frameDifference > expectedFrames - 1))
{
if (self->mShouldStop > 0)
{
debugIOLog ("? AppleUSBAudioEngine::writeHandler() - stopping: %d", self->mShouldStop);
self->mShouldStop++;
}
goto Exit;
}
}
if (self->mCurrentFrameList == self->mNumUSBFrameLists - 1)
{
self->mCurrentFrameList = 0;
}
else
{
self->mCurrentFrameList++;
}
if (self->mShouldStop > 0)
{
debugIOLog ("? AppleUSBAudioEngine::writeHandler() - stopping: %d", self->mShouldStop);
self->mShouldStop++;
}
else
{
frameListToWrite = (self->mCurrentFrameList - 1) + self->mNumUSBFrameListsToQueue;
if (frameListToWrite >= self->mNumUSBFrameLists)
{
frameListToWrite -= self->mNumUSBFrameLists;
}
self->writeFrameList (frameListToWrite);
}
Exit:
self->mInCompletion = FALSE;
return;
}
void AppleUSBAudioEngine::writeHandlerForUHCI (void * object, void * parameter, IOReturn result, IOUSBLowLatencyIsocFrame * pFrames) {
AppleUSBAudioEngine * self;
UInt64 curUSBFrameNumber;
SInt64 frameDifference;
SInt32 expectedFrames;
UInt32 frameListToWrite;
UInt32 numberOfFramesToCheck;
self = (AppleUSBAudioEngine *)object;
FailIf (TRUE == self->mInCompletion, Exit);
self->mInCompletion = TRUE;
FailIf (NULL == self->mStreamInterface, Exit);
curUSBFrameNumber = self->mStreamInterface->GetDevice()->GetBus()->GetFrameNumber ();
frameDifference = (SInt64)(self->mUSBFrameToQueue - curUSBFrameNumber);
expectedFrames = (SInt32)(self->mNumUSBFramesPerList * (self->mNumUSBFrameListsToQueue / 2)) + 1;
numberOfFramesToCheck = 0;
#if DEBUGUHCI
debugIOLog ("? AppleUSBAudioEngine[%p]::writeHandlerForUHCI () - writeHandlerForUHCI: curUSBFrameNumber = %llu parameter = 0x%x mUSBFrameToQueue = %llu", curUSBFrameNumber, (UInt32)parameter, self->mUSBFrameToQueue);
debugIOLog ("? AppleUSBAudioEngine[%p]::writeHandlerForUHCI () - %llu ?> %lu", frameDifference, expectedFrames);
#endif
if (kIOReturnAborted != result)
{
if (kIOReturnSuccess != result)
{
debugIOLog ("! AppleUSBAudioEngine::writeHandlerForUHCI () - Frame list %d (split for UHCI) write returned with error 0x%x", self->mCurrentFrameList, result);
}
#ifdef DEBUG
numberOfFramesToCheck = (self->mUHCISupport ? (self->mNumTransactionsPerList - self->mNumFramesInFirstList) : self->mNumTransactionsPerList);
for (UInt16 i = 0; i < numberOfFramesToCheck && pFrames; i++)
{
if ( (kIOReturnSuccess != pFrames[i].frStatus)
|| (pFrames[i].frActCount != pFrames[i].frReqCount))
{
debugIOLog ("! AppleUSBAudioEngine::writeHandlerForUHCI () - pFrames[%d].frStatus = 0x%x ", i, pFrames[i].frStatus);
debugIOLog (" pFrames[%d].frReqCount = %lu", i, pFrames[i].frReqCount);
debugIOLog (" pFrames[%d].frActCount = %lu", i, pFrames[i].frActCount);
debugIOLog (" pFrames[%d].frTimeStamp = 0x%x", i, * (UInt64 *) &(pFrames[i].frTimeStamp));
}
}
#endif
if (self->mUSBFrameToQueue <= curUSBFrameNumber)
{
debugIOLog ("! AppleUSBAudioEngine[%p]::writeHandlerForUHCI () - Fell behind! mUSBFrameToQueue = %llu, curUSBFrameNumber = %llu", self->mUSBFrameToQueue, curUSBFrameNumber);
debugIOLog ("! AppleUSBAudioEngine[%p]::writeHandlerForUHCI () - Skipping ahead ...");
self->mUSBFrameToQueue = curUSBFrameNumber + kMinimumFrameOffset;
}
}
if (self->mCurrentFrameList == self->mNumUSBFrameLists - 1)
{
self->mCurrentFrameList = 0;
}
else
{
self->mCurrentFrameList++;
}
if (0 == self->mShouldStop)
{
frameListToWrite = (self->mCurrentFrameList - 1) + self->mNumUSBFrameListsToQueue;
if (frameListToWrite >= self->mNumUSBFrameLists)
{
frameListToWrite -= self->mNumUSBFrameLists;
}
self->writeFrameList (frameListToWrite);
}
else
{
debugIOLog ("? AppleUSBAudioEngine[%p]::writeHandlerForUHCI () - Halting.", self);
}
Exit:
self->mInCompletion = FALSE;
return;
}
Generated by GNU enscript 1.6.4.