HandlerThread audio recorder doesn't start recording after which a message has been sent to its handler

209 Views Asked by At

I'm trying to write a sound recorder app. The whole app consists of two components: Main Activity which only contains a fragment called RecordFragment, and RecordThread class in charge of recording the audio.

RecordThread is extended from HandlerThread.

The idea is that user presses a button and a handler which is attached to RecordThread looper sends an empty message to start recording. Then the thread is supposed to handle that message and start recording until the user presses the button again to stop the recording, which again handler sends another message (I think thread's message queue) to stop recording.

Problem #1: The RecordThread never starts recording or even handling the messages from queue.

Problem #2: How I'm suppose to handle messages in recordThread?

RecordThread.java

public class RecordThread extends HandlerThread {
    private final String TAG = "RecordThread";
    private final int RECORD_START = 1;
    private final int RECORD_STOP = 3;

    private MediaRecorder mRecorder;
    private String mFilePath = null;
    private String mFileName = null;
    private Handler mHandler;

    public RecordThread(String name) {
        super(name);
    }

    @Override
    protected void onLooperPrepared() {
        super.onLooperPrepared();

        mHandler = new Handler(getLooper()) {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                switch (msg.what) {
                    case RECORD_START:
                        startRecording();
                        Log.d(TAG, "Recording");
                        break;

                    case RECORD_STOP:
                        stopRecording();
                        Log.d(TAG, "Stopping");
                        break;
                }
            }
        };
    }

    // prepares the media recorder and starts recording
    private void startRecording() {
        seuUpFilePath();

        mRecorder = new MediaRecorder();
        mRecorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT);
        mRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
        mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
        mRecorder.setOutputFile(mFilePath);
        mRecorder.setAudioChannels(1);

        try {
            mRecorder.prepare();
            mRecorder.start();
        } catch (IOException e) {
            Log.e(TAG, "Error while preparing Media Recorder" + e.toString());
        }
    }

    /**
     * create file's name and path for storing it on external storage
     */
    private void seuUpFilePath() {
        // building file's name
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd-HH:mm:ss",
                new Locale("en", "IR"));

        Date date = Calendar.getInstance().getTime();

        String currentTime = dateFormat.format(date);
        mFileName = "Record" + currentTime + ".mp4";

        // creating file's path
        mFilePath = Environment.getExternalStorageDirectory().getAbsolutePath();
        mFilePath += "/Sound Recorder/" + mFileName;
        Log.d(TAG, "FilePath: " + mFilePath);
    }

    private void stopRecording() {
        mRecorder.stop();
        mRecorder.reset();
        mRecorder.release();
        mRecorder = null;
    }

    @RequiresApi(api = Build.VERSION_CODES.N)
    private void resumeRecorder() {
        mRecorder.resume();
    }

    @RequiresApi(api = Build.VERSION_CODES.N)
    private void pauseRecording() {
        mRecorder.pause();
    }


}

RecordFragment.java

public class RecordFragment extends Fragment {

    private static final String TAG = "RecordFragment";
    private final String THREAD_RECORDING = "recording thread";
    private final int RECORD_START = 1;
    private final int RECORD_STOP = 3;

    int count = 1;

    private FloatingActionButton mRecordFab;
    private boolean isRecording = false;
    private boolean paused = false;
    private RecordThread mRecordThread;
    private Handler mRecordHandler;
    private Chronometer mChronometer;
    private TextView mMessage;
    private long timeWhenPaused;


    public RecordFragment() {
        // Required empty public constructor
    }

    public static RecordFragment newInstance() {
        return new RecordFragment();
    }

    /**
     * getting reference to views and setting basic attributes
     */
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View view = inflater.inflate(R.layout.fragment_record, container, false);

        mChronometer = view.findViewById(R.id.chronometer);

        mMessage = view.findViewById(R.id.recording_status_tv);
        mMessage.setText("Tap the button to start recording");

        mRecordFab = view.findViewById(R.id.record_fab);

        return view;
    }

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        mChronometer.setOnChronometerTickListener(new Chronometer.OnChronometerTickListener() {
            @Override
            public void onChronometerTick(Chronometer chronometer) {
                switch (count) {
                    case 1:
                        mMessage.setText("Recording.");
                        count++;
                        break;

                    case 2:
                        mMessage.setText("Recording..");
                        count++;
                        break;

                    case 3:
                        mMessage.setText("Recording...");
                        count = 1;
                        break;
                }
            }
        });

        mRecordFab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                // stop recording
                if (isRecording) {
                    Log.d(TAG, "Stopping");
                    mRecordFab.setImageResource(R.drawable.ic_mic_white_36dp);
                    mChronometer.stop();
                    mChronometer.setBase(SystemClock.elapsedRealtime());
                    mMessage.setText("Tap the button to start recording");

                    mRecordHandler.sendEmptyMessage(RECORD_STOP);

                    Log.d(TAG, "thread state:" + mRecordThread.getState());
                    Log.d(TAG, "thread interrupted?: " + mRecordThread.isInterrupted());
                    Log.d(TAG, "thread is alive? " + mRecordThread.isAlive());

                    isRecording = false;
                }

                // start recording
                else {
                    // changing views attributes
                    mRecordFab.setImageResource(R.drawable.ic_media_stop);
                    mChronometer.setBase(SystemClock.elapsedRealtime());
                    mChronometer.start();

                    isRecording = true;

                    Log.d(TAG, "handler succeeded? " + mRecordHandler.sendEmptyMessage(RECORD_START));

                    Log.d(TAG, "Recording");
                    Log.d(TAG, "thread interrupted?: " + mRecordThread.isInterrupted());
                    Log.d(TAG, "thread state:" + mRecordThread.getState());
                    Log.d(TAG, "thread is alive? " + mRecordThread.isAlive());
                }
    }

    @Override
    public void onResume() {
        super.onResume();

        mRecordThread = new RecordThread(THREAD_RECORDING);
        mRecordThread.start();
        mRecordHandler = new Handler(mRecordThread.getLooper());
        mRecordHandler.sendEmptyMessage(RECORD_START);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        mRecordThread.quit();
    }
}

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RECORD_AUDIO"/>

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">
    <activity android:name=".MainActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
</application>

0

There are 0 best solutions below