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