Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a5875c00 authored by 2bllw8's avatar 2bllw8
Browse files

Recorder: use java.nio.Path instead of java.io.File

Change-Id: Iad39dbe48b23eef29a9301987ee061cde4591c4b
parent 3f91bb3d
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -20,8 +20,8 @@ import android.media.MediaRecorder;

import androidx.annotation.RequiresPermission;

import java.io.File;
import java.io.IOException;
import java.nio.file.Path;

public class GoodQualityRecorder implements SoundRecording {
    private static final String FILE_NAME_EXTENSION_AAC = "m4a";
@@ -32,9 +32,9 @@ public class GoodQualityRecorder implements SoundRecording {

    @Override
    @RequiresPermission(Manifest.permission.RECORD_AUDIO)
    public void startRecording(File file) throws IOException {
    public void startRecording(Path path) throws IOException {
        mRecorder = new MediaRecorder();
        mRecorder.setOutputFile(file);
        mRecorder.setOutputFile(path.toFile());
        mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
        mRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
        mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
+8 −9
Original line number Diff line number Diff line
@@ -27,10 +27,9 @@ import org.lineageos.recorder.utils.PcmConverter;
import org.lineageos.recorder.utils.Utils;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.AtomicBoolean;

@@ -45,7 +44,7 @@ public class HighQualityRecorder implements SoundRecording {
            CHANNEL_IN, FORMAT);

    private AudioRecord mRecord;
    private File mFile;
    private Path mPath;

    private volatile byte[] mData;
    private Thread mThread;
@@ -54,8 +53,8 @@ public class HighQualityRecorder implements SoundRecording {

    @Override
    @RequiresPermission(Manifest.permission.RECORD_AUDIO)
    public void startRecording(File file) {
        mFile = file;
    public void startRecording(Path path) {
        mPath = path;
        mRecord = new AudioRecord(MediaRecorder.AudioSource.DEFAULT,
                SAMPLING_RATE, CHANNEL_IN, FORMAT, BUFFER_SIZE);
        mData = new byte[BUFFER_SIZE];
@@ -83,7 +82,7 @@ public class HighQualityRecorder implements SoundRecording {
        // needed to prevent app crash when starting and stopping too fast
        try {
            mRecord.stop();
            PcmConverter.convertToWave(mFile, BUFFER_SIZE);
            PcmConverter.convertToWave(mPath, BUFFER_SIZE);
        } catch (RuntimeException rte) {
            return false;
        } finally {
@@ -144,7 +143,7 @@ public class HighQualityRecorder implements SoundRecording {
    private void recordingThreadImpl() {
        BufferedOutputStream out = null;
        try {
            out = new BufferedOutputStream(new FileOutputStream(mFile));
            out = new BufferedOutputStream(Files.newOutputStream(mPath));

            while (mIsRecording.get()) {
                mPauseSemaphore.acquireUninterruptibly();
@@ -168,7 +167,7 @@ public class HighQualityRecorder implements SoundRecording {
                    mPauseSemaphore.release();
                }
            }
        } catch (FileNotFoundException e) {
        } catch (IOException e) {
            Log.e(TAG, "Can't find output file", e);
        } finally {
            Utils.closeQuietly(out);
+29 −15
Original line number Diff line number Diff line
@@ -47,11 +47,13 @@ import org.lineageos.recorder.task.TaskExecutor;
import org.lineageos.recorder.utils.LastRecordHelper;
import org.lineageos.recorder.utils.Utils;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
import java.util.Optional;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.atomic.AtomicLong;
@@ -77,7 +79,7 @@ public class SoundRecorderService extends Service {

    private final IBinder mBinder = new RecorderBinder(this);
    private SoundRecording mRecorder = null;
    private File mRecordFile = null;
    private Path mRecordPath = null;

    private TimerTask mVisualizerTask;
    @Nullable
@@ -152,14 +154,22 @@ public class SoundRecorderService extends Service {
        boolean highQuality = Utils.getRecordInHighQuality(this);
        mRecorder = highQuality ? new HighQualityRecorder() : new GoodQualityRecorder();

        mRecordFile = createNewAudioFile(locationName, mRecorder.getFileExtension());
        final Optional<Path> optPath = createNewAudioFile(locationName,
                mRecorder.getFileExtension());
        // No .isEmpty for android
        //noinspection SimplifyOptionalCallChains
        if (!optPath.isPresent()) {
            Log.e(TAG, "Failed to prepare output file");
            return START_NOT_STICKY;
        }
        mRecordPath = optPath.get();
        mIsPaused = false;
        mElapsedTime.set(0);

        try {
            if (checkSelfPermission(Manifest.permission.RECORD_AUDIO)
                    == PackageManager.PERMISSION_GRANTED) {
                mRecorder.startRecording(mRecordFile);
                mRecorder.startRecording(mRecordPath);
            } else {
                Log.e(TAG, "Missing permission to record audio");
                return START_NOT_STICKY;
@@ -192,14 +202,14 @@ public class SoundRecorderService extends Service {
        stopTimers();

        boolean success = mRecorder.stopRecording();
        if (!success || mRecordFile == null) {
        if (!success || mRecordPath == null) {
            onRecordFailed();
            return START_NOT_STICKY;
        }

        mTaskExecutor.runTask(new AddRecordingToContentProviderTask(
                        getContentResolver(),
                        mRecordFile,
                        mRecordPath,
                        mRecorder.getMimeType()),
                this::onRecordCompleted,
                () -> Log.e(TAG, "Failed to save recording"));
@@ -368,19 +378,23 @@ public class SoundRecorderService extends Service {
    }

    @NonNull
    private File createNewAudioFile(@Nullable String locationName,
    private Optional<Path> createNewAudioFile(@Nullable String locationName,
                                              @NonNull String extension) {
        String fileName = String.format(FILE_NAME_BASE,
        final String fileName = String.format(FILE_NAME_BASE,
                locationName == null ? FILE_NAME_LOCATION_FALLBACK : locationName,
                mDateFormat.format(LocalDateTime.now()),
                extension);
        File file = new File(getExternalFilesDir(Environment.DIRECTORY_RECORDINGS), fileName);
        File recordingDir = file.getParentFile();
        if (recordingDir != null && !recordingDir.exists()) {
            //noinspection ResultOfMethodCallIgnored
            recordingDir.mkdirs();
        final Path recordingDir = getExternalFilesDir(Environment.DIRECTORY_RECORDINGS).toPath();
        final Path path = recordingDir.resolve(fileName);
        if (!Files.exists(recordingDir)) {
            try {
                Files.createDirectories(recordingDir);
            } catch (IOException e) {
                Log.e(TAG, "Failed to create parent directories for output");
                return Optional.empty();
            }
        }
        return file;
        return Optional.of(path);
    }

    private void startElapsedTimeTask() {
+2 −2
Original line number Diff line number Diff line
@@ -19,13 +19,13 @@ import android.Manifest;

import androidx.annotation.RequiresPermission;

import java.io.File;
import java.io.IOException;
import java.nio.file.Path;

public interface SoundRecording {

    @RequiresPermission(Manifest.permission.RECORD_AUDIO)
    void startRecording(File file) throws IOException;
    void startRecording(Path path) throws IOException;

    boolean stopRecording();

+15 −13
Original line number Diff line number Diff line
@@ -25,10 +25,10 @@ import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Optional;
import java.util.concurrent.Callable;

@@ -41,29 +41,28 @@ public final class AddRecordingToContentProviderTask implements Callable<Optiona
    @Nullable
    private final ContentResolver cr;
    @Nullable
    private final File file;
    private final Path path;
    @NonNull
    private final String mimeType;

    public AddRecordingToContentProviderTask(@Nullable ContentResolver cr,
                                             // TODO: Convert to Path
                                             @Nullable File file,
                                             @Nullable Path path,
                                             @NonNull String mimeType) {
        this.cr = cr;
        this.file = file;
        this.path = path;
        this.mimeType = mimeType;
    }

    @Override
    public Optional<String> call() {
        if (cr == null || file == null) {
        if (cr == null || path == null) {
            return Optional.empty();
        }

        final Uri uri = cr.insert(MediaStore.Audio.Media.getContentUri(
                MediaStore.VOLUME_EXTERNAL_PRIMARY), buildCv(file));
                MediaStore.VOLUME_EXTERNAL_PRIMARY), buildCv(path));
        if (uri == null) {
            Log.e(TAG, "Failed to insert " + file.getAbsolutePath());
            Log.e(TAG, "Failed to insert " + path.toAbsolutePath().toString());
            return Optional.empty();
        }

@@ -72,14 +71,16 @@ public final class AddRecordingToContentProviderTask implements Callable<Optiona
                return Optional.empty();
            }
            try (FileOutputStream oStream = new FileOutputStream(pfd.getFileDescriptor())) {
                Files.copy(file.toPath(), oStream);
                Files.copy(path, oStream);
            }

            final ContentValues values = new ContentValues();
            values.put(MediaStore.MediaColumns.IS_PENDING, 0);
            cr.update(uri, values, null, null);

            if (!file.delete()) {
            try {
                Files.delete(path);
            } catch (IOException e) {
                Log.w(TAG, "Failed to delete tmp file");
            }
            return Optional.of(uri.toString());
@@ -89,10 +90,11 @@ public final class AddRecordingToContentProviderTask implements Callable<Optiona
        }
    }

    private ContentValues buildCv(@NonNull File file) {
    private ContentValues buildCv(@NonNull Path path) {
        final String name = path.getFileName().toString();
        final ContentValues values = new ContentValues();
        values.put(MediaStore.Audio.Media.DISPLAY_NAME, file.getName());
        values.put(MediaStore.Audio.Media.TITLE, file.getName());
        values.put(MediaStore.Audio.Media.DISPLAY_NAME, name);
        values.put(MediaStore.Audio.Media.TITLE, name);
        values.put(MediaStore.Audio.Media.MIME_TYPE, mimeType);
        values.put(MediaStore.Audio.Media.ARTIST, ARTIST);
        values.put(MediaStore.Audio.Media.ALBUM, ALBUM);
Loading