1

I am trying to play a .wav file, that I recorded using AudioRecord Class, from external storage on my android device. I have two buttons Play/Pause and Stop. I read the other SO posts but I could not solve my problem.

My code is as follows:

            final MediaPlayer m = new MediaPlayer();
        final Button buttonStop = (Button) mView.findViewById(R.id.btnStop);
        buttonStop.setEnabled(false);


        final Button buttonPlay = (Button) mView.findViewById(R.id.btnPlay);

        buttonPlay.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                String fileName = getFileSelected();
                Log.i("Info: ", "Play pressed");
                    if ( (!isPlaying && !isPaused) && (getFileSelected().endsWith(".3gp") || getFileSelected().endsWith(".wav"))) {
                        isPlaying = true;
                        isPaused = false;
                        try {
                            m.setDataSource(getActivity().getApplicationContext().getExternalFilesDir(null).toString() + File.separator + fileName);
                        } catch (IOException e) {
                            e.printStackTrace();
                        } catch (IllegalArgumentException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        } catch (IllegalStateException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                        Log.i("Info: ", "DataSource set");

                        try {
                            m.prepare();
                        } catch (IllegalStateException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }


       Log.i("Info: ", "Media Player prepare");
//                            m.setOnPreparedListener(new OnPreparedListener() {
//                                @Override
//                                public void onPrepared(MediaPlayer mediaPlayer) {
//                                    m.seekTo(0);
//                                    m.start();
//                                }
//                            });
                            buttonPlay.setText("Pause");
                            Log.i("Info: ", "Button Set to Pause");
                            m.seekTo(0);
                            Log.i("Info: ", "SeektoZero");
                            m.start();
                            Log.i("Info: ", "MesiaPlayer Started");
                            buttonStop.setEnabled(true);
                            Log.i("Info: ", "Stop Button enabled");
                            Toast.makeText(getActivity().getApplicationContext(), "Playing audio", Toast.LENGTH_LONG).show();
                            m.setOnCompletionListener(new OnCompletionListener() {
                                @Override
                                public void onCompletion(MediaPlayer mediaPlayer) {
                                    isPlaying = false;
                                    buttonPlay.setEnabled(true);
                                    buttonPlay.setText("Play Selected Recording");
                                    buttonStop.setEnabled(false);

                                }
                            });
                        }

                        //paused
                        else if (isPaused){
                            m.seekTo(songPos);
                            m.start();
                            buttonStop.setEnabled(true);
                            buttonPlay.setText("Pause");
                            isPaused = false;
                            isPlaying = true;

                        }

                        //isPlaying and not paused
                        else{
                            songPos = m.getCurrentPosition();
                            m.pause();
                            isPaused = true;
                            isPlaying = false;
                            buttonPlay.setText("Play");
                            buttonStop.setEnabled(false);

                        }
                }
            });

            buttonStop.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    if (isPlaying && !isPaused){
                        isPlaying = false;
                        isPaused = false;
                        m.pause();
                        buttonPlay.setEnabled(true);
                        buttonPlay.setText("Play Selected Recording");
                        buttonStop.setEnabled(false);
                    }
                }
            });

