X-Git-Url: https://git.pterodactylus.net/?a=blobdiff_plain;ds=sidebyside;f=src%2Fmain%2Fjava%2Fnet%2Fpterodactylus%2Fsonitus%2Fdata%2Fsink%2FIcecast2Sink.java;h=36413f96b6ae6e1b859cb4778e5cbf4ab54f07ef;hb=09f8bd2297dc864e24baa67c65be97104e00c320;hp=3bf942edec7ae8e748f4af79148c654788c56ac9;hpb=5b3515c2fe22320f0a0d8e2e2f10145c89a4cf92;p=sonitus.git
diff --git a/src/main/java/net/pterodactylus/sonitus/data/sink/Icecast2Sink.java b/src/main/java/net/pterodactylus/sonitus/data/sink/Icecast2Sink.java
index 3bf942e..36413f9 100644
--- a/src/main/java/net/pterodactylus/sonitus/data/sink/Icecast2Sink.java
+++ b/src/main/java/net/pterodactylus/sonitus/data/sink/Icecast2Sink.java
@@ -17,8 +17,6 @@
package net.pterodactylus.sonitus.data.sink;
-import static com.google.common.base.Preconditions.*;
-
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@@ -26,14 +24,14 @@ import java.io.UnsupportedEncodingException;
import java.net.Socket;
import java.net.URLEncoder;
import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
-import net.pterodactylus.sonitus.data.ConnectException;
-import net.pterodactylus.sonitus.data.Connection;
+import net.pterodactylus.sonitus.data.Controller;
import net.pterodactylus.sonitus.data.Metadata;
import net.pterodactylus.sonitus.data.Sink;
-import net.pterodactylus.sonitus.data.Source;
import net.pterodactylus.sonitus.io.InputStreamDrainer;
import com.google.common.base.Function;
@@ -44,8 +42,8 @@ import com.google.common.io.BaseEncoding;
import com.google.common.io.Closeables;
/**
- * {@link Sink} implementation that delivers all incoming data to an Icecast2
- * server.
+ * {@link net.pterodactylus.sonitus.data.Sink} implementation that delivers all
+ * incoming data to an Icecast2 server.
*
* @author David âBombeâ Roden
*/
@@ -78,8 +76,7 @@ public class Icecast2Sink implements Sink {
/** Whether to publish the server. */
private final boolean publishServer;
- /** The connected source. */
- private Source source;
+ private OutputStream socketOutputStream;
/**
* Creates a new Icecast2 sink.
@@ -114,101 +111,103 @@ public class Icecast2Sink implements Sink {
}
//
- // SINK METHODS
+ // CONTROLLED METHODS
//
@Override
- public void connect(Source source) throws ConnectException {
- checkNotNull(source, "source must not be null");
+ public String name() {
+ return String.format("icecast://%s:%d/%s", server, port, mountPoint);
+ }
- this.source = source;
- try {
- logger.info(String.format("Icecast2Sink: Connecting to %s:%d...", server, port));
- final Socket socket = new Socket(server, port);
- logger.info("Icecast2Sink: Connected.");
- final OutputStream socketOutputStream = socket.getOutputStream();
- final InputStream socketInputStream = socket.getInputStream();
-
- sendLine(socketOutputStream, String.format("SOURCE /%s ICE/1.0", mountPoint));
- sendLine(socketOutputStream, String.format("Authorization: Basic %s", generatePassword(password)));
- sendLine(socketOutputStream, String.format("Content-Type: %s", getContentType(source.metadata())));
- sendLine(socketOutputStream, String.format("ICE-Name: %s", serverName));
- sendLine(socketOutputStream, String.format("ICE-Description: %s", serverDescription));
- sendLine(socketOutputStream, String.format("ICE-Genre: %s", genre));
- sendLine(socketOutputStream, String.format("ICE-Public: %d", publishServer ? 1 : 0));
- sendLine(socketOutputStream, "");
- socketOutputStream.flush();
-
- new Thread(new InputStreamDrainer(socketInputStream)).start();
- new Thread(new Connection(source) {
-
- private long counter;
-
- @Override
- protected int bufferSize() {
- return 4096;
- }
+ @Override
+ public List> controllers() {
+ return Collections.emptyList();
+ }
- @Override
- protected void feed(byte[] buffer) throws IOException {
- socketOutputStream.write(buffer);
- socketOutputStream.flush();
- counter += buffer.length;
- logger.finest(String.format("Wrote %d Bytes.", counter));
- }
+ //
+ // SINK METHODS
+ //
- @Override
- protected void finish() throws IOException {
- Closeables.close(socketOutputStream, true);
- if (socket != null) {
- socket.close();
- }
- }
- }).start();
+ @Override
+ public void open(Metadata metadata) throws IOException {
+ logger.info(String.format("Connecting to %s:%d...", server, port));
+ Socket socket = new Socket(server, port);
+ logger.info("Connected.");
+ socketOutputStream = socket.getOutputStream();
+ InputStream socketInputStream = socket.getInputStream();
+
+ sendLine(socketOutputStream, String.format("SOURCE /%s ICE/1.0", mountPoint));
+ sendLine(socketOutputStream, String.format("Authorization: Basic %s", generatePassword(password)));
+ sendLine(socketOutputStream, String.format("Content-Type: %s", getContentType(metadata)));
+ sendLine(socketOutputStream, String.format("ICE-Name: %s", serverName));
+ sendLine(socketOutputStream, String.format("ICE-Description: %s", serverDescription));
+ sendLine(socketOutputStream, String.format("ICE-Genre: %s", genre));
+ sendLine(socketOutputStream, String.format("ICE-Public: %d", publishServer ? 1 : 0));
+ sendLine(socketOutputStream, "");
+ socketOutputStream.flush();
+
+ new Thread(new InputStreamDrainer(socketInputStream)).start();
+
+ metadataUpdated(metadata);
+ }
- metadataUpdated();
- } catch (IOException ioe1) {
- throw new ConnectException(ioe1);
+ @Override
+ public void close() {
+ try {
+ Closeables.close(socketOutputStream, true);
+ } catch (IOException e) {
+ /* will never throw. */
}
}
@Override
- public void metadataUpdated() {
- Metadata metadata = source.metadata();
- String metadataString = String.format("%s (%s)", Joiner.on(" - ").skipNulls().join(FluentIterable.from(Arrays.asList(metadata.artist(), metadata.name())).transform(new Function, Object>() {
+ public void metadataUpdated(final Metadata metadata) {
+ new Thread(new Runnable() {
@Override
- public Object apply(Optional input) {
- return input.orNull();
- }
- })), "Sonitus");
- logger.info(String.format("Updating metadata to %s", metadataString));
+ public void run() {
+ String metadataString = String.format("%s (%s)", Joiner.on(" - ").skipNulls().join(FluentIterable.from(Arrays.asList(metadata.artist(), metadata.name())).transform(new Function, Object>() {
- Socket socket = null;
- OutputStream socketOutputStream = null;
- try {
- socket = new Socket(server, port);
- socketOutputStream = socket.getOutputStream();
-
- sendLine(socketOutputStream, String.format("GET /admin/metadata?pass=%s&mode=updinfo&mount=/%s&song=%s HTTP/1.0", password, mountPoint, URLEncoder.encode(metadataString, "UTF-8")));
- sendLine(socketOutputStream, String.format("Authorization: Basic %s", generatePassword(password)));
- sendLine(socketOutputStream, String.format("User-Agent: Mozilla/Sonitus"));
- sendLine(socketOutputStream, "");
- socketOutputStream.flush();
-
- new InputStreamDrainer(socket.getInputStream()).run();
- } catch (IOException ioe1) {
- logger.log(Level.WARNING, "Could not update metadata!", ioe1);
- } finally {
- try {
- Closeables.close(socketOutputStream, true);
- if (socket != null) {
- socket.close();
+ @Override
+ public Object apply(Optional input) {
+ return input.orNull();
+ }
+ })), "Sonitus");
+ logger.info(String.format("Updating metadata to %s", metadataString));
+
+ Socket socket = null;
+ OutputStream socketOutputStream = null;
+ try {
+ socket = new Socket(server, port);
+ socketOutputStream = socket.getOutputStream();
+
+ sendLine(socketOutputStream, String.format("GET /admin/metadata?pass=%s&mode=updinfo&mount=/%s&song=%s HTTP/1.0", password, mountPoint, URLEncoder.encode(metadataString, "UTF-8")));
+ sendLine(socketOutputStream, String.format("Authorization: Basic %s", generatePassword(password)));
+ sendLine(socketOutputStream, String.format("User-Agent: Mozilla/Sonitus"));
+ sendLine(socketOutputStream, "");
+ socketOutputStream.flush();
+
+ new InputStreamDrainer(socket.getInputStream()).run();
+ } catch (IOException ioe1) {
+ logger.log(Level.WARNING, "Could not update metadata!", ioe1);
+ } finally {
+ try {
+ Closeables.close(socketOutputStream, true);
+ if (socket != null) {
+ socket.close();
+ }
+ } catch (IOException ioe1) {
+ /* ignore. */
+ }
}
- } catch (IOException ioe1) {
- /* ignore. */
}
- }
+ }).start();
+ }
+
+ @Override
+ public void process(byte[] buffer) throws IOException {
+ socketOutputStream.write(buffer);
+ socketOutputStream.flush();
}
//
@@ -223,7 +222,7 @@ public class Icecast2Sink implements Sink {
* The output stream to send the line to
* @param line
* The line to send
- * @throws IOException
+ * @throws java.io.IOException
* if an I/O error occurs
*/
private static void sendLine(OutputStream outputStream, String line) throws IOException {
@@ -237,7 +236,7 @@ public class Icecast2Sink implements Sink {
* @param password
* The password to encode
* @return The encoded password
- * @throws UnsupportedEncodingException
+ * @throws java.io.UnsupportedEncodingException
* if the UTF-8 encoding is not supported (which can never happen)
*/
private static String generatePassword(String password) throws UnsupportedEncodingException {
@@ -245,8 +244,8 @@ public class Icecast2Sink implements Sink {
}
/**
- * Returns a MIME type for the given metadata. Currently only Vorbis, MP3, and
- * PCM formats are recognized.
+ * Returns a MIME type for the given metadata. Currently only Vorbis, MP3, PCM,
+ * Ogg Vorbis, Opus, and FLAC formats are recognized.
*
* @param metadata
* The metadata to get a MIME type for
@@ -263,6 +262,15 @@ public class Icecast2Sink implements Sink {
if ("PCM".equalsIgnoreCase(encoding)) {
return "audio/vnd.wave";
}
+ if ("Vorbis".equalsIgnoreCase(encoding)) {
+ return "application/ogg";
+ }
+ if ("Opus".equalsIgnoreCase(encoding)) {
+ return "audio/ogg; codecs=opus";
+ }
+ if ("FLAC".equalsIgnoreCase(encoding)) {
+ return "audio/flac";
+ }
return "application/octet-stream";
}