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 <log/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 aaudio; 29 30 IsochronousClockModel::IsochronousClockModel() 31 : mMarkerFramePosition(0) 32 , mMarkerNanoTime(0) 33 , mSampleRate(48000) 34 , mFramesPerBurst(64) 35 , mMaxLatenessInNanos(0) 36 , mState(STATE_STOPPED) 37 { 38 } 39 40 IsochronousClockModel::~IsochronousClockModel() { 41 } 42 43 void IsochronousClockModel::setPositionAndTime(int64_t framePosition, int64_t nanoTime) { 44 ALOGV("IsochronousClockModel::setPositionAndTime(%lld, %lld)", 45 (long long) framePosition, (long long) nanoTime); 46 mMarkerFramePosition = framePosition; 47 mMarkerNanoTime = nanoTime; 48 } 49 50 void IsochronousClockModel::start(int64_t nanoTime) { 51 ALOGV("IsochronousClockModel::start(nanos = %lld)\n", (long long) nanoTime); 52 mMarkerNanoTime = nanoTime; 53 mState = STATE_STARTING; 54 } 55 56 void IsochronousClockModel::stop(int64_t nanoTime) { 57 ALOGV("IsochronousClockModel::stop(nanos = %lld)\n", (long long) nanoTime); 58 setPositionAndTime(convertTimeToPosition(nanoTime), nanoTime); 59 // TODO should we set position? 60 mState = STATE_STOPPED; 61 } 62 63 bool IsochronousClockModel::isStarting() { 64 return mState == STATE_STARTING; 65 } 66 67 void IsochronousClockModel::processTimestamp(int64_t framePosition, int64_t nanoTime) { 68 // ALOGD("processTimestamp() - framePosition = %lld at nanoTime %llu", 69 // (long long)framePosition, 70 // (long long)nanoTime); 71 int64_t framesDelta = framePosition - mMarkerFramePosition; 72 int64_t nanosDelta = nanoTime - mMarkerNanoTime; 73 if (nanosDelta < 1000) { 74 return; 75 } 76 77 // ALOGD("processTimestamp() - mMarkerFramePosition = %lld at mMarkerNanoTime %llu", 78 // (long long)mMarkerFramePosition, 79 // (long long)mMarkerNanoTime); 80 81 int64_t expectedNanosDelta = convertDeltaPositionToTime(framesDelta); 82 // ALOGD("processTimestamp() - expectedNanosDelta = %lld, nanosDelta = %llu", 83 // (long long)expectedNanosDelta, 84 // (long long)nanosDelta); 85 86 // ALOGD("processTimestamp() - mSampleRate = %d", mSampleRate); 87 // ALOGD("processTimestamp() - mState = %d", mState); 88 switch (mState) { 89 case STATE_STOPPED: 90 break; 91 case STATE_STARTING: 92 setPositionAndTime(framePosition, nanoTime); 93 mState = STATE_SYNCING; 94 break; 95 case STATE_SYNCING: 96 // This will handle a burst of rapid transfer at the beginning. 97 if (nanosDelta < expectedNanosDelta) { 98 setPositionAndTime(framePosition, nanoTime); 99 } else { 100 // ALOGD("processTimestamp() - advance to STATE_RUNNING"); 101 mState = STATE_RUNNING; 102 } 103 break; 104 case STATE_RUNNING: 105 if (nanosDelta < expectedNanosDelta) { 106 // Earlier than expected timestamp. 107 // This data is probably more accurate so use it. 108 // or we may be drifting due to a slow HW clock. 109 // ALOGD("processTimestamp() - STATE_RUNNING - %d < %d micros - EARLY", 110 // (int) (nanosDelta / 1000), (int)(expectedNanosDelta / 1000)); 111 setPositionAndTime(framePosition, nanoTime); 112 } else if (nanosDelta > (expectedNanosDelta + mMaxLatenessInNanos)) { 113 // Later than expected timestamp. 114 // ALOGD("processTimestamp() - STATE_RUNNING - %d > %d + %d micros - LATE", 115 // (int) (nanosDelta / 1000), (int)(expectedNanosDelta / 1000), 116 // (int) (mMaxLatenessInNanos / 1000)); 117 setPositionAndTime(framePosition - mFramesPerBurst, nanoTime - mMaxLatenessInNanos); 118 } 119 break; 120 default: 121 break; 122 } 123 124 // ALOGD("processTimestamp() - mState = %d", mState); 125 } 126 127 void IsochronousClockModel::setSampleRate(int32_t sampleRate) { 128 mSampleRate = sampleRate; 129 update(); 130 } 131 132 void IsochronousClockModel::setFramesPerBurst(int32_t framesPerBurst) { 133 mFramesPerBurst = framesPerBurst; 134 update(); 135 } 136 137 void IsochronousClockModel::update() { 138 int64_t nanosLate = convertDeltaPositionToTime(mFramesPerBurst); // uses mSampleRate 139 mMaxLatenessInNanos = (nanosLate > MIN_LATENESS_NANOS) ? nanosLate : MIN_LATENESS_NANOS; 140 } 141 142 int64_t IsochronousClockModel::convertDeltaPositionToTime(int64_t framesDelta) const { 143 return (AAUDIO_NANOS_PER_SECOND * framesDelta) / mSampleRate; 144 } 145 146 int64_t IsochronousClockModel::convertDeltaTimeToPosition(int64_t nanosDelta) const { 147 return (mSampleRate * nanosDelta) / AAUDIO_NANOS_PER_SECOND; 148 } 149 150 int64_t IsochronousClockModel::convertPositionToTime(int64_t framePosition) const { 151 if (mState == STATE_STOPPED) { 152 return mMarkerNanoTime; 153 } 154 int64_t nextBurstIndex = (framePosition + mFramesPerBurst - 1) / mFramesPerBurst; 155 int64_t nextBurstPosition = mFramesPerBurst * nextBurstIndex; 156 int64_t framesDelta = nextBurstPosition - mMarkerFramePosition; 157 int64_t nanosDelta = convertDeltaPositionToTime(framesDelta); 158 int64_t time = mMarkerNanoTime + nanosDelta; 159 // ALOGD("IsochronousClockModel::convertPositionToTime: pos = %llu --> time = %llu", 160 // (unsigned long long)framePosition, 161 // (unsigned long long)time); 162 return time; 163 } 164 165 int64_t IsochronousClockModel::convertTimeToPosition(int64_t nanoTime) const { 166 if (mState == STATE_STOPPED) { 167 return mMarkerFramePosition; 168 } 169 int64_t nanosDelta = nanoTime - mMarkerNanoTime; 170 int64_t framesDelta = convertDeltaTimeToPosition(nanosDelta); 171 int64_t nextBurstPosition = mMarkerFramePosition + framesDelta; 172 int64_t nextBurstIndex = nextBurstPosition / mFramesPerBurst; 173 int64_t position = nextBurstIndex * mFramesPerBurst; 174 // ALOGD("IsochronousClockModel::convertTimeToPosition: time = %llu --> pos = %llu", 175 // (unsigned long long)nanoTime, 176 // (unsigned long long)position); 177 // ALOGD("IsochronousClockModel::convertTimeToPosition: framesDelta = %llu, mFramesPerBurst = %d", 178 // (long long) framesDelta, mFramesPerBurst); 179 return position; 180 } 181 182 void IsochronousClockModel::dump() const { 183 ALOGD("IsochronousClockModel::mMarkerFramePosition = %lld", (long long) mMarkerFramePosition); 184 ALOGD("IsochronousClockModel::mMarkerNanoTime = %lld", (long long) mMarkerNanoTime); 185 ALOGD("IsochronousClockModel::mSampleRate = %6d", mSampleRate); 186 ALOGD("IsochronousClockModel::mFramesPerBurst = %6d", mFramesPerBurst); 187 ALOGD("IsochronousClockModel::mMaxLatenessInNanos = %6d", mMaxLatenessInNanos); 188 ALOGD("IsochronousClockModel::mState = %6d", mState); 189 } 190