[plain text]
#include "AppleUSBAudioStream.h"
#include "AppleUSBAudioEngine.h"
#include "AppleUSBAudioPlugin.h"
#define super IOAudioStream
OSDefineMetaClassAndStructors(AppleUSBAudioStream, IOAudioStream)
#pragma mark -IOKit Routines-
void AppleUSBAudioStream::free () {
UInt32 i;
debugIOLog ("+ AppleUSBAudioStream[%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 (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 (mUSBAudioDevice)
{
mUSBAudioDevice->release ();
mUSBAudioDevice = NULL;
}
if (mUSBAudioEngine)
{
mUSBAudioEngine->release ();
mUSBAudioEngine = NULL;
}
if (mStreamInterface)
{
mStreamInterface->release ();
mStreamInterface = NULL;
}
super::free ();
debugIOLog ("- AppleUSBAudioStream[%p]::free()", this);
}
bool AppleUSBAudioStream::initWithAudioEngine (AppleUSBAudioDevice * device, AppleUSBAudioEngine * engine, IOUSBInterface * streamInterface, IOAudioSampleRate sampleRate, const char *streamDescription, OSDictionary *properties) {
AUAConfigurationDictionary * configDictionary;
Boolean result = false;
UInt32 startChannelID;
debugIOLog("+ AppleUSBAudioStream[%p]::initWithAudioEngine ()", this);
FailIf (NULL == device, Exit);
FailIf (NULL == engine, Exit);
FailIf (NULL == streamInterface, Exit);
result = FALSE;
mUSBAudioDevice = device;
mUSBAudioDevice->retain ();
mUSBAudioEngine = engine;
mUSBAudioEngine->retain ();
mStreamInterface = streamInterface;
mStreamInterface->retain ();
mInterfaceNumber = mStreamInterface->GetInterfaceNumber ();
debugIOLog ("? AppleUSBAudioStream[%p]::initWithAudioEngine () - mInterfaceNumber = %d", this, mInterfaceNumber);
mVendorID = mUSBAudioDevice->getVendorID ();
mProductID = mUSBAudioDevice->getProductID ();
FailIf (NULL == (configDictionary = mUSBAudioDevice->getConfigDictionary ()), Exit);
FailIf (kIOReturnSuccess != GetDefaultSettings (&mAlternateSettingID, &sampleRate), Exit);
FailIf (kIOReturnSuccess != configDictionary->getIsocEndpointDirection (&mDirection, mInterfaceNumber, mAlternateSettingID), Exit);
startChannelID = ( kIOAudioStreamDirectionOutput == mDirection ) ? mUSBAudioEngine->mStartOutputChannelID : mUSBAudioEngine->mStartInputChannelID;
FailIf (FALSE == super::initWithAudioEngine (engine, (IOAudioStreamDirection)mDirection, startChannelID, streamDescription, properties), Exit);
FailIf ((INTERFACE_PROTOCOL_UNDEFINED != mStreamInterface->GetInterfaceProtocol()) && (IP_VERSION_02_00 != mStreamInterface->GetInterfaceProtocol()), Exit);
setProperty ("IOAudioStreamSampleFormatByteOrder", "Little Endian");
attach ( mStreamInterface );
result = TRUE;
Exit:
debugIOLog("- AppleUSBAudioStream[%p]::initWithAudioEngine ()", this);
return result;
}
bool AppleUSBAudioStream::requestTerminate (IOService * provider, IOOptionBits options) {
bool result;
debugIOLog ("+ AppleUSBAudioStream[%p]::requestTerminate (%p, %x)", this, provider, options);
if ( mUSBAudioEngine == provider || mStreamInterface == provider )
{
result = TRUE; }
else
{
result = FALSE; }
debugIOLog ("- AppleUSBAudioStream[%p]::requestTerminate (%p, %x) = %d", this, provider, options, result);
return result;
}
void AppleUSBAudioStream::stop (IOService * provider) {
debugIOLog("+ AppleUSBAudioStream[%p]::stop (%p)", this, provider);
if (NULL != mPluginInitThread)
{
thread_call_cancel (mPluginInitThread);
thread_call_free (mPluginInitThread);
mPluginInitThread = NULL;
}
if (mPlugin)
{
mPlugin->close (this);
mPlugin = NULL;
}
if (mUSBAudioDevice)
{
mUSBAudioDevice->release ();
mUSBAudioDevice = NULL;
}
if (mUSBAudioEngine)
{
mUSBAudioEngine->release ();
mUSBAudioEngine = NULL;
}
if (mPipe)
{
mPipe->release ();
mPipe = NULL;
}
if (mAssociatedPipe)
{
mAssociatedPipe->release ();
mAssociatedPipe = NULL;
}
if ( (mStreamInterface)
&& ( (provider == mUSBAudioEngine) || (provider == mStreamInterface) )
&& (mStreamInterface->isOpen()))
{
debugIOLog ("! AppleUSBAudioStream[%p]::stop () - mStreamInterface was still open when stop() was called. Closing ...", this);
mStreamInterface->close (this);
mStreamInterface->release ();
mStreamInterface = NULL;
}
super::stop (provider);
debugIOLog ("- AppleUSBAudioStream[%p]::stop (%p) - rc=%ld", this, provider, getRetainCount());
}
bool AppleUSBAudioStream::terminate (IOOptionBits options) {
bool shouldTerminate;
bool result;
result = TRUE;
shouldTerminate = TRUE;
debugIOLog ("+ AppleUSBAudioStream[%p]::terminate ()", this);
if (shouldTerminate)
{
result = super::terminate (options);
}
debugIOLog ("- AppleUSBAudioStream[%p]::terminate ()", this);
return result;
}
bool AppleUSBAudioStream::matchPropertyTable(OSDictionary * table, SInt32 *score)
{
bool returnValue = false;
if (super::matchPropertyTable (table, score))
{
if (compareProperty (table, kIDVendorString) &&
compareProperty (table, kIDProductString) &&
compareProperty (table, kIOAudioStreamDirectionKey))
{
returnValue = true;
}
}
return returnValue;
}
#pragma mark -USB Audio driver-
IOReturn AppleUSBAudioStream::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;
Boolean isClockSourceProgrammable = TRUE;
debugIOLog ("+ AppleUSBAudioStream[%p]::addAvailableFormats (%p)", this, configDictionary);
FailIf (NULL == configDictionary, Exit);
FailIf (kIOReturnSuccess != configDictionary->getNumAltSettings (&numAltInterfaces, mInterfaceNumber), Exit);
debugIOLog ("? AppleUSBAudioStream[%p]::addAvailableFormats () - There are %d alternate interfaces @ interface %d", this, numAltInterfaces, mInterfaceNumber);
hasNativeAC3Format = FALSE;
candidateAC3AltSetting = 0;
if ( ( IP_VERSION_02_00 == mUSBAudioDevice->mControlInterface->GetInterfaceProtocol() ) && ( 0 != mUSBAudioEngine->mCurrentClockSourceID ) )
{
isClockSourceProgrammable = configDictionary->clockSourceHasFrequencyControl ( mUSBAudioDevice->mControlInterface->GetInterfaceNumber (), 0, mUSBAudioEngine->mCurrentClockSourceID, true );
}
altSettingIndex = configDictionary->alternateSettingZeroCanStream (mInterfaceNumber) ? 0 : 1;
for ( ; altSettingIndex < numAltInterfaces; altSettingIndex++)
{
if ( isClockSourceProgrammable )
{
if ( kIOReturnSuccess != configDictionary->getNumSampleRates (&numSampleRates, mInterfaceNumber, altSettingIndex) )
{
continue;
}
sampleRates = configDictionary->getSampleRates (mInterfaceNumber, altSettingIndex);
}
else
{
numSampleRates = 0;
sampleRates = NULL;
}
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 ("? AppleUSBAudioStream[%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 ("? AppleUSBAudioStream[%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 ("? AppleUSBAudioStream[%p]::addAvailableFormats () - Interface format = 0x%x not published.", this, format);
continue; }
debugIOLog ("? AppleUSBAudioStream[%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;
this->addAvailableFormat (&streamFormat, &streamFormatExtension, &lowSampleRate, &lowSampleRate);
if (kIOAudioStreamSampleFormatLinearPCM == streamFormat.fSampleFormat)
{
streamFormat.fIsMixable = FALSE;
this->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;
this->addAvailableFormat (&streamFormat, &streamFormatExtension, &lowSampleRate, &highSampleRate);
if (kIOAudioStreamSampleFormatLinearPCM == streamFormat.fSampleFormat)
{
streamFormat.fIsMixable = FALSE;
this->addAvailableFormat (&streamFormat, &streamFormatExtension, &lowSampleRate, &highSampleRate);
}
}
else
{
if ( !isClockSourceProgrammable )
{
OSArray * clockPath = NULL;
OSArray * clockPathGroup = mUSBAudioDevice->getClockPathGroup ( mInterfaceNumber, altSettingIndex );
FailIf ( NULL == clockPathGroup, Exit );
FailIf ( NULL == ( clockPath = OSDynamicCast ( OSArray, clockPathGroup->getObject ( mUSBAudioEngine->mCurrentClockPathIndex - 1 ) ) ), Exit );
if ( kIOReturnSuccess == mUSBAudioDevice->getClockPathCurSampleRate ( &thisSampleRate, NULL, clockPath ) )
{
debugIOLog (" %d", thisSampleRate);
lowSampleRate.whole = thisSampleRate;
lowSampleRate.fraction = 0;
this->addAvailableFormat (&streamFormat, &streamFormatExtension, &lowSampleRate, &lowSampleRate);
}
}
}
}
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;
this->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;
this->addAvailableFormat (&streamFormat, &streamFormatExtension, &lowSampleRate, &highSampleRate);
}
}
result = kIOReturnSuccess;
Exit:
debugIOLog ("- AppleUSBAudioStream[%p]::addAvailableFormats (%p) = 0x%x", this, configDictionary, result);
return result;
}
IOBufferMemoryDescriptor * AppleUSBAudioStream::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 ("+ AppleUSBAudioStream[%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 ("? AppleUSBAudioStream[%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 ("- AppleUSBAudioStream[%p]::allocateBufferDescriptor () = %p", this, bufferDescriptorPtr);
return bufferDescriptorPtr;
}
void AppleUSBAudioStream::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;
}
#if SHOWCADENCE
UInt32 transferSampleRate;
UInt32 currentSampleRate;
UInt32 remainder;
UInt32 accumulatedSamples = 0ul;
UInt16 transfer = 0;
UInt16 cycleLength = 0;
UInt8 powerOfTwo = 0;
UInt8 transactionsPerMS;
transactionsPerMS = mTransactionsPerUSBFrame;
while ( transactionsPerMS > 1 )
{
transactionsPerMS >>= 1;
powerOfTwo++;
}
transferSampleRate = sampleRate << ( 16 - powerOfTwo );
currentSampleRate = ( sampleRate / ( mTransactionsPerUSBFrame * 1000 ) );
currentSampleRate *= 1000;
currentSampleRate <<= 16;
remainder = transferSampleRate - currentSampleRate;
debugIOLog ( "? AppleUSBAudioStream[%p]::calculateSamplesPerPacket - transferSampleRate = 0x%8X, currentSampleRate = 0x%X", this, transferSampleRate, currentSampleRate );
transfer = 1;
cycleLength = 0;
while ( ( remainder )
&& ( ( 0 == accumulatedSamples )
|| ( accumulatedSamples % ( 1000 << 16 ) ) ) )
{
accumulatedSamples += remainder;
if ( accumulatedSamples >= ( 1000 << 16 ) )
{
debugIOLog ( "? AppleUSBAudioStream[%p]::calculateSamplesPerPacket - large packet on transfer %d (1-indexed)", this , transfer );
accumulatedSamples -= ( 1000 << 16 );
}
transfer++;
cycleLength++;
if ( ! accumulatedSamples )
{
break;
}
}
debugIOLog ( "? AppleUSBAudioStream[%p]::calculateSamplesPerPacket - cycleLength = %d", this, cycleLength );
#endif
}
IOReturn AppleUSBAudioStream::checkForFeedbackEndpoint (AUAConfigurationDictionary * configDictionary)
{
IOUSBFindEndpointRequest associatedEndpoint;
IOReturn result;
UInt16 maxPacketSize;
UInt8 assocEndpoint;
UInt8 address;
UInt8 syncType;
result = kIOReturnSuccess;
mAssociatedPipe = NULL;
FailIf (NULL == mUSBAudioDevice, Exit);
FailIf (NULL == mStreamInterface, 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 ("? AppleUSBAudioStream[%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 ("? AppleUSBAudioStream[%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 ("? AppleUSBAudioStream[%p]::checkForFeedbackEndpoint () - Need to adjust mNumUSBFramesPerList: %ld < %ld", mFramesUntilRefresh, mNumUSBFramesPerList);
if (NULL != mUSBIsocFrames)
{
debugIOLog ("? AppleUSBAudioStream[%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 ("? AppleUSBAudioStream[%p]::checkForFeedbackEndpoint () - mNumUSBFramesPerList = %d, mNumUSBFrameListsToQueue = %d, mNumUSBFrameLists = %d", this, mNumUSBFramesPerList, mNumUSBFrameListsToQueue, mNumUSBFrameLists);
mUSBIsocFrames = (IOUSBLowLatencyIsocFrame *)IOMalloc (mNumUSBFrameLists * mNumTransactionsPerList * sizeof (IOUSBLowLatencyIsocFrame));
debugIOLog ("? AppleUSBAudioStream[%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 ("! AppleUSBAudioStream[%p]::checkForFeedbackEndpoint () - No associated synch endpoint found.", this);
}
} else
{
debugIOLog ("? AppleUSBAudioStream[%p]::checkForFeedbackEndpoint () - No associated synch endpoint.", this);
}
Exit:
return result;
}
IOReturn AppleUSBAudioStream::CoalesceInputSamples (UInt32 numBytesToCoalesce, IOUSBLowLatencyIsocFrame * pFrames) {
IOReturn result = kIOReturnSuccess;
AbsoluteTime time;
UInt32 usbFrameIndex;
UInt32 firstUSBFrameIndex; UInt32 totalNumUSBFrames; 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 ("+ AppleUSBAudioStream[%p]::CoalesceInputSamples (%lu, %p)", this, numBytesToCoalesce, pFrames);
#endif
originalBufferOffset = 0;
if (0 != numBytesToCoalesce)
{
onCoreAudioThread = true;
originalBufferOffset = mBufferOffset; #if DEBUGINPUT
debugIOLog ("! AppleUSBAudioStream[%p]::CoalesceInputSamples () - Coalesce from %ld %ld bytes (framelist %ld) on CoreAudio thread", this, originalBufferOffset, numBytesToCoalesce, mCurrentFrameList);
#endif
if ( mMasterMode && !mHaveTakenFirstTimeStamp )
{
debugIOLog ("! AppleUSBAudioStream[%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);
firstUSBFrameIndex = (mCurrentFrameList * mNumTransactionsPerList);
totalNumUSBFrames = (mNumUSBFrameLists * mNumTransactionsPerList);
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 - 2 * mSampleSize))))) {
debugIOLog ("! AppleUSBAudioStream[%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))
{
if ( mMasterMode )
{
debugIOLog ("? AppleUSBAudioStream::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)
{
if ( mMasterMode )
{
time = generateTimeStamp (usbFrameIndex, preWrapBytes, byteCount);
takeTimeStamp (TRUE, &time);
}
}
}
dest += numBytesToCopy;
source += pFrames[usbFrameIndex].frReqCount;
usbFrameIndex++;
numFramesChecked++;
if (0 != numBytesToCoalesce && (usbFrameIndex + firstUSBFrameIndex) == totalNumUSBFrames)
{
pFrames = &mUSBIsocFrames[0]; usbFrameIndex = 0;
firstUSBFrameIndex = 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 )
&& ( NULL != mStreamInterface ) )
{
debugIOLog ("! AppleUSBAudioStream[%p]::CoalesceInputSamples () - Requested: %lu, Remaining: %lu on frame list %lu", this, numBytesToCoalesce, numBytesLeft, mCurrentFrameList);
}
#if DEBUGINPUT
debugIOLog ("- AppleUSBAudioStream[%p]::CoalesceInputSamples (%lu, %p)", this, numBytesToCoalesce, pFrames);
#endif
if (mCoalescenceMutex)
{
IOLockUnlock (mCoalescenceMutex);
}
if ( kIOReturnSuccess != result )
{
debugIOLog ( "! AppleUSBAudioStream[%p]::CoalesceInputSamples (%lu, %p) = 0x%x", this, numBytesToCoalesce, pFrames, result );
}
return result;
}
IOReturn AppleUSBAudioStream::controlledFormatChange (const IOAudioStreamFormat *newFormat, const IOAudioSampleRate *newSampleRate)
{
IOReturn result;
AUAConfigurationDictionary * configDictionary = NULL;
void * sampleBuffer;
UInt32 i;
UInt32 numSamplesInBuffer;
UInt16 averageFrameSamples;
UInt16 additionalSampleFrameFreq;
UInt16 maxPacketSize;
UInt8 endpointAddress;
UInt8 interval;
UInt8 newAlternateSettingID;
UInt8 newDirection;
UInt8 oldTransactionsPerFrame;
bool needToChangeChannels;
debugIOLog ("+ AppleUSBAudioStream[%p]::controlledFormatChange (%p, %p)", this, newFormat, newSampleRate);
result = kIOReturnError;
FailIf (NULL == mStreamInterface, Exit);
FailIf (NULL == mUSBAudioDevice, Exit);
FailIf (NULL == (configDictionary = mUSBAudioDevice->getConfigDictionary()), Exit);
FailIf (NULL == newFormat, Exit);
mInterfaceNumber = (UInt8)(newFormat->fDriverTag >> 16);
newAlternateSettingID = (UInt8)(newFormat->fDriverTag);
if (newFormat->fNumChannels != this->format.fNumChannels)
{
needToChangeChannels = TRUE;
debugIOLog ("? AppleUSBAudioStream[%p]::controlledFormatChange () - Need to adjust channel controls (cur = %d, new = %d)", this, this->format.fNumChannels, newFormat->fNumChannels);
if (kIOAudioStreamDirectionOutput == mDirection)
{
if (1 == newFormat->fNumChannels)
{
mUSBAudioDevice->setMonoState (TRUE);
}
else
{
mUSBAudioDevice->setMonoState (FALSE);
}
}
}
else
{
needToChangeChannels = FALSE;
}
if (newSampleRate)
{
debugIOLog ("? AppleUSBAudioStream[%p]::controlledFormatChange () - Changing sampling rate to %d", this, newSampleRate->whole);
mCurSampleRate = *newSampleRate;
}
else
{
}
if (mPlugin)
{
mPlugin->pluginSetFormat (newFormat, &mCurSampleRate);
}
if (false == configDictionary->verifySampleRateIsSupported (mInterfaceNumber, newAlternateSettingID, mCurSampleRate.whole))
{
debugIOLog ("? AppleUSBAudioStream[%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 ("? AppleUSBAudioStream[%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 ( "! AppleUSBAudioStream[%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 (IP_VERSION_02_00 == mStreamInterface->GetInterfaceProtocol())
{
OSArray * pathArray = NULL;
if ( NULL != mUSBAudioEngine->mClockSelectorControl && 0 != mUSBAudioEngine->mCurrentClockPathIndex )
{
UInt32 pathIndex = mUSBAudioEngine->mCurrentClockPathIndex;
FailIf ( 0 == pathIndex, Exit );
OSArray * clockPathGroup = mUSBAudioDevice->getClockPathGroup ( mInterfaceNumber, mAlternateSettingID );
FailIf ( NULL == clockPathGroup, Exit );
pathArray = OSDynamicCast ( OSArray, clockPathGroup->getObject ( pathIndex - 1 ) );
}
else
{
pathArray = mUSBAudioDevice->getOptimalClockPath ( mUSBAudioEngine, 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 ("? AppleUSBAudioStream[%p]::controlledFormatChange () - averageFrameSamples = %d", this, averageFrameSamples);
mSampleBitWidth = newFormat->fBitWidth;
mNumChannels = newFormat->fNumChannels;
mSampleSize = newFormat->fNumChannels * (newFormat->fBitWidth / 8);
mAverageFrameSize = averageFrameSamples * mSampleSize;
mAlternateFrameSize = (averageFrameSamples + 1) * mSampleSize;
debugIOLog ("? AppleUSBAudioStream[%p]::controlledFormatChange () - mAverageFrameSize = %d, mAlternateFrameSize = %d", this, mAverageFrameSize, mAlternateFrameSize);
if (kUSBIn == mDirection)
{
FailIf ( kIOReturnSuccess != configDictionary->getIsocEndpointMaxPacketSize ( &maxPacketSize, mInterfaceNumber, mAlternateSettingID, mDirection ), Exit );
mReadUSBFrameListSize = ( ( mAlternateFrameSize + 2 * mSampleSize ) < maxPacketSize ) ? ( mAlternateFrameSize + 2 * 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 ) && ( kUSBIn != mDirection ) ) {
mSampleBufferSizeExtended = mSampleBufferSize + PAGE_SIZE;
}
else
{
mSampleBufferSizeExtended = mSampleBufferSize;
}
debugIOLog("? AppleUSBAudioStream[%p]::controlledFormatChange () - New mSampleBufferSize = %d numSamplesInBuffer = %d", this, mSampleBufferSize, numSamplesInBuffer );
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)
{
this->setSampleBuffer (NULL, 0);
mSampleBufferMemoryDescriptor->release ();
}
mSampleBufferMemoryDescriptor = IOBufferMemoryDescriptor::withOptions (kIODirectionInOut, mSampleBufferSize, PAGE_SIZE);
FailIf (NULL == mSampleBufferMemoryDescriptor, Exit);
sampleBuffer = mSampleBufferMemoryDescriptor->getBytesNoCopy ();
}
else
{
if (NULL != mUSBBufferDescriptor)
{
this->setSampleBuffer (NULL, 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);
}
this->setSampleBuffer (sampleBuffer, mSampleBufferSize);
updateSampleOffsetAndLatency ();
debugIOLog ("? AppleUSBAudioStream[%p]::controlledFormatChange () - Called setNumSampleFramesPerBuffer with %d", this, mSampleBufferSize / (mSampleSize ? mSampleSize : 1));
debugIOLog ("? AppleUSBAudioStream[%p]::controlledFormatChange () - newFormat->fNumChannels = %d, newFormat->fBitWidth %d", this, newFormat->fNumChannels, newFormat->fBitWidth);
result = kIOReturnSuccess;
Exit:
debugIOLog ("- AppleUSBAudioStream[%p]::controlledFormatChange () = 0x%x", this, result);
return result;
}
void AppleUSBAudioStream::updateSampleOffsetAndLatency ()
{
UInt32 minimumSafeSampleOffset;
UInt32 cautiousSafeSampleOffset;
UInt16 averageFrameSamples;
UInt16 additionalSampleFrameFreq;
bool highSpeedCompensation;
OSDictionary * sampleOffsetDictionary = NULL;
OSDictionary * sampleLatencyDictionary = NULL;
UInt32 newSampleOffset;
UInt32 newSampleLatency;
calculateSamplesPerPacket (mCurSampleRate.whole, &averageFrameSamples, &additionalSampleFrameFreq);
if (kUSBIn == mDirection)
{
if (mSplitTransactions)
{
debugIOLog ("? AppleUSBAudioStream[%p]::updateSampleOffsetAndLatency () - Compensating for high speed timing difference in sample offset", this);
highSpeedCompensation = true;
}
else
{
highSpeedCompensation = false;
}
minimumSafeSampleOffset = averageFrameSamples + 1;
cautiousSafeSampleOffset = minimumSafeSampleOffset + (minimumSafeSampleOffset / kUSBInputRecoveryTimeFraction);
newSampleOffset = cautiousSafeSampleOffset;
if ( mSyncCompensation )
{
debugIOLog ("? AppleUSBAudioStream[%p]::updateSampleOffsetAndLatency () - Compensating for time stamp generation in sample offset", this);
newSampleOffset += cautiousSafeSampleOffset * 3 / 2;
}
sampleOffsetDictionary = OSDynamicCast ( OSDictionary, mStreamInterface->getProperty ( kIOAudioEngineInputSampleOffsetKey ) );
if (NULL == sampleOffsetDictionary)
{
sampleOffsetDictionary = OSDynamicCast ( OSDictionary, mStreamInterface->getProperty ( kIOAudioEngineSampleOffsetKey ) );
}
if (NULL != sampleOffsetDictionary)
{
char sampleOffsetKeyString[16];
snprintf (sampleOffsetKeyString, 16, "%d", mCurSampleRate.whole);
OSNumber * sampleOffset = OSDynamicCast ( OSNumber, sampleOffsetDictionary->getObject ( sampleOffsetKeyString ) );
if ( NULL != sampleOffset )
{
debugIOLog ("? AppleUSBAudioEngine[%p]::updateSampleOffsetAndLatency () - override input sample offset (%lu) to %lu sample frames", this, newSampleOffset, sampleOffset->unsigned32BitValue ());
newSampleOffset = sampleOffset->unsigned32BitValue ();
}
}
newSampleOffset += (highSpeedCompensation ? (5 * minimumSafeSampleOffset / 3) : 0);
mUSBAudioEngine->setInputSampleOffset (newSampleOffset);
debugIOLog ("? AppleUSBAudioEngine[%p]::updateSampleOffsetAndLatency () - setting input sample offset to %lu sample frames", this, newSampleOffset);
newSampleLatency = averageFrameSamples * ( 1);
sampleLatencyDictionary = OSDynamicCast ( OSDictionary, mStreamInterface->getProperty ( kIOAudioEngineInputSampleLatencyKey ) );
if (NULL != sampleLatencyDictionary)
{
char sampleLatencyKeyString[16];
snprintf (sampleLatencyKeyString, 16, "%d", mCurSampleRate.whole);
OSNumber * sampleLatency = OSDynamicCast ( OSNumber, sampleLatencyDictionary->getObject ( sampleLatencyKeyString ) );
if ( NULL != sampleLatency )
{
debugIOLog ("? AppleUSBAudioEngine[%p]::updateSampleOffsetAndLatency () - override input sample latency (%lu) to %lu sample frames", this, newSampleLatency, sampleLatency->unsigned32BitValue ());
newSampleLatency = sampleLatency->unsigned32BitValue ();
}
}
mUSBAudioEngine->setInputSampleLatency (newSampleLatency);
debugIOLog ("? AppleUSBAudioEngine[%p]::updateSampleOffsetAndLatency () - setting input sample latency to %lu sample frames", this, newSampleLatency);
}
else
{
cautiousSafeSampleOffset = averageFrameSamples + 1;
if ( mSyncCompensation )
{
debugIOLog ("? AppleUSBAudioStream[%p]::updateSampleOffsetAndLatency () - Compensating for time stamp generation in sample offset", this);
minimumSafeSampleOffset = cautiousSafeSampleOffset;
}
else
{
minimumSafeSampleOffset = cautiousSafeSampleOffset / 2;
}
newSampleOffset = minimumSafeSampleOffset;
sampleOffsetDictionary = OSDynamicCast ( OSDictionary, mStreamInterface->getProperty ( kIOAudioEngineSampleOffsetKey ) );
if (NULL != sampleOffsetDictionary)
{
char sampleOffsetKeyString[16];
snprintf (sampleOffsetKeyString, 16, "%d", mCurSampleRate.whole);
OSNumber * sampleOffset = OSDynamicCast ( OSNumber, sampleOffsetDictionary->getObject ( sampleOffsetKeyString ) );
if ( NULL != sampleOffset )
{
debugIOLog ("? AppleUSBAudioEngine[%p]::updateSampleOffsetAndLatency () - override output sample offset (%lu) to %lu sample frames", this, newSampleOffset, sampleOffset->unsigned32BitValue ());
newSampleOffset = sampleOffset->unsigned32BitValue ();
}
}
mUSBAudioEngine->setOutputSampleOffset (newSampleOffset);
debugIOLog ("? AppleUSBAudioEngine[%p]::updateSampleOffsetAndLatency () - setting output sample offset to %lu sample frames", this, newSampleOffset);
newSampleLatency = additionalSampleFrameFreq ? averageFrameSamples + 1 : averageFrameSamples;
sampleLatencyDictionary = OSDynamicCast ( OSDictionary, mStreamInterface->getProperty ( kIOAudioEngineOutputSampleLatencyKey ) );
if (NULL != sampleLatencyDictionary)
{
char sampleLatencyKeyString[16];
snprintf (sampleLatencyKeyString, 16, "%d", mCurSampleRate.whole);
OSNumber * sampleLatency = OSDynamicCast ( OSNumber, sampleLatencyDictionary->getObject ( sampleLatencyKeyString ) );
if ( NULL != sampleLatency )
{
debugIOLog ("? AppleUSBAudioEngine[%p]::updateSampleOffsetAndLatency () - override output sample latency (%lu) to %lu sample frames", this, newSampleLatency, sampleLatency->unsigned32BitValue ());
newSampleLatency = sampleLatency->unsigned32BitValue ();
}
}
mUSBAudioEngine->setOutputSampleLatency (newSampleLatency);
debugIOLog ("? AppleUSBAudioEngine[%p]::updateSampleOffsetAndLatency () - setting output sample latency to %lu sample frames", this, newSampleLatency);
}
}
IOReturn AppleUSBAudioStream::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;
}
AbsoluteTime AppleUSBAudioStream::generateTimeStamp (UInt32 transactionIndex, 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 remainingTransactionsMinusOne = 0ul;
UInt32 partialFrame = 0;
bool anchorInFuture;
UInt32 numOutstandingTransactions = 0;
UInt32 numOutStandingUSBFrames = 0;
FailIf ( NULL == mFrameQueuedForList, Exit );
FailIf ( NULL == mUSBAudioDevice, Exit );
FailIf ( 0 == mTransactionsPerUSBFrame, Exit );
FailIf ( kIOReturnSuccess != copyAnchor ( &anchorFrame, &anchorTime ), Exit );
numOutstandingTransactions = transactionIndex + 1;
numOutStandingUSBFrames = numOutstandingTransactions / mTransactionsPerUSBFrame;
if ( 0 < numOutStandingUSBFrames )
{
thisFrameNum = mFrameQueuedForList[mCurrentFrameList] + numOutStandingUSBFrames - 1;
remainingTransactionsMinusOne = ( numOutstandingTransactions - ( ( numOutStandingUSBFrames - 1 ) * mTransactionsPerUSBFrame ) ) - 1; }
else
{
thisFrameNum = mFrameQueuedForList[mCurrentFrameList];
remainingTransactionsMinusOne = numOutstandingTransactions - 1; }
#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 * remainingTransactionsMinusOne ) : 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 ( " transactionIndex = %lu, remainingTransactionsMinusOne = %lu, preWrapBytes = %u, byteCount = %u", transactionIndex, remainingTransactionsMinusOne, 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, remainingTransactionsMinusOne = %lu", thisFrameNum, mFrameQueuedForList[mCurrentFrameList], remainingTransactionsMinusOne );
}
}
mLastTimeStamp_nanos = time_nanos;
if (0ull != stampDifference)
{
mLastStampDifference = stampDifference;
}
mLastWrapFrame = thisFrameNum;
#endif
Exit:
nanoseconds_to_absolutetime (time_nanos, &time);
return time;
}
UInt32 AppleUSBAudioStream::getCurrentSampleFrame () {
const IOAudioStreamFormat *theFormat;
UInt32 currentSampleFrame;
currentSampleFrame = 0;
theFormat = this->getFormat ();
if (getDirection () == kIOAudioStreamDirectionOutput)
{
currentSampleFrame = mSafeErasePoint;
}
else
{
currentSampleFrame = (mBufferOffset == mSampleBufferSize ? 0 : mBufferOffset);
}
currentSampleFrame /= (theFormat->fNumChannels * (theFormat->fBitWidth / 8));
return currentSampleFrame;
}
IOReturn AppleUSBAudioStream::GetDefaultSettings (UInt8 * altSettingID, IOAudioSampleRate * sampleRate) {
IOReturn result;
UInt16 format;
UInt8 newAltSettingID;
IOAudioSampleRate newSampleRate;
AUAConfigurationDictionary * configDictionary = NULL;
debugIOLog ("+ AppleUSBAudioStream[%p]::GetDefaultSettings ()", this);
result = kIOReturnError;
newSampleRate.whole = sampleRate->whole;
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 ) ) ) )
{
UInt8 numAltSettings = 0;
if (kIOReturnSuccess == configDictionary->getNumAltSettings (&numAltSettings, mInterfaceNumber))
{
bool startAtZero = configDictionary->alternateSettingZeroCanStream (mInterfaceNumber);
for (UInt8 altSetting = (startAtZero ? 0 : 1); altSetting < numAltSettings; altSetting++)
{
if ( ( configDictionary->verifySampleRateIsSupported (mInterfaceNumber, altSetting, newSampleRate.whole ) )
&& ( kIOReturnSuccess == configDictionary->getFormat( &format, mInterfaceNumber, altSetting )
&& ( PCM == format ) ) )
{
newAltSettingID = altSetting;
result = kIOReturnSuccess;
break;
}
}
}
}
if ( ( kIOReturnSuccess != result )
|| ( ( kIOReturnSuccess == configDictionary->getFormat( &format, mInterfaceNumber, newAltSettingID )
&& ( PCM != format ) ) ) )
{
newAltSettingID = configDictionary->alternateSettingZeroCanStream (mInterfaceNumber) ? 0 : 1;
debugIOLog ("? AppleUSBAudioStream[%p]::GetDefaultSettings () - Taking first available alternate setting (%d)", this, newAltSettingID);
FailIf (kIOReturnSuccess != (result = configDictionary->getHighestSampleRate (&(newSampleRate.whole), mInterfaceNumber, newAltSettingID)), Exit);;
}
debugIOLog ("? AppleUSBAudioStream[%p]::GetDefaultSettings () - Default sample rate is %d", this, newSampleRate.whole);
debugIOLog ("? AppleUSBAudioStream[%p]::GetDefaultSettings () - Default alternate setting ID is %d", this, newAltSettingID);
FailIf (0 == newSampleRate.whole, Exit);
*sampleRate = newSampleRate;
*altSettingID = newAltSettingID;
result = kIOReturnSuccess;
Exit:
debugIOLog ("- AppleUSBAudioStream[%p]::GetDefaultSettings (%d, %lu) = 0x%x", this, *altSettingID, sampleRate->whole, result);
return result;
}
#if DEBUGLATENCY
UInt64 AppleUSBAudioStream::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 ("? AppleUSBAudioStream::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 AppleUSBAudioStream::configureAudioStream (IOAudioSampleRate sampleRate) {
OSNumber * idVendor = NULL;
OSNumber * idProduct = NULL;
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 ("+ AppleUSBAudioStream[%p]::configureAudioStream ()", this);
resultBool = FALSE;
mTerminatingDriver = FALSE;
mCoalescenceMutex = NULL;
FailIf (NULL == mStreamInterface, Exit);
FailIf (NULL == (configDictionary = mUSBAudioDevice->getConfigDictionary ()), Exit);
if (kUSBIn == mDirection)
{
debugIOLog ("? AppleUSBAudioStream[%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 ("? AppleUSBAudioStream[%p]::configureAudioStream () - 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
{
FailIf ("Couldn't get the endpoint direction!", Exit);
}
mUHCISupport = mUSBAudioDevice->checkForUHCI ();
mSplitTransactions = mUSBAudioDevice->detectSplitTransactions ();
mFrameQueuedForList = NULL;
mFrameQueuedForList = new UInt64[mNumUSBFrameLists];
FailIf (NULL == mFrameQueuedForList, Exit);
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;
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:
FailIf ("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 = this->setFormat (&streamFormat)), 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);
resultBool = true;
idVendor = OSNumber::withNumber (mUSBAudioDevice->getVendorID (), 16);
if (NULL != idVendor)
{
setProperty (kIDVendorString, idVendor);
idVendor->release ();
}
idProduct = OSNumber::withNumber (mUSBAudioDevice->getProductID (), 16);
if (NULL != idProduct)
{
setProperty (kIDProductString, idProduct);
idProduct->release ();
}
Exit:
debugIOLog("- AppleUSBAudioStream[%p]::configureAudioStream(), resultCode = %x, resultBool = %d", this, resultCode, resultBool);
return resultBool;
}
bool AppleUSBAudioStream::openStreamInterface () {
bool result = FALSE;
if ( NULL != mStreamInterface )
{
result = mStreamInterface->open (this);
}
return result;
}
void AppleUSBAudioStream::closeStreamInterface () {
if ( NULL != mStreamInterface )
{
mStreamInterface->close (this);
}
}
void AppleUSBAudioStream::queueInputFrames () {
UInt64 curUSBFrameNumber;
UInt64 framesLeftInQueue;
#if 1 if (0 == mShouldStop && TRUE != mInCompletion && NULL != mStreamInterface)
{
curUSBFrameNumber = mStreamInterface->GetDevice()->GetBus()->GetFrameNumber ();
framesLeftInQueue = mUSBFrameToQueue - curUSBFrameNumber;
if ( framesLeftInQueue < ( mNumUSBFramesPerList * ( mNumUSBFrameListsToQueue / 2 )) / 2 ) {
while ( framesLeftInQueue < mNumUSBFramesPerList * ( 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
}
void AppleUSBAudioStream::queueOutputFrames () {
UInt64 curUSBFrameNumber;
UInt64 framesLeftInQueue;
if (0 == mShouldStop && TRUE != mInCompletion && NULL != mStreamInterface)
{
curUSBFrameNumber = mStreamInterface->GetDevice()->GetBus()->GetFrameNumber ();
framesLeftInQueue = mUSBFrameToQueue - curUSBFrameNumber;
if ( framesLeftInQueue < ( mNumUSBFramesPerList * ( mNumUSBFrameListsToQueue / 2 )) / 2 ) {
debugIOLog ("! AppleUSBAudioStream::queueSampleFrameWrite () - Queue a write from clipOutputSamples: framesLeftInQueue = %ld", (UInt32)framesLeftInQueue);
writeHandler (this, mUSBCompletion[mCurrentFrameList].parameter, kIOReturnSuccess, &mUSBIsocFrames[mCurrentFrameList * mNumUSBFramesPerList]);
}
}
}
UInt16 AppleUSBAudioStream::getAlternateFrameSize () {
return mAlternateFrameSize;
}
IOReturn AppleUSBAudioStream::PrepareWriteFrameList (UInt32 arrayIndex) {
const IOAudioStreamFormat * theFormat;
IOReturn result;
UInt32 thisFrameListSize;
#if DEBUGLATENCY
UInt32 frameListByteCount; #endif
UInt32 thisFrameSize;
UInt32 firstFrame;
UInt32 numBytesToBufferEnd;
UInt32 lastPreparedByte;
UInt32 numTransactionsPrepared;
UInt32 transactionSampleRate; UInt32 remainderedSamples;
UInt16 integerSamplesInFrame;
UInt16 averageSamplesInFrame;
UInt16 bytesAfterWrap = 0; UInt8 transactionsPerMS;
UInt8 powerOfTwo = 0;
Boolean haveWrapped;
result = kIOReturnError; FailIf ( 0 == mTransactionsPerUSBFrame, Exit );
haveWrapped = FALSE;
firstFrame = arrayIndex * mNumTransactionsPerList;
mUSBCompletion[arrayIndex].target = (void *)this;
mUSBCompletion[arrayIndex].action = writeHandler;
mUSBCompletion[arrayIndex].parameter = 0;
theFormat = this->getFormat ();
numBytesToBufferEnd = getSampleBufferSize () - mLastPreparedBufferOffset;
lastPreparedByte = mLastPreparedBufferOffset;
thisFrameListSize = 0;
#if DEBUGLATENCY
frameListByteCount = 0;
#endif
transactionsPerMS = mTransactionsPerUSBFrame;
while ( transactionsPerMS > 1 )
{
transactionsPerMS >>= 1;
powerOfTwo++;
}
transactionSampleRate = mAverageSampleRate << ( 16 - powerOfTwo );
averageSamplesInFrame = mAverageSampleRate / ( 1000 * mTransactionsPerUSBFrame );
remainderedSamples = transactionSampleRate - ( ( averageSamplesInFrame * 1000 ) << 16 );
for (numTransactionsPrepared = 0; numTransactionsPrepared < mNumTransactionsPerList; numTransactionsPrepared++)
{
integerSamplesInFrame = averageSamplesInFrame;
mFractionalSamplesLeft += remainderedSamples;
if ( mFractionalSamplesLeft >= ( 1000 << 16 ) )
{
integerSamplesInFrame++;
mFractionalSamplesLeft -= ( 1000 << 16 );
}
thisFrameSize = integerSamplesInFrame * mSampleSize;
#if DEBUGLATENCY
frameListByteCount += thisFrameSize;
#endif
if (thisFrameSize >= numBytesToBufferEnd)
{
bytesAfterWrap = thisFrameSize - numBytesToBufferEnd;
mNumFramesInFirstList = numTransactionsPrepared + 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, numTransactionsPrepared = %d, numTransactionsPerList %d", bytesAfterWrap, numTransactionsPrepared, 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 + numTransactionsPrepared].frStatus = -1;
mUSBIsocFrames[firstFrame + numTransactionsPrepared].frActCount = 0;
mUSBIsocFrames[firstFrame + numTransactionsPrepared].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 AppleUSBAudioStream::PrepareAndReadFrameLists (UInt8 sampleSize, UInt8 numChannels, UInt32 usbFrameListIndex) {
IOReturn result;
UInt32 firstFrame;
UInt32 numTransactionsPrepared;
UInt16 averageFrameSamples;
UInt16 additionalSampleFrameFreq;
UInt16 bytesToRead;
#if DEBUGINPUT
debugIOLog ("+ AppleUSBAudioStream::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 (numTransactionsPrepared = 0; numTransactionsPrepared < mNumTransactionsPerList; numTransactionsPrepared++)
{
mUSBIsocFrames[firstFrame + numTransactionsPrepared].frStatus = -1;
mUSBIsocFrames[firstFrame + numTransactionsPrepared].frActCount = 0;
mUSBIsocFrames[firstFrame + numTransactionsPrepared].frReqCount = bytesToRead;
* (UInt64 *) ( & ( mUSBIsocFrames[firstFrame + numTransactionsPrepared].frTimeStamp)) = 0ull;
}
if (NULL != mPipe)
{
result = mPipe->Read (mSampleBufferDescriptors[usbFrameListIndex], mUSBFrameToQueue, mNumTransactionsPerList, &mUSBIsocFrames[firstFrame], &mUSBCompletion[usbFrameListIndex], 1); if (result != kIOReturnSuccess)
{
debugIOLog ("! AppleUSBAudioStream[%p]::PrepareAndReadFrameLists () - Error 0x%x reading from pipe", this, result);
}
if (NULL != mFrameQueuedForList)
{
mFrameQueuedForList[usbFrameListIndex] = mUSBFrameToQueue;
}
mUSBFrameToQueue += mNumUSBFramesPerList;
}
else
{
debugIOLog ("! AppleUSBAudioStream[%p]::PrepareAndReadFrameLists () - mPipe is NULL!", this);
}
#if DEBUGINPUT
debugIOLog ("- AppleUSBAudioStream::PrepareAndReadFrameLists ()");
#endif
return result;
}
#if PRIMEISOCINPUT
void AppleUSBAudioStream::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 ("? AppleUSBAudioStream::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 AppleUSBAudioStream::primeInputPipeHandler (void * object, void * parameter, IOReturn result, IOUSBLowLatencyIsocFrame * pFrames)
{
AppleUSBAudioStream * self;
UInt32 usbFramesToDelay;
debugIOLog ("+ AppleUSBAudioStream::primeInputPipeHandler (%p, %lu, 0x%x, %p)", object, (uintptr_t) parameter, result, pFrames);
self = (AppleUSBAudioStream *)object;
FailIf (NULL == self, Exit);
Exit:
if (self->mPrimeInputIsocFrames)
{
usbFramesToDelay = (UInt32)(uintptr_t)( parameter );
IOFree (self->mPrimeInputIsocFrames, usbFramesToDelay * sizeof (IOUSBLowLatencyIsocFrame));
self->mPrimeInputIsocFrames = NULL;
}
debugIOLog ("- AppleUSBAudioStream::primeInputPipeHandler (%p, %lu, 0x%x, %p)", object, (uintptr_t) parameter, result, pFrames);
}
#endif
IOReturn AppleUSBAudioStream::readFrameList (UInt32 frameListNum) {
const IOAudioStreamFormat * theFormat;
IOReturn result;
#if DEBUGINPUT
debugIOLog ("+ AppleUSBAudioStream::readFrameList ()");
#endif
theFormat = this->getFormat ();
result = PrepareAndReadFrameLists (theFormat->fBitWidth / 8, theFormat->fNumChannels, frameListNum);
#if DEBUGINPUT
debugIOLog ("- AppleUSBAudioStream::readFrameList ()");
#endif
return result;
}
void AppleUSBAudioStream::readHandler (void * object, void * parameter, IOReturn result, IOUSBLowLatencyIsocFrame * pFrames) {
AppleUSBAudioStream * self;
UInt64 currentUSBFrameNumber;
UInt32 frameListToRead;
UInt32 thisActCount = 0;
UInt32 minimumUSBFrameSize = 0;
UInt8 frameIndex;
IOReturn thisStatus = 0;
bool flagOverrun;
#if DEBUGINPUT
debugIOLog ("+ AppleUSBAudioStream::readHandler ()");
#endif
self = (AppleUSBAudioStream *)object;
FailIf (TRUE == self->mInCompletion, Exit);
self->mInCompletion = TRUE;
if ( (self->mUSBAudioDevice)
&& (false == self->mUSBAudioDevice->getSingleSampleRateDevice ()) && (kIOReturnOverrun == result)) {
debugIOLog ("! AppleUSBAudioStream::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->mUSBAudioEngine);
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 - 2 * self->mSampleSize;
#ifdef DEBUG
if ( (!(self->mShouldStop))
&& (thisStatus != kIOReturnSuccess)
&& ( (thisStatus != kIOReturnUnderrun)
|| ( (thisStatus == kIOReturnUnderrun)
&& (thisActCount < minimumUSBFrameSize))))
{
debugIOLog ("! AppleUSBAudioStream::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("? AppleUSBAudioStream::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 ("- AppleUSBAudioStream::readHandler ()");
#endif
return;
}
void AppleUSBAudioStream::sampleRateHandler (void * target, void * parameter, IOReturn result, IOUSBIsocFrame * pFrames) {
AppleUSBAudioStream * self;
IOFixed sampleRate;
UInt16 fixed;
IOFixed fract;
UInt32 oldSampleRate = 0;
UInt32 newSampleRate = 0;
UInt32 framesToAdvance = 0;
IOReturn readStatus = kIOReturnError;
self = (AppleUSBAudioStream *)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 ( self->mTransactionsPerUSBFrame )
{
newSampleRate *= self->mTransactionsPerUSBFrame;
}
if (newSampleRate && newSampleRate != oldSampleRate)
{
if ( ( newSampleRate > ( oldSampleRate + 1000 ) )
|| ( newSampleRate < ( oldSampleRate - 1000 ) ) )
{
debugIOLog ( "! AppleUSBAudioStream::sampleRateHandler () - ignoring sample rate %d as out of bounds", newSampleRate );
}
else
{
self->mAverageSampleRate = newSampleRate;
debugIOLog ("? AppleUSBAudioStream::sampleRateHandler () - Sample rate changed, requestedFrameRate = %d", self->mAverageSampleRate);
}
}
}
else
{
debugIOLog ("! AppleUSBAudioStream::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 ( "! AppleUSBAudioStream::sampleRateHandler () - framesToAdvance = %d, mNextSyncReadFrame = %llu, readStatus = 0x%x", framesToAdvance, self->mNextSyncReadFrame, readStatus );
self->mNextSyncReadFrame -= framesToAdvance;
framesToAdvance *= 2;
}
}
if ( kIOReturnSuccess != readStatus )
{
debugIOLog ( "! AppleUSBAudioStream::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 ( "? AppleUSBAudioStream::sampleRateHandler () - Stopping feedback chain because stream is stopping." );
}
return;
}
IOReturn AppleUSBAudioStream::setSampleRateControl (UInt8 address, UInt32 sampleRate) {
IOUSBDevRequest devReq;
UInt32 theSampleRate;
IOReturn result;
result = kIOReturnError;
FailIf (NULL == mStreamInterface, Exit);
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 ("? AppleUSBAudioStream[%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 ("! AppleUSBAudioStream[%p]::setSampleRateControl () = 0x%x", this, result);
}
return result;
}
UInt8 AppleUSBAudioStream::getSyncType () {
AUAConfigurationDictionary * configDictionary;
UInt8 direction = 0;
UInt8 address = 0;
UInt8 syncType = kNoneSyncType;
FailIf ( NULL == ( configDictionary = mUSBAudioDevice->getConfigDictionary () ), Exit );
FailIf ( kIOReturnSuccess != configDictionary->getIsocEndpointDirection ( &direction, mInterfaceNumber, mAlternateSettingID ), Exit );
FailIf ( kIOReturnSuccess != configDictionary->getIsocEndpointAddress ( &address, mInterfaceNumber, mAlternateSettingID, direction ), Exit );
FailIf ( kIOReturnSuccess != configDictionary->getIsocEndpointSyncType ( &syncType, mInterfaceNumber, mAlternateSettingID, address ), Exit );
Exit:
return syncType;
}
UInt32 AppleUSBAudioStream::getLockDelayFrames () {
AUAConfigurationDictionary * configDictionary;
UInt32 usbFramesToDelay = 0;
UInt16 averageFrameSamples;
UInt16 additionalSampleFrameFreq;
UInt8 lockDelay = 0;
UInt8 lockDelayUnits = 0;
FailIf (NULL == (configDictionary = mUSBAudioDevice->getConfigDictionary()), Exit);
calculateSamplesPerPacket (mCurSampleRate.whole, &averageFrameSamples, &additionalSampleFrameFreq);
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;
}
Exit:
return usbFramesToDelay;
}
IOReturn AppleUSBAudioStream::prepareUSBStream () {
const IOAudioStreamFormat * theFormat;
IOReturn resultCode;
IOUSBFindEndpointRequest audioIsochEndpoint;
AUAConfigurationDictionary * configDictionary;
UInt32 numQueued;
UInt16 averageFrameSamples;
UInt16 additionalSampleFrameFreq;
UInt16 maxFrameSize;
UInt16 maxPacketSize = 0;
UInt8 endpointAddress;
debugIOLog ("+ AppleUSBAudioStream[%p]::prepareUSBStream ()", this);
resultCode = kIOReturnError;
numQueued = 0;
mCurrentFrameList = 0;
mSafeErasePoint = 0;
mLastSafeErasePoint = 0;
mBufferOffset = 0;
mLastPreparedBufferOffset = 0; mFractionalSamplesLeft = 0;
mShouldStop = 0;
mAverageSampleRate = mCurSampleRate.whole;
FailIf ((mNumUSBFrameLists < mNumUSBFrameListsToQueue), Exit);
FailIf (NULL == (configDictionary = mUSBAudioDevice->getConfigDictionary()), Exit);
FailIf (NULL == mStreamInterface, Exit);
resultCode = mStreamInterface->SetAlternateInterface (this, mAlternateSettingID);
debugIOLog ("? AppleUSBAudioStream[%p]::prepareUSBStream () - 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 = this->getFormat ();
FailIf ( kIOReturnSuccess != configDictionary->getIsocEndpointMaxPacketSize ( &maxPacketSize, mInterfaceNumber, mAlternateSettingID, mDirection ), Exit );
FailIf ( 0 == maxPacketSize, Exit );
if (kUSBIn == mDirection)
{
maxFrameSize = ( averageFrameSamples + 3 ) * ( theFormat->fNumChannels * ( theFormat->fBitWidth / 8 ) );
maxFrameSize = ( maxFrameSize > maxPacketSize ) ? maxPacketSize : maxFrameSize;
debugIOLog ( "? AppleUSBAudioStream[%p]::prepareUSBStream () - 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 ("? AppleUSBAudioStream[%p]::prepareUSBStream () - calling SetPipePolicy (%d)", this, maxFrameSize);
resultCode = mPipe->SetPipePolicy (maxFrameSize, 0);
FailIf (kIOReturnSuccess != resultCode, Exit);
Exit:
debugIOLog ("- AppleUSBAudioStream[%p]::prepareUSBStream () = %x", this, resultCode);
return resultCode;
}
IOReturn AppleUSBAudioStream::startUSBStream (UInt64 currentUSBFrame, UInt32 usbFramesToDelay) {
const IOAudioStreamFormat * theFormat;
IOReturn resultCode = kIOReturnError;
IOReturn interimResult;
AUAConfigurationDictionary * configDictionary;
UInt32 frameListNum;
UInt16 maxConsecutiveFramesToPrime;
UInt16 transactionsToQueue;
UInt16 remainingFrames;
UInt16 averageFrameSamples;
UInt16 additionalSampleFrameFreq;
UInt16 maxFrameSize;
UInt16 maxPacketSize = 0;
bool encounteredQueuingError = false;
debugIOLog ("+ AppleUSBAudioStream[%p]::startUSBStream (%lld, %ld, %d)", this, currentUSBFrame, usbFramesToDelay, maxFrameSize);
FailIf ((mNumUSBFrameLists < mNumUSBFrameListsToQueue), Exit);
FailIf (NULL == (configDictionary = mUSBAudioDevice->getConfigDictionary()), Exit);
FailIf (NULL == mStreamInterface, Exit);
#if DEBUGTIMESTAMPS
mLastTimeStamp_nanos = 0ull;
mLastStampDifference = 0ull;
mStampDrift = 0ll;
mLastWrapFrame = 0ull;
#endif
calculateSamplesPerPacket (mCurSampleRate.whole, &averageFrameSamples, &additionalSampleFrameFreq);
theFormat = this->getFormat ();
FailIf ( kIOReturnSuccess != configDictionary->getIsocEndpointMaxPacketSize ( &maxPacketSize, mInterfaceNumber, mAlternateSettingID, mDirection ), Exit );
FailIf ( 0 == maxPacketSize, Exit );
if (kUSBIn == mDirection)
{
maxFrameSize = ( averageFrameSamples + 3 ) * ( theFormat->fNumChannels * ( theFormat->fBitWidth / 8 ) );
maxFrameSize = ( maxFrameSize > maxPacketSize ) ? maxPacketSize : maxFrameSize;
debugIOLog ( "? AppleUSBAudioStream[%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 ) );
}
}
mUSBFrameToQueue = currentUSBFrame + kMinimumFrameOffset;
debugIOLog ("? AppleUSBAudioStream[%p]::startUSBStream () - mUSBFrameToQueue = %llu", this, mUSBFrameToQueue);
if (NULL != mAssociatedPipe)
{
mNextSyncReadFrame = mUSBFrameToQueue;
debugIOLog ("? AppleUSBAudioStream[%p]::startUSBStream () - Starting feedback endpoint stream at frame %llu", this, mNextSyncReadFrame);
(void)mAssociatedPipe->Read (mAssociatedEndpointMemoryDescriptor, mNextSyncReadFrame, 1, &mSampleRateFrame, &mSampleRateCompletion);
debugIOLog ("? AppleUSBAudioStream[%p]::startUSBStream () - Feedback endpoint stream started.", this);
}
mHaveTakenFirstTimeStamp = false;
if (getDirection () == kIOAudioStreamDirectionInput)
{
#if PRIMEISOCINPUT
maxConsecutiveFramesToPrime = mSampleBufferSize / maxFrameSize;
FailIf ( 0 == maxConsecutiveFramesToPrime, Exit );
transactionsToQueue = ( usbFramesToDelay / maxConsecutiveFramesToPrime ) + ( ( usbFramesToDelay % maxConsecutiveFramesToPrime ) ? 1 : 0 );
debugIOLog ("? AppleUSBAudioStream[%p]::startUSBStream () - Priming input stream at frame %llu ( %d USB frames ) in %d transaction(s)", this, mUSBFrameToQueue, usbFramesToDelay, transactionsToQueue );
remainingFrames = usbFramesToDelay;
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 ("? AppleUSBAudioStream[%p]::startUSBStream () - Starting input stream at frame %llu", this, mUSBFrameToQueue);
for (frameListNum = mCurrentFrameList; frameListNum < mNumUSBFrameListsToQueue; frameListNum++)
{
interimResult = readFrameList (frameListNum);
if (kIOReturnSuccess != interimResult)
{
debugIOLog ("! AppleUSBAudioStream[%p]::startUSBStream () - readFrameList (%d) failed with error 0x%x!", this, frameListNum, interimResult);
encounteredQueuingError = true;
}
}
}
else
{
#if PRIMEISOCINPUT
mUSBFrameToQueue += usbFramesToDelay;
#endif
* (UInt64 *) ( & (mUSBIsocFrames[0].frTimeStamp)) = 0xFFFFFFFFFFFFFFFFull;
mUSBIsocFrames[0].frStatus = kUSBLowLatencyIsochTransferKey;
for (frameListNum = mCurrentFrameList; frameListNum < mNumUSBFrameListsToQueue; frameListNum++)
{
interimResult = writeFrameList (frameListNum);
if (kIOReturnSuccess != interimResult)
{
debugIOLog ("! AppleUSBAudioStream[%p]::startUSBStream () - writeFrameList (%d) failed with error 0x%x!", this, frameListNum, interimResult);
encounteredQueuingError = true;
}
}
}
if (encounteredQueuingError)
{
debugIOLog ("! AppleUSBAudioStream[%p]::startUSBStream () - Stream will *NOT* start because of queuing errors", this);
resultCode = kIOReturnError;
}
else
{
mUSBStreamRunning = TRUE;
resultCode = kIOReturnSuccess;
}
if ( kIOReturnSuccess == resultCode )
{
debugIOLog ("\n");
debugIOLog (" -------------------- Starting Stream (interface %d, alternate setting %d) --------------------", mInterfaceNumber, mAlternateSettingID);
debugIOLog (" format = %p", getFormat ());
debugIOLog (" fNumChannels = %d", getFormat ()->fNumChannels);
debugIOLog (" fBitDepth = %d", getFormat ()->fBitDepth);
debugIOLog (" fDriverTag = 0x%x", getFormat ()->fDriverTag);
debugIOLog ("\n");
}
Exit:
debugIOLog ("- AppleUSBAudioStream[%p]::startUSBStream () = %x", this, resultCode);
return resultCode;
}
IOReturn AppleUSBAudioStream::stopUSBStream () {
debugIOLog ("+ AppleUSBAudioStream[%p]::stopUSBStream ()", this);
if (0 == mShouldStop)
{
mShouldStop = 1;
}
if (NULL != mPipe)
{
if (FALSE == mTerminatingDriver)
{
mPipe->SetPipePolicy (0, 0);
mPipe->Abort ();
}
mPipe->release ();
mPipe = NULL;
}
if (NULL != mAssociatedPipe)
{
if (FALSE == mTerminatingDriver)
{
mAssociatedPipe->Abort ();
}
mAssociatedPipe->release ();
mAssociatedPipe = NULL;
}
if (FALSE == mTerminatingDriver)
{
if (NULL != mStreamInterface)
{ (void)mStreamInterface->SetAlternateInterface (this, kRootAlternateSetting);
}
}
mUSBStreamRunning = FALSE;
debugIOLog ("- AppleUSBAudioStream[%p]::stopUSBStream ()", this);
return kIOReturnSuccess;
}
bool AppleUSBAudioStream::willTerminate (IOService * provider, IOOptionBits options) {
debugIOLog ("+ AppleUSBAudioStream[%p]::willTerminate (%p)", this, provider);
if ( (mUSBAudioEngine == provider) || (mStreamInterface == provider) )
{
mTerminatingDriver = TRUE;
debugIOLog ("? AppleUSBAudioStream[%p]::willTerminate () - Closing stream interface", this);
if ( ( mUSBStreamRunning )
&& ( NULL != mPipe ) )
{
mPipe->Abort ();
if ( 0 == mShouldStop )
{
mShouldStop++;
}
}
if ( NULL != mStreamInterface )
{
mStreamInterface->close (this);
}
}
debugIOLog ("- AppleUSBAudioStream[%p]::willTerminate ()", this);
return super::willTerminate (provider, options);
}
IOReturn AppleUSBAudioStream::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 ("? AppleUSBAudioStream::writeFrameList () - Writing mSampleBufferWrapDescriptors[0]");
#endif
result = mPipe->Write (mWrapDescriptors[0], mUSBFrameToQueue, mNumFramesInFirstList, &mUSBIsocFrames[frameListNum * mNumTransactionsPerList], &mUSBCompletion[frameListNum], 1);
if ( mNumFramesInFirstList < mNumTransactionsPerList )
{
#if DEBUGUHCI
debugIOLog ("? AppleUSBAudioStream::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 ("? AppleUSBAudioStream[%p]::writeFrameList () - failed with error 0x%x", this, result);
}
return result;
}
void AppleUSBAudioStream::writeHandler (void * object, void * parameter, IOReturn result, IOUSBLowLatencyIsocFrame * pFrames) {
AppleUSBAudioStream * self;
AbsoluteTime time;
UInt64 curUSBFrameNumber;
UInt32 frameListToWrite;
UInt32 byteOffset;
UInt32 frameIndex;
UInt32 byteCount;
UInt32 preWrapBytes;
UInt32 numberOfFramesToCheck;
SInt64 frameDifference;
SInt32 expectedFrames;
self = (AppleUSBAudioStream *)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 ("? AppleUSBAudioStream::writeHandler () - writeHandler: curUSBFrameNumber = %llu parameter = 0x%x mUSBFrameToQueue = %llu", curUSBFrameNumber, (UInt32)parameter, self->mUSBFrameToQueue);
debugIOLog ("? AppleUSBAudioStream::writeHandler () - %llu ?> %lu", frameDifference, expectedFrames);
#endif
if ( (frameDifference > expectedFrames)
&& ( (!(self->mUHCISupport)) || (0 == parameter))) {
debugIOLog ("? AppleUSBAudioStream::writeHandler () - Not advancing frame list");
goto Exit;
}
if (kIOReturnAborted != result)
{
if (kIOReturnSuccess != result)
{
debugIOLog ("! AppleUSBAudioStream::writeHandler () - Frame list %d write returned with error 0x%x", self->mCurrentFrameList, result);
}
numberOfFramesToCheck = ((self->mUHCISupport && (UInt32) (uintptr_t) parameter) ? self->mNumFramesInFirstList : self->mNumTransactionsPerList);
if ( self->mMasterMode
&& (!(self->mHaveTakenFirstTimeStamp))
&& (0 == self->mBufferOffset))
{
for (UInt16 i = 0; i < numberOfFramesToCheck && pFrames; i++)
{
if (pFrames[i].frActCount)
{
debugIOLog ("? AppleUSBAudioStream::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 ("! AppleUSBAudioStream::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 ("! AppleUSBAudioStream::writeHandler - Fell behind! mUSBFrameToQueue = %llu, curUSBFrameNumber = %llu", self->mUSBFrameToQueue, curUSBFrameNumber);
self->mUSBFrameToQueue = curUSBFrameNumber + kMinimumFrameOffset;
}
}
if (0 != parameter)
{
if ( self->mMasterMode )
{
byteOffset = (UInt32)(uintptr_t)parameter & 0xFFFF; frameIndex = ((UInt32)(uintptr_t)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 ("? AppleUSBAudioStream::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 ("? AppleUSBAudioStream::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 AppleUSBAudioStream::writeHandlerForUHCI (void * object, void * parameter, IOReturn result, IOUSBLowLatencyIsocFrame * pFrames) {
AppleUSBAudioStream * self;
UInt64 curUSBFrameNumber;
SInt64 frameDifference;
SInt32 expectedFrames;
UInt32 frameListToWrite;
UInt32 numberOfFramesToCheck;
self = (AppleUSBAudioStream *)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 ("? AppleUSBAudioStream[%p]::writeHandlerForUHCI () - writeHandlerForUHCI: curUSBFrameNumber = %llu parameter = 0x%x mUSBFrameToQueue = %llu", curUSBFrameNumber, (UInt32)parameter, self->mUSBFrameToQueue);
debugIOLog ("? AppleUSBAudioStream[%p]::writeHandlerForUHCI () - %llu ?> %lu", frameDifference, expectedFrames);
#endif
if (kIOReturnAborted != result)
{
if (kIOReturnSuccess != result)
{
debugIOLog ("! AppleUSBAudioStream::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 ("! AppleUSBAudioStream::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 ("! AppleUSBAudioStream[%p]::writeHandlerForUHCI () - Fell behind! mUSBFrameToQueue = %llu, curUSBFrameNumber = %llu", self->mUSBFrameToQueue, curUSBFrameNumber);
debugIOLog ("! AppleUSBAudioStream[%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 ("? AppleUSBAudioStream[%p]::writeHandlerForUHCI () - Halting.", self);
}
Exit:
self->mInCompletion = FALSE;
return;
}
void AppleUSBAudioStream::takeTimeStamp (bool incrementLoopCount, AbsoluteTime *timestamp)
{
if ( NULL != mUSBAudioEngine )
{
if (false == mHaveTakenFirstTimeStamp)
{
mUSBAudioEngine->takeTimeStamp (false, timestamp);
debugIOLog ("? AppleUSBAudioStream[%p]::takeTimeStamp (0, %p) - First timestamp taken", this, timestamp);
mHaveTakenFirstTimeStamp = true;
}
else
{
mUSBAudioEngine->takeTimeStamp (incrementLoopCount, timestamp);
}
}
}
#pragma mark -USB Audio Plugin-
void AppleUSBAudioStream::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 AppleUSBAudioStream::pluginLoaded (AppleUSBAudioStream * usbAudioStreamObject) {
IOReturn result;
if (usbAudioStreamObject->mPlugin && usbAudioStreamObject->mStreamInterface)
{
usbAudioStreamObject->mPlugin->open (usbAudioStreamObject);
result = usbAudioStreamObject->mPlugin->pluginInit (usbAudioStreamObject, usbAudioStreamObject->mStreamInterface->GetDevice()->GetVendorID (), usbAudioStreamObject->mStreamInterface->GetDevice()->GetProductID ());
if (result == kIOReturnSuccess)
{
debugIOLog ("success initing the plugin");
usbAudioStreamObject->mPlugin->pluginSetDirection ((IOAudioStreamDirection) usbAudioStreamObject->mDirection);
usbAudioStreamObject->mPlugin->pluginSetFormat (usbAudioStreamObject->getFormat (), &usbAudioStreamObject->mCurSampleRate);
}
else
{
debugIOLog ("Error initing the plugin");
usbAudioStreamObject->mPlugin->close (usbAudioStreamObject);
usbAudioStreamObject->mPlugin = NULL;
}
}
return;
}
IOReturn AppleUSBAudioStream::pluginDeviceRequest (IOUSBDevRequest * request, IOUSBCompletion * completion) {
IOReturn result;
result = kIOReturnBadArgument;
if (request)
{
result = mUSBAudioDevice->deviceRequest (request, mUSBAudioDevice, completion);
}
return result;
}
void AppleUSBAudioStream::pluginSetConfigurationApp (const char * bundleID) {
if (bundleID)
{
mUSBAudioDevice->setConfigurationApp (bundleID);
}
}
#pragma mark -AppleUSBAudioStreamNode-
OSDefineMetaClassAndStructors ( AppleUSBAudioStreamNode, IOService )
bool AppleUSBAudioStreamNode::start ( IOService * provider )
{
debugIOLog ( "+ AppleUSBAudioStreamNode[%p]::start (%p)", this, provider );
if ( IOService::start ( provider ) )
{
if ( provider )
{
provider->setProperty ( "AppleUSBAudioStreamPropertiesReady", "Yes" );
}
IOService::stop ( provider ); }
debugIOLog ( "- AppleUSBAudioStreamNode[%p]::start (%p)", this, provider );
return FALSE; }
Generated by GNU enscript 1.6.4.