java - IllegalStateException: play() 在未初始化的 AudioTrack 上调用
问题描述
每次我尝试单击开始按钮时,我的应用程序都会崩溃。我收到“在未初始化的 AudioTrack 上调用的 play()”,但 audioTrack 已初始化。我已经尝试过其他解决方案,但我似乎无法找到自己的解决方案。
完整的堆栈跟踪:
FATAL EXCEPTION: main
Process: com.example.recorder, PID: 5010
java.lang.IllegalStateException: Could not execute method for android:onClick
at androidx.appcompat.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:390)
at android.view.View.performClick(View.java:6600)
at android.view.View.performClickInternal(View.java:6577)
at android.view.View.access$3100(View.java:781)
at android.view.View$PerformClick.run(View.java:25912)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6923)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:870)
Caused by: java.lang.reflect.InvocationTargetException
at java.lang.reflect.Method.invoke(Native Method)
at androidx.appcompat.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:385)
at android.view.View.performClick(View.java:6600)
at android.view.View.performClickInternal(View.java:6577)
at android.view.View.access$3100(View.java:781)
at android.view.View$PerformClick.run(View.java:25912)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6923)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:870)
Caused by: java.lang.IllegalStateException: play() called on uninitialized AudioTrack.
at android.media.AudioTrack.play(AudioTrack.java:2074)
at com.example.recorder.MainActivity.start(MainActivity.java:93)
at com.example.recorder.MainActivity.requestAudioPermissions(MainActivity.java:152)
at com.example.recorder.MainActivity.startRecording(MainActivity.java:49)
主要活动:
private int freq =44100;//frequencia de amostragem
private AudioRecord audioRecord = null;//variavel para gravação
private Thread Rthread = null;
//private AudioManager audioManager=null;
private AudioTrack audioTrack=null;//variavel para play
//byte[] buffer = new byte[freq];
public static final String LOG_TAG = "YOUR-TAG-NAME";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
//função com chamada as permissões nescessárias para captação e execução de áudio pelo celular
public void startRecording(View view) {
requestAudioPermissions();
}
protected void start() {
android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO);
final int bufferSizeIn = AudioRecord.getMinBufferSize(freq, //buffer
AudioFormat.CHANNEL_IN_MONO,
AudioFormat.ENCODING_PCM_16BIT);
final int bufferSizeOut = AudioTrack.getMinBufferSize(freq, //buffer
AudioFormat.CHANNEL_OUT_MONO,
AudioFormat.ENCODING_PCM_16BIT);
//configurando as variaveis que serão utilizadas para captação e reprodução do áudio
audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, freq,
AudioFormat.CHANNEL_IN_MONO,
AudioFormat.ENCODING_PCM_16BIT, bufferSizeIn);
audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, freq,
AudioFormat.CHANNEL_OUT_MONO,
AudioFormat.ENCODING_PCM_16BIT, bufferSizeOut,
AudioTrack.MODE_STATIC);
//audioTrack.setPlaybackRate(freq);
final byte[] bufferIn = new byte[bufferSizeIn];
final byte[] bufferOut = new byte[bufferSizeOut];
audioRecord.startRecording(); //começa a captar a voz
Log.i(LOG_TAG, "Audio Recording started");
audioTrack.play(); //começa a transmitir a voz
Log.i(LOG_TAG, "Audio Playing started");
Rthread = new Thread(new Runnable() {
public void run() {
while (true) {
try {
audioRecord.read(bufferIn, 0, bufferSizeIn);
audioTrack.write(bufferOut, 0, bufferSizeOut);
} catch (Throwable t) {
Log.e("Error", "Read write failed");
t.printStackTrace();
}
}
}
});
Rthread.start();
}
public void stopRecording(View view) {
if(audioRecord!=null){
audioRecord.stop();
}
}
//Requesting run-time permissions
//Create placeholder for user's consent to record_audio permission.
//This will be used in handling callback
private final int MY_PERMISSIONS_RECORD_AUDIO = 1;
private void requestAudioPermissions() {
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.RECORD_AUDIO)
!= PackageManager.PERMISSION_GRANTED) {
//When permission is not granted by user, show them message why this permission is needed.
if (ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.RECORD_AUDIO)) {
Toast.makeText(this, "Please grant permissions to record audio", Toast.LENGTH_LONG).show();
//Give user option to still opt-in the permissions
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.RECORD_AUDIO},
MY_PERMISSIONS_RECORD_AUDIO);
} else {
// Show user dialog to grant permission to record audio
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.RECORD_AUDIO},
MY_PERMISSIONS_RECORD_AUDIO);
}
}
//If permission is granted, then go ahead recording audio
else if (ContextCompat.checkSelfPermission(this,
Manifest.permission.RECORD_AUDIO)
== PackageManager.PERMISSION_GRANTED) {
//Go ahead with recording audio now
start();
}
}
//Handling callback
@Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
switch (requestCode) {
case MY_PERMISSIONS_RECORD_AUDIO: {
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// permission was granted, yay!
start();
} else {
// permission denied, boo! Disable the
// functionality that depends on this permission.
Toast.makeText(this, "Permissions Denied to record audio", Toast.LENGTH_LONG).show();
}
return;
}
}
}
活动主:
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Aperte Start para começar"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_bias="0.503"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.274" />
<Button
android:id="@+id/btnStart"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="116dp"
android:layout_marginLeft="116dp"
android:layout_marginTop="188dp"
android:layout_marginEnd="8dp"
android:layout_marginRight="116dp"
android:onClick="startRecording"
android:text="Start"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/btnStop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginLeft="116dp"
android:layout_marginTop="28dp"
android:layout_marginEnd="116dp"
android:layout_marginRight="116dp"
android:onClick="stopRecording"
android:text="Stop"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/btnStart" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_begin="20dp" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_begin="20dp" />
<androidx.constraintlayout.widget.Barrier
android:id="@+id/barrier"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:barrierDirection="top" />
安卓清单:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.recorder">
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
找不到问题所在。
解决方案
推荐阅读
- android - activity_splash.xml 的背景没有改变
- python - 从熊猫数据框中的句子列表创建二元组
- java - 类似查询的设计模式
- mysql - Codesignal.com 闹钟解决方案
- html - 两个输入框使用一个标签,输入框排列不正确
- javascript - 如何根据条件对对象数组中的属性求和
- javascript - 比萨饼和甜甜圈与 html
- python - 尝试使用 Python shell 中的输入/输出重定向时出现错误“无效语法”
- google-cloud-dataflow - 在配置时间后以编程方式终止订阅中的 PubSubIO.readMessages?
- laravel - 带有访问令牌而不是普通 webhook 的 Laravel 松弛通知