App zur Steuerung des mpv Mediaplayers auf einem Raspberry Pi über HTTP
undisclosed
2023-01-06 098eefb772fa398997afeea9bef0cca4f22251f4
Umgestellt auf mkv. Calypso ist nach einigen Erprobungen zur Zeit eher eine Baustelle. Es ist produktiv nutzbar, muss aber nach dem Einbau von mkv um viele unnuetze und teils noch nicht sauber gebaute Dinge bereinigt werden.
2 files modified
5 files added
296 ■■■■■ changed files
src/de/uhilger/calypso/App.java 9 ●●●●● patch | view | raw | blame | history
src/de/uhilger/calypso/Server.java 17 ●●●●● patch | view | raw | blame | history
src/de/uhilger/calypso/handler/MPVKillHandler.java 21 ●●●●● patch | view | raw | blame | history
src/de/uhilger/calypso/handler/MPVPlayHandler.java 27 ●●●●● patch | view | raw | blame | history
src/de/uhilger/calypso/handler/MPVPlayer.java 114 ●●●●● patch | view | raw | blame | history
src/de/uhilger/calypso/handler/MPVSeekHandler.java 62 ●●●●● patch | view | raw | blame | history
src/de/uhilger/calypso/handler/SocketHandler.java 46 ●●●●● patch | view | raw | blame | history
src/de/uhilger/calypso/App.java
@@ -18,10 +18,12 @@
package de.uhilger.calypso;
import de.uhilger.calypso.handler.MPVPlayer;
import de.uhilger.calypso.handler.MPlayer;
import de.uhilger.calypso.handler.OMXPlayer;
import de.uhilger.calypso.handler.Player;
import de.uhilger.calypso.handler.VLCPlayer;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.logging.Level;
@@ -59,8 +61,10 @@
  public static final String VLC_PLAYER = "vlc";
  public static final String OMX_PLAYER = "omx";
  public static final String M_PLAYER = "mpl";
  public static final String MPV_PLAYER = "mpv";
  public static final String OMX_WD = "omx.wd";
  public static final String CTX = "ctx";
  public static final String CONF_PATH = "conf";
  
  public static final String DEFAULT_CTX = "/calypso";
  