My code for record button:

                btnStart.setOnClickListener(new View.OnClickListener(){
                @Override
                public void onClick(View view) {

                    if (!isRecordingCheckButton) {

                        startRecording();

                        isRecordingCheckButton = true;
                        setButtonLabel(R.id.btnStart, "Stop Recording");
Toast.makeText(getActivity().getApplicationContext(), "Recording started", Toast.LENGTH_LONG).show();
                    }
                    else{
                        stopRecording();
                    }
                }
private void startRecording(){

            int hasRecordAudioPermission = ContextCompat.checkSelfPermission(getActivity().getApplicationContext(), permission.RECORD_AUDIO);

            if (hasRecordAudioPermission != PackageManager.PERMISSION_GRANTED) {
                if (!shouldShowRequestPermissionRationale(permission.RECORD_AUDIO)) {
                    showMessageOKCancel("You must give permission to write to storage.",
                            new DialogInterface.OnClickListener() {
                                @Override
                                public void onClick(DialogInterface dialog, int which) {
                                    requestPermissions(new String[] {permission.RECORD_AUDIO},
                                            111);
                                }
                            });
                    return;
                }

                requestPermissions(new String[] {permission.RECORD_AUDIO},
                        111);
                return;
            }


            recorder = new AudioRecord(AudioSource.VOICE_RECOGNITION,
                    RECORDER_SAMPLERATE, RECORDER_CHANNELS,RECORDER_AUDIO_ENCODING, bufferSize);

            int i = recorder.getState();
            if(i==1)
                recorder.startRecording();

            isRecording = true;

            recordingThread = new Thread(new Runnable() {

                @Override
                public void run() {
                    writeAudioDataToFile();
                }
            },"AudioRecorder Thread");

            recordingThread.start();
        }

        private void writeAudioDataToFile(){


            int hasWriteFilePermission = ContextCompat.checkSelfPermission(getActivity().getApplicationContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE);

            if (hasWriteFilePermission != PackageManager.PERMISSION_GRANTED) {
                if (!shouldShowRequestPermissionRationale(permission.WRITE_EXTERNAL_STORAGE)) {
                    showMessageOKCancel("You must give permission to write to storage.",
                            new DialogInterface.OnClickListener() {
                                @Override
                                public void onClick(DialogInterface dialog, int which) {
                                    requestPermissions(new String[] {permission.WRITE_EXTERNAL_STORAGE},
                                            111);
                                }
                            });
                    return;
                }

                requestPermissions(new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE},
                        111);
                return;
            }
            byte data[] = new byte[bufferSize];
            String filename = getTempFilename();
            FileOutputStream os = null;

            try {
                os = new FileOutputStream(filename);
            } catch (FileNotFoundException e) {
// TODO Auto-generated catch block
                e.printStackTrace();
            }

            int read = 0;

            if(null != os){
                while(isRecording){
                    read = recorder.read(data, 0, bufferSize);

                    if(AudioRecord.ERROR_INVALID_OPERATION != read){
                        try {
                            os.write(data);
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }

                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

Wave File

Header:

private void WriteWaveFileHeader(

        FileOutputStream out, long totalAudioLen,
        long totalDataLen, long longSampleRate, int channels,
        long byteRate) throws IOException {

        byte[] header = new byte[44];

        header[0] = 'R'; // RIFF/WAVE header
        header[1] = 'I';
        header[2] = 'F';
        header[3] = 'F';
        header[4] = (byte) (totalDataLen & 0xff);
        header[5] = (byte) ((totalDataLen >> 8) & 0xff);
        header[6] = (byte) ((totalDataLen >> 16) & 0xff);
        header[7] = (byte) ((totalDataLen >> 24) & 0xff);
        header[8] = 'W';
        header[9] = 'A';
        header[10] = 'V';
        header[11] = 'E';
        header[12] = 'f'; // 'fmt ' chunk
        header[13] = 'm';
        header[14] = 't';
        header[15] = ' ';
        header[16] = 16; // 4 bytes: size of 'fmt ' chunk
        header[17] = 0;
        header[18] = 0;
        header[19] = 0;
        header[20] = 1; // format = 1
        header[21] = 0;
        header[22] = (byte) channels;
        header[23] = 0;
        header[24] = (byte) (longSampleRate & 0xff);
        header[25] = (byte) ((longSampleRate >> 8) & 0xff);
        header[26] = (byte) ((longSampleRate >> 16) & 0xff);
        header[27] = (byte) ((longSampleRate >> 24) & 0xff);
        header[28] = (byte) (byteRate & 0xff);
        header[29] = (byte) ((byteRate >> 8) & 0xff);
        header[30] = (byte) ((byteRate >> 16) & 0xff);
        header[31] = (byte) ((byteRate >> 24) & 0xff);
        header[32] = (byte) (2 * 16 / 8); // block align
        header[33] = 0;
        header[34] = RECORDER_BPP; // bits per sample
        header[35] = 0;
        header[36] = 'd';
        header[37] = 'a';
        header[38] = 't';
        header[39] = 'a';
        header[40] = (byte) (totalAudioLen & 0xff);
        header[41] = (byte) ((totalAudioLen >> 8) & 0xff);
        header[42] = (byte) ((totalAudioLen >> 16) & 0xff);
        header[43] = (byte) ((totalAudioLen >> 24) & 0xff);

        out.write(header, 0, 44);
    }

I am getting the following error when I press play after selecting one of the files I just recorded:

      07-11 02:59:56.571 20450-20450/com.ibm.watson.developer_cloud.android.examples I/Info:: Media Player prepare
07-11 02:59:56.581 20450-20450/com.ibm.watson.developer_cloud.android.examples I/Info:: Button Set to Pause
07-11 02:59:56.581 20450-20450/com.ibm.watson.developer_cloud.android.examples E/MediaPlayer: Attempt to perform seekTo in wrong state: mPlayer=0x7f6521e3c0, mCurrentState=0
07-11 02:59:56.581 20450-20450/com.ibm.watson.developer_cloud.android.examples E/MediaPlayer: error (-38, 0)
07-11 02:59:56.581 20450-20450/com.ibm.watson.developer_cloud.android.examples I/Info:: SeektoZero
07-11 02:59:56.581 20450-20450/com.ibm.watson.developer_cloud.android.examples E/MediaPlayer: start called in state 0
07-11 02:59:56.581 20450-20450/com.ibm.watson.developer_cloud.android.examples E/MediaPlayer: error (-38, 0)
07-11 02:59:56.581 20450-20450/com.ibm.watson.developer_cloud.android.examples I/Info:: MesiaPlayer Started
07-11 02:59:56.581 20450-20450/com.ibm.watson.developer_cloud.android.examples I/Info:: Stop Button enabled
07-11 02:59:56.611 20450-20450/com.ibm.watson.developer_cloud.android.examples I/MediaPlayer: send context aware event
07-11 02:59:56.611 20450-20450/com.ibm.watson.developer_cloud.android.examples I/MediaPlayer: sendBroadcast CONTEXT_AWARE_MUSIC_INFO - type(error) - id (261)
07-11 02:59:56.611 20450-20450/com.ibm.watson.developer_cloud.android.examples E/MediaPlayer: Error (-38,0)
07-11 02:59:56.621 20450-20450/com.ibm.watson.developer_cloud.android.examples E/MediaPlayer: Error (-38,0)
07-11 02:59:56.671 20450-20450/com.ibm.watson.developer_cloud.android.examples W/DisplayListCanvas: DisplayListCanvas is started on unbinded RenderNode (without mOwningView)

I know that the (-38,0) is related to state but I am having trouble fixing it. The same code was working fine on API 19 but is throwing this error on API 23. I read on a few SO posts that the error (1, -2147483648) may be because the app doesn't have proper permission to read the file, however, I could not solve the problem. I don't know where I am going wrong or if I need to add anything for API 23. Could this be related to runtime permission as mediaPlayer reads the file from external storage? If so, where should I request permission. The wav file was recorded properly as I transferred it and played it on my computer.

UPDATE: I used another wav file to check if the mediaRecord class and the conditions were working properly, they were. I now realize the problem is only the files that the app is recording and saving as wav cannot be read (but can be played fine on computer). I cannot figure it out as I was recording the same way on API 19 without checking for runtime permissions.

UPDATE 2: I had to call the reset method on the stop button onClickListener and onCompletionListener to reset data source. I also copied one of the recorded files on my computer and renamed it from 2016-07-10 22:39:40_Recording.wav to blabla.wav and put it back. It played fine. But I can still read other types of files with the similar date and time name format. Not sure if the problem is only with the name.

Any help regarding this issue will be appreciated!

skbrhmn
  • 1,124
  • 1
  • 14
  • 36
  • im not sure this will solve your problem, but i might have found a potential bug, in `buttonStop.setOnClickListener` the `isPlaying` and `isPaused` are both set to false. do look into it – hello_world Jul 11 '16 at 05:50
  • I am getting the errors when I press Play/Pause. I was using isPlaying and isPaused as checks, so once the stop button is pressed, the mediaPlayer is stopped (paused without keeping any track of position), so the next time play is pressed, MediaPlayer starts playing the from the beginning. – skbrhmn Jul 11 '16 at 06:16
  • can you check your first if statement. your conditions look incorrect, i mean `(!isPlaying && !isPaused)` look suspicious! Also, throw in some log statements and check the flow of the app. – hello_world Jul 11 '16 at 06:42
  • The conditions, though not most efficient, works as I have tested it on another device running API 19. I am getting these error after I set my compile and target sdk to 23. I have put in a few logs and updated the errors. I am not sure where the problem is. Even though the button text is set to Pause and the code is executed, the button text remains same. I am not sure if I should request runtime permissions for MediaPlayer. – skbrhmn Jul 11 '16 at 07:11
  • Hi, Issue is when you are asking for permission at that time also you are continue your code which need permission, so untill user grant permission you should not perform any other task, check my answer at this : http://stackoverflow.com/questions/37725699/issues-in-writing-files-to-sd-card-in-android-api-23marshmallow/37725902#37725902 – Vickyexpert Jul 11 '16 at 09:30
  • But you see files 'are' being written to storage and files 'are' being read from the storage (as I put an externally created file for testing which was played perfectly). Audio is also being recorded properly as I played the files on my computer. The only problem is I cannot play the files 'I' recorded in the app. These should not have happened if there was a problem with permissions, right? – skbrhmn Jul 11 '16 at 10:43

1 Answers1

0

I solved the problem. Removing the colons in the name of the file solved error (1, -2147483648). MediaPlayer was not able to recognize and read the files. Changing the names to a different format solved this problem.

Error (-38, 0) was related to states and took a while to figure out where the problem was. The State Diagram was a great help. The following code worked:

final MediaPlayer m = new MediaPlayer();
        final Button buttonStop = (Button) mView.findViewById(R.id.btnStop);
        buttonStop.setEnabled(false);


        final Button buttonPlay = (Button) mView.findViewById(R.id.btnPlay);

        buttonPlay.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                String fileName = getFileSelected();
                if(!fileName.endsWith(".3gp") && !fileName.endsWith(".wav")){

                }
                else if ( (!isPlaying && !isPaused)) {
                    isPlaying = true;
                    isPaused = false;

                    int hasReadFilesPermission = ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.READ_EXTERNAL_STORAGE);
                    if (hasReadFilesPermission != PackageManager.PERMISSION_GRANTED) {
                        if (!shouldShowRequestPermissionRationale(permission.READ_EXTERNAL_STORAGE)) {
                            showMessageOKCancel("You must give permission to read from storage.",
                                    new DialogInterface.OnClickListener() {
                                        @Override
                                        public void onClick(DialogInterface dialog, int which) {
                                            requestPermissions(new String[] {permission.READ_EXTERNAL_STORAGE},
                                                    223);
                                        }
                                    });
                            return ;
                        }

                        requestPermissions(new String[] {permission.READ_EXTERNAL_STORAGE},
                                223);
                        return ;
                    }
                    fileName = getFileSelected();
                    displayResult(getActivity().getApplicationContext().getExternalFilesDir(null).toString() + File.separator + fileName);
                    try {
                        m.setDataSource(getActivity().getApplicationContext().getExternalFilesDir(null).toString() + File.separator + fileName);
                    } catch (IOException e) {
                        e.printStackTrace();
                    } catch (IllegalArgumentException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    } catch (IllegalStateException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    try {
                        m.prepare();
                    } catch (IllegalStateException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    buttonPlay.setText("Pause");
                    m.seekTo(0);
                    m.start();
                    buttonStop.setEnabled(true);
                    Toast.makeText(getActivity().getApplicationContext(), "Playing audio", Toast.LENGTH_LONG).show();
                    m.setOnCompletionListener(new OnCompletionListener() {
                        @Override
                        public void onCompletion(MediaPlayer mediaPlayer) {
                            m.reset();
                            isPlaying = false;
                            isPaused = false;
                            buttonPlay.setEnabled(true);
                            buttonPlay.setText("Play Selected Recording");
                            buttonStop.setEnabled(false);

                        }
                    });
                }

                //paused
                else if (isPaused){
                    m.seekTo(songPos);
                    m.start();
                    buttonStop.setEnabled(true);
                    buttonPlay.setText("Pause");
                    isPaused = false;
                    isPlaying = true;

                }

                //isPlaying and not paused
                else{
                    songPos = m.getCurrentPosition();
                    m.pause();
                    isPaused = true;
                    isPlaying = false;
                    buttonPlay.setText("Play");
                    buttonStop.setEnabled(false);

                }
            }
        });
skbrhmn
  • 1,124
  • 1
  • 14
  • 36