2015-01-24 2 views
5

Я реализую прямую трансляцию с MIC на java-сервер на другом ПК. Но я слышу только белый шум.Live audio stream java

Я приложил клиент и сервер программы

Client: 

import java.io.IOException; 
import java.net.DatagramPacket; 
import java.net.DatagramSocket; 
import java.net.InetAddress; 
import java.net.SocketException; 
import java.net.UnknownHostException; 

import javax.sound.sampled.AudioFormat; 
import javax.sound.sampled.AudioInputStream; 
import javax.sound.sampled.AudioSystem; 
import javax.sound.sampled.DataLine; 
import javax.sound.sampled.LineUnavailableException; 
import javax.sound.sampled.TargetDataLine; 

public class Mic 
{ 
    public byte[] buffer; 
    private int port; 
    static AudioInputStream ais; 

    public static void main(String[] args) 
    { 
     TargetDataLine line; 
     DatagramPacket dgp; 

     AudioFormat.Encoding encoding = AudioFormat.Encoding.PCM_SIGNED; 
     float rate = 44100.0f; 
     int channels = 2; 
     int sampleSize = 16; 
     boolean bigEndian = true; 
     InetAddress addr; 


     AudioFormat format = new AudioFormat(encoding, rate, sampleSize, channels, (sampleSize/8) * channels, rate, bigEndian); 

     DataLine.Info info = new DataLine.Info(TargetDataLine.class, format); 
     if (!AudioSystem.isLineSupported(info)) { 
      System.out.println("Line matching " + info + " not supported."); 
      return; 
     } 

     try 
     { 
      line = (TargetDataLine) AudioSystem.getLine(info); 

      int buffsize = line.getBufferSize()/5; 
      buffsize += 512; 

      line.open(format); 

      line.start(); 

      int numBytesRead; 
      byte[] data = new byte[buffsize]; 

      addr = InetAddress.getByName("127.0.0.1"); 
      DatagramSocket socket = new DatagramSocket(); 
      while (true) { 
        // Read the next chunk of data from the TargetDataLine. 
        numBytesRead = line.read(data, 0, data.length); 
        // Save this chunk of data. 
        dgp = new DatagramPacket (data,data.length,addr,50005); 

        socket.send(dgp); 
       } 

     }catch (LineUnavailableException e) { 
      e.printStackTrace(); 
     }catch (UnknownHostException e) { 
      // TODO: handle exception 
     } catch (SocketException e) { 
      // TODO: handle exception 
     } catch (IOException e2) { 
      // TODO: handle exception 
     } 
    } 
} 

и на стороне сервера, это не проблема. Он отлично работает с Android-клиентом AudioRecord.

Server: 

import java.io.ByteArrayInputStream; 
import java.net.DatagramPacket; 
import java.net.DatagramSocket; 

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

public class Server { 

    AudioInputStream audioInputStream; 
    static AudioInputStream ais; 
    static AudioFormat format; 
    static boolean status = true; 
    static int port = 50005; 
    static int sampleRate = 44100; 

    static DataLine.Info dataLineInfo; 
    static SourceDataLine sourceDataLine; 

    public static void main(String args[]) throws Exception 
    { 
     System.out.println("Server started at port:"+port); 

     DatagramSocket serverSocket = new DatagramSocket(port); 

     /** 
     * Formula for lag = (byte_size/sample_rate)*2 
     * Byte size 9728 will produce ~ 0.45 seconds of lag. Voice slightly broken. 
     * Byte size 1400 will produce ~ 0.06 seconds of lag. Voice extremely broken. 
     * Byte size 4000 will produce ~ 0.18 seconds of lag. Voice slightly more broken then 9728. 
     */ 

     byte[] receiveData = new byte[4096]; 

     format = new AudioFormat(sampleRate, 16, 1, true, false); 
     dataLineInfo = new DataLine.Info(SourceDataLine.class, format); 
     sourceDataLine = (SourceDataLine) AudioSystem.getLine(dataLineInfo); 
     sourceDataLine.open(format); 
     sourceDataLine.start(); 

     //FloatControl volumeControl = (FloatControl) sourceDataLine.getControl(FloatControl.Type.MASTER_GAIN); 
     //volumeControl.setValue(1.00f); 

     DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length); 

     ByteArrayInputStream baiss = new ByteArrayInputStream(receivePacket.getData()); 

     while (status == true) 
     { 
      serverSocket.receive(receivePacket); 
      ais = new AudioInputStream(baiss, format, receivePacket.getLength()); 
      toSpeaker(receivePacket.getData()); 
     } 

     sourceDataLine.drain(); 
     sourceDataLine.close(); 
    } 

    public static void toSpeaker(byte soundbytes[]) { 
     try 
     { 
      System.out.println("At the speaker"); 
      sourceDataLine.write(soundbytes, 0, soundbytes.length); 
     } catch (Exception e) { 
      System.out.println("Not working in speakers..."); 
      e.printStackTrace(); 
     } 
    } 
} 

ответ

2

Итак, я наполнил микрофон синусоидальной волной (или что-то, что в некотором неопределенном смысле напоминает синусоидальную волну), и ваша программа отлично работает.

Мои специфические изменения были таким образом:

package audioclient; 

import java.io.*; 
import java.net.*; 
import java.nio.ByteBuffer; 

import javax.sound.sampled.*; 

public class Mic { 
    public byte[] buffer; 
    private int port; 
    static AudioInputStream ais; 

