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