我正在尝试将从麦克风获得的输入传递到扬声器(目标是将来能够实时执行音频处理)。这是代码:
public class MainActivity extends Activity {
AudioManager am = null;
AudioRecord record =null;
AudioTrack track =null;
final int SAMPLE_FREQUENCY = 44100;
final int SIZE_OF_RECORD_ARRAY = 1024; // 1024 ORIGINAL
final int WAV_SAMPLE_MULTIPLICATION_FACTOR = 1;
int i= 0;
boolean isPlaying = true;
class MyThread extends Thread{
@Override
public void run(){
recordAndPlay();
}
}
MyThread newThread;
private void init() {
int min = AudioRecord.getMinBufferSize(SAMPLE_FREQUENCY, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT);
record = new AudioRecord(MediaRecorder.AudioSource.VOICE_COMMUNICATION, SAMPLE_FREQUENCY, AudioFormat.CHANNEL_IN_MONO,
AudioFormat.ENCODING_PCM_16BIT, min);
int maxJitter = AudioTrack.getMinBufferSize(SAMPLE_FREQUENCY, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT);
track = new AudioTrack(AudioManager.MODE_IN_COMMUNICATION, SAMPLE_FREQUENCY, AudioFormat.CHANNEL_OUT_MONO,
AudioFormat.ENCODING_PCM_16BIT, maxJitter, AudioTrack.MODE_STREAM);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setVolumeControlStream(AudioManager.MODE_IN_COMMUNICATION);
init();
newThread = new MyThread();
newThread.start();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
private void recordAndPlay() {
short[] lin = new short[SIZE_OF_RECORD_ARRAY];
int num = 0;
am = (AudioManager) this.getSystemService(Context.AUDIO_SERVICE);
am.setMode(AudioManager.MODE_IN_COMMUNICATION);
record.startRecording();
track.play();
while (true) {
num = record.read(lin, 0, SIZE_OF_RECORD_ARRAY);
for(i=0;i<lin.length;i++)
lin[i] *= WAV_SAMPLE_MULTIPLICATION_FACTOR;
track.write(lin, 0, num);
}
}
public void passStop(View view){
Button playBtn = (Button) findViewById(R.id.playBtn);
// /*
if(!isPlaying){
record.startRecording();
track.play();
isPlaying = true;
playBtn.setText("Pause");
}
else{
record.stop();
track.pause();
isPlaying=false;
playBtn.setText("Pass through");
}
// */
}
/*
@SuppressWarnings("deprecation")
@Override
public void onDestroy(){
newThread.stop();
}
*/
@Override
protected void onDestroy() {
android.os.Process.killProcess(android.os.Process.myPid());
// killProcess(android.os.Process.myPid());
}
}
简要概述:函数中
的while(true) {}
无限循环recordAndPlay()
不断地从麦克风中读取原始音频样本并将原始样本输出到扬声器。从函数recordAndPlay()
中启动的线程调用。onCreate()
因此,一旦程序启动,它就会开始将麦克风上的输入发送到扬声器(实际上延迟了几秒钟,但我认为这种延迟是不可避免的)。我还有一个按钮可以暂停和恢复此通过。现在,如果线程没有停止,即使我退出应用程序或应用程序失去焦点,传递也会继续(所以即使手机在桌面上,它也会继续传递)。
@SuppressWarnings("deprecation")
@Override
public void onDestroy(){
newThread.stop();
}
此代码导致应用程序在退出时崩溃(为什么?)所以我使用
@Override
protected void onDestroy() {
android.os.Process.killProcess(android.os.Process.myPid());
// killProcess(android.os.Process.myPid());
}
我在stackoverflow的某个地方找到的(我忘了在哪里)。它现在似乎在做我想做的事,但我想知道这是否是停止线程的正确方法。它可以满足我的需要,也就是说,当我退出应用程序时它会停止传递,但我不确定 killProcess() 函数对我的应用程序到底做了什么,以及它是否是停止线程的最佳方法我开始我自己。
此外,如果我在暂停直通时退出我的应用程序(或失去对它的关注),我可以获得相同的效果。但我认为这意味着线程仍在运行,这意味着无限循环也在持续运行。这样做是个好主意,也就是说,只要我的整个程序按照我的意愿运行,就让线程继续运行吗?如果我有很多线程或其他后台进程在运行怎么办?如果应用程序变得太大,这种做法是否会导致将来出现内存问题?