• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright (c) 2020 The WebRTC project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 package org.webrtc.audio;
12 
13 import android.media.AudioTrack;
14 import android.os.Build;
15 import org.webrtc.Logging;
16 
17 // Lowers the buffer size if no underruns are detected for 100 ms. Once an
18 // underrun is detected, the buffer size is increased by 10 ms and it will not
19 // be lowered further. The buffer size will never be increased more than
20 // 5 times, to avoid the possibility of the buffer size increasing without
21 // bounds.
22 class LowLatencyAudioBufferManager {
23   private static final String TAG = "LowLatencyAudioBufferManager";
24   // The underrun count that was valid during the previous call to maybeAdjustBufferSize(). Used to
25   // detect increases in the value.
26   private int prevUnderrunCount;
27   // The number of ticks to wait without an underrun before decreasing the buffer size.
28   private int ticksUntilNextDecrease;
29   // Indicate if we should continue to decrease the buffer size.
30   private boolean keepLoweringBufferSize;
31   // How often the buffer size was increased.
32   private int bufferIncreaseCounter;
33 
LowLatencyAudioBufferManager()34   public LowLatencyAudioBufferManager() {
35     this.prevUnderrunCount = 0;
36     this.ticksUntilNextDecrease = 10;
37     this.keepLoweringBufferSize = true;
38     this.bufferIncreaseCounter = 0;
39   }
40 
maybeAdjustBufferSize(AudioTrack audioTrack)41   public void maybeAdjustBufferSize(AudioTrack audioTrack) {
42     if (Build.VERSION.SDK_INT >= 26) {
43       final int underrunCount = audioTrack.getUnderrunCount();
44       if (underrunCount > prevUnderrunCount) {
45         // Don't increase buffer more than 5 times. Continuing to increase the buffer size
46         // could be harmful on low-power devices that regularly experience underruns under
47         // normal conditions.
48         if (bufferIncreaseCounter < 5) {
49           // Underrun detected, increase buffer size by 10ms.
50           final int currentBufferSize = audioTrack.getBufferSizeInFrames();
51           final int newBufferSize = currentBufferSize + audioTrack.getPlaybackRate() / 100;
52           Logging.d(TAG,
53               "Underrun detected! Increasing AudioTrack buffer size from " + currentBufferSize
54                   + " to " + newBufferSize);
55           audioTrack.setBufferSizeInFrames(newBufferSize);
56           bufferIncreaseCounter++;
57         }
58         // Stop trying to lower the buffer size.
59         keepLoweringBufferSize = false;
60         prevUnderrunCount = underrunCount;
61         ticksUntilNextDecrease = 10;
62       } else if (keepLoweringBufferSize) {
63         ticksUntilNextDecrease--;
64         if (ticksUntilNextDecrease <= 0) {
65           // No underrun seen for 100 ms, try to lower the buffer size by 10ms.
66           final int bufferSize10ms = audioTrack.getPlaybackRate() / 100;
67           // Never go below a buffer size of 10ms.
68           final int currentBufferSize = audioTrack.getBufferSizeInFrames();
69           final int newBufferSize = Math.max(bufferSize10ms, currentBufferSize - bufferSize10ms);
70           if (newBufferSize != currentBufferSize) {
71             Logging.d(TAG,
72                 "Lowering AudioTrack buffer size from " + currentBufferSize + " to "
73                     + newBufferSize);
74             audioTrack.setBufferSizeInFrames(newBufferSize);
75           }
76           ticksUntilNextDecrease = 10;
77         }
78       }
79     }
80   }
81 }
82