1

Я пытаюсь воспроизвести WAV-файл, который я записал с использованием AudioRecord Class, из внешнего хранения на моем устройстве Android. У меня есть две кнопки Play/Pause и Stop. Я прочитал другие сообщения SO, но я не мог решить свою проблему.Запись, а затем воспроизведение файлов wav: ошибка (1, -2147483648) и (-38, 0) (API 23 Runtime Permission?)

Мой код выглядит следующим образом:

  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 

Заголовок:

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 был записан правильно, когда я передал его и воспроизвел его на своем компьютере.

UPDATE: Я использовал другой файл wav для проверки правильности работы класса mediaRecord и условий. Теперь я понимаю, что проблема заключается только в файлах, которые приложение записывает и сохраняет, поскольку wav не может быть прочитан (но может отлично воспроизводиться на компьютере). Я не могу понять, как я записывал то же самое на API 19, не проверяя разрешения на выполнение.

ОБНОВЛЕНИЕ 2: я должен был вызвать метод reset на кнопку остановки onClickListener и onCompletionListener для сброса источника данных. Я также скопировал один из записанных файлов на свой компьютер и переименовал его с 2016-07-10 22:39:40_Recording.wav в blabla.wav и положил его обратно. Он играл отлично. Но я все еще могу читать другие типы файлов с похожим форматом имени и даты. Не уверен, что проблема связана только с именем.

Любая помощь по этому вопросу будет оценена по достоинству!

+0

им не уверен, что это решит вашу проблему, но я мог бы найти потенциальную ошибку, в '' buttonStop.setOnClickListener' isPlaying' и 'isPaused' оба устанавливаются в ложь. загляните в него –

+0

Я получаю ошибки, когда нажимаю Play/Pause. Я использовал isPlaying и isPaused как проверки, поэтому после нажатия кнопки остановки MediaPlayer останавливается (приостанавливается без сохранения какой-либо позиции), поэтому при следующем нажатии на воспроизведение MediaPlayer начинает играть с самого начала. – skbrhmn

+0

Вы можете проверить свой первый оператор if.ваши условия выглядят некорректно, я имею в виду '(! isPlaying &&! isPaused)' выглядят подозрительно! Кроме того, бросьте несколько операторов журналов и проверьте поток приложения. –

ответ

0

Я решил проблему. Удаление двоеточий в имени файла, который разрешил ошибку (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); 

       } 
      } 
     });