Search code examples
javaandroidandroid-recyclerviewandroid-mediaplayermedia-player

MediaPlayer error trying to play audio in Android app


I'm doing a Simple Media Recorder/Player App and the recording part is successfully done. But now I'm having problems with the media player's part. Let me tell you the issues:

When I try to play a media file with the Media Player it says a preparing error like this:

java.io.IOException: Prepare failed.: status=0x1

How can I solve this problem?

My Three Classes:

-RecordFragment.java:

import android.Manifest;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.media.MediaRecorder;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.core.content.ContextCompat;
import androidx.core.content.res.ResourcesCompat;
import androidx.fragment.app.Fragment;

import android.os.Environment;
import android.os.SystemClock;
import android.provider.Settings;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Chronometer;
import android.widget.TextView;
import android.widget.Toast;

import com.airbnb.lottie.LottieAnimationView;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.venomapps.voicerecorder.R;
import com.venomapps.voicerecorder.Utils.Constants;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

public class RecordFragment extends Fragment {

    private TextView textViewInformation;
    private FloatingActionButton floatingActionButtonStartRecording;
    private FloatingActionButton floatingActionButtonFinishRecording;
    private FloatingActionButton floatingActionButtonCancelRecording;
    private int recordingStatus = 0;
    private String fileName = "";
    private Context context;
    String[] permissions = {Manifest.permission.RECORD_AUDIO, Manifest.permission.WRITE_EXTERNAL_STORAGE};
    private MediaRecorder mediaRecorder;
    private String outPutFilePath;
    private Chronometer chronometerRecord;
    private boolean running;
    private long pauseOffset;
    private LottieAnimationView lottieAnimationViewVoice;

