Rabbit-R1/android (non root)/java/sources/org/webrtc/voiceengine/WebRtcAudioTrack.java
2024-05-21 17:08:36 -04:00

369 lines
15 KiB
Java

package org.webrtc.voiceengine;
import android.media.AudioAttributes;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
import android.os.Process;
import java.nio.ByteBuffer;
import org.webrtc.ContextUtils;
import org.webrtc.Logging;
import org.webrtc.ThreadUtils;
/* loaded from: classes3.dex */
public class WebRtcAudioTrack {
private static final long AUDIO_TRACK_THREAD_JOIN_TIMEOUT_MS = 2000;
private static final int BITS_PER_SAMPLE = 16;
private static final int BUFFERS_PER_SECOND = 100;
private static final int CALLBACK_BUFFER_SIZE_MS = 10;
private static final boolean DEBUG = false;
private static final int DEFAULT_USAGE;
private static final String TAG = "WebRtcAudioTrack";
private static ErrorCallback errorCallback;
private static WebRtcAudioTrackErrorCallback errorCallbackOld;
private static volatile boolean speakerMute;
private static int usageAttribute;
private final AudioManager audioManager;
private AudioTrackThread audioThread;
private AudioTrack audioTrack;
private ByteBuffer byteBuffer;
private byte[] emptyBytes;
private final long nativeAudioTrack;
private final ThreadUtils.ThreadChecker threadChecker;
/* loaded from: classes3.dex */
public enum AudioTrackStartErrorCode {
AUDIO_TRACK_START_EXCEPTION,
AUDIO_TRACK_START_STATE_MISMATCH
}
/* loaded from: classes3.dex */
public interface ErrorCallback {
void onWebRtcAudioTrackError(String str);
void onWebRtcAudioTrackInitError(String str);
void onWebRtcAudioTrackStartError(AudioTrackStartErrorCode audioTrackStartErrorCode, String str);
}
@Deprecated
/* loaded from: classes3.dex */
public interface WebRtcAudioTrackErrorCallback {
void onWebRtcAudioTrackError(String str);
void onWebRtcAudioTrackInitError(String str);
void onWebRtcAudioTrackStartError(String str);
}
private int channelCountToConfiguration(int i) {
return i == 1 ? 4 : 12;
}
private static int getDefaultUsageAttribute() {
return 2;
}
private native void nativeCacheDirectBufferAddress(ByteBuffer byteBuffer, long j);
/* JADX INFO: Access modifiers changed from: private */
public native void nativeGetPlayoutData(int i, long j);
static {
int defaultUsageAttribute = getDefaultUsageAttribute();
DEFAULT_USAGE = defaultUsageAttribute;
usageAttribute = defaultUsageAttribute;
}
public static synchronized void setAudioTrackUsageAttribute(int i) {
synchronized (WebRtcAudioTrack.class) {
Logging.w(TAG, "Default usage attribute is changed from: " + DEFAULT_USAGE + " to " + i);
usageAttribute = i;
}
}
@Deprecated
public static void setErrorCallback(WebRtcAudioTrackErrorCallback webRtcAudioTrackErrorCallback) {
Logging.d(TAG, "Set error callback (deprecated");
errorCallbackOld = webRtcAudioTrackErrorCallback;
}
public static void setErrorCallback(ErrorCallback errorCallback2) {
Logging.d(TAG, "Set extended error callback");
errorCallback = errorCallback2;
}
/* loaded from: classes3.dex */
private class AudioTrackThread extends Thread {
private volatile boolean keepAlive;
public AudioTrackThread(String str) {
super(str);
this.keepAlive = true;
}
@Override // java.lang.Thread, java.lang.Runnable
public void run() {
Process.setThreadPriority(-19);
Logging.d(WebRtcAudioTrack.TAG, "AudioTrackThread" + WebRtcAudioUtils.getThreadInfo());
WebRtcAudioTrack.assertTrue(WebRtcAudioTrack.this.audioTrack.getPlayState() == 3);
int capacity = WebRtcAudioTrack.this.byteBuffer.capacity();
while (this.keepAlive) {
WebRtcAudioTrack webRtcAudioTrack = WebRtcAudioTrack.this;
webRtcAudioTrack.nativeGetPlayoutData(capacity, webRtcAudioTrack.nativeAudioTrack);
WebRtcAudioTrack.assertTrue(capacity <= WebRtcAudioTrack.this.byteBuffer.remaining());
if (WebRtcAudioTrack.speakerMute) {
WebRtcAudioTrack.this.byteBuffer.clear();
WebRtcAudioTrack.this.byteBuffer.put(WebRtcAudioTrack.this.emptyBytes);
WebRtcAudioTrack.this.byteBuffer.position(0);
}
int writeBytes = writeBytes(WebRtcAudioTrack.this.audioTrack, WebRtcAudioTrack.this.byteBuffer, capacity);
if (writeBytes != capacity) {
Logging.e(WebRtcAudioTrack.TAG, "AudioTrack.write played invalid number of bytes: " + writeBytes);
if (writeBytes < 0) {
this.keepAlive = false;
WebRtcAudioTrack.this.reportWebRtcAudioTrackError("AudioTrack.write failed: " + writeBytes);
}
}
WebRtcAudioTrack.this.byteBuffer.rewind();
}
if (WebRtcAudioTrack.this.audioTrack != null) {
Logging.d(WebRtcAudioTrack.TAG, "Calling AudioTrack.stop...");
try {
WebRtcAudioTrack.this.audioTrack.stop();
Logging.d(WebRtcAudioTrack.TAG, "AudioTrack.stop is done.");
} catch (IllegalStateException e) {
Logging.e(WebRtcAudioTrack.TAG, "AudioTrack.stop failed: " + e.getMessage());
}
}
}
private int writeBytes(AudioTrack audioTrack, ByteBuffer byteBuffer, int i) {
return audioTrack.write(byteBuffer, i, 0);
}
public void stopThread() {
Logging.d(WebRtcAudioTrack.TAG, "stopThread");
this.keepAlive = false;
}
}
WebRtcAudioTrack(long j) {
ThreadUtils.ThreadChecker threadChecker = new ThreadUtils.ThreadChecker();
this.threadChecker = threadChecker;
threadChecker.checkIsOnValidThread();
Logging.d(TAG, "ctor" + WebRtcAudioUtils.getThreadInfo());
this.nativeAudioTrack = j;
this.audioManager = (AudioManager) ContextUtils.getApplicationContext().getSystemService("audio");
}
private int initPlayout(int i, int i2, double d) {
this.threadChecker.checkIsOnValidThread();
Logging.d(TAG, "initPlayout(sampleRate=" + i + ", channels=" + i2 + ", bufferSizeFactor=" + d + ")");
this.byteBuffer = ByteBuffer.allocateDirect(i2 * 2 * (i / 100));
Logging.d(TAG, "byteBuffer.capacity: " + this.byteBuffer.capacity());
this.emptyBytes = new byte[this.byteBuffer.capacity()];
nativeCacheDirectBufferAddress(this.byteBuffer, this.nativeAudioTrack);
int channelCountToConfiguration = channelCountToConfiguration(i2);
int minBufferSize = (int) (AudioTrack.getMinBufferSize(i, channelCountToConfiguration, 2) * d);
Logging.d(TAG, "minBufferSizeInBytes: " + minBufferSize);
if (minBufferSize < this.byteBuffer.capacity()) {
reportWebRtcAudioTrackInitError("AudioTrack.getMinBufferSize returns an invalid value.");
return -1;
}
if (this.audioTrack != null) {
reportWebRtcAudioTrackInitError("Conflict with existing AudioTrack.");
return -1;
}
try {
AudioTrack createAudioTrackOnLollipopOrHigher = createAudioTrackOnLollipopOrHigher(i, channelCountToConfiguration, minBufferSize);
this.audioTrack = createAudioTrackOnLollipopOrHigher;
if (createAudioTrackOnLollipopOrHigher == null || createAudioTrackOnLollipopOrHigher.getState() != 1) {
reportWebRtcAudioTrackInitError("Initialization of audio track failed.");
releaseAudioResources();
return -1;
}
logMainParameters();
logMainParametersExtended();
return minBufferSize;
} catch (IllegalArgumentException e) {
reportWebRtcAudioTrackInitError(e.getMessage());
releaseAudioResources();
return -1;
}
}
private boolean startPlayout() {
this.threadChecker.checkIsOnValidThread();
Logging.d(TAG, "startPlayout");
assertTrue(this.audioTrack != null);
assertTrue(this.audioThread == null);
try {
this.audioTrack.play();
if (this.audioTrack.getPlayState() != 3) {
reportWebRtcAudioTrackStartError(AudioTrackStartErrorCode.AUDIO_TRACK_START_STATE_MISMATCH, "AudioTrack.play failed - incorrect state :" + this.audioTrack.getPlayState());
releaseAudioResources();
return false;
}
AudioTrackThread audioTrackThread = new AudioTrackThread("AudioTrackJavaThread");
this.audioThread = audioTrackThread;
audioTrackThread.start();
return true;
} catch (IllegalStateException e) {
reportWebRtcAudioTrackStartError(AudioTrackStartErrorCode.AUDIO_TRACK_START_EXCEPTION, "AudioTrack.play failed: " + e.getMessage());
releaseAudioResources();
return false;
}
}
private boolean stopPlayout() {
this.threadChecker.checkIsOnValidThread();
Logging.d(TAG, "stopPlayout");
assertTrue(this.audioThread != null);
logUnderrunCount();
this.audioThread.stopThread();
Logging.d(TAG, "Stopping the AudioTrackThread...");
this.audioThread.interrupt();
if (!ThreadUtils.joinUninterruptibly(this.audioThread, 2000L)) {
Logging.e(TAG, "Join of AudioTrackThread timed out.");
WebRtcAudioUtils.logAudioState(TAG);
}
Logging.d(TAG, "AudioTrackThread has now been stopped.");
this.audioThread = null;
releaseAudioResources();
return true;
}
private int getStreamMaxVolume() {
this.threadChecker.checkIsOnValidThread();
Logging.d(TAG, "getStreamMaxVolume");
assertTrue(this.audioManager != null);
return this.audioManager.getStreamMaxVolume(0);
}
private boolean setStreamVolume(int i) {
this.threadChecker.checkIsOnValidThread();
Logging.d(TAG, "setStreamVolume(" + i + ")");
assertTrue(this.audioManager != null);
if (isVolumeFixed()) {
Logging.e(TAG, "The device implements a fixed volume policy.");
return false;
}
this.audioManager.setStreamVolume(0, i, 0);
return true;
}
private boolean isVolumeFixed() {
return this.audioManager.isVolumeFixed();
}
private int getStreamVolume() {
this.threadChecker.checkIsOnValidThread();
Logging.d(TAG, "getStreamVolume");
assertTrue(this.audioManager != null);
return this.audioManager.getStreamVolume(0);
}
private void logMainParameters() {
Logging.d(TAG, "AudioTrack: session ID: " + this.audioTrack.getAudioSessionId() + ", channels: " + this.audioTrack.getChannelCount() + ", sample rate: " + this.audioTrack.getSampleRate() + ", max gain: " + AudioTrack.getMaxVolume());
}
private static AudioTrack createAudioTrackOnLollipopOrHigher(int i, int i2, int i3) {
Logging.d(TAG, "createAudioTrackOnLollipopOrHigher");
int nativeOutputSampleRate = AudioTrack.getNativeOutputSampleRate(0);
Logging.d(TAG, "nativeOutputSampleRate: " + nativeOutputSampleRate);
if (i != nativeOutputSampleRate) {
Logging.w(TAG, "Unable to use fast mode since requested sample rate is not native");
}
if (usageAttribute != DEFAULT_USAGE) {
Logging.w(TAG, "A non default usage attribute is used: " + usageAttribute);
}
return new AudioTrack(new AudioAttributes.Builder().setUsage(usageAttribute).setContentType(1).build(), new AudioFormat.Builder().setEncoding(2).setSampleRate(i).setChannelMask(i2).build(), i3, 1, 0);
}
private static AudioTrack createAudioTrackOnLowerThanLollipop(int i, int i2, int i3) {
return new AudioTrack(0, i, i2, 2, i3, 1);
}
private void logBufferSizeInFrames() {
Logging.d(TAG, "AudioTrack: buffer size in frames: " + this.audioTrack.getBufferSizeInFrames());
}
private int getBufferSizeInFrames() {
return this.audioTrack.getBufferSizeInFrames();
}
private void logBufferCapacityInFrames() {
Logging.d(TAG, "AudioTrack: buffer capacity in frames: " + this.audioTrack.getBufferCapacityInFrames());
}
private void logMainParametersExtended() {
logBufferSizeInFrames();
logBufferCapacityInFrames();
}
private void logUnderrunCount() {
Logging.d(TAG, "underrun count: " + this.audioTrack.getUnderrunCount());
}
/* JADX INFO: Access modifiers changed from: private */
public static void assertTrue(boolean z) {
if (!z) {
throw new AssertionError("Expected condition to be true");
}
}
public static void setSpeakerMute(boolean z) {
Logging.w(TAG, "setSpeakerMute(" + z + ")");
speakerMute = z;
}
private void releaseAudioResources() {
Logging.d(TAG, "releaseAudioResources");
AudioTrack audioTrack = this.audioTrack;
if (audioTrack != null) {
audioTrack.release();
this.audioTrack = null;
}
}
private void reportWebRtcAudioTrackInitError(String str) {
Logging.e(TAG, "Init playout error: " + str);
WebRtcAudioUtils.logAudioState(TAG);
WebRtcAudioTrackErrorCallback webRtcAudioTrackErrorCallback = errorCallbackOld;
if (webRtcAudioTrackErrorCallback != null) {
webRtcAudioTrackErrorCallback.onWebRtcAudioTrackInitError(str);
}
ErrorCallback errorCallback2 = errorCallback;
if (errorCallback2 != null) {
errorCallback2.onWebRtcAudioTrackInitError(str);
}
}
private void reportWebRtcAudioTrackStartError(AudioTrackStartErrorCode audioTrackStartErrorCode, String str) {
Logging.e(TAG, "Start playout error: " + audioTrackStartErrorCode + ". " + str);
WebRtcAudioUtils.logAudioState(TAG);
WebRtcAudioTrackErrorCallback webRtcAudioTrackErrorCallback = errorCallbackOld;
if (webRtcAudioTrackErrorCallback != null) {
webRtcAudioTrackErrorCallback.onWebRtcAudioTrackStartError(str);
}
ErrorCallback errorCallback2 = errorCallback;
if (errorCallback2 != null) {
errorCallback2.onWebRtcAudioTrackStartError(audioTrackStartErrorCode, str);
}
}
/* JADX INFO: Access modifiers changed from: private */
public void reportWebRtcAudioTrackError(String str) {
Logging.e(TAG, "Run-time playback error: " + str);
WebRtcAudioUtils.logAudioState(TAG);
WebRtcAudioTrackErrorCallback webRtcAudioTrackErrorCallback = errorCallbackOld;
if (webRtcAudioTrackErrorCallback != null) {
webRtcAudioTrackErrorCallback.onWebRtcAudioTrackError(str);
}
ErrorCallback errorCallback2 = errorCallback;
if (errorCallback2 != null) {
errorCallback2.onWebRtcAudioTrackError(str);
}
}
}