Home | History | Annotate | Download | only in client
      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