session-android/app/src/main/java/org/thoughtcrime/securesms/audio/AudioRecorder.java

99 lines
3.0 KiB
Java

package org.thoughtcrime.securesms.audio;
import android.annotation.TargetApi;
import android.content.Context;
import android.net.Uri;
import android.os.Build;
import android.os.ParcelFileDescriptor;
import androidx.annotation.NonNull;
import org.thoughtcrime.securesms.logging.Log;
import android.util.Pair;
import org.thoughtcrime.securesms.providers.BlobProvider;
import org.thoughtcrime.securesms.util.MediaUtil;
import org.session.libsession.utilities.ThreadUtil;
import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.concurrent.ListenableFuture;
import org.thoughtcrime.securesms.util.concurrent.SettableFuture;
import java.io.IOException;
import java.util.concurrent.ExecutorService;
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
public class AudioRecorder {
private static final String TAG = AudioRecorder.class.getSimpleName();
private static final ExecutorService executor = ThreadUtil.newDynamicSingleThreadedExecutor();
private final Context context;
private AudioCodec audioCodec;
private Uri captureUri;
public AudioRecorder(@NonNull Context context) {
this.context = context;
}
public void startRecording() {
Log.i(TAG, "startRecording()");
executor.execute(() -> {
Log.i(TAG, "Running startRecording() + " + Thread.currentThread().getId());
try {
if (audioCodec != null) {
throw new AssertionError("We can only record once at a time.");
}
ParcelFileDescriptor fds[] = ParcelFileDescriptor.createPipe();
captureUri = BlobProvider.getInstance()
.forData(new ParcelFileDescriptor.AutoCloseInputStream(fds[0]), 0)
.withMimeType(MediaUtil.AUDIO_AAC)
.createForSingleSessionOnDisk(context, e -> Log.w(TAG, "Error during recording", e));
audioCodec = new AudioCodec();
audioCodec.start(new ParcelFileDescriptor.AutoCloseOutputStream(fds[1]));
} catch (IOException e) {
Log.w(TAG, e);
}
});
}
public @NonNull ListenableFuture<Pair<Uri, Long>> stopRecording() {
Log.i(TAG, "stopRecording()");
final SettableFuture<Pair<Uri, Long>> future = new SettableFuture<>();
executor.execute(() -> {
if (audioCodec == null) {
sendToFuture(future, new IOException("MediaRecorder was never initialized successfully!"));
return;
}
audioCodec.stop();
try {
long size = MediaUtil.getMediaSize(context, captureUri);
sendToFuture(future, new Pair<>(captureUri, size));
} catch (IOException ioe) {
Log.w(TAG, ioe);
sendToFuture(future, ioe);
}
audioCodec = null;
captureUri = null;
});
return future;
}
private <T> void sendToFuture(final SettableFuture<T> future, final Exception exception) {
Util.runOnMain(() -> future.setException(exception));
}
private <T> void sendToFuture(final SettableFuture<T> future, final T result) {
Util.runOnMain(() -> future.set(result));
}
}