• 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 package org.drrickorang.loopback;
18 
19 import android.os.Bundle;
20 import android.os.Parcel;
21 import android.os.Parcelable;
22 
23 import java.util.Iterator;
24 
25 /**
26  * Maintains and returns pairs of callback timestamps (in milliseconds since beginning of test) and
27  * lengths (milliseconds between a callback and the previous callback).
28  */
29 public class BufferCallbackTimes implements Iterable<BufferCallbackTimes.BufferCallback>,
30         Parcelable {
31     private final int[] mTimeStamps;
32     private final short[] mCallbackDurations;
33     private final short mExpectedBufferPeriod;
34     private boolean mExceededCapacity;
35     private int mIndex;
36 
BufferCallbackTimes(int maxRecords, int expectedBufferPeriod)37     public BufferCallbackTimes(int maxRecords, int expectedBufferPeriod) {
38         mIndex = 0;
39         mTimeStamps = new int[maxRecords];
40         mCallbackDurations = new short[maxRecords];
41         mExceededCapacity = false;
42         mExpectedBufferPeriod = (short) expectedBufferPeriod;
43     }
44 
45     /**
46      * Instantiates an iterable object with already recorded callback times and lengths
47      * used for callbacks recorded by native sles callback functions.
48      *
49      * exceededCapacity should be set to true only when there were late callbacks observed but
50      * unable to be recorded because allocated arrays were already at capacity
51      */
BufferCallbackTimes(int[] timeStamps, short[] callbackDurations, boolean exceededCapacity, short expectedBufferPeriod)52     public BufferCallbackTimes(int[] timeStamps, short[] callbackDurations,
53                                boolean exceededCapacity, short expectedBufferPeriod) {
54         mTimeStamps = timeStamps;
55         mCallbackDurations = callbackDurations;
56         mExceededCapacity = exceededCapacity;
57         mIndex = mTimeStamps.length;
58         mExpectedBufferPeriod = expectedBufferPeriod;
59     }
60 
61     /** Record the length of a late/early callback and the time it occurred. Used by Java Thread. */
recordCallbackTime(int timeStamp, short callbackLength)62     public void recordCallbackTime(int timeStamp, short callbackLength) {
63         if (!mExceededCapacity && callbackLength != mExpectedBufferPeriod
64                 && callbackLength != mExpectedBufferPeriod + 1) {
65             //only marked as exceeded if attempting to record a late callback after arrays full
66             if (mIndex == mTimeStamps.length) {
67                 mExceededCapacity = true;
68                 return;
69             }
70             mTimeStamps[mIndex] = timeStamp;
71             mCallbackDurations[mIndex] = callbackLength;
72             mIndex++;
73         }
74     }
75 
76     @Override
toString()77     public String toString() {
78         StringBuilder sb = new StringBuilder();
79         for (BufferCallback callback : this) {
80             sb.append(callback.timeStamp);
81             sb.append(",");
82             sb.append(callback.callbackDuration);
83             sb.append("\n");
84         }
85         return sb.toString();
86     }
87 
88     // True only if arrays are full and recording more late or early callbacks is attempted.
isCapacityExceeded()89     public boolean isCapacityExceeded() {
90         return mExceededCapacity;
91     }
92 
getNumLateOrEarlyCallbacks()93     public int getNumLateOrEarlyCallbacks() {
94         return mIndex;
95     }
96 
getExpectedBufferPeriod()97     public short getExpectedBufferPeriod() {
98         return mExpectedBufferPeriod;
99     }
100 
101     @Override
iterator()102     public Iterator<BufferCallback> iterator() {
103         return new Iterator<BufferCallback>() {
104             int mIteratorIndex = 0;
105 
106             @Override
107             public boolean hasNext() {
108                 return mIteratorIndex < mIndex;
109             }
110 
111             @Override
112             public BufferCallback next() {
113                 return new BufferCallback(mTimeStamps[mIteratorIndex],
114                         mCallbackDurations[mIteratorIndex++]);
115             }
116 
117             @Override
118             public void remove() {
119                 throw new UnsupportedOperationException("Buffer Time Stamps are Immutable");
120             }
121         };
122     }
123 
124     @Override
describeContents()125     public int describeContents() {
126         return 0;
127     }
128 
129     @Override
writeToParcel(Parcel dest, int flags)130     public void writeToParcel(Parcel dest, int flags) {
131         Bundle out = new Bundle();
132         out.putIntArray("mTimeStamps", mTimeStamps);
133         out.putShortArray("mCallbackDurations", mCallbackDurations);
134         out.putShort("mExpectedBufferPeriod", mExpectedBufferPeriod);
135         out.putBoolean("mExceededCapacity", mExceededCapacity);
136         out.putInt("mIndex", mIndex);
137         dest.writeBundle(out);
138     }
139 
BufferCallbackTimes(Parcel source)140     private BufferCallbackTimes(Parcel source) {
141         Bundle in = source.readBundle(getClass().getClassLoader());
142         mTimeStamps = in.getIntArray("mTimeStamps");
143         mCallbackDurations = in.getShortArray("mCallbackDurations");
144         mExpectedBufferPeriod = in.getShort("mExpectedBufferPeriod");
145         mExceededCapacity = in.getBoolean("mExceededCapacity");
146         mIndex = in.getInt("mIndex");
147     }
148 
149     public static final Parcelable.Creator<BufferCallbackTimes> CREATOR
150              = new Parcelable.Creator<BufferCallbackTimes>() {
151          public BufferCallbackTimes createFromParcel(Parcel in) {
152              return new BufferCallbackTimes(in);
153          }
154 
155          public BufferCallbackTimes[] newArray(int size) {
156              return new BufferCallbackTimes[size];
157          }
158      };
159 
160     /** Wrapper for iteration over timestamp and length pairs */
161     public class BufferCallback {
162         public final int timeStamp;
163         public final short callbackDuration;
164 
BufferCallback(final int ts, final short cd)165         BufferCallback(final int ts, final short cd) {
166             timeStamp = ts;
167             callbackDuration = cd;
168         }
169     }
170 
171 }
172