2012-11-05 4 views
1

동시에 두 개의 다른 버퍼 (버퍼 A와 B)를 SourceDataLine으로 멀티 스레드하여 동시에 사운드를 재생하려고합니다. 하지만 그것은 버퍼 A와 버퍼 B간에 전환을 유지하고, 내 SourceDataLine에 쓰기 전에 버퍼를 병합해야합니까, 아니면 동기화 된 방법으로 재생할 수 있습니까?Java는 SourceDataLine과 동시에 2 바이트 버퍼를 재생합니다.

class PlayThread extends Thread { 
    byte[] buffer = new byte[2 * 1024]; 

    @Override 
    public void run() { 
     try { 
      while (true) { 
       DatagramPacket receive = new DatagramPacket(buffer, buffer.length); 
       mDatagramSocket.receive(receive); 
       mSourceDataLine.write(receive.getData(), 0, receive.getData().length); 

       System.out.println("Received!"); 
      } 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 
} 

다른 수신 버퍼가있는 2 개의 PlayThread 인스턴스가 있습니다. 아래는 SourceDataLine이 초기화되는 함수입니다.

private void init() { 
    try { 
     DataLine.Info sourceDataLineInfo = new DataLine.Info(
       SourceDataLine.class, audioFormat); 
     DataLine.Info targetDataLineInfo = new DataLine.Info(
       TargetDataLine.class, audioFormat); 

     Mixer.Info[] mixerInfo = AudioSystem.getMixerInfo(); 

     Mixer mixer = AudioSystem.getMixer(mixerInfo[3]); 
     mSourceDataLine = (SourceDataLine) AudioSystem 
       .getLine(sourceDataLineInfo); 
     mTargetDataLine = (TargetDataLine) mixer.getLine(targetDataLineInfo); 

     mSourceDataLine.open(audioFormat, 2 * 1024); 
     mSourceDataLine.start(); 

     mTargetDataLine.open(audioFormat, 2 * 1024); 
     mTargetDataLine.start(); 
    } catch (LineUnavailableException ex) { 
     ex.printStackTrace(); 
    } 
} 

고맙습니다.

답변

1

절대적으로 병합해야합니다. 두 스레드에서 파일에 번호를 작성하는 상상 :

123456... 
123456... 

당신에게 무슨 일이 일어나고 있는지입니다

11234235656... 

될 수 있습니다.

또 다른 문제는 네트워크에서 들어오는 데이터를 버퍼링해야하거나 그렇지 않을 가능성이 있습니다. 적어도 두 개의 스레드가 필요합니다. 하나는 읽기 용이고 다른 하나는 작동시키기위한 것입니다. 그러나 귀하의 경우에는 각 입력 패킷 스트림에 대해 하나의 판독기 스레드를 사용하는 것이 더 나을 것입니다. (내 대화 슬라이드를 참조하십시오 : http://blog.bjornroche.com/2011/11/slides-from-fundamentals-of-audio.html 특별히 여기에서 관련있는 http에서 스트리밍에 대한 슬라이드가 있습니다.

그래서 여러 개의 PlayThread 대신 여러 개의 ReaderThread를 만들어 데이터를 기다린 다음 일종의 버퍼에 씁니다. (PipedInputPipedOutputStream은 Java에서 잘 작동 함). 그런 다음 버퍼에서 데이터를 읽고 스트림에 COMBINED 데이터를 쓰는 다른 스레드가 필요합니다.

이렇게하면 원래의 데이터 결합 방법에 관한 질문이 남습니다. 대답은 단일 대답이 없지만 일반적으로 가장 쉬운 올바른 방법은 샘플별로 데이터를 평균하는 것입니다. 그러나 코드 작성 방법은 코드에 포함되지 않은 데이터 형식에 따라 다릅니다. 빅 엔디안 16 비트 정수라고 가정하면 들어오는 원시 데이터를 단락으로 변환하고 단락을 평균화 한 다음 평균 단락을 바이트로 변환해야합니다.

byte ~ short 변환은 DataInputStreamDataOutputStream을 사용하면 가장 쉽게 수행 할 수 있습니다.