2012-02-11 10 views
29

Tôi đang cố phát trực tuyến âm thanh từ micrô từ 1 Android này sang micrô khác qua WiFi. Sau khi xem xét một số ví dụ, tôi đã tạo 2 ứng dụng với một hoạt động đơn lẻ trong mỗi ứng dụng, 1 để chụp và gửi âm thanh và một ứng dụng khác để nhận.Phát trực tiếp giọng nói giữa Điện thoại Android qua WiFi

Tôi đã sử dụng các lớp Audiorecord và Audiotrack để chụp và phát. Tuy nhiên, tôi chỉ nghe thấy một số âm thanh tanh tách (hiện đã dừng sau khi tôi thực hiện một số thay đổi mặc dù tôi đã hoàn nguyên trở lại)

Hoạt động gửi giọng nói.

public class VoiceSenderActivity extends Activity { 

private EditText target; 
private TextView streamingLabel; 
private Button startButton,stopButton; 

public byte[] buffer; 
public static DatagramSocket socket; 
private int port=50005;   //which port?? 
AudioRecord recorder; 

//Audio Configuration. 
private int sampleRate = 8000;  //How much will be ideal? 
private int channelConfig = AudioFormat.CHANNEL_CONFIGURATION_MONO;  
private int audioFormat = AudioFormat.ENCODING_PCM_16BIT;  

private boolean status = true; 




@Override 
public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.main); 

    target = (EditText) findViewById (R.id.target_IP); 
    streamingLabel = (TextView) findViewById(R.id.streaming_label); 
    startButton = (Button) findViewById (R.id.start_button); 
    stopButton = (Button) findViewById (R.id.stop_button); 

    streamingLabel.setText("Press Start! to begin"); 

    startButton.setOnClickListener (startListener); 
    stopButton.setOnClickListener (stopListener); 
} 

private final OnClickListener stopListener = new OnClickListener() { 

    @Override 
    public void onClick(View arg0) { 
       status = false; 
       recorder.release(); 
       Log.d("VS","Recorder released"); 
    } 

}; 

private final OnClickListener startListener = new OnClickListener() { 

    @Override 
    public void onClick(View arg0) { 
       status = true; 
       startStreaming();   
    } 

}; 

public void startStreaming() { 


    Thread streamThread = new Thread(new Runnable() { 

     @Override 
     public void run() { 
      try { 


       int minBufSize = AudioRecord.getMinBufferSize(sampleRate, channelConfig, audioFormat); 
       DatagramSocket socket = new DatagramSocket(); 
       Log.d("VS", "Socket Created"); 

       byte[] buffer = new byte[minBufSize]; 

       Log.d("VS","Buffer created of size " + minBufSize); 
       DatagramPacket packet; 

       final InetAddress destination = InetAddress.getByName(target.getText().toString()); 
       Log.d("VS", "Address retrieved"); 


       recorder = new AudioRecord(MediaRecorder.AudioSource.MIC,sampleRate,channelConfig,audioFormat,minBufSize); 
       Log.d("VS", "Recorder initialized"); 

       recorder.startRecording(); 


       while(status == true) { 


        //reading data from MIC into buffer 
        minBufSize = recorder.read(buffer, 0, buffer.length); 

        //putting buffer in the packet 
        packet = new DatagramPacket (buffer,buffer.length,destination,port); 

        socket.send(packet); 


       } 



      } catch(UnknownHostException e) { 
       Log.e("VS", "UnknownHostException"); 
      } catch (IOException e) { 
       Log.e("VS", "IOException"); 
      } 


     } 

    }); 
    streamThread.start(); 
} 
} 

Hoạt động để nhận giọng

public class VoiceReceiverActivity extends Activity { 


private Button receiveButton,stopButton; 

public static DatagramSocket socket; 
private AudioTrack speaker; 

//Audio Configuration. 
private int sampleRate = 8000;  //How much will be ideal? 
private int channelConfig = AudioFormat.CHANNEL_CONFIGURATION_MONO;  
private int audioFormat = AudioFormat.ENCODING_PCM_16BIT;  

private boolean status = true; 


@Override 
public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.main); 

    receiveButton = (Button) findViewById (R.id.receive_button); 
    stopButton = (Button) findViewById (R.id.stop_button); 
    findViewById(R.id.receive_label); 

    receiveButton.setOnClickListener(receiveListener); 
    stopButton.setOnClickListener(stopListener); 

} 


private final OnClickListener stopListener = new OnClickListener() { 

    @Override 
    public void onClick(View v) { 
     status = false; 
     speaker.release(); 
     Log.d("VR","Speaker released"); 

    } 

}; 


private final OnClickListener receiveListener = new OnClickListener() { 

    @Override 
    public void onClick(View arg0) { 
     status = true; 
     startReceiving(); 

    } 

}; 

public void startReceiving() { 

    Thread receiveThread = new Thread (new Runnable() { 

     @Override 
     public void run() { 

      try { 

       DatagramSocket socket = new DatagramSocket(50005); 
       Log.d("VR", "Socket Created"); 


       byte[] buffer = new byte[256]; 


       //minimum buffer size. need to be careful. might cause problems. try setting manually if any problems faced 
       int minBufSize = AudioRecord.getMinBufferSize(sampleRate, channelConfig, audioFormat); 

       speaker = new AudioTrack(AudioManager.STREAM_MUSIC,sampleRate,channelConfig,audioFormat,minBufSize,AudioTrack.MODE_STREAM); 

       speaker.play(); 

       while(status == true) { 
        try { 


         DatagramPacket packet = new DatagramPacket(buffer,buffer.length); 
         socket.receive(packet); 
         Log.d("VR", "Packet Received"); 

         //reading content from packet 
         buffer=packet.getData(); 
         Log.d("VR", "Packet data read into buffer"); 

         //sending data to the Audiotrack obj i.e. speaker 
         speaker.write(buffer, 0, minBufSize); 
         Log.d("VR", "Writing buffer content to speaker"); 

        } catch(IOException e) { 
         Log.e("VR","IOException"); 
        } 
       } 


      } catch (SocketException e) { 
       Log.e("VR", "SocketException"); 
      } 


     } 

    }); 
    receiveThread.start(); 
} 

} 

tôi đã sử dụng Wireshark để kiểm tra xem các gói tin đang được gửi đi và tôi có thể nhìn thấy các gói dữ liệu. Tuy nhiên, nguồn là địa chỉ MAC của thiết bị gửi và đích cũng giống như một địa chỉ vật lý. Không chắc chắn nếu điều này là có liên quan mặc dù.

Vậy vấn đề là gì?

+1

Có ít nhất ba vấn đề bạn phải giải quyết: dữ liệu bị trễ (hoặc thiếu), thông lượng dữ liệu tổng thể và khả năng tần suất lấy mẫu hơi không khớp. Điện thoại IP thực tế phải có một phương tiện để đối phó với cả ba. Đồng hồ không phù hợp là đáng ngạc nhiên khó khăn - ban đầu bạn có thể giới thiệu một sự chậm trễ để cung cấp cho một số phụ cấp đệm, nhưng nếu người gửi chậm hơn bạn sẽ sử dụng bộ đệm và người nhận sẽ bị bỏ đói cho dữ liệu; trong khi nếu người gửi nhanh hơn thì bộ đệm cuối cùng sẽ tràn với dữ liệu chưa được phát. –

+0

Tôi đã cố gắng thực hiện công việc này. Đã không thực sự có một vấn đề của tần số không phù hợp. Chậm trễ trong dữ liệu, vâng. Đã có một loại giao thức của riêng tôi để phù hợp với đồng hồ người nhận/người gửi. Cuối cùng nó đã làm việc nhưng chỉ với một số tụt hậu (tăng khoảng cách từ bộ định tuyến không dây) – Alabhya

+0

Xin chào, tôi đã triển khai một ứng dụng thử nghiệm cho mã bạn có ở trên, thực hiện tất cả các thay đổi cần thiết được đề xuất bên dưới nhưng tôi vẫn gặp sự cố . Tôi đang nhận được comms giữa hai điện thoại không có vấn đề, nhưng tôi không nghĩ rằng mic được ghi đúng cách như tôi không nghe bất kỳ âm thanh ở đầu bên kia. Bạn có lẽ có một liên kết đến một giải pháp mẫu mà tôi có thể xem? – chuckliddell0

Trả lời

3

Tôi sẽ thử chia sự cố thành ba phần.

Phần 1

Đảm bảo Connection Ổ cắm đang làm việc tốt bằng cách bình luận tất cả mọi thứ liên quan đến âm thanh

Phần 2

Gửi đơn giản chỉ là một văn bản tùy ý tin nhắn [Địa ngục o WiFi] từ người gửi, sau đó nhận và in nó trong ứng dụng bên nhận.

Phần 3

Cho dù máy ghi âm được thực sự làm việc? cố gắng thử nghiệm cách ghi âm của bạn trong dự án riêng biệt để xem nó có hoạt động đúng hay không.

Sử dụng mã this để chụp micrô và phát.

Kinh nghiệm của tôi

Tôi đã từng làm việc trên một dự án tương tự và kiểm tra nó, những gì tôi đã làm là sau khi ghi âm tôi đã viết các dữ liệu âm thanh ghi lại như một tập tin trên sdcard

(nó sẽ là âm thanh thô, vì vậy hầu hết người chơi nhạc sẽ không thể phát ... mPlayer nên chơi nó, tôi đoán)

+0

Ok tôi đã làm việc đó. Giọng nói bị vỡ quá nhiều và có độ trễ. Cần tìm ra tỷ lệ lấy mẫu chính xác và kích thước bộ đệm cho điều này. Sẽ là tuyệt vời nếu bất kỳ đầu vào trên đó. Dù sao, cảm ơn rất nhiều. những gì bạn nói đã giúp. – Alabhya

+0

Trong hoạt động thu của bạn, trong phương thức startReceiving() không sử dụng 256 làm kích thước bộ đệm nhưng sử dụng minBufSize mà bạn đang nhận được trong dòng tiếp theo. Khác hơn thế, có thể muốn chơi một chút với tỷ lệ lấy mẫu khác nhau nhưng ngay cả 8k cũng tốt. –

+1

Ok tôi đã làm việc đó. Rõ ràng minBufSize là quá nhiều và do đó sự chậm trễ và phá vỡ. Đặt minBufSize thành 256 và trong khi khởi tạo các đối tượng AudioRecord và AudioTrack đặt kích thước bộ đệm thành minBufSize * 10 .. Đã thử các kết hợp khác nhau của tỷ lệ lấy mẫu và điều này và đã đạt được mức thỏa đáng ngay bây giờ. Cảm ơn rất nhiều! – Alabhya

2

Bạn cần xem xét cẩn thận việc sử dụng UDP (lớp DatagramSocket) làm giao thức mạng.

UDP là giao thức gọn nhẹ không đảm bảo duy trì thứ tự các gói đã nhận. Đây có thể là một phần lý do tại sao âm thanh bị cắt xén.Một gói tin nhận được không đúng thứ tự sẽ dẫn đến một gói tin có giá trị âm thanh được phát ra theo thứ tự. Tại ranh giới của các gói ngoài chuỗi này, bạn sẽ nghe thấy các nhấp chuột/cửa sổ nơi mẫu âm thanh bị hỏng hiệu quả. Thêm vào đó, các gói UDP không được đảm bảo để được gửi thành công. Bất kỳ gói bị bỏ nào rõ ràng sẽ thêm vào bất kỳ sự xáo trộn hoặc biến dạng nào được nghe thấy.

TCP (Lớp ổ cắm) sẽ là lựa chọn tốt hơn cho chất lượng âm thanh tối ưu. TCP là một giao thức mạnh mẽ hơn để duy trì thứ tự các gói tin được nhận. Nó cũng có kiểm tra lỗi trong xây dựng và sẽ gửi lại bất kỳ gói tin bị loại bỏ nào. Tuy nhiên, do chức năng chú ý này, TCP có chi phí mạng cao hơn.

Tôi đã bắt đầu phản hồi này bằng cách nói rằng bạn cần xem xét cẩn thận giao thức bạn sử dụng. Điều này là do có trường hợp sử dụng hoặc tùy thuộc vào những gì quan trọng đối với bạn ..

Nếu bạn muốn phát lại độ trễ cực thấp nhưng rất sẵn lòng hy sinh chất lượng âm thanh thì UDP sẽ hoạt động. Tuy nhiên, nó sẽ mất một số thử nghiệm để tìm bộ đệm tốt nhất và kích thước mẫu.

Nếu bạn muốn sản xuất lại âm thanh tốt nhất có thể với biến dạng bằng 0 nhưng vui mừng giới thiệu độ trễ hơi hơn thì TCP là tuyến đường cần thực hiện.

Tôi không thể nói thêm độ trễ TCP sẽ thêm. Nhưng có thể nó có thể được thực hiện mà không ảnh hưởng đến trải nghiệm người dùng. Cách duy nhất để tìm ra là thử và xem.

7

Có thư viện mã nguồn mở có tên "Libstreaming" được sử dụng để phát trực tuyến thoại/video qua mạng bằng WIFI. Chỉ cần có một cái nhìn vào nó:

https://github.com/fyhertz/libstreaming

Ngoài ra còn có một số ví dụ được cung cấp, xin vui lòng có một cái nhìn vào nó:

https://github.com/fyhertz/libstreaming-examples

Tôi đã sử dụng các thư viện để Suối RTSP âm thanh qua mạng, hy vọng nó có thể hữu ích.

+0

Bạn có thể hướng dẫn, làm cách nào bạn chỉ thực hiện luồng âm thanh mà không cần phát trực tuyến video? – kAmol