import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.Socket;
+import java.net.URLEncoder;
+import java.util.Arrays;
+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.Format;
+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;
+import com.google.common.base.Joiner;
+import com.google.common.base.Optional;
+import com.google.common.collect.FluentIterable;
import com.google.common.io.BaseEncoding;
import com.google.common.io.Closeables;
/** Whether to publish the server. */
private final boolean publishServer;
+ /** The connected source. */
+ private Source source;
+
/**
* Creates a new Icecast2 sink.
*
public void connect(Source source) throws ConnectException {
checkNotNull(source, "source must not be null");
+ this.source = source;
try {
- logger.info(String.format("Icecast2Sink: Connecting to %s:%d...", server, port));
+ logger.info(String.format("Connecting to %s:%d...", server, port));
final Socket socket = new Socket(server, port);
- logger.info("Icecast2Sink: Connected.");
+ logger.info("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.format())));
+ 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));
@Override
protected void finish() throws IOException {
Closeables.close(socketOutputStream, true);
- Closeables.close(socket, true);
+ if (socket != null) {
+ socket.close();
+ }
}
}).start();
+
+ metadataUpdated();
} catch (IOException ioe1) {
throw new ConnectException(ioe1);
}
}
+ @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<Optional<String>, Object>() {
+
+ @Override
+ public Object apply(Optional<String> 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. */
+ }
+ }
+ }
+
//
// PRIVATE METHODS
//
}
/**
- * Returns a MIME type for the given format. Currently only Vorbis, MP3, and
+ * Returns a MIME type for the given metadata. Currently only Vorbis, MP3, and
* PCM formats are recognized.
*
- * @param format
- * The format to get a MIME type for
- * @return The MIME type of the format
+ * @param metadata
+ * The metadata to get a MIME type for
+ * @return The MIME type of the metadata
*/
- private static String getContentType(Format format) {
- switch (format.encoding().toUpperCase()) {
- case "VORBIS":
- return "audio/ogg";
- case "MP3":
- return "audio/mpeg";
- case "PCM":
- return "audio/vnd.wave";
- default:
- return "application/octet-stream";
+ private static String getContentType(Metadata metadata) {
+ String encoding = metadata.encoding();
+ if ("Vorbis".equalsIgnoreCase(encoding)) {
+ return "audio/ogg";
+ }
+ if ("MP3".equalsIgnoreCase(encoding)) {
+ return "audio/mpeg";
+ }
+ if ("PCM".equalsIgnoreCase(encoding)) {
+ return "audio/vnd.wave";
}
+ return "application/octet-stream";
}
}