    public RecordFragment() {
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_record, container, false);
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        context = getActivity();
        bindUI(view);
        setListeners();
    }

    private void bindUI(View view) {
        textViewInformation = view.findViewById(R.id.textViewInformation);
        floatingActionButtonStartRecording = view.findViewById(R.id.floatingActionButtonStartRecording);
        floatingActionButtonFinishRecording = view.findViewById(R.id.floatingActionButtonFinishRecording);
        floatingActionButtonCancelRecording = view.findViewById(R.id.floatingActionButtonCancelRecording);
        chronometerRecord = view.findViewById(R.id.chronometerRecord);
        lottieAnimationViewVoice = view.findViewById(R.id.lottieAnimationViewVoice);
    }

    private void setListeners() {
        floatingActionButtonStartRecording.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (ContextCompat.checkSelfPermission(context,
                        Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED && ContextCompat.checkSelfPermission(context,
                        Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED) {
                    switch (recordingStatus) {
                        case 0:
                            startRecording();
                            break;
                        case 1:
                            if (Build.VERSION.SDK_INT >= 24) {
                                pauseRecording();
                            } else {
                                finishRecording();
                            }
                            break;
                        case 2:
                            resumeRecording();
                        case 3:
                            break;
                    }
                } else {
                    askPermissions();
                }
            }
        });
        floatingActionButtonFinishRecording.setOnClickListener(new View.OnClickListener() {
            @SuppressLint("SetTextI18n")
            @Override
            public void onClick(View view) {
                if (recordingStatus == 1 || recordingStatus == 2) {
                    finishRecording();
                } else {
                    Toast.makeText(getActivity(), getString(R.string.not_recording), Toast.LENGTH_SHORT).show();
                }
            }
        });
        floatingActionButtonCancelRecording.setOnClickListener(new View.OnClickListener() {
            @SuppressLint("SetTextI18n")
            @Override
            public void onClick(View view) {
                if (recordingStatus == 1 || recordingStatus == 2) {
                    cancelRecording();
                } else {
                    Toast.makeText(getActivity(), getString(R.string.not_recording), Toast.LENGTH_SHORT).show();
                }
            }
        });
        chronometerRecord.setOnChronometerTickListener(new Chronometer.OnChronometerTickListener() {
            @Override
            public void onChronometerTick(Chronometer chronometer) {
                long time = SystemClock.elapsedRealtime() - chronometer.getBase();
                int h = (int) (time / 3600000);
                int m = (int) (time - h * 3600000) / 60000;
                int s = (int) (time - h * 3600000 - m * 60000) / 1000;
                String t = (h < 10 ? "0" + h : h) + ":" + (m < 10 ? "0" + m : m) + ":" + (s < 10 ? "0" + s : s);
                chronometer.setText(t);
            }
        });
    }

    @SuppressLint("SetTextI18n")
    private void startRecording() {
        String basePath = Environment.getExternalStorageDirectory().toString();
        String date = getCurrentDateFormatted();
        String myDirectory = "Voice Recorder";
        fileName = getString(R.string.recording_file) + date;
        fileName = fileName.replace(" ", "");
        fileName = fileName.replace("|", "");
        fileName = fileName + ".mp3";
        outPutFilePath = basePath + File.separator + myDirectory + File.separator + fileName;
        String filePath = basePath + File.separator + myDirectory;
        File newFolder = new File(filePath);
        if (!newFolder.exists()) {
            boolean createFolder = newFolder.mkdirs();
            if (createFolder) {
                Log.d("VOICE_RECORDER", "Created folder successfully!");
            }
        }
        recordingStatus = 1;
        mediaRecorder = new MediaRecorder();
        if (Build.VERSION.SDK_INT >= 24) {
            floatingActionButtonStartRecording.setImageDrawable(ResourcesCompat.getDrawable(getResources(), R.drawable.ic_pause_orange, null));
        } else {
            floatingActionButtonStartRecording.setImageDrawable(ResourcesCompat.getDrawable(getResources(), R.drawable.ic_stop_red, null));
        }
        textViewInformation.setText(getString(R.string.recording));
        lottieAnimationViewVoice.playAnimation();
        lottieAnimationViewVoice.setVisibility(View.VISIBLE);
        mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
        mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
        mediaRecorder.setOutputFile(outPutFilePath);
        mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
        mediaRecorder.setAudioEncodingBitRate(16 * 44100);
        mediaRecorder.setAudioSamplingRate(44100);
        try {
            mediaRecorder.prepare();
            mediaRecorder.start();
            if (!running) {
                chronometerRecord.setVisibility(View.VISIBLE);
                chronometerRecord.setBase(SystemClock.elapsedRealtime());
                chronometerRecord.start();
                running = true;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void pauseRecording() {
        if (Build.VERSION.SDK_INT >= 24) {
            mediaRecorder.pause();
        }
        if (running) {
            chronometerRecord.stop();
            pauseOffset = SystemClock.elapsedRealtime() - chronometerRecord.getBase();
            running = false;
        }
        lottieAnimationViewVoice.cancelAnimation();
        lottieAnimationViewVoice.setFrame(0);
        lottieAnimationViewVoice.setVisibility(View.INVISIBLE);
        recordingStatus = 2;
        floatingActionButtonStartRecording.setImageDrawable(ResourcesCompat.getDrawable(getResources(), R.drawable.ic_play_green, null));
        textViewInformation.setText(getString(R.string.tap_to_resume));
        Toast.makeText(context, getString(R.string.paused), Toast.LENGTH_SHORT).show();
    }

    private void resumeRecording() {
        if (Build.VERSION.SDK_INT >= 24) {
            mediaRecorder.resume();
        }
        chronometerRecord.setBase(SystemClock.elapsedRealtime() - pauseOffset);
        chronometerRecord.start();
        lottieAnimationViewVoice.playAnimation();
        lottieAnimationViewVoice.setVisibility(View.VISIBLE);
        recordingStatus = 1;
        floatingActionButtonStartRecording.setImageDrawable(ResourcesCompat.getDrawable(getResources(), R.drawable.ic_pause_orange, null));
        textViewInformation.setText(getString(R.string.recording));
        Toast.makeText(context, getString(R.string.resume), Toast.LENGTH_SHORT).show();
    }

    @SuppressLint("SetTextI18n")
    private void finishRecording() {
        chronometerRecord.setVisibility(View.INVISIBLE);
        chronometerRecord.stop();
        chronometerRecord.setBase(SystemClock.elapsedRealtime());
        pauseOffset = 0;
        mediaRecorder.stop();
        mediaRecorder = null;
        recordingStatus = 3;
        floatingActionButtonStartRecording.setImageDrawable(ResourcesCompat.getDrawable(getResources(), R.drawable.ic_app, null));
        Toast.makeText(context, getString(R.string.saved) + " " + fileName, Toast.LENGTH_LONG).show();
        textViewInformation.setText(getString(R.string.tap_to_record));
        lottieAnimationViewVoice.cancelAnimation();
        lottieAnimationViewVoice.setFrame(0);
        lottieAnimationViewVoice.setVisibility(View.INVISIBLE);
        recordingStatus = 0;
    }

    @SuppressLint("SetTextI18n")
    private void cancelRecording() {
        chronometerRecord.setVisibility(View.INVISIBLE);
        chronometerRecord.stop();
        chronometerRecord.setBase(SystemClock.elapsedRealtime());
        pauseOffset = 0;
        try {
            mediaRecorder.stop();
        } catch (RuntimeException e) {
            e.printStackTrace();
            mediaRecorder = null;
            mediaRecorder = new MediaRecorder();
        } finally {
            if (mediaRecorder != null) {
                mediaRecorder = null;
            }
        }
        File file = new File(outPutFilePath);
        if (file.exists()) {
            boolean deleted = file.delete();
            if (deleted) {
                Log.d("Voice Recorder", "Deleted file successfully!");
            }
        }
        recordingStatus = 3;
        floatingActionButtonStartRecording.setImageDrawable(ResourcesCompat.getDrawable(getResources(), R.drawable.ic_app, null));
        Toast.makeText(context, getString(R.string.cancelled) + " " + fileName, Toast.LENGTH_LONG).show();
        textViewInformation.setText(getString(R.string.tap_to_record));
        lottieAnimationViewVoice.cancelAnimation();
        lottieAnimationViewVoice.setFrame(0);
        lottieAnimationViewVoice.setVisibility(View.INVISIBLE);
        recordingStatus = 0;
    }

    private String getCurrentDateFormatted() {
        return new SimpleDateFormat("dd-MM-yy|hh:mm:ss", Locale.getDefault()).format(new Date());
    }

    private void askPermissions() {
        if (ContextCompat.checkSelfPermission(context,
                Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(context,
                Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
            assert getParentFragment() != null;
            requestPermissions(permissions, Constants.RECORD_AUDIO_AND_WRITE_EXTERNAL_STORAGE_PERMISSION_REQUEST_CODE);
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull final String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (ContextCompat.checkSelfPermission(context,
                Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED && ContextCompat.checkSelfPermission(context,
                Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED) {
            Toast.makeText(context, getString(R.string.permission_granted), Toast.LENGTH_SHORT).show();
        } else {
            AlertDialog.Builder builder = new AlertDialog.Builder(context);
            builder.setMessage(getString(R.string.no_read_permission))
                    .setPositiveButton(getString(R.string.ok), new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialogInterface, int i) {
                            dialogInterface.dismiss();
                            if (ContextCompat.checkSelfPermission(context,
                                    Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(context,
                                    Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
                                requestPermissions(permissions, Constants.RECORD_AUDIO_AND_WRITE_EXTERNAL_STORAGE_PERMISSION_REQUEST_CODE);
                            }
                        }
                    }).setNegativeButton(getString(R.string.go_to_settings), new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    Intent intent = new Intent();
                    intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
                    Uri uri = Uri.fromParts("package", "com.venomapps.voicerecorder", null);
                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
                    intent.setData(uri);
                    context.startActivity(intent);
                    requireActivity().finish();
                }
            });
            builder.create();
            builder.show();
        }
    }
}

PlaylistFragment.java:

import android.content.Context;
import android.media.AudioAttributes;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import android.os.Environment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import com.google.android.material.bottomsheet.BottomSheetBehavior;
import com.venomapps.voicerecorder.Adapters.PlaylistAdapter;
import com.venomapps.voicerecorder.R;

import java.io.File;
import java.io.IOException;

public class PlaylistFragment extends Fragment implements  PlaylistAdapter.onItemListClick {

    private BottomSheetBehavior bottomSheetBehavior;
    private RecyclerView recyclerViewPlaylist;
    private File[] files;
    private PlaylistAdapter playlistAdapter;
    private MediaPlayer mediaPlayer = null;
    private boolean isPlaying = false;
    private File fileToPlay;

    public PlaylistFragment() {
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getFiles();
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_playlist_item_list, container, false);

        // Set the adapter
        if (view instanceof RecyclerView) {
            Context context = view.getContext();
            RecyclerView recyclerView = (RecyclerView) view;
            LinearLayoutManager linearLayoutManager = new LinearLayoutManager(context);
            recyclerView.setLayoutManager(linearLayoutManager);
        }
        return view;
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        bindUI(view);
        setListeners();
        setAdapter();
    }

    private void bindUI(View view) {
        ConstraintLayout constraintLayoutMediaPlayer = view.findViewById(R.id.constraintLayoutMediaPlayer);
        bottomSheetBehavior = BottomSheetBehavior.from(constraintLayoutMediaPlayer);
        recyclerViewPlaylist = view.findViewById(R.id.recyclerViewPlaylist);
    }

    private void setListeners() {
        bottomSheetBehavior.addBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
            @Override
            public void onStateChanged(@NonNull View bottomSheet, int newState) {
                if (newState == BottomSheetBehavior.STATE_HIDDEN) {
                    bottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
                }
            }

            @Override
            public void onSlide(@NonNull View bottomSheet, float slideOffset) {

            }
        });
    }

    private void getFiles() {
        String path = Environment.getExternalStorageDirectory().toString() + File.separator + "Voice Recorder";
        File directory = new File(path);
        files = directory.listFiles();
    }

    private void setAdapter() {
        playlistAdapter = new PlaylistAdapter(files, this);
        recyclerViewPlaylist.setHasFixedSize(true);
        recyclerViewPlaylist.setLayoutManager(new LinearLayoutManager(getContext()));
        recyclerViewPlaylist.setAdapter(playlistAdapter);
    }

    @Override
    public void onClickListener(File file, int position) throws IOException {
        if(isPlaying){
            stopAudio();
            playAudio(fileToPlay);
        }else{
            fileToPlay = file;
            playAudio(fileToPlay);
        }
    }

    private void playAudio(File fileToPlay) {
        mediaPlayer = new MediaPlayer();
        try {
            mediaPlayer.setDataSource(fileToPlay.getAbsolutePath());
            mediaPlayer.prepare();
            mediaPlayer.start();
        }catch (Exception e){
            e.printStackTrace();
        }

        isPlaying = true;
    }

    private void stopAudio(){
        isPlaying = false;
    }
}

-PlaylistAdapter.java:

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.venomapps.voicerecorder.Utils.TimeAgo;
import com.venomapps.voicerecorder.R;

import java.io.File;
import java.io.IOException;

public class PlaylistAdapter extends RecyclerView.Adapter<PlaylistAdapter.PlaylistViewHolder> {

    private static File[] files;
    private TimeAgo timeAgo;
    private Context context;

    private static onItemListClick onItemListClick;

    public PlaylistAdapter(File[] files, onItemListClick onItemListClick) {
        PlaylistAdapter.files = files;
        PlaylistAdapter.onItemListClick = onItemListClick;
    }

    @NonNull
    @Override
    public PlaylistViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.fragment_playlist_item, parent, false);
        context = parent.getContext();
        timeAgo = new TimeAgo();
        return new PlaylistViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull PlaylistViewHolder holder, int position) {
        holder.textViewPlaylistFileName.setText(files[position].getName());
        holder.textViewPlaylistStats.setText(timeAgo.getTimeAgo(files[position].lastModified(), context));
        if(position == getItemCount() - 1){
            holder.playlistSeparator.setVisibility(View.INVISIBLE);
        }
    }

    @Override
    public int getItemCount() {
        return files.length;
    }

    public static class PlaylistViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
        private final TextView textViewPlaylistFileName;
        private final TextView textViewPlaylistStats;
        private final View playlistSeparator;
        private final FloatingActionButton floatingActionButtonPlaylistPlay;
        private final ImageButton imageButtonPlaylistItem;

        public PlaylistViewHolder(@NonNull View itemView) {
            super(itemView);

            textViewPlaylistFileName = itemView.findViewById(R.id.textViewPlaylistFileName);
            textViewPlaylistStats = itemView.findViewById(R.id.textViewPlaylistStats);
            playlistSeparator = itemView.findViewById(R.id.playlistSeparator);
            floatingActionButtonPlaylistPlay = itemView.findViewById(R.id.floatingActionButtonPlaylistPlay);
            imageButtonPlaylistItem = itemView.findViewById(R.id.imageButtonPlaylistItem);

            floatingActionButtonPlaylistPlay.setOnClickListener(this);
        }

        @Override
        public void onClick(View v) {
            try {
                onItemListClick.onClickListener(files[getAdapterPosition()], getAdapterPosition());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public interface onItemListClick{
        void onClickListener(File file, int position) throws IOException;
    }
}

Solution

  • Firstly, I suggest you to post full error log, and only the code which create the problem (and not your entire project ...)

    There is 3 possibilities which can create your problem :

    1. File problem (path or file not exist).
    2. Wrong format (or not supported one).
    3. Not permission. Do file.setReadable(true); to fix this

    More informations here : https://stackoverflow.com/a/11977292/10952503