1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #define LOG_TAG "AAudio" 18 //#define LOG_NDEBUG 0 19 #include <utils/Log.h> 20 21 #include <stdint.h> 22 23 #include "utility/AudioClock.h" 24 #include "IsochronousClockModel.h" 25 26 #define MIN_LATENESS_NANOS (10 * AAUDIO_NANOS_PER_MICROSECOND) 27 28 using namespace android; 29 using namespace aaudio; 30 31 IsochronousClockModel::IsochronousClockModel() 32 : mMarkerFramePosition(0) 33 , mMarkerNanoTime(0) 34 , mSampleRate(48000) 35 , mFramesPerBurst(64) 36 , mMaxLatenessInNanos(0) 37 , mState(STATE_STOPPED) 38 { 39 } 40 41 IsochronousClockModel::~IsochronousClockModel() { 42 } 43 44 void IsochronousClockModel::start(int64_t nanoTime) { 45 ALOGD("IsochronousClockModel::start(nanos = %lld)\n", (long long) nanoTime); 46 mMarkerNanoTime = nanoTime; 47 mState = STATE_STARTING; 48 } 49 50 void IsochronousClockModel::stop(int64_t nanoTime) { 51 ALOGD("IsochronousClockModel::stop(nanos = %lld)\n", (long long) nanoTime); 52 mMarkerNanoTime = nanoTime; 53 mMarkerFramePosition = convertTimeToPosition(nanoTime); // TODO should we do this? 54 mState = STATE_STOPPED; 55 } 56 57 void IsochronousClockModel::processTimestamp(int64_t framePosition, int64_t nanoTime) { 58 int64_t framesDelta = framePosition - mMarkerFramePosition; 59 int64_t nanosDelta = nanoTime - mMarkerNanoTime; 60 if (nanosDelta < 1000) { 61 return; 62 } 63 64 // ALOGD("processTimestamp() - mMarkerFramePosition = %lld at mMarkerNanoTime %llu", 65 // (long long)mMarkerFramePosition, 66 // (long long)mMarkerNanoTime); 67 // ALOGD("processTimestamp() - framePosition = %lld at nanoTime %llu", 68 // (long long)framePosition, 69 // (long long)nanoTime); 70 71 int64_t expectedNanosDelta = convertDeltaPositionToTime(framesDelta); 72 // ALOGD("processTimestamp() - expectedNanosDelta = %lld, nanosDelta = %llu", 73 // (long long)expectedNanosDelta, 74 // (long long)nanosDelta); 75 76 // ALOGD("processTimestamp() - mSampleRate = %d", mSampleRate); 77 // ALOGD("processTimestamp() - mState = %d", mState); 78 switch (mState) { 79 case STATE_STOPPED: 80 break; 81 case STATE_STARTING: 82 mMarkerFramePosition = framePosition; 83 mMarkerNanoTime = nanoTime; 84 mState = STATE_SYNCING; 85 break; 86 case STATE_SYNCING: 87 // This will handle a burst of rapid transfer at the beginning. 88 if (nanosDelta < expectedNanosDelta) { 89 mMarkerFramePosition = framePosition; 90 mMarkerNanoTime = nanoTime; 91 } else { 92 // ALOGD("processTimestamp() - advance to STATE_RUNNING"); 93 mState = STATE_RUNNING; 94 } 95 break; 96 case STATE_RUNNING: 97 if (nanosDelta < expectedNanosDelta) { 98 // Earlier than expected timestamp. 99 // This data is probably more accurate so use it. 100 // or we may be drifting due to a slow HW clock. 101 mMarkerFramePosition = framePosition; 102 mMarkerNanoTime = nanoTime; 103 // ALOGD("processTimestamp() - STATE_RUNNING - %d < %d micros - EARLY", 104 // (int) (nanosDelta / 1000), (int)(expectedNanosDelta / 1000)); 105 } else if (nanosDelta > (expectedNanosDelta + mMaxLatenessInNanos)) { 106 // Later than expected timestamp. 107 mMarkerFramePosition = framePosition; 108 mMarkerNanoTime = nanoTime - mMaxLatenessInNanos; 109 // ALOGD("processTimestamp() - STATE_RUNNING - %d > %d + %d micros - LATE", 110 // (int) (nanosDelta / 1000), (int)(expectedNanosDelta / 1000), 111 // (int) (mMaxLatenessInNanos / 1000)); 112 } 113 break; 114 default: 115 break; 116 } 117 } 118 119 void IsochronousClockModel::setSampleRate(int32_t sampleRate) { 120 mSampleRate = sampleRate; 121 update(); 122 } 123 124 void IsochronousClockModel::setFramesPerBurst(int32_t framesPerBurst) { 125 mFramesPerBurst = framesPerBurst; 126 update(); 127 } 128 129 void IsochronousClockModel::update() { 130 int64_t nanosLate = convertDeltaPositionToTime(mFramesPerBurst); // uses mSampleRate 131 mMaxLatenessInNanos = (nanosLate > MIN_LATENESS_NANOS) ? nanosLate : MIN_LATENESS_NANOS; 132 } 133 134 int64_t IsochronousClockModel::convertDeltaPositionToTime( 135 int64_t framesDelta) const { 136 return (AAUDIO_NANOS_PER_SECOND * framesDelta) / mSampleRate; 137 } 138 139 int64_t IsochronousClockModel::convertDeltaTimeToPosition(int64_t nanosDelta) const { 140 return (mSampleRate * nanosDelta) / AAUDIO_NANOS_PER_SECOND; 141 } 142 143 int64_t IsochronousClockModel::convertPositionToTime(int64_t framePosition) const { 144 if (mState == STATE_STOPPED) { 145 return mMarkerNanoTime; 146 } 147 int64_t nextBurstIndex = (framePosition + mFramesPerBurst - 1) / mFramesPerBurst; 148 int64_t nextBurstPosition = mFramesPerBurst * nextBurstIndex; 149 int64_t framesDelta = nextBurstPosition - mMarkerFramePosition; 150 int64_t nanosDelta = convertDeltaPositionToTime(framesDelta); 151 int64_t time = (int64_t) (mMarkerNanoTime + nanosDelta); 152 // ALOGD("IsochronousClockModel::convertPositionToTime: pos = %llu --> time = %llu", 153 // (unsigned long long)framePosition, 154 // (unsigned long long)time); 155 return time; 156 } 157 158 int64_t IsochronousClockModel::convertTimeToPosition(int64_t nanoTime) const { 159 if (mState == STATE_STOPPED) { 160 return mMarkerFramePosition; 161 } 162 int64_t nanosDelta = nanoTime - mMarkerNanoTime; 163 int64_t framesDelta = convertDeltaTimeToPosition(nanosDelta); 164 int64_t nextBurstPosition = mMarkerFramePosition + framesDelta; 165 int64_t nextBurstIndex = nextBurstPosition / mFramesPerBurst; 166 int64_t position = nextBurstIndex * mFramesPerBurst; 167 // ALOGD("IsochronousClockModel::convertTimeToPosition: time = %llu --> pos = %llu", 168 // (unsigned long long)nanoTime, 169 // (unsigned long long)position); 170 // ALOGD("IsochronousClockModel::convertTimeToPosition: framesDelta = %llu, mFramesPerBurst = %d", 171 // (long long) framesDelta, mFramesPerBurst); 172 return position; 173 } 174