외부에서 AudioRecord 클래스를 사용하여 기록한 .wav 파일을 재생하려고합니다. 내 안드로이드 기기의 저장 공간. Play/Pause와 Stop의 두 가지 버튼이 있습니다. 다른 게시물을 읽었지만 문제를 해결할 수 없었습니다. 다음과 같이녹음 및 wav 파일 재생 : 오류 (1, -2147483648) 및 (-38, 0) (API 23 런타임 권한?)
내 코드는 다음과 같습니다
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에서이 오류가 발생했습니다. 앱에서 파일을 읽을 수있는 권한이 없기 때문에 오류 (1, -2147483648)가있을 수있는 몇 가지 게시물을 읽었습니다. 그러나, 나는 문제를 해결할 수 없었다. 내가 잘못 가고있는 곳이 어디인지, 아니면 API 23을 추가 할 필요가 있는지 모르겠습니다. mediaPlayer가 외부 저장소에서 파일을 읽으면서 런타임 권한과 관련 될 수 있습니까? 그렇다면 어디에서 허가해야합니까? 내가 그것을 전송하고 내 컴퓨터에서 재생할 때 wav 파일이 제대로 녹음되었습니다.
업데이트 : mediaRecord 클래스와 조건이 제대로 작동하는지 확인하기 위해 다른 wav 파일을 사용했습니다. 이제 문제는 앱이 wav를 읽을 수 없기 때문에 기록하고 저장하는 파일 일뿐입니다 (컴퓨터에서 정상적으로 재생할 수 있음). 나는 런타임 권한을 확인하지 않고 API 19에서 같은 방식으로 기록하고 있으므로 알아낼 수 없습니다.
업데이트 2 : 나는 데이터 소스를 재설정 정지 버튼 onClickListener
및 onCompletionListener
에 reset
메소드를 호출했다. 또한 컴퓨터에 기록 된 파일 중 하나를 복사하여 2016-07-10 22:39:40_Recording.wav
에서 blabla.wav
으로 이름을 바꾼 후 다시 넣습니다. 잘 했어. 하지만 비슷한 날짜 및 시간 이름 형식의 다른 유형의 파일은 읽을 수 있습니다. 문제가 이름과 관련된 것인지 확실하지 않습니다.
이 문제와 관련하여 도움을 받으실 수 있습니다!
메신저 확인이가 문제를 해결하는 것입니다,하지만 난'isPlaying'하고'isPaused'이 모두 false로 설정되어 buttonStop.setOnClickListener''에, 잠재적 인 버그를 발견했을 수도 있습니다. 살펴보기 –
재생/일시 중지를 누르면 오류가 발생합니다. isPlaying과 isPaused를 체크로 사용 했으므로 stop 버튼을 누르면 mediaPlayer가 멈추고 (위치 추적없이 일시 중지됨) 다음에 재생을 누르면 MediaPlayer가 처음부터 재생을 시작합니다. – skbrhmn
첫 번째 if 문을 확인할 수 있습니다.당신의 조건이 틀린 것, 나는'(! isPlaying &&! isPaused)'이 의심스러워 보입니다! 또한, 일부 로그 문을 던져서 응용 프로그램의 흐름을 확인하십시오. –