录制然后播放wav文件:error (1, -2147483648) and (-38, 0) (API 23 Runtime Permission?)

Recording and then playing wav files: error (1, -2147483648) and (-38, 0) (API 23 Runtime Permission?)

我正在尝试播放我 android 设备上的外部存储中使用 AudioRecord Class 录制的 .wav 文件。我有两个按钮 Play/Pause 和停止。我阅读了其他 SO 帖子,但无法解决我的问题。

我的代码如下:

            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);
                    }
                }
            });

我的录制按钮代码:

                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);
    }

当我选择刚刚录制的其中一个文件后按下播放时出现以下错误:

      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)

我知道 (-38,0) 与状态有关,但我无法修复它。相同的代码在 API 19 上运行良好,但在 API 23 上抛出此错误。我在一些 SO 帖子上读到错误 (1, -2147483648) 可能是因为应用程序没有具有读取文件的适当权限,但是,我无法解决问题。我不知道我哪里出错了,或者我是否需要为 API 添加任何内容 23. 这可能与 mediaPlayer 从外部存储读取文件时的运行时权限有关吗?如果是这样,我应该在哪里请求许可。 wav文件在我传输并在我的电脑上播放时被正确记录。

更新: 我使用了另一个 wav 文件来检查 mediaRecord class 和条件是否正常工作,它们是。我现在意识到问题只是应用程序正在录制和保存为 wav 的文件无法读取(但可以在计算机上正常播放)。我无法弄清楚,因为我在 API 19 上以相同的方式录制,而没有检查运行时权限。

更新 2: 我必须在停止按钮 onClickListeneronCompletionListener 上调用 reset 方法来重置数据源。 我也将其中一个录音文件复制到我的电脑上,并将其从 2016-07-10 22:39:40_Recording.wav 重命名为 blabla.wav 并放回去。它打得很好。但我仍然可以读取具有类似日期和时间名称格式的其他类型的文件。不确定问题是否仅与名称有关。

任何有关此问题的帮助将不胜感激!

我解决了这个问题。删除文件名中的冒号解决了错误 (1, -2147483648)。 MediaPlayer 无法识别和读取文件。将名称更改为不同的格式解决了这个问题。

错误 (-38, 0) 与状态有关,需要一段时间才能找出问题所在。 State Diagram 帮了大忙。以下代码有效:

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);

                }
            }
        });