1 /* 2 * Copyright (C) 2015 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 com.android.tv.tuner.exoplayer.audio; 18 19 import android.os.SystemClock; 20 import android.util.Log; 21 import android.util.Pair; 22 import com.google.android.exoplayer.util.MimeTypes; 23 import java.util.ArrayList; 24 import java.util.HashSet; 25 import java.util.Set; 26 27 /** Monitors the rendering position of {@link AudioTrack}. */ 28 public class AudioTrackMonitor { 29 private static final String TAG = "AudioTrackMonitor"; 30 private static final boolean DEBUG = false; 31 32 // For fetched audio samples 33 private final ArrayList<Pair<Long, Integer>> mPtsList = new ArrayList<>(); 34 private final Set<Integer> mSampleSize = new HashSet<>(); 35 private final Set<Integer> mCurSampleSize = new HashSet<>(); 36 private final Set<Integer> mHeader = new HashSet<>(); 37 38 private long mExpireMs; 39 private long mDuration; 40 private long mSampleCount; 41 private long mTotalCount; 42 private long mStartMs; 43 44 private boolean mIsMp2; 45 flush()46 private void flush() { 47 mExpireMs += mDuration; 48 mSampleCount = 0; 49 mCurSampleSize.clear(); 50 mPtsList.clear(); 51 } 52 53 /** 54 * Resets and initializes {@link AudioTrackMonitor}. 55 * 56 * @param duration the frequency of monitoring in milliseconds 57 */ reset(long duration)58 public void reset(long duration) { 59 mExpireMs = SystemClock.elapsedRealtime(); 60 mDuration = duration; 61 mTotalCount = 0; 62 mStartMs = 0; 63 mSampleSize.clear(); 64 mHeader.clear(); 65 flush(); 66 } 67 setEncoding(String mime)68 public void setEncoding(String mime) { 69 mIsMp2 = MimeTypes.AUDIO_MPEG_L2.equalsIgnoreCase(mime); 70 } 71 72 /** 73 * Adds an audio sample information for monitoring. 74 * 75 * @param pts the presentation timestamp of the sample 76 * @param sampleSize the size in bytes of the sample 77 * @param header the bitrate & sampling information header of the sample 78 */ addPts(long pts, int sampleSize, int header)79 public void addPts(long pts, int sampleSize, int header) { 80 mTotalCount++; 81 mSampleCount++; 82 mSampleSize.add(sampleSize); 83 mHeader.add(header); 84 mCurSampleSize.add(sampleSize); 85 if (mTotalCount == 1) { 86 mStartMs = SystemClock.elapsedRealtime(); 87 } 88 if (mPtsList.isEmpty() || mPtsList.get(mPtsList.size() - 1).first != pts) { 89 mPtsList.add(Pair.create(pts, 1)); 90 return; 91 } 92 Pair<Long, Integer> pair = mPtsList.get(mPtsList.size() - 1); 93 mPtsList.set(mPtsList.size() - 1, Pair.create(pair.first, pair.second + 1)); 94 } 95 96 /** 97 * Logs if interested events are present. 98 * 99 * <p>Periodic logging is not enabled in release mode in order to avoid verbose logging. 100 */ maybeLog()101 public void maybeLog() { 102 long now = SystemClock.elapsedRealtime(); 103 if (mExpireMs != 0 && now >= mExpireMs) { 104 if (DEBUG) { 105 long unitDuration = 106 mIsMp2 107 ? MpegTsDefaultAudioTrackRenderer.MP2_SAMPLE_DURATION_US 108 : MpegTsDefaultAudioTrackRenderer.AC3_SAMPLE_DURATION_US; 109 long sampleDuration = (mTotalCount - 1) * unitDuration / 1000; 110 long totalDuration = now - mStartMs; 111 StringBuilder ptsBuilder = new StringBuilder(); 112 ptsBuilder 113 .append("PTS received ") 114 .append(mSampleCount) 115 .append(", ") 116 .append(totalDuration - sampleDuration) 117 .append(' '); 118 119 for (Pair<Long, Integer> pair : mPtsList) { 120 ptsBuilder 121 .append('[') 122 .append(pair.first) 123 .append(':') 124 .append(pair.second) 125 .append("], "); 126 } 127 Log.d(TAG, ptsBuilder.toString()); 128 } 129 if (DEBUG || mCurSampleSize.size() > 1) { 130 Log.d( 131 TAG, 132 "PTS received sample size: " 133 + String.valueOf(mSampleSize) 134 + mCurSampleSize 135 + mHeader); 136 } 137 flush(); 138 } 139 } 140 } 141