@@ -72,6 +76,7 @@
   * @param args the command line arguments
   */
  public static void main(String[] args) {
    Logger.getLogger(App.class.getName()).log(Level.INFO, new File(".").getAbsolutePath());
    initParams = new HashMap();
    for(String arg: args) {
      String[] argParts = arg.split("=");
@@ -80,6 +85,9 @@
        
    String playerType = getInitParameter(IP_PLAYER);
    switch(playerType) {
      case MPV_PLAYER:
        player = new MPVPlayer();
        break;
      case M_PLAYER:
        player = new MPlayer();
        break;
@@ -91,6 +99,7 @@
        break;
    }
    Server server = new Server(Integer.parseInt(getInitParameter(IP_PORT)));
    server.setPath(getInitParameter(CONF_PATH));
    String ctx = getInitParameter(CTX);
    if(ctx != null && ctx.length() > 0) {
      server.setContextName(ctx);    
src/de/uhilger/calypso/Server.java
@@ -23,6 +23,10 @@
import de.uhilger.calypso.handler.DBusHandler;
import de.uhilger.calypso.handler.FileHandler;
import de.uhilger.calypso.handler.LogHandler;
import de.uhilger.calypso.handler.MPVKillHandler;
import de.uhilger.calypso.handler.MPVPlayHandler;
import de.uhilger.calypso.handler.MPVPlayer;
import de.uhilger.calypso.handler.MPVSeekHandler;
import de.uhilger.calypso.handler.MPlayHandler;
import de.uhilger.calypso.handler.MPlayer;
import de.uhilger.calypso.handler.OMXPlayer;
@@ -30,10 +34,12 @@
import de.uhilger.calypso.handler.PlayHandler;
import de.uhilger.calypso.handler.PlayOnHandler;
import de.uhilger.calypso.handler.SeekHandler;
import de.uhilger.calypso.handler.SocketHandler;
import de.uhilger.calypso.handler.StopServerHandler;
import de.uhilger.calypso.handler.VLCKillHandler;
import de.uhilger.calypso.handler.VLCPlayer;
import de.uhilger.calypso.handler.VLCSeekHandler;
import java.io.File;
import java.io.IOException;
import java.util.logging.Logger;
import java.net.InetSocketAddress;
@@ -75,12 +81,18 @@
  private String contextName;
  private String path;
  public Server(int port) {
    this.port = port;
  }
  public void setPort(int port) {
    this.port = port;
  }
  public void setPath(String path) {
    this.path = path;
  }
  /**
@@ -117,6 +129,11 @@
      server.createContext(contextName + "/play", new MPlayHandler());
      server.createContext(contextName + "/pause", new CmdHandler(MPlayer.CMD_PAUSE_RESUME));
      server.createContext(contextName + "/stop", new CmdHandler(MPlayer.CMD_STOP));
    } else if (playerType.equals(App.MPV_PLAYER)) {
      server.createContext(contextName + "/play", new MPVPlayHandler());
      server.createContext(contextName + "/pause", new SocketHandler(path + MPVPlayer.CMD_PAUSE_RESUME));
      server.createContext(contextName + "/seek", new MPVSeekHandler(path + MPVPlayer.CMD_SEEK));
      server.createContext(contextName + "/stop", new MPVKillHandler());
    }
    server.createContext(contextName + "/ui", new FileHandler(App.getInitParameter(App.IP_WWW_DATA)));
    server.createContext(contextName + "/ping", new PingHandler(BasePlayer.F_PING));
src/de/uhilger/calypso/handler/MPVKillHandler.java
New file
@@ -0,0 +1,21 @@
package de.uhilger.calypso.handler;
import com.sun.net.httpserver.HttpExchange;
import de.uhilger.calypso.App;
/**
 *
 * @author Ulrich Hilger
 */
public class MPVKillHandler extends AbstractHandler {
  @Override
  protected String process(HttpExchange t, String params) {
      Process p = App.getPlayerProcess();
      p.destroy();
      App.setPlayerProcess(null);
    String antwort = "Player-Prozess beendet.";
    return antwort;
  }
}
src/de/uhilger/calypso/handler/MPVPlayHandler.java
New file
@@ -0,0 +1,27 @@
package de.uhilger.calypso.handler;
import com.sun.net.httpserver.HttpExchange;
import de.uhilger.calypso.App;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
 *
 * @author Ulrich Hilger
 */
public class MPVPlayHandler extends AbstractHandler {
  private static final Logger logger = Logger.getLogger(MPVPlayHandler.class.getName());
  @Override
  protected String process(HttpExchange t, String params) {
    Player player = App.getPlayer();
    String antwort = player.abspielen(
            player.getParam(map, "titel"), params, player.getParam(map, "r"), "1");
    logger.log(Level.FINE, antwort);
    return antwort;
  }
}
src/de/uhilger/calypso/handler/MPVPlayer.java
New file
@@ -0,0 +1,114 @@
package de.uhilger.calypso.handler;
import com.sun.net.httpserver.HttpExchange;
import de.uhilger.calypso.App;
import de.uhilger.calypso.MeldeThread;
import java.io.IOException;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
 *
 * @author ulrich
 */
public class MPVPlayer extends BasePlayer implements Player {
  private static final Logger logger = Logger.getLogger(MPVPlayer.class.getName());
  /*
echo '{ "command": ["get_property", "playback-time"] }' | socat - /tmp/mpvsocket
{"data":190.482000,"error":"success"}
echo 'show-text ${playback-time}' | socat - /tmp/mpvsocket
  { "command": ["set_property", "pause", true] }
  { "error": "success" }
{"command": ["cycle", "pause"]}
  */
  public static final String SOCK_PREFIX = "";
  public static final String CMD_PAUSE_RESUME = "pause";
  public static final String CMD_SEEK = "seek";
  @Override
  public String abspielen(String urlStr, String parameter, String meldeUrlStr, String token) {
    String antwort;// = null;
    try {
      //Object o = t.getAttribute(App.PI_PLAYER);
      Process o = App.getPlayerProcess();
      if(o != null) {
        tilgen();
      }
      StringBuilder kommando = new StringBuilder("mpv --input-ipc-server=/tmp/mpvsocket --no-terminal ");
      /*
      if(parameter != null) {
        kommando.append(parameter);
        kommando.append(BLANK);
      }
      */
      if(urlStr.startsWith("http")) {
        kommando.append(urlStr.replace(" ", "%20"));
        kommando.append("?t=");
        kommando.append(token);
      } else {
        /*
          //url z.B.: Filme/H/HEAT_D2.m4v
          hier muss noch der Pfad hinzugefuegt werden, unter
          dem auf dem raspi die Datenquelle via NFS eingebunden ist,
          z.B. /media/mc/
          dieser Teil des Pfades muss in pirc als Init-Parameter oder
          etwas aehnliches hinterlegt sein, weil es lokal zum jeweils
          verwendeten raspi gehoert
        */
        String pfad = App.getInitParameter("nfs-prefix");
        kommando.append(pfad);
        kommando.append(urlStr);
      }
      //kommando.append(" vlc://quit");
      logger.log(Level.FINE, "kommando: {0}", kommando.toString());
      Process player_process = Runtime.getRuntime().exec(kommando.toString());
      if(meldeUrlStr != null) {
        MeldeThread mt = new MeldeThread();
        mt.setProcess(player_process);
        mt.lauscherHinzufuegen(this);
        mt.setMeldeUrl(meldeUrlStr);
        mt.start();
      }
      //servletContext.setAttribute(App.PI_PLAYER, player_process);
      //t.setAttribute(App.PI_PLAYER, player_process);
      App.setPlayerProcess(player_process);
      //Runtime.getRuntime().exec("killall dbus-daemon");
      antwort = "Abspielen gestartet, url: " + urlStr;
    }
    catch(IOException ex) {
      antwort = "Fehler: " + ex.getMessage();
    }
    return antwort;
  }
  /*
  public String kommando(String k) {
    if(k.equalsIgnoreCase(VLCPlayer.CMD_STOP)) {
      Process p = App.getPlayerProcess();
      p.destroy();
      App.setPlayerProcess(null);
    }
    String antwort = "Kommando '" + k + "' ausgefuehrt.";
    return antwort;
  }
*/
  @Override
  public StringBuilder buildParams(HttpExchange t, Map m) {
    return new StringBuilder();
  }
}
src/de/uhilger/calypso/handler/MPVSeekHandler.java
New file
@@ -0,0 +1,62 @@
package de.uhilger.calypso.handler;
import com.sun.net.httpserver.HttpExchange;
import de.uhilger.calypso.App;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
 * http://server:9090/calypso/seek?pos=30 (30 Sekunden vor) oder pos=-30 (zurueck)
 *
 * echo '{"command": ["seek", '30']}' | socat - /tmp/mpvsocket
 * echo '{"command": ["seek", '-30']}' | socat - /tmp/mpvsocket
 *
 * in einem Shell Skript
 * echo '{"command": ["seek", '$1']}' | socat - /tmp/mpvsocket
 *
 *
 * @author Ulrich Hilger
 */
public class MPVSeekHandler extends CmdHandler {
  private static final Logger logger = Logger.getLogger(MPVSeekHandler.class.getName());
  public MPVSeekHandler(String cmd) {
    super(cmd);
  }
  @Override
  protected String process(HttpExchange t, String params) {
    String antwort;// = null;
    try {
      StringBuilder kommando = new StringBuilder();
      //kommando.append(VLCPlayer.DBUS_PREFIX);
      kommando.append(cmd);
      kommando.append(params);
      logger.log(Level.FINE, "kommando: {0}", kommando.toString());
      Process player_process = Runtime.getRuntime().exec(kommando.toString());
      antwort = "Kommando ausgefuehrt: " + kommando;
    } catch (IOException ex) {
      antwort = "Fehler: " + ex.getMessage();
    }
    return antwort;
  }
  @Override
  protected StringBuilder buildParams(HttpExchange t) {
    Player player = App.getPlayer();
    StringBuilder params = super.buildParams(t);
    if (player instanceof MPVPlayer) {
      String pos = player.getParam(map, "pos");
      if (!pos.isEmpty()) {
        params.append(" ");
        params.append(pos);
      }
    }
    logger.log(Level.FINER, "params: " + params.toString());
    return params;
  }
}
src/de/uhilger/calypso/handler/SocketHandler.java
New file
@@ -0,0 +1,46 @@
package de.uhilger.calypso.handler;
import com.sun.net.httpserver.HttpExchange;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
 * Hier muss noch die Implementierung mit Unix Domain Sockets folgen,
 * sobald Java 16 fuer 64-bit Raspberry Pi 4 erhaeltlich ist.
 *
 * Bis dahin wird hier (dirty trick) ein Shell Skript aufgerufen,
 * das mit Hilfe des Tools socat das Kommando ausfuehrt. socat muss
 * dafuer auf dem Raspberry Pi installiert sein.
 *
 * Kommandos
 *
 * pause: echo '{"command": ["cycle", "pause"]}' | socat - /tmp/mpvsocket
 * seek: echo '{"command": ["seek", '30']}' | socat - /tmp/mpvsocket
 *
 * @author Ulrich Hilger
 */
public class SocketHandler extends CmdHandler {
  private static final Logger logger = Logger.getLogger(SocketHandler.class.getName());
  public SocketHandler(String cmd) {
    super(cmd);
  }
  @Override
  protected String process(HttpExchange t, String params) {
      String antwort;// = null;
    try {
      StringBuilder kommando = new StringBuilder();
      kommando.append(MPVPlayer.SOCK_PREFIX);
      kommando.append(cmd);
      logger.log(Level.FINE, "kommando: {0}", kommando.toString());
      Process player_process = Runtime.getRuntime().exec(kommando.toString());
      antwort = "Kommando ausgefuehrt: " + kommando;
    } catch (IOException ex) {
      antwort = "Fehler: " + ex.getMessage();
    }
    return antwort;
  }
}