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