# Mikrofonaudio über Java Server an Webbrowser streamen



## Twister21 (19. Nov 2017)

Hallo,

ich möchte das Audio von einem an meinem Raspberry Pi angeschlossenen Mikrofon live über einen Java HTTP-Server an einen Webbrowser streamen, der auf diesen Server zugreift.

Dazu wäre es sicherlich sinnvoller das UDP-Protokoll zu nutzen, um die Datenübertragung schnell zu ermöglichen. Jedoch habe ich mich damit noch nicht wirklich auseinandergesetzt, weshalb mein derzeitiger Ansatz auf dem TCP-Protokoll basiert. Jedoch scheint der derzeitige Ansatz nicht wirklich sinnvoll zu sein.

Ich habe dazu folgende Klasse:

```
private Socket client;
private DataOutputStream output;
private TargetDataLine microphone;

public HTTPServer(Socket client, TargetDataLine microphone) {
    this.client = client;
    this.microphone = microphone;
}

public void run() {
    try {
        System.out.println("The Client " + client.getInetAddress() + ":" + client.getPort() + " is connected");
        output = new DataOutputStream(client.getOutputStream());

        sendResponse();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

public void sendResponse() throws Exception {
    String statusLine = "HTTP/1.1 200 OK\r\n";
    String serverDetails = "Server: HTTP-Server\r\n";
    String contentTypeLine = "Content-Type: audio/mpeg\r\n";
    String contentLengthLine = "Content-Length: " + microphone.getBufferSize() + "\r\n";

    output.writeBytes(statusLine);
    output.writeBytes(serverDetails);
    output.writeBytes(contentTypeLine);
    output.writeBytes(contentLengthLine);
    output.writeBytes("\r\n");

    int numBytesRead;
    int bufferSize = microphone.getBufferSize() / 5;
    bufferSize += 512;

    microphone.open();
    microphone.start();

    byte[] targetData = new byte[bufferSize];

    while (true) {
        numBytesRead = microphone.read(targetData, 0, targetData.length);

        if (numBytesRead == -1) break;
        output.write(targetData, 0, numBytesRead);
    }
}
```

Leider erscheint beim Aufrufen der URL zwar ein Element zum Abspielen einer Audio-Datei, jedoch kann der Play-Button nicht angeklickt werden. Edge zeigt zudem auch an, dass der Audiodateityp nicht unterstützt wird. Der Java-Server gibt in der Konsole "java.net.SocketException: Broken pipe" aus.

Wie kann ich weiter vorgehen bzw. muss ich meinen Ansatz überarbeiten?


----------



## JuKu (22. Nov 2017)

Ich selbst habe noch nie Audios über HTTP streamen müssen, also kann ich es dir nicht genau sagen.
Aber ob das so funktioniert, wie du das gerade darstellst, ist für mich sehr fraglich.

Leider lässt es sich nicht ganz aus dem Code entnehmen, ob du einen Websocket oder eine Anfrage verwendest.
Meiner Meinung nach eine einfache HTTP Anfrage.
Auch ist die Content-Length nicht die Puffergröße, wenn ich mich nicht irre.

Und die Exception kommt vermutlich dadurch zustande, dass du immer nur schreibst, aber nie flushest. Und vermutlich schließt der Browser die Verbindung auch nach einem Timeout, wenn du nicht mit normalen Requests arbeitest. Ich glaube dieser ganze Ansatz funktioniert so nicht. Aber wie gesagt, ich habe das selbst noch nicht gemacht.


----------



## Twister21 (23. Nov 2017)

Hallo,

ich habe auch großen Zweifel daran, ob es über diesen Ansatz überhaupt zu einer Lösung des Problems kommen kann. Ich denke, dass ich mir verschiedene Web Server für Java anschauen werden. Eventuell haben diese bereits eine Streaming-Lösung integriert.


----------



## JuKu (23. Nov 2017)

Die Frage ist, ob du überhaupt einen Web Server benötigst. Da gibt es nämlich wesentlich sinnvollere Protokolle für:
https://de.wikipedia.org/wiki/Streaming-Protokoll


----------



## Twister21 (24. Nov 2017)

Hallo,

wie genau würdest du einen der angegebenen Streaming-Protokolle in Java implementieren? Ich würde am liebsten auf ein Webinterface über einen Webserver zugreifen können, der auf dem Raspberry Pi gehostet wird. Damit sollen dann neben dem Streamen des Mikrofonaudios auch noch weitere Funktionen zur Verfügung stehen. Dieses Problem ist aber derzeit meine einzige Schwierigkeit.


----------



## JuKu (26. Nov 2017)

Wie gesagt, ich habe es selbst noch nie gemacht, kann dir da also nicht wirklich einen brauchbaren Tipp geben.
Aber vllt. weiß ja jemand anders Rat?
(@mrBrown ?)

Am besten suchst du dir irgendeine fertige Java Library, die das schon kann.


----------



## Twister21 (26. Nov 2017)

Das Problem ist, dass ich nicht wirklich weiß, wo ich nach so einer Library suchen kann. Auf GitHub konnte ich noch nichts dieser Art finden.


----------



## JuKu (26. Nov 2017)

Wie kommst du denn an die Daten des Mikrofons?
Erhälst du diese als Byte Stream? Oder welches Protokoll verwendet denn dein Mikrofon / die dazugehörige Api?


----------



## Twister21 (26. Nov 2017)

Hier ist der entsprechende Abschnitt:


```
ServerSocket server = null;
        try {
            server = new ServerSocket(8888);
        } catch (IOException e) {
            e.printStackTrace();
        }
        AudioFormat format = getAudioFormat();
        DataLine.Info micInfo = new DataLine.Info(TargetDataLine.class, format);
        TargetDataLine mic = null;
        try {
            mic = (TargetDataLine) AudioSystem.getLine(micInfo);
        } catch (LineUnavailableException e) {
            e.printStackTrace();
        }
        System.out.println("TCPServer Waiting for client on port 8888");
        while (true) {
            Socket connected = null;
            try {
                connected = server.accept();
            } catch (IOException e) {
                e.printStackTrace();
            }
            new HTTPServer(connected, mic).start();
        }

public AudioFormat getAudioFormat(){
    float sampleRate = 48000.0F;
    int sampleSizeInBits = 16;
    int channels = 1;

    boolean signed = true;
    boolean bigEndian = false;

    return new AudioFormat(sampleRate, sampleSizeInBits, channels, signed, bigEndian);
}
```


----------



## JuKu (2. Dez 2017)

Hast du schon geprüft, ob AudioSystem.getLine() verwertbare Daten liefert?


----------



## Twister21 (2. Dez 2017)

Es liefert Daten, da ich so auch für meine Spracherkennung auf das Mikrofon zugreife. Dabei schicke ich die Daten aber direkt an den Google Server. Ich kann sie wahrscheinlich jedoch nicht direkt per HTTP streamen.


----------



## JuKu (3. Dez 2017)

Ja. Ich habe leider selbst zu wenig Erfahrung mit Audio Streams, als dass ich dir dabei ernsthaft helfen könnte.

Vllt. helfen dir diese Links weiter:

http://www.xuggle.com/xuggler/
http://www.jcraft.com/jroar/

EDIT:
Noch was gefunden: https://stackoverflow.com/questions/28122097/live-audio-stream-java


----------



## Manuel.R (22. Dez 2017)

Was ist denn mit den Standard-Protokollen für das Streamen:
RTP, RTSP(2.0), RTMP
Die Definition zu den Protokollen sagt nichts dazu aus, dass nur Videoformate damit übertragen werden können. Ob TCP oder UDP genutzt wird, ist bereits in den Streaming-Protokollen implementiert.

Gängie Audioformate für das Streaming sind:
*MP3, AAC, Ogg Vorbis*

*Guck dir mal den GStreamer an: https://github.com/gstreamer-java*


----------



## Twister21 (22. Dez 2017)

Hallo,

danke für die Hilfe, aber ich werde nun erstmal Icecast in Verbindung mit Darkice nutzen, um mein Mikrofon zu streamen.


----------

