| 5093 | } |
| 5094 | |
| 5095 | OSStatus ProxyAudioDevice::GetZeroTimeStamp(AudioServerPlugInDriverRef inDriver, |
| 5096 | AudioObjectID inDeviceObjectID, |
| 5097 | UInt32 inClientID, |
| 5098 | Float64 *outSampleTime, |
| 5099 | UInt64 *outHostTime, |
| 5100 | UInt64 *outSeed) { |
| 5101 | // This method returns the current zero time stamp for the device. The HAL models the timing of |
| 5102 | // a device as a series of time stamps that relate the sample time to a host time. The zero |
| 5103 | // time stamps are spaced such that the sample times are the value of |
| 5104 | // kAudioDevicePropertyZeroTimeStampPeriod apart. This is often modeled using a ring buffer |
| 5105 | // where the zero time stamp is updated when wrapping around the ring buffer. |
| 5106 | // |
| 5107 | // For this device, the zero time stamps' sample time increments every kDevice_RingBufferSize |
| 5108 | // frames and the host time increments by kDevice_RingBufferSize * gDevice_HostTicksPerFrame. |
| 5109 | |
| 5110 | #pragma unused(inClientID) |
| 5111 | |
| 5112 | // declare the local variables |
| 5113 | OSStatus theAnswer = 0; |
| 5114 | UInt64 theCurrentHostTime; |
| 5115 | Float64 theHostTicksPerRingBuffer; |
| 5116 | Float64 theHostTickOffset; |
| 5117 | UInt64 theNextHostTime; |
| 5118 | |
| 5119 | // check the arguments |
| 5120 | FailWithAction(inDriver != gAudioServerPlugInDriverRef, |
| 5121 | theAnswer = kAudioHardwareBadObjectError, |
| 5122 | Done, |
| 5123 | "GetZeroTimeStamp: bad driver reference"); |
| 5124 | FailWithAction(inDeviceObjectID != kObjectID_Device, |
| 5125 | theAnswer = kAudioHardwareBadObjectError, |
| 5126 | Done, |
| 5127 | "GetZeroTimeStamp: bad device ID"); |
| 5128 | |
| 5129 | { |
| 5130 | CAMutex::Locker locker(&getZeroTimestampMutex); |
| 5131 | |
| 5132 | // get the current host time |
| 5133 | theCurrentHostTime = mach_absolute_time(); |
| 5134 | |
| 5135 | // In order to keep the input and output IO in sync, we keep a running |
| 5136 | // average of the output IO proc's mRateScalar field for its output time. |
| 5137 | // Then each time we calculate the next zero timestamp we slightly adjust |
| 5138 | // the tick count for our ring buffer by however much the output IO proc |
| 5139 | // deviated from its sample rate. |
| 5140 | |
| 5141 | Float64 rateRatio = 1.0; |
| 5142 | |
| 5143 | if (outputAccumulatedRateRatioSamples > 0) { |
| 5144 | rateRatio = outputAccumulatedRateRatio / outputAccumulatedRateRatioSamples; |
| 5145 | } |
| 5146 | |
| 5147 | // calculate the next host time |
| 5148 | theHostTicksPerRingBuffer = |
| 5149 | gDevice_HostTicksPerFrame * ((Float64)kDevice_RingBufferSize) * rateRatio; |
| 5150 | theHostTickOffset = gDevice_ElapsedTicks + theHostTicksPerRingBuffer; |
| 5151 | theNextHostTime = gDevice_AnchorHostTime + ((UInt64)theHostTickOffset); |
| 5152 |
no outgoing calls
no test coverage detected