2015-01-24 37 views
5

Sto implementando lo streaming live da MIC a server java su un altro PC. Ma sento solo un rumore bianco.Stream audio live java

Ho attaccato entrambi programma server

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 
     } 
    } 
} 

client e lato server e non è un problema. Funziona perfettamente con il client 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(); 
     } 
    } 
} 

risposta

2

Così, ho riempito il microfono con un'onda sinusoidale (o qualcosa che, in un certo senso vago, assomiglia a un'onda sinusoidale), e il tuo programma funziona perfettamente.

mie modifiche specifiche erano dunque:

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 
     } 
    } 
} 

Ovviamente ho male interpretato come un 512 byte-lungo pezzo e pasticciate l'onda sinusoidale, ma la cosa è, ha prodotto esattamente il suono che è stato concepito per - un rantolo intorpidito da una nota specifica.

Questo in mente, non sospetto che il problema sia esplicitamente nel codice. La prima cosa che controllerei è quale linea il tuo sistema sta toccando per l'audio. Hai più microfoni collegati? Un microfono per webcam, forse? Potresti prendere una utility come PulseAudio Volume Control per verificare. Se non hai già controllato la funzionalità del tuo microfono, puoi farlo anche tu; hanno una durata di vita su di loro.

Non è affatto raro scramble i bit in un flusso audio, né è difficile; ma non vedo da nessuna parte dove potresti farlo.

Un pensiero potrebbe essere quello di modificare il programma per tentare di riprodurre il suono localmente, prima di inviarlo al server. In questo modo, puoi almeno determinare se il problema è pre- o post-Mic.

0

Suggerisco di scrivere prima su un file l'audio registrato sul client. Questo ti permetterà di verificare se l'audio catturato è OK. Puoi convertire il PCM in WAV usando utility come sox.

1

Quando client e server utilizzano buffer di dati di dimensioni diverse, uno verrà troncato e potrebbe causare uno o entrambi per produrre artefatti.

la dimensione del buffer del server è impostato su byte[] receiveData = new byte[4096];

la dimensione del buffer cliente è per qualche ragione dinamica, e impostato su byte[] data = new byte[buffsize];

Impostare la dimensione del buffer client a un statica 4096 per abbinare il server: byte[] data = new byte[4096];

Oppure assicurati che abbiano entrambe le stesse dimensioni ...

0

È importante abbinare il formato audio sia al client che al server, ad esempio cambiare quello in C lient.java a: format = new AudioFormat(sampleRate, 16, 1, true, false); È inoltre necessario utilizzare la stessa dimensione del buffer su entrambi i programmi.