250 lines
10 KiB
Java
250 lines
10 KiB
Java
package co.discord.media_engine;
|
|
|
|
import android.media.AudioRecord;
|
|
import android.os.Process;
|
|
import android.util.Log;
|
|
import c.d.b.a.a;
|
|
import com.discord.models.domain.ModelAuditLogEntry;
|
|
import d0.z.d.m;
|
|
import java.nio.ByteBuffer;
|
|
import kotlin.jvm.internal.DefaultConstructorMarker;
|
|
import org.webrtc.ThreadUtils;
|
|
import org.webrtc.TimestampAligner;
|
|
/* compiled from: SoundshareAudioSource.kt */
|
|
public final class SoundshareAudioSource {
|
|
private static final long AUDIO_RECORD_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 BUFFER_SIZE_FACTOR = 2;
|
|
private static final int CALLBACK_BUFFER_SIZE_MS = 10;
|
|
public static final Companion Companion = new Companion(null);
|
|
private static final String TAG = "SoundshareAudioSource";
|
|
private static volatile boolean microphoneMute;
|
|
private AudioRecord audioRecord;
|
|
private AudioRecordThread audioThread;
|
|
private ByteBuffer byteBuffer;
|
|
private final long nativeInstance = nativeCreateInstance();
|
|
private boolean released;
|
|
|
|
/* compiled from: SoundshareAudioSource.kt */
|
|
public final class AudioRecordThread extends Thread {
|
|
private final AudioRecord audioRecord;
|
|
private final ByteBuffer byteBuffer;
|
|
private final byte[] emptyBytes;
|
|
private volatile boolean keepAlive = true;
|
|
public final /* synthetic */ SoundshareAudioSource this$0;
|
|
private long timestamp;
|
|
|
|
/* JADX INFO: super call moved to the top of the method (can break code semantics) */
|
|
public AudioRecordThread(SoundshareAudioSource soundshareAudioSource, String str, AudioRecord audioRecord, ByteBuffer byteBuffer, long j) {
|
|
super(str);
|
|
m.checkNotNullParameter(str, ModelAuditLogEntry.CHANGE_KEY_NAME);
|
|
m.checkNotNullParameter(audioRecord, "audioRecord");
|
|
m.checkNotNullParameter(byteBuffer, "byteBuffer");
|
|
this.this$0 = soundshareAudioSource;
|
|
this.audioRecord = audioRecord;
|
|
this.byteBuffer = byteBuffer;
|
|
this.timestamp = j;
|
|
this.emptyBytes = new byte[byteBuffer.capacity()];
|
|
}
|
|
|
|
@Override // java.lang.Thread, java.lang.Runnable
|
|
public void run() {
|
|
Process.setThreadPriority(-19);
|
|
Companion.access$assertTrue(SoundshareAudioSource.Companion, this.audioRecord.getRecordingState() == 3);
|
|
while (this.keepAlive) {
|
|
AudioRecord audioRecord = this.audioRecord;
|
|
ByteBuffer byteBuffer = this.byteBuffer;
|
|
int read = audioRecord.read(byteBuffer, byteBuffer.capacity());
|
|
this.timestamp = TimestampAligner.getRtcTimeNanos();
|
|
if (read == this.byteBuffer.capacity()) {
|
|
if (SoundshareAudioSource.access$getMicrophoneMute$cp()) {
|
|
this.byteBuffer.clear();
|
|
this.byteBuffer.put(this.emptyBytes);
|
|
}
|
|
if (this.keepAlive) {
|
|
SoundshareAudioSource.access$dataIsRecorded(this.this$0, read, this.timestamp);
|
|
}
|
|
} else {
|
|
String str = "AudioRecord.read failed: " + read;
|
|
Log.e(SoundshareAudioSource.TAG, str);
|
|
if (read == -3) {
|
|
this.keepAlive = false;
|
|
SoundshareAudioSource.access$reportSoundshareAudioSourceError(this.this$0, str);
|
|
}
|
|
}
|
|
}
|
|
try {
|
|
this.audioRecord.stop();
|
|
} catch (IllegalStateException e) {
|
|
StringBuilder K = a.K("AudioRecord.stop failed: ");
|
|
K.append(e.getMessage());
|
|
Log.e(SoundshareAudioSource.TAG, K.toString());
|
|
}
|
|
}
|
|
|
|
public final void stopThread() {
|
|
this.keepAlive = false;
|
|
}
|
|
}
|
|
|
|
/* compiled from: SoundshareAudioSource.kt */
|
|
public static final class Companion {
|
|
private Companion() {
|
|
}
|
|
|
|
public /* synthetic */ Companion(DefaultConstructorMarker defaultConstructorMarker) {
|
|
this();
|
|
}
|
|
|
|
public static final /* synthetic */ void access$assertTrue(Companion companion, boolean z2) {
|
|
companion.assertTrue(z2);
|
|
}
|
|
|
|
private final void assertTrue(boolean z2) {
|
|
if (!z2) {
|
|
throw new AssertionError("Expected condition to be true");
|
|
}
|
|
}
|
|
|
|
public final void setMicrophoneMute(boolean z2) {
|
|
Log.w(SoundshareAudioSource.TAG, "setMicrophoneMute(" + z2 + ')');
|
|
SoundshareAudioSource.access$setMicrophoneMute$cp(z2);
|
|
}
|
|
}
|
|
|
|
public static final /* synthetic */ void access$dataIsRecorded(SoundshareAudioSource soundshareAudioSource, int i, long j) {
|
|
soundshareAudioSource.dataIsRecorded(i, j);
|
|
}
|
|
|
|
public static final /* synthetic */ boolean access$getMicrophoneMute$cp() {
|
|
return microphoneMute;
|
|
}
|
|
|
|
public static final /* synthetic */ void access$reportSoundshareAudioSourceError(SoundshareAudioSource soundshareAudioSource, String str) {
|
|
soundshareAudioSource.reportSoundshareAudioSourceError(str);
|
|
}
|
|
|
|
public static final /* synthetic */ void access$setMicrophoneMute$cp(boolean z2) {
|
|
microphoneMute = z2;
|
|
}
|
|
|
|
private final int channelCountToConfiguration(int i) {
|
|
return i == 1 ? 16 : 12;
|
|
}
|
|
|
|
private final synchronized void dataIsRecorded(int i, long j) {
|
|
if (!this.released) {
|
|
nativeDataIsRecorded(this.nativeInstance, i, j);
|
|
}
|
|
}
|
|
|
|
private final native synchronized void nativeCacheDirectBufferAddress(long j, ByteBuffer byteBuffer);
|
|
|
|
private final native synchronized long nativeCreateInstance();
|
|
|
|
private final native void nativeDataIsRecorded(long j, int i, long j2);
|
|
|
|
private final native synchronized void nativeDestroyInstance(long j);
|
|
|
|
private final native void nativeSetSampleFormat(long j, int i, int i2, int i3);
|
|
|
|
private final void reportSoundshareAudioSourceError(String str) {
|
|
Log.e(TAG, "Run-time recording error: " + str);
|
|
}
|
|
|
|
private final void reportSoundshareAudioSourceInitError(String str) {
|
|
Log.e(TAG, "Init recording error: " + str);
|
|
}
|
|
|
|
private final void reportSoundshareAudioSourceStartError(String str) {
|
|
Log.e(TAG, "Start recording error: " + str);
|
|
}
|
|
|
|
public final long getNativeInstance() {
|
|
return this.nativeInstance;
|
|
}
|
|
|
|
public final synchronized void release() {
|
|
if (!this.released) {
|
|
AudioRecord audioRecord = this.audioRecord;
|
|
if (audioRecord != null) {
|
|
audioRecord.release();
|
|
}
|
|
this.audioRecord = null;
|
|
nativeDestroyInstance(this.nativeInstance);
|
|
this.released = true;
|
|
}
|
|
}
|
|
|
|
public final void setSampleFormat(int i, int i2, int i3) {
|
|
nativeSetSampleFormat(this.nativeInstance, i, i2, i3);
|
|
}
|
|
|
|
public final boolean startRecording(AudioRecord audioRecord) {
|
|
m.checkNotNullParameter(audioRecord, "audioRecord");
|
|
int channelCount = audioRecord.getChannelCount();
|
|
int sampleRate = audioRecord.getSampleRate();
|
|
if (this.audioRecord != null) {
|
|
reportSoundshareAudioSourceInitError("StartRecording called twice without StopRecording.");
|
|
return false;
|
|
}
|
|
this.audioRecord = audioRecord;
|
|
setSampleFormat(sampleRate, 16, channelCount);
|
|
ByteBuffer allocateDirect = ByteBuffer.allocateDirect((sampleRate / 100) * channelCount * 2);
|
|
this.byteBuffer = allocateDirect;
|
|
nativeCacheDirectBufferAddress(this.nativeInstance, allocateDirect);
|
|
int minBufferSize = AudioRecord.getMinBufferSize(sampleRate, channelCountToConfiguration(channelCount), 2);
|
|
if (minBufferSize == -1 || minBufferSize == -2) {
|
|
reportSoundshareAudioSourceInitError(a.j("AudioRecord.getMinBufferSize failed: ", minBufferSize));
|
|
return false;
|
|
}
|
|
Math.max(minBufferSize * 2, allocateDirect.capacity());
|
|
if (audioRecord.getState() != 1) {
|
|
reportSoundshareAudioSourceInitError("Failed to create a new AudioRecord instance");
|
|
release();
|
|
return false;
|
|
}
|
|
try {
|
|
Companion.access$assertTrue(Companion, this.audioThread == null);
|
|
try {
|
|
long rtcTimeNanos = TimestampAligner.getRtcTimeNanos();
|
|
try {
|
|
audioRecord.startRecording();
|
|
if (audioRecord.getRecordingState() != 3) {
|
|
reportSoundshareAudioSourceStartError("AudioRecord.startRecording failed - incorrect state :" + audioRecord.getRecordingState());
|
|
return false;
|
|
}
|
|
m.checkNotNullExpressionValue(allocateDirect, "byteBuffer");
|
|
AudioRecordThread audioRecordThread = new AudioRecordThread(this, "SoundshareThread", audioRecord, allocateDirect, rtcTimeNanos);
|
|
this.audioThread = audioRecordThread;
|
|
m.checkNotNull(audioRecordThread);
|
|
audioRecordThread.start();
|
|
return true;
|
|
} catch (IllegalStateException e) {
|
|
reportSoundshareAudioSourceStartError("AudioRecord.startRecording failed: " + e.getMessage());
|
|
return false;
|
|
}
|
|
} catch (Throwable th) {
|
|
Log.e(TAG, "SoundshareAudioSource.startRecording fail hard!", th);
|
|
throw th;
|
|
}
|
|
} catch (Throwable th2) {
|
|
Log.e(TAG, "WebrtcAudioRecord.startRecording: audioThread != null!", th2);
|
|
throw th2;
|
|
}
|
|
}
|
|
|
|
public final boolean stopRecording() {
|
|
AudioRecordThread audioRecordThread = this.audioThread;
|
|
if (audioRecordThread == null) {
|
|
return false;
|
|
}
|
|
audioRecordThread.stopThread();
|
|
if (!ThreadUtils.joinUninterruptibly(audioRecordThread, AUDIO_RECORD_THREAD_JOIN_TIMEOUT_MS)) {
|
|
Log.e(TAG, "Join of SoundshareThread timed out");
|
|
}
|
|
this.audioThread = null;
|
|
return true;
|
|
}
|
|
}
|