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!
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 –
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
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. –