问题
I know there are a few of these on SO already but none of them really were able to help my issue, but when I am running the code and start recording audio and then press my stop button it always fails because it is in the wrong state. I am not sure how I would go about fixing my states for this.
Here is my MainActivity.java code:
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.MediaRecorder;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.view.View;
import android.widget.Button;
import android.widget.RadioGroup;
import android.widget.Toast;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import java.io.IOException;
import static android.Manifest.permission.RECORD_AUDIO;
import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
public class MainActivity extends AppCompatActivity {
Button buttonStartRecording, buttonStopRecording, buttonPlayLastRecordAudio,
buttonStopPlayingRecording;
String AudioSavePathInDevice = null;
MediaRecorder mediaRecorder;
public static final int RequestPermissionCode = 1;
MediaPlayer mediaPlayer;
AudioManager audioManager;
boolean isAudioPlayInSameDevice = true;
// AudioRouter audioRouter;
RadioGroup mRadioGroup;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
buttonStartRecording = (Button) findViewById(R.id.start_recording);
buttonStopRecording = (Button) findViewById(R.id.stop_rec);
buttonPlayLastRecordAudio = (Button) findViewById(R.id.play_last_rec);
buttonStopPlayingRecording = (Button) findViewById(R.id.stop_playing_btn);
// mRadioGroup = (RadioGroup) findViewById(R.id.radioGroup);
buttonStopRecording.setEnabled(false);
buttonPlayLastRecordAudio.setEnabled(false);
buttonStopPlayingRecording.setEnabled(false);
buttonStartRecording.setOnClickListener(new View.OnClickListener() {
@RequiresApi(api = Build.VERSION_CODES.O)
@Override
public void onClick(View view) {
// Check audio permission
if (checkPermission()) {
AudioSavePathInDevice =
Environment.getExternalStorageDirectory().getAbsolutePath() + "/" + "AudioRecording.3gp";
// Start Media recorder
MediaRecorderReady();
try {
mediaRecorder.prepare();
mediaRecorder.start();
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
buttonStartRecording.setEnabled(false);
buttonStopRecording.setEnabled(true);
Toast.makeText(MainActivity.this, "Recording started",
Toast.LENGTH_LONG).show();
} else {
requestPermission();
}
}
});
buttonStopRecording.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
buttonStopRecording.setEnabled(false);
buttonPlayLastRecordAudio.setEnabled(true);
buttonStartRecording.setEnabled(true);
buttonStopPlayingRecording.setEnabled(false);
// Stop Media recorder
mediaRecorder.stop();
Toast.makeText(MainActivity.this, "Recording Completed",
Toast.LENGTH_LONG).show();
}
});
buttonPlayLastRecordAudio.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) throws IllegalArgumentException,
SecurityException, IllegalStateException {
int selectedId = 1;
if (selectedId == 1) {
isAudioPlayInSameDevice = true;
} else {
isAudioPlayInSameDevice = false;
}
// if you want to play audio on your Mobile speaker then set isAudioPlayInSameDevice true
// and if you want to play audio to connected device then set isAudioPlayInSameDevice false.
if (isAudioPlayInSameDevice) {
audioManager.setMode(audioManager.STREAM_MUSIC);
audioManager.setSpeakerphoneOn(true);
} else {
audioManager.setSpeakerphoneOn(false);
audioManager.setMode(audioManager.MODE_NORMAL);
}
audioManager.setBluetoothScoOn(false);
audioManager.stopBluetoothSco();
buttonStopRecording.setEnabled(false);
buttonStartRecording.setEnabled(false);
buttonStopPlayingRecording.setEnabled(true);
mediaPlayer = new MediaPlayer();
try {
// Start media player
System.out.println("Recorded Audio Path-" + AudioSavePathInDevice);
mediaPlayer.setDataSource(AudioSavePathInDevice);
if (isAudioPlayInSameDevice) {
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
}
mediaPlayer.prepare();
mediaPlayer.start();
} catch (IOException e) {
e.printStackTrace();
}
Toast.makeText(MainActivity.this, "Recording Playing",
Toast.LENGTH_LONG).show();
}
});
buttonStopPlayingRecording.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
buttonStopRecording.setEnabled(false);
buttonStartRecording.setEnabled(true);
buttonStopPlayingRecording.setEnabled(false);
buttonPlayLastRecordAudio.setEnabled(true);
if (mediaPlayer != null) {
// Stop Media Player
mediaPlayer.stop();
mediaPlayer.release();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
MediaRecorderReady();
}
}
}
});
}
private BroadcastReceiver mBluetoothScoReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
int state = intent.getIntExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, -1);
System.out.println("ANDROID Audio SCO state: " + state);
if (AudioManager.SCO_AUDIO_STATE_CONNECTED == state) {
/*
* Now the connection has been established to the bluetooth device.
* Record audio or whatever (on another thread).With AudioRecord you can record with an object created like this:
* new AudioRecord(MediaRecorder.AudioSource.MIC, 8000, AudioFormat.CHANNEL_CONFIGURATION_MONO,
* AudioFormat.ENCODING_PCM_16BIT, audioBufferSize);
*
* After finishing, don't forget to unregister this receiver and
* to stop the bluetooth connection with am.stopBluetoothSco();
*/
}
}
};
@RequiresApi(api = Build.VERSION_CODES.O)
public void MediaRecorderReady() {
mediaRecorder = new MediaRecorder();
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_2_TS);
mediaRecorder.setAudioEncoder(MediaRecorder.OutputFormat.AMR_NB);
mediaRecorder.setOutputFile(AudioSavePathInDevice);
}
@Override
protected void onResume() {
super.onResume();
IntentFilter intentFilter = new IntentFilter(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED);
registerReceiver(mBluetoothScoReceiver, intentFilter);
audioManager = (AudioManager) getApplicationContext().getSystemService(getApplicationContext().AUDIO_SERVICE);
// Start Bluetooth SCO.
audioManager.setMode(audioManager.MODE_NORMAL);
audioManager.setBluetoothScoOn(true);
audioManager.startBluetoothSco();
// Stop Speaker.
audioManager.setSpeakerphoneOn(false);
}
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(mBluetoothScoReceiver);
// Stop Bluetooth SCO.
audioManager.stopBluetoothSco();
audioManager.setMode(audioManager.MODE_NORMAL);
audioManager.setBluetoothScoOn(false);
// Start Speaker.
audioManager.setSpeakerphoneOn(true);
}
private void requestPermission() {
ActivityCompat.requestPermissions(MainActivity.this, new
String[]{WRITE_EXTERNAL_STORAGE, RECORD_AUDIO}, RequestPermissionCode);
}
@Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
switch (requestCode) {
case RequestPermissionCode:
if (grantResults.length > 0) {
boolean StoragePermission = grantResults[0] ==
PackageManager.PERMISSION_GRANTED;
boolean RecordPermission = grantResults[1] ==
PackageManager.PERMISSION_GRANTED;
// if (StoragePermission && RecordPermission) {
// Toast.makeText(BluetoothAudioRecorder.this, "Permission Granted",
// Toast.LENGTH_LONG).show();
// } else {
// Toast.makeText(BluetoothAudioRecorder.this,"Permission Denied",Toast.LENGTH_LONG).show();
// }
}
break;
}
}
public boolean checkPermission() {
int result = ContextCompat.checkSelfPermission(getApplicationContext(),
WRITE_EXTERNAL_STORAGE);
int result1 = ContextCompat.checkSelfPermission(getApplicationContext(),
RECORD_AUDIO);
return result == PackageManager.PERMISSION_GRANTED &&
result1 == PackageManager.PERMISSION_GRANTED;
}
}
And then my logcat of when the error occurs:
2019-11-24 11:26:54.440 29627-29683/com.example.esense_application E/libc: Access denied finding property "vendor.gralloc.disable_ahardware_buffer"
2019-11-24 11:26:54.435 29627-29627/com.example.esense_application W/RenderThread: type=1400 audit(0.0:17779): avc: denied { read } for name="u:object_r:vendor_default_prop:s0" dev="tmpfs" ino=24699 scontext=u:r:untrusted_app:s0:c7,c257,c512,c768 tcontext=u:object_r:vendor_default_prop:s0 tclass=file permissive=0
2019-11-24 11:26:54.487 29627-29627/com.example.esense_application I/System.out: ANDROID Audio SCO state: 1
2019-11-24 11:26:54.487 29627-29627/com.example.esense_application I/System.out: ANDROID Audio SCO state: 2
2019-11-24 11:26:54.868 29627-29627/com.example.esense_application I/System.out: ANDROID Audio SCO state: 1
2019-11-24 11:26:57.769 29627-29627/com.example.esense_application I/System.out: ANDROID Audio SCO state: 1
2019-11-24 11:27:00.647 29627-29627/com.example.esense_application W/System.err: java.io.FileNotFoundException: /storage/emulated/0/AudioRecording.3gp: open failed: EACCES (Permission denied)
2019-11-24 11:27:00.647 29627-29627/com.example.esense_application W/System.err: at libcore.io.IoBridge.open(IoBridge.java:496)
2019-11-24 11:27:00.647 29627-29627/com.example.esense_application W/System.err: at java.io.RandomAccessFile.<init>(RandomAccessFile.java:289)
2019-11-24 11:27:00.647 29627-29627/com.example.esense_application W/System.err: at java.io.RandomAccessFile.<init>(RandomAccessFile.java:152)
2019-11-24 11:27:00.647 29627-29627/com.example.esense_application W/System.err: at android.media.MediaRecorder.prepare(MediaRecorder.java:1046)
2019-11-24 11:27:00.647 29627-29627/com.example.esense_application W/System.err: at com.example.esense_application.MainActivity$1.onClick(MainActivity.java:67)
2019-11-24 11:27:00.647 29627-29627/com.example.esense_application W/System.err: at android.view.View.performClick(View.java:7140)
2019-11-24 11:27:00.647 29627-29627/com.example.esense_application W/System.err: at android.view.View.performClickInternal(View.java:7117)
2019-11-24 11:27:00.647 29627-29627/com.example.esense_application W/System.err: at android.view.View.access$3500(View.java:801)
2019-11-24 11:27:00.647 29627-29627/com.example.esense_application W/System.err: at android.view.View$PerformClick.run(View.java:27351)
2019-11-24 11:27:00.647 29627-29627/com.example.esense_application W/System.err: at android.os.Handler.handleCallback(Handler.java:883)
2019-11-24 11:27:00.648 29627-29627/com.example.esense_application W/System.err: at android.os.Handler.dispatchMessage(Handler.java:100)
2019-11-24 11:27:00.648 29627-29627/com.example.esense_application W/System.err: at android.os.Looper.loop(Looper.java:214)
2019-11-24 11:27:00.648 29627-29627/com.example.esense_application W/System.err: at android.app.ActivityThread.main(ActivityThread.java:7356)
2019-11-24 11:27:00.648 29627-29627/com.example.esense_application W/System.err: at java.lang.reflect.Method.invoke(Native Method)
2019-11-24 11:27:00.648 29627-29627/com.example.esense_application W/System.err: at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
2019-11-24 11:27:00.648 29627-29627/com.example.esense_application W/System.err: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
2019-11-24 11:27:00.648 29627-29627/com.example.esense_application W/System.err: Caused by: android.system.ErrnoException: open failed: EACCES (Permission denied)
2019-11-24 11:27:00.648 29627-29627/com.example.esense_application W/System.err: at libcore.io.Linux.open(Native Method)
2019-11-24 11:27:00.648 29627-29627/com.example.esense_application W/System.err: at libcore.io.ForwardingOs.open(ForwardingOs.java:167)
2019-11-24 11:27:00.648 29627-29627/com.example.esense_application W/System.err: at libcore.io.BlockGuardOs.open(BlockGuardOs.java:252)
2019-11-24 11:27:00.648 29627-29627/com.example.esense_application W/System.err: at libcore.io.ForwardingOs.open(ForwardingOs.java:167)
2019-11-24 11:27:00.648 29627-29627/com.example.esense_application W/System.err: at android.app.ActivityThread$AndroidOs.open(ActivityThread.java:7255)
2019-11-24 11:27:00.648 29627-29627/com.example.esense_application W/System.err: at libcore.io.IoBridge.open(IoBridge.java:482)
2019-11-24 11:27:00.648 29627-29627/com.example.esense_application W/System.err: ... 15 more
2019-11-24 11:27:03.528 29627-29627/com.example.esense_application E/MediaRecorder: stop called in an invalid state: 4
2019-11-24 11:27:03.528 29627-29627/com.example.esense_application D/AndroidRuntime: Shutting down VM
2019-11-24 11:27:03.529 29627-29627/com.example.esense_application E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.esense_application, PID: 29627
java.lang.IllegalStateException
at android.media.MediaRecorder.stop(Native Method)
at com.example.esense_application.MainActivity$2.onClick(MainActivity.java:98)
at android.view.View.performClick(View.java:7140)
at android.view.View.performClickInternal(View.java:7117)
at android.view.View.access$3500(View.java:801)
at android.view.View$PerformClick.run(View.java:27351)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7356)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
2019-11-24 11:27:03.540 29627-29627/com.example.esense_application I/Process: Sending signal. PID: 29627 SIG: 9
回答1:
Your MediaRecorder
is throwing when you try to stop()
it because it has never entered the "recording" state. In fact, it never even entered the "prepared" state, because your call to prepare()
did not complete successfully.
SOLUTION
Do not allow a call to start() until the
prepare()
call has returned (without throwing).Do not allow a call to stop() until the
start()
call has returned (without throwing).Make sure you have chosen a valid location for your output file. Try using getExternalFilesDir( null ) instead of
Environment.getExternalStorageDirectory()
. The bad file path is the reason yourprepare()
call is currently failing with anEACCESS
.
As you can see, swallowing exceptions without addressing their root cause (i.e., just doing a e.printStackTrace()
and carrying on), can rapidly lead to problems -- even in rough code used for learning/experimentation. If you are going to add an exception handler, it is better to provide real error handling -- and always make sure you understand why an exception is being thrown.
来源:https://stackoverflow.com/questions/59017202/mediarecorder-stop-failed