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 <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