【问题标题】:Microphone Streaming is Not Clear麦克风流不清晰
【发布时间】:2014-01-02 14:28:40
【问题描述】:

我正在尝试通过 UDP 传输麦克风,但我的输出噪音太大,无法理解输入音频。这是我的代码:

服务器端:

import java.io.DataOutputStream;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.Mixer;
import javax.sound.sampled.Port;
import javax.sound.sampled.TargetDataLine;

public class MicPlayer {

    private static final String IP_TO_STREAM_TO   = "localhost" ;
    private static final int PORT_TO_STREAM_TO     = 8888 ;

    /** Creates a new instance of MicPlayer */
    public MicPlayer() {

    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
    Mixer.Info minfo[] = AudioSystem.getMixerInfo() ;
    for( int i = 0 ; i < minfo.length ; i++ )
    {
     System.out.println( minfo[i] ) ;    
    }


    if (AudioSystem.isLineSupported(Port.Info.MICROPHONE)) {
    try {


      DataLine.Info dataLineInfo = new DataLine.Info(
              TargetDataLine.class , getAudioFormat() ) ;
     final TargetDataLine targetDataLine = (TargetDataLine)AudioSystem.getLine( dataLineInfo  ) ;
      targetDataLine.open( getAudioFormat() );
      targetDataLine.start();
      byte tempBuffer[] = new byte[targetDataLine.getBufferSize() / 5] ;
      int cnt = 0 ;
      while( true )
      {
      targetDataLine.read( tempBuffer , 0 , tempBuffer.length );
      sendThruUDP( tempBuffer ) ;
      }

    }
    catch(Exception e )
    {
    System.out.println(" not correct " ) ;
    System.exit(0) ;
    }
    }



    }


    public static AudioFormat getAudioFormat(){
    float sampleRate = 8000.0F;
    //8000,11025,16000,22050,44100
    int sampleSizeInBits = 16;
    //8,16
    int channels = 1;
    //1,2
    boolean signed = true;
    //true,false
    boolean bigEndian = false;
    //true,false
    return new AudioFormat( sampleRate, sampleSizeInBits, channels, signed, bigEndian );
    }


    public static void sendThruUDP( byte soundpacket[] )
    {
       try
       {
       DatagramSocket sock = new DatagramSocket() ; 
       sock.send( new DatagramPacket( soundpacket , soundpacket.length , InetAddress.getByName( IP_TO_STREAM_TO ) , PORT_TO_STREAM_TO ) ) ; 
       sock.close() ;
       }
       catch( Exception e )
       {
       e.printStackTrace() ;
       System.out.println(" Unable to send soundpacket using UDP " ) ;   
       }

    }

    }

我不认为客户端有问题,但这里是代码;

客户端:

import java.io.DataInputStream;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.SourceDataLine;

public class RadioReceiver extends Thread {
    private static final String IP_TO_STREAM_TO   = "localhost" ;
    private static final int PORT_TO_STREAM_TO     = 8888 ;

    /** Creates a new instance of RadioReceiver */
    public RadioReceiver() {
    }

    public void run()
    {
        byte b[] = null ;
        while( true )
        {
           b = receiveThruUDP() ; 
           toSpeaker( b ) ;
        }        
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {

    RadioReceiver r = new RadioReceiver() ;
    r.start() ;

    }

    public static byte[] receiveThruUDP()
    {
       try
       {
       DatagramSocket sock = new DatagramSocket(PORT_TO_STREAM_TO) ; 
       byte soundpacket[] = new byte[1230] ;
       DatagramPacket datagram = new DatagramPacket( soundpacket , soundpacket.length , InetAddress.getByName( IP_TO_STREAM_TO ) , PORT_TO_STREAM_TO ) ;
       sock.receive( datagram ) ; 
       sock.close() ;       return datagram.getData() ; // soundpacket ;
       }
       catch( Exception e )
       {
       System.out.println(" Unable to send soundpacket using UDP " ) ;   
       return null ;
       } 

    }


     public static void toSpeaker( byte soundbytes[] )
     {

      try{  
      DataLine.Info dataLineInfo = new DataLine.Info( SourceDataLine.class , getAudioFormat() ) ;
      SourceDataLine sourceDataLine = (SourceDataLine)AudioSystem.getLine( dataLineInfo );
      sourceDataLine.open( getAudioFormat() ) ;
      sourceDataLine.start();

      int cnt = 0;
      sourceDataLine.write( soundbytes , 0, soundbytes.length );
      sourceDataLine.drain() ;
      sourceDataLine.close() ;
      }
      catch(Exception e )
      {
      System.out.println("not working in speakers " ) ;
      }

    }


    public static AudioFormat getAudioFormat()
    {
    float sampleRate = 8000.0F;
    //8000,11025,16000,22050,44100
    int sampleSizeInBits = 16;
    //8,16
    int channels = 1;
    //1,2
    boolean signed = true;
    //true,false
    boolean bigEndian = false;
    //true,false
    return new AudioFormat( sampleRate, sampleSizeInBits, channels, signed, bigEndian );
    }


}

我确定我的连接正常,但我不知道为什么我的输出如此嘈杂。这让我发疯了,我一直在努力工作到 1 周,请帮助我。谢谢。

【问题讨论】:

  • 你为什么使用UDP?恕我直言,您应该将 TCP 用于此类应用程序。
  • 您能告诉我您使用的是哪一种 API 吗?
  • @user2336315,我不知道如何使用 tcp :( 如果你知道,你能帮我吗?
  • @Touregsys:我建议在这里使用 UDP。如果您想学习 TCP,请在此处阅读我的答案:stackoverflow.com/questions/4615958/…
  • @MartijnCourteaux 虽然 UPD 更快,但 TCP 保证数据包按顺序到达应用层且没有错误。此外,许多防火墙和路由器未配置为允许 UDP 数据包。但是@ Touregsys 可以同时尝试两者,看看哪种最合适。

标签: java udp streaming


【解决方案1】:

原因可能是您的数据报包太小,导致您发送一大堆包,从而产生大量开销。这可能会导致巨大的丢包率并使它们以错误的顺序到达。

所以,让你的缓冲区更大:

byte tempBuffer[] = new byte[8192] ;

这来自DatagramSocket.receive()JavaDoc:

此方法阻塞,直到收到数据报。数据报包对象的长度字段包含接收到的消息的长度。 如果消息长于数据包的长度,则消息被截断。

这也可能是个问题。尝试使用相同的大小发送和接收数据包。

byte soundpacket[] = new byte[8192];

另外,不要连续打开和关闭到扬声器的 AudioLine。也不要连续创建 DatagramSockets。创建一个并保留它。

【讨论】:

  • 实际上,我认为他的问题是,由于 UDP 不是面向连接的,因此数据包“一起”到达并且没有特定的顺序进行处理,并且可能不同步。所以我建议也让 UDP 数据包包含一个序列号,并且在读取数据时,确保您正在按顺序读取它们,或者至少在新数据包到达后不读取旧数据包
  • 感谢您的回答,但我仍然无法解决我的问题。
  • 即使它是有道理的,我不明白我是否应该在 sendThruUDP 函数中使用这个“DatagramSocket sock = new DatagramSocket();”
  • 哦...当我为 DatagramSocket 做一个全局变量时,它的工作更加干净。但我还有一点点噪音。我不明白如何做“不要连续打开和关闭 AudioLine 到扬声器”部分。十分感谢。等待您的答复。
  • 您的 toSpeaker 方法每次调用它时都会打开一个新的 AudioLine。将这些变量也设为全局变量。
猜你喜欢
  • 2015-12-24
  • 1970-01-01
  • 1970-01-01
  • 2015-07-09
  • 1970-01-01
  • 2014-08-11
  • 2017-06-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多