102 lines
3.0 KiB
Java
102 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.session.libsession.utilities.MediaTypes;
|
|
import org.session.libsignal.utilities.Log;
|
|
import android.util.Pair;
|
|
|
|
import org.thoughtcrime.securesms.providers.BlobProvider;
|
|
import org.thoughtcrime.securesms.util.MediaUtil;
|
|
|
|
import org.session.libsignal.utilities.ThreadUtils;
|
|
import org.session.libsession.utilities.Util;
|
|
import org.session.libsignal.utilities.ListenableFuture;
|
|
import org.session.libsignal.utilities.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 = ThreadUtils.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(MediaTypes.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));
|
|
}
|
|
}
|