1

Ich versuche eine .wav-Datei abzuspielen, die ich mit AudioRecord Class von extern aufgenommen habe Speicher auf meinem Android-Gerät. Ich habe zwei Tasten Play/Pause und Stop. Ich habe die anderen SO-Posts gelesen, aber ich konnte mein Problem nicht lösen.WAV-Dateien aufnehmen und abspielen: Fehler (1, -2147483648) und (-38, 0) (API 23 Runtime Permission?)

Mein Code ist wie folgt:

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

Mein Code für Aufnahmetaste:

   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 

Rubrik:

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

Ich erhalte die folgende Fehlermeldung, wenn ich spiele drücken nach Auswählen einer der gerade aufgezeichneten Dateien:

 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) 

Ich weiß, dass die (-38,0) im Zusammenhang mit Zustand, aber ich habe Probleme, es zu beheben. Derselbe Code funktionierte gut für API 19, wirft diesen Fehler aber auf API 23. Ich habe in einigen SO-Posts gelesen, dass der Fehler (1, -2147483648) möglicherweise darauf zurückzuführen ist, dass die App nicht über die entsprechende Berechtigung zum Lesen der Datei verfügt. Ich konnte das Problem jedoch nicht lösen. Ich weiß nicht, wo ich falsch liege oder ob ich etwas für API 23 hinzufügen muss. Könnte das mit der Laufzeitberechtigung zu tun haben, während mediaPlayer die Datei aus dem externen Speicher liest? Wenn ja, wo soll ich um Erlaubnis bitten? Die WAV-Datei wurde korrekt aufgenommen, als ich sie übertragen und auf meinem Computer abgespielt habe.

UPDATE: Ich benutzte eine andere WAV-Datei, um zu überprüfen, ob die MediaRecord-Klasse und die Bedingungen ordnungsgemäß funktionierten, sie waren. Mir ist jetzt klar, dass das Problem nur die Dateien sind, die die App aufzeichnet und speichert, da WAV nicht gelesen werden kann (aber auf dem Computer gut abgespielt werden kann). Ich kann es nicht herausfinden, da ich den gleichen Weg auf API 19 aufzeichnete, ohne nach Laufzeitberechtigungen zu suchen.

UPDATE 2: Ich hatte die reset Methode auf der Stopp-Taste onClickListener und onCompletionListener rief Datenquelle zurück. Ich kopierte auch eine der aufgezeichneten Dateien auf meinem Computer und benannte sie von 2016-07-10 22:39:40_Recording.wav in blabla.wav um und legte sie zurück. Es hat gut gespielt. Aber ich kann immer noch andere Dateitypen mit dem ähnlichen Namenformat für Datum und Uhrzeit lesen. Nicht sicher, ob das Problem nur mit dem Namen zusammenhängt.

Jede Hilfe in Bezug auf dieses Problem wird geschätzt!

+0

im nicht sicher, dies wird Ihr Problem lösen, aber ich könnte einen potenziellen Fehler gefunden haben, in 'buttonStop.setOnClickListener' die' isPlaying' und 'isPaused' sind falsch beide gesetzt. schaue hinein –

+0

Ich bekomme die Fehler, wenn ich Play/Pause drücke. Ich benutzte isPlaying und isPause als Checks, also wird der mediaPlayer nach dem Drücken der Stop-Taste angehalten (pausiert, ohne die Position zu verfolgen), so dass der MediaPlayer beim nächsten Mal die Wiedergabe von Anfang an startet. – skbrhmn

+0

können Sie Ihre erste if-Anweisung überprüfen.Deine Bedingungen sehen falsch aus, ich meine '(! isPlaying &&! isPaused)' schau verdächtig! Werfen Sie auch einige Protokollanweisungen ein und überprüfen Sie den Ablauf der App. –

Antwort

0

Ich löste das Problem. Entfernen der Doppelpunkte im Namen der Datei behoben Fehler (1, -2147483648). Der MediaPlayer konnte die Dateien nicht erkennen und lesen. Das Ändern der Namen in ein anderes Format hat dieses Problem gelöst.

Fehler (-38, 0) wurde mit Zuständen in Verbindung gebracht und dauerte eine Weile, um herauszufinden, wo das Problem lag. Die State Diagram war eine große Hilfe. Der folgende Code funktioniert:

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

       } 
      } 
     });