     public static void main(String[] args) { 
     TargetDataLine line; 
     DatagramPacket dgp; 

     AudioFormat.Encoding encoding = AudioFormat.Encoding.PCM_SIGNED; 
     float rate = 44100.0f; 
     int channels = 2; 
     int sampleSize = 16; 
     boolean bigEndian = true; 
     InetAddress addr; 

     AudioFormat format = new AudioFormat(encoding, rate, sampleSize, channels, (sampleSize/8) * channels, rate, bigEndian); 

     DataLine.Info info = new DataLine.Info(TargetDataLine.class, format); 
     if (!AudioSystem.isLineSupported(info)) { 
      System.out.println("Line matching " + info + " not supported."); 
      return; 
     } 

     try { 
      line = (TargetDataLine) AudioSystem.getLine(info); 

      //TOTALLY missed this. 
      int buffsize = line.getBufferSize()/5; 
      buffsize += 512; 

      line.open(format); 

      line.start(); 

      int numBytesRead; 
      byte[] data = new byte[buffsize]; 

      /* 
      * MICK's injection: We have a buffsize of 512; it is best if the frequency 
      * evenly fits into this (avoid skips, bumps, and pops). Additionally, 44100 Hz, 
      * with two channels and two bytes per sample. That's four bytes; divide 
      * 512 by it, you have 128. 
      * 
      * 128 samples, 44100 per second; that's a minimum of 344 samples, or 172 Hz. 
      * Well within hearing range; slight skip from the uneven division. Maybe 
      * bump it up to 689 Hz. 
      * 
      * That's a sine wave of shorts, repeated twice for two channels, with a 
      * wavelength of 32 samples. 
      * 
      * Note: Changed my mind, ignore specific numbers above. 
      * 
      */ 
      { 
       final int λ = 16; 
       ByteBuffer buffer = ByteBuffer.allocate(λ * 2 * 8); 
       for(int j = 0; j < 2; j++) { 
        for(double i = 0.0; i < λ; i++) { 
         System.out.println(j + " " + i); 
         //once for each sample 
         buffer.putShort((short)(Math.sin(Math.PI * (λ/i)) * Short.MAX_VALUE)); 
         buffer.putShort((short)(Math.sin(Math.PI * (λ/i)) * Short.MAX_VALUE)); 
        } 
       } 

       data = buffer.array(); 
      } 

      addr = InetAddress.getByName("127.0.0.1"); 
      try(DatagramSocket socket = new DatagramSocket()) { 
       while (true) { 
        for(byte b : data) System.out.print(b + " "); 

        // Read the next chunk of data from the TargetDataLine. 
//     numBytesRead = line.read(data, 0, data.length); 

        for(int i = 0; i < 64; i++) { 
         byte b = data[i]; 
         System.out.print(b + " "); 
        } 
        System.out.println(); 

        // Save this chunk of data. 
        dgp = new DatagramPacket(data, data.length, addr, 50005);  

        for(int i = 0; i < 64; i++) { 
         byte b = dgp.getData()[i]; 
         System.out.print(b + " "); 
        } 
        System.out.println(); 

        socket.send(dgp); 
       } 
      } 

     } catch (LineUnavailableException e) { 
      e.printStackTrace(); 
     } catch (UnknownHostException e) { 
      // TODO: handle exception 
     } catch (SocketException e) { 
      // TODO: handle exception 
     } catch (IOException e2) { 
      // TODO: handle exception 
     } 
    } 
} 

Очевидно, что я неправильно истолковал его как 512 байт-длинный кусок и провалил синусоиду, но дело в том, что производится именно звук, который она должна была - ошеломляющий головокружение на определенной высоте.

Помните, что я не подозреваю, что проблема явно указана в вашем коде. Первое, что я хотел бы проверить, это то, что ваша система использует для аудио. У вас несколько подключенных микрофонов? Может быть, микрофон для веб-камеры? Вы можете захватить утилиту, такую ​​как PulseAudio Volume Control, для проверки. Если вы еще не проверили функциональность своего микрофона, вы тоже можете это сделать; у них есть продолжительность жизни.

Это не редкость для скремблирования бит в аудиопотоке, и это не сложно; но я не вижу нигде, где вы могли бы это сделать.

Возможно, вы захотите изменить свою программу, чтобы попытаться воспроизвести звук локально, прежде чем отправлять его на сервер. Таким образом, вы можете, по крайней мере, определить, есть ли проблема до или после микрофона.

0

Предлагаю вам сначала записать в файл аудиозапись на клиенте. Это позволит вам проверить, правильно ли записано записанное аудио. Вы можете преобразовать PCM в WAV, используя утилиты, такие как sox.

1

Когда клиент и сервер используют буферы данных разных размеров, вы получите усечение и может привести к тому, что один или оба будут производить артефакты.

Ваш размер буфера сервера установлен в byte[] receiveData = new byte[4096];

Ваш размер буфера клиента по какой-то причине динамический, и установить его в byte[] data = new byte[buffsize];

Установить размер буфера клиента к статическому 4096, чтобы соответствовать сервер: byte[] data = new byte[4096];

Или просто убедитесь, что они оба одинакового размера ...

0

Важно согласовать аудиоформат как на клиенте, так и на сервере, например, изменить его на C lient.java: format = new AudioFormat(sampleRate, 16, 1, true, false); Вам также необходимо использовать один и тот же размер буфера для обеих программ.