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 "IsochronousClockModel" 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 28using namespace aaudio; 29 30IsochronousClockModel::IsochronousClockModel() 31 : mMarkerFramePosition(0) 32 , mMarkerNanoTime(0) 33 , mSampleRate(48000) 34 , mFramesPerBurst(64) 35 , mMaxLatenessInNanos(0) 36 , mState(STATE_STOPPED) 37{ 38} 39 40IsochronousClockModel::~IsochronousClockModel() { 41} 42 43void IsochronousClockModel::setPositionAndTime(int64_t framePosition, int64_t nanoTime) { 44 ALOGV("setPositionAndTime(%lld, %lld)", 45 (long long) framePosition, (long long) nanoTime); 46 mMarkerFramePosition = framePosition; 47 mMarkerNanoTime = nanoTime; 48} 49 50void IsochronousClockModel::start(int64_t nanoTime) { 51 ALOGV("start(nanos = %lld)\n", (long long) nanoTime); 52 mMarkerNanoTime = nanoTime; 53 mState = STATE_STARTING; 54} 55 56void IsochronousClockModel::stop(int64_t nanoTime) { 57 ALOGV("stop(nanos = %lld)\n", (long long) nanoTime); 58 setPositionAndTime(convertTimeToPosition(nanoTime), nanoTime); 59 // TODO should we set position? 60 mState = STATE_STOPPED; 61} 62 63bool IsochronousClockModel::isStarting() { 64 return mState == STATE_STARTING; 65} 66 67void 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 127void IsochronousClockModel::setSampleRate(int32_t sampleRate) { 128 mSampleRate = sampleRate; 129 update(); 130} 131 132void IsochronousClockModel::setFramesPerBurst(int32_t framesPerBurst) { 133 mFramesPerBurst = framesPerBurst; 134 update(); 135} 136 137void IsochronousClockModel::update() { 138 int64_t nanosLate = convertDeltaPositionToTime(mFramesPerBurst); // uses mSampleRate 139 mMaxLatenessInNanos = (nanosLate > MIN_LATENESS_NANOS) ? nanosLate : MIN_LATENESS_NANOS; 140} 141 142int64_t IsochronousClockModel::convertDeltaPositionToTime(int64_t framesDelta) const { 143 return (AAUDIO_NANOS_PER_SECOND * framesDelta) / mSampleRate; 144} 145 146int64_t IsochronousClockModel::convertDeltaTimeToPosition(int64_t nanosDelta) const { 147 return (mSampleRate * nanosDelta) / AAUDIO_NANOS_PER_SECOND; 148} 149 150int64_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("convertPositionToTime: pos = %llu --> time = %llu", 160// (unsigned long long)framePosition, 161// (unsigned long long)time); 162 return time; 163} 164 165int64_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("convertTimeToPosition: time = %llu --> pos = %llu", 175// (unsigned long long)nanoTime, 176// (unsigned long long)position); 177// ALOGD("convertTimeToPosition: framesDelta = %llu, mFramesPerBurst = %d", 178// (long long) framesDelta, mFramesPerBurst); 179 return position; 180} 181 182void IsochronousClockModel::dump() const { 183 ALOGD("mMarkerFramePosition = %lld", (long long) mMarkerFramePosition); 184 ALOGD("mMarkerNanoTime = %lld", (long long) mMarkerNanoTime); 185 ALOGD("mSampleRate = %6d", mSampleRate); 186 ALOGD("mFramesPerBurst = %6d", mFramesPerBurst); 187 ALOGD("mMaxLatenessInNanos = %6d", mMaxLatenessInNanos); 188 ALOGD("mState = %6d", mState); 189} 190