|
|
@@ -0,0 +1,153 @@
|
|
|
+package homespeakers.knacki.info.homespeakersandroid;
|
|
|
+
|
|
|
+import android.app.Notification;
|
|
|
+import android.app.PendingIntent;
|
|
|
+import android.content.Intent;
|
|
|
+import android.os.IBinder;
|
|
|
+import android.preference.PreferenceManager;
|
|
|
+import android.support.v4.app.NotificationCompat;
|
|
|
+import android.util.JsonReader;
|
|
|
+
|
|
|
+import java.io.BufferedReader;
|
|
|
+import java.io.IOException;
|
|
|
+import java.io.InputStreamReader;
|
|
|
+import java.io.StringReader;
|
|
|
+import java.net.InetAddress;
|
|
|
+import java.net.InetSocketAddress;
|
|
|
+import java.net.Socket;
|
|
|
+import java.util.ArrayDeque;
|
|
|
+import java.util.Collection;
|
|
|
+import java.util.logging.Level;
|
|
|
+import java.util.logging.Logger;
|
|
|
+
|
|
|
+import homespeakers.knacki.info.homespeakersandroid.radio.Input;
|
|
|
+import homespeakers.knacki.info.homespeakersandroid.radio.InputPlayer;
|
|
|
+import homespeakers.knacki.info.homespeakersandroid.radio.InputReader;
|
|
|
+
|
|
|
+public class Service extends android.app.Service {
|
|
|
+ public final static String NOTIFICATION_CHANNEL_ID = "info.knacki.homespeakers.service";
|
|
|
+ public final static int NOTIFICATION_ID = NOTIFICATION_CHANNEL_ID.hashCode();
|
|
|
+ public final static long RECONNECT_DELAY = 60000; // 1 minute
|
|
|
+ public final static String ADDRESS = "192.168.0.5";
|
|
|
+ public final static short PORT = 9001;
|
|
|
+
|
|
|
+ private final static Logger log = Logger.getLogger(Service.class.getName());
|
|
|
+ private Collection<InputPlayer> playingInputs = new ArrayDeque<>();
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void onCreate() {
|
|
|
+ super.onCreate();
|
|
|
+ Intent notificationIntent = new Intent(this, Service.class);
|
|
|
+ PendingIntent pendingIntent =
|
|
|
+ PendingIntent.getActivity(this, 0, notificationIntent, 0);
|
|
|
+
|
|
|
+ Notification notification =
|
|
|
+ new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID)
|
|
|
+ .setContentTitle(getText(R.string.app_name))
|
|
|
+ .setContentText(getText(R.string.app_name))
|
|
|
+ .setSmallIcon(R.drawable.ic_launcher_background)
|
|
|
+ .setContentIntent(pendingIntent)
|
|
|
+ .setTicker(getText(R.string.app_name))
|
|
|
+ .build();
|
|
|
+
|
|
|
+ Logger.getAnonymousLogger().severe("Service started !");
|
|
|
+ startForeground(NOTIFICATION_ID, notification);
|
|
|
+
|
|
|
+ new Thread() {
|
|
|
+ @Override
|
|
|
+ public void run() {
|
|
|
+ createSocket();
|
|
|
+ }
|
|
|
+ }.start();
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public IBinder onBind(Intent intent) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ public String getName() {
|
|
|
+ final String value = PreferenceManager.getDefaultSharedPreferences(this).getString("name", null);
|
|
|
+ return value == null || value.isEmpty() ? null : value;
|
|
|
+ }
|
|
|
+
|
|
|
+ public void setInputs(Collection<Input> inputs) {
|
|
|
+ oldLoop: for (InputPlayer i : playingInputs) {
|
|
|
+ for (Input j : inputs) {
|
|
|
+ if (i.fName.equals(j.fName)) {
|
|
|
+ if (!j.isActive()) {
|
|
|
+ // No longer playing source, kill it
|
|
|
+ i.stop();
|
|
|
+ playingInputs.remove(i);
|
|
|
+ }
|
|
|
+ continue oldLoop;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // Source removed from server, kill it
|
|
|
+ i.stop();
|
|
|
+ playingInputs.remove(i);
|
|
|
+ }
|
|
|
+ newLoop: for (Input i : inputs) {
|
|
|
+ if (i.isActive()) {
|
|
|
+ for (InputPlayer j : playingInputs)
|
|
|
+ if (i.fName.equals(j.fName))
|
|
|
+ continue newLoop;
|
|
|
+ // New source, add it
|
|
|
+ InputPlayer player = new InputPlayer(i);
|
|
|
+ player.start();
|
|
|
+ playingInputs.add(player);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public void manageSocket(BufferedReader stream) throws IOException {
|
|
|
+ while (true) {
|
|
|
+ String config = stream.readLine();
|
|
|
+ if (config == null)
|
|
|
+ return;
|
|
|
+ Collection<Input> inputs = InputReader.Read(new JsonReader(new StringReader(config)));
|
|
|
+ setInputs(inputs);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private static Socket fSock;
|
|
|
+
|
|
|
+ private static void sendName(String name) {
|
|
|
+ if (fSock == null) return;
|
|
|
+ try {
|
|
|
+ fSock.getOutputStream().write(("HELO " +name + "\n").getBytes("utf-8"));
|
|
|
+ }
|
|
|
+ catch (IOException e) {}
|
|
|
+ }
|
|
|
+
|
|
|
+ public void createSocket() {
|
|
|
+ fSock = null;
|
|
|
+ while (true) {
|
|
|
+ try {
|
|
|
+ fSock = new Socket();
|
|
|
+ log.info("Connecting to " +ADDRESS +" port " +PORT);
|
|
|
+ fSock.connect(new InetSocketAddress(InetAddress.getByName(ADDRESS), PORT));
|
|
|
+ String name = getName();
|
|
|
+ if (name != null)
|
|
|
+ sendName(name);
|
|
|
+ manageSocket(new BufferedReader(new InputStreamReader(fSock.getInputStream())));
|
|
|
+ } catch (IOException e) {
|
|
|
+ fSock = null;
|
|
|
+ log.log(Level.SEVERE, "Cannot connect to server", e);
|
|
|
+ try {
|
|
|
+ Thread.sleep(RECONNECT_DELAY);
|
|
|
+ }
|
|
|
+ catch (InterruptedException e2) {}
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public static void setName(String value) {
|
|
|
+ new Thread() {
|
|
|
+ @Override
|
|
|
+ public void run() {
|
|
|
+ sendName(value);
|
|
|
+ }
|
|
|
+ }.start();
|
|
|
+ }
|
|
|
+}
|