2013-08-20 4 views
0

나는 스피커에 마이크에서 얻은 오디오 샘플을 통과하는 것을 시도하고는
이 프로그램이 잘 실행 처음 실행, 소리에 동안 suggestions I obtained here스레드가 동일한 응용 프로그램이 다음에 실행될 때 상태를 기억합니까?

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{ 
     private boolean passThroughMode = true; 
     /* 
     @Override 
     public void run(){ 
      recordAndPlay(passThroughMode); 
     } 
     */ 

     MyThread(){ 
      super(); 
     } 

     MyThread(boolean newPTV){ 
      this.passThroughMode = newPTV; 
     } 

     @Override 
     public void run(){ 
      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 (passThroughMode) { 
      while (!isInterrupted()) { 
       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 stopThread(){ 
      passThroughMode = false; 
     } 
     */ 
    } 

    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(true); 
     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(boolean pTM) { 
     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 (pTM) { 
      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() { 
     super.onDestroy(); 
     // android.os.Process.killProcess(android.os.Process.myPid()); 
     // killProcess(android.os.Process.myPid()); 
     // newThread.stopThread(); 
     newThread.interrupt(); 
    } 
} 

를 사용하여, 내가 사용하고있는 코드입니다 마이크가 스피커로 전달되고 리턴 버튼을 누를 때 실이 멈추는 것처럼 보이므로 앱이 종료 될 때 통과가 중지됩니다. 그러나 앱을 다시 실행하면 통과가 발생하지 않습니다.

newThread = new MyThread(true); 
newThread.start(); 
는 새로운 스레드를 응용 프로그램이 실행될 때마다 시작

않는다 (즉,에서 onCreate()가 호출된다), 또는 어떤 이유로 이전 스레드의 상태를 기억 하는가? 이 앱을 완전히 재설정하면 완전히 새로운 앱이 실행될 때마다 시작될 수 있습니다.

--- 편집 ---

인터럽트없이

대체 버전 :

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{ 
     private volatile boolean passThroughMode = true; 
     /* 
     @Override 
     public void run(){ 
      recordAndPlay(passThroughMode); 
     } 
     // */ 


     // /* 
     MyThread(){ 
      super(); 
     } 

     MyThread(boolean newPTV){ 
      this.passThroughMode = newPTV; 
     } 
     // */ 

     // /* 
     @Override 
     public void run(){ 
      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 (passThroughMode) { 
      // while (!isInterrupted()) { 
       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); 
      } 
      record.stop(); 
      track.stop(); 
      record.release(); 
      track.release(); 
     } 
     // */ 

     // /* 
     public void stopThread(){ 
      passThroughMode = false; 
     } 
     // */ 
    } 

    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(); 
     Log.d("MYLOG", "onCreate() called"); 

     //Toast.makeText(getApplicationContext(), "HERE", Toast.LENGTH_SHORT).show(); 
     // newThread = new MyThread(true); // -> Moved this to onResume(); 
     // newThread = new MyThread(); 
     // newThread.start(); // -> Moved this to onResume() 
     // newThread.run(); 
    } 

    @Override 
    protected void onResume(){ 
     super.onResume(); 
     // newThread.stopThread(); 
     Log.d("MYLOG", "onResume() called"); 
     newThread = new MyThread(true); 
     newThread.start(); 
    } 

    @Override 
    protected void onPause(){ 
     super.onPause(); 
     Log.d("MYLOG", "onPause() called"); 
     newThread.stopThread(); 
     // android.os.Process.killProcess(android.os.Process.myPid()); 
    } 


    @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(boolean pTM) { 
     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 (pTM) { 
      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(); 
     newThread.stopThread(); 
    } 
    // */ 

    // /* 
    @Override 
    protected void onDestroy() { 
     super.onDestroy(); 
     newThread.stopThread(); 
     // android.os.Process.killProcess(android.os.Process.myPid()); 
     // killProcess(android.os.Process.myPid()); 
     // newThread.interrupt(); 
     Log.d("MYLOG", "onDestroy() called"); 
    } 
    // */ 
} 

--- EDIT 2 ---

08-20 20:57:58.266: D/MYLOG(21936): onResume() called 
08-20 20:57:58.266: W/dalvikvm(21936): threadid=11: thread exiting with uncaught exception (group=0x416f5700) 
08-20 20:57:58.266: E/AndroidRuntime(21936): FATAL EXCEPTION: Thread-897 
08-20 20:57:58.266: E/AndroidRuntime(21936): java.lang.IllegalStateException: startRecording() called on an uninitialized AudioRecord. 
08-20 20:57:58.266: E/AndroidRuntime(21936): at android.media.AudioRecord.startRecording(AudioRecord.java:517) 
08-20 20:57:58.266: E/AndroidRuntime(21936): at com.example.mypassthrough.MainActivity$MyThread.run(MainActivity.java:54) 
08-20 20:57:58.286: D/MYLOG(21936): onPause() called 
08-20 20:57:58.366: D/MYLOG(21936): onDestroy() called 
+0

스레드가 두 번 실행되지 않습니다. 귀하의 질문은 이해하기 시작하지 않습니다. – EJP

+0

그 다음 일시 중지하고 다시 시작하려면 어떻게해야합니까? – user13267

답변

1

아니, Thread의 어떤 상태 지속성이 없다 Activity 인스턴스의 개체 그러나 앱을 실행할 때마다 새로운 활동이 있다고 가정하여 실수를 저질렀습니다. 활동은 Android OS가 해당 활동을 제거하기로 결정할 때까지 지속됩니다. 앱을 다시 입력하면 새로운 인스턴스가 생성됩니다. 그렇지 않으면 과 동일한 액티비티를 얻게되고 은 다시 호출되지 않습니다.이 경우입니다.

즉, init/deinit 대신 onResume()onPause()을 사용해야합니다. 자세한 내용은 lifecycle page을 확인하십시오.

편집 : 다른 문제는 interrupt()을 사용하여 스레드의 흐름을 제어한다는 것입니다. interrupt()에는 several side effects and may not even set the interrupt status to true depending on what's going with the thread이 있으므로 항상 좋은 생각은 아닙니다. 이제는 "shouldStop"필드를 사용해야합니다. 그 이후로 의미가 설정됩니다.

이 "shouldStop"필드는 필드이어야하며 인수로 전달하면 작동하지 않습니다. onPause()에,

@Override 
    public void run(){ 
     short[] lin = new short[SIZE_OF_RECORD_ARRAY]; 
     int num = 0; 
     record.startRecording(); 
     track.play(); 
     while (passThroughMode) { 
      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); 
     } 
    } 

과 : 당신은 MyThread이 뭔가를해야 스레드가 여전히 멈추지 않는 경우, 전화가 나는 전형적인 인을 차단

@Override 
protected void onPause() { 
    super.onPause(); 
    newThread.stopThread(); 
} 

/O 작업.

편집 2 : 또 다른 문제는 당신이 할 것입니다하지 stop()release() 당신의 AudioTrackAudioRecord 플레이어 스레드합니다 (while 루프 후) 종료된다.I/O와 관련된 무언가를 사용하면 경험적으로 "수동"릴리스 (때로는 할당)가 필요한 "원시"리소스에 연결되는 경우가 많습니다. 이러한 경우 클래스 API를 항상 확인해야합니다.

편집 3 : ... 그리고 MyThread 인스턴스뿐만 아니라 모든 같은 다른 자원은, 하지onCreate()에에, 거기에 새로운 인스턴스를 생성 포함하는, onResume() 완전히 초기화해야한다.

+1

onDestroy() 호출이 활동이 종료되었음을 암시하지 않습니까? 그리고 다음에 활동을 다시 시작할 때 onCreate()가 호출되므로 새 스레드를 시작하면 안됩니까? – user13267

+0

여기에서 공유 한 코드를 테스트했는데 : http://stackoverflow.com/questions/18325654/basics-of-android-activity-life-cycle-functions – user13267

+0

이 코드에서 onDestroy()가 호출되면 내 활동이 포 그라운드에있을 때 돌아 가기 버튼, 다음에 다시 실행할 때 onCreate()가 호출됩니다. 나는 같은 것을 여기에 적용 할 것인가, 그렇지 않다고 생각 했는가? – user13267

0

스레드는 외부 클래스에 대한 참조를 가지고 있고 사용하는 내부 클래스입니다 (MainActivity). 이렇게하면 새 스레드 객체 자체가 이전 인스턴스에서 아무 것도 상속받지 않더라도 스레드의 두 번째 인스턴스가 첫 번째 인스턴스와 다르게 실행될 수 있습니다. @ TheTerribleSwiftTomato가 말했듯이, 당신의 활동은 지속될 수 있습니다.

+0

해결 방법에 대한 아이디어를 알려주세요. 즉, 코드를 실행할 때마다 "새로운"코드로 실행됩니다. – user13267

관련 문제