App zur Steuerung des mpv Mediaplayers auf einem Raspberry Pi über HTTP
ulrich
2022-05-11 37f9ab18251d7be3b154e2af30954fa95496f4d2
commit | author | age
60719c 1 /*
U 2     AV-Direktor - Control OMXPlayer on Raspberry Pi via HTTP
3     Copyright (C) 2021  Ulrich Hilger
4
5     This program is free software: you can redistribute it and/or modify
6     it under the terms of the GNU Affero General Public License as
7     published by the Free Software Foundation, either version 3 of the
8     License, or (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU Affero General Public License for more details.
14
15     You should have received a copy of the GNU Affero General Public License
16     along with this program.  If not, see <https://www.gnu.org/licenses/>.
17 */
18
229976 19 package de.uhilger.calypso.handler;
8e2038 20
229976 21 import de.uhilger.calypso.App;
U 22 import de.uhilger.calypso.MeldeThread;
23 import de.uhilger.calypso.ProzessLauscher;
8e2038 24 import java.io.BufferedWriter;
2dd7a5 25 import java.io.File;
8e2038 26 import java.io.IOException;
U 27 import java.io.OutputStream;
28 import java.io.OutputStreamWriter;
29 import java.io.Writer;
30 import java.net.HttpURLConnection;
31 import java.net.URL;
2dd7a5 32 import java.util.ArrayList;
U 33 import java.util.Arrays;
34 import java.util.List;
8e2038 35 import java.util.logging.Level;
U 36 import java.util.logging.Logger;
37
38 /**
cc2a32 39  * Methoden zur Ausfuehrung des Programmes omxplayer des Raspberry Pi 
U 40  * sowie zum Senden von Kommandos an eine laufende Instanz des 
41  * omxplayer.
42  * 
43  * Die Klasse OMXPlayer stellt als abstrakte Basisklasse ihre Methoden 
44  * den Handler-Klassen zur Verfuegung.
8e2038 45  *
U 46  * @author ulrich
47  */
cfe367 48 public class OMXPlayer implements Player , ProzessLauscher {
8e2038 49   
U 50   private static final Logger logger = Logger.getLogger(OMXPlayer.class.getName());
0c8d27 51   
6ff352 52   public static final String NAME = "omxplayer";
U 53   
cfe367 54   public static final String BLANK = " ";
37f9ab 55   public static final String CMD_TOGGLE_INFO = "z";
0af362 56   public static final String CMD_DEC_SPEED = "1";
U 57   public static final String CMD_DEC_VOL = "-";
cfe367 58   public static final String CMD_INC_SPEED = "2";
37f9ab 59   public static final String CMD_INC_VOL = "="; // oder "+";
cfe367 60   public static final String CMD_NEXT_AUDIO = "k";
U 61   public static final String CMD_NEXT_CHAPTER = "o";
62   public static final String CMD_NEXT_SUB = "m";
63   public static final String CMD_PAUSE_RESUME = "p";
64   public static final String CMD_PREV_AUDIO = "j";
65   public static final String CMD_PREV_CHAPTER = "i";
66   public static final String CMD_PREV_SUB = "n";
67   public static final String CMD_STOP = "q";
68   public static final String CMD_TOGGLE_SUB = "s";
69   public static final String F_PING = "ping";
0af362 70   public static final String F_PLAY = "play";
2dd7a5 71   public static final String F_PLAY_ON = "playon";
0af362 72   public static final String F_SEEK = "seek";
cfe367 73   public static final String OPT_HDMI_AUDIO = "-o%20hdmi";
U 74   public static final String OPT_LOCAL_AUDIO = "-o%20local";
75   public static final String PFEIL_HERAUF = "5b41";
76   public static final String PFEIL_HERUNTER = "5b42";
77   public static final String PFEIL_LINKS = "5b44";
78   public static final String PFEIL_RECHTS = "5b43";
79   public static final String SP_RUECK_30 = "rueck30";
80   public static final String SP_RUECK_600 = "rueck600";
81   public static final String SP_VOR_30 = "rueck30";
82   public static final String SP_VOR_600 = "vor600";
0af362 83
cfe367 84   @Override
b6a8f0 85   public String abspielen(String urlStr, String parameter, String meldeUrlStr, String token) {
8e2038 86     String antwort;// = null;
U 87     try {
a7f0a1 88       Process o = App.getPlayerProcess();
8e2038 89       if(o != null) {
a7f0a1 90         tilgen();        
8e2038 91       }
2dd7a5 92       List<String> kommando = new ArrayList();
6ff352 93       kommando.add(NAME);
2dd7a5 94       kommando.addAll(Arrays.asList(parameter.split(BLANK)));
8e2038 95       if(urlStr.startsWith("http")) {
2dd7a5 96         kommando.add(urlStr.replace(" ", "%20"));
8e2038 97       } else {
2dd7a5 98         kommando.add(App.getInitParameter("nfs-prefix") + urlStr);        
U 99       }      
100       logger.log(Level.FINE, "parameter: {0}", parameter);
8e2038 101       logger.log(Level.FINE, "kommando: {0}", kommando.toString());
2dd7a5 102       ProcessBuilder pb = new ProcessBuilder(kommando);
U 103       pb.directory(new File(System.getProperty("omx.wd")));
104       Process player_process = pb.start();
8e2038 105       if(meldeUrlStr != null) {
U 106         MeldeThread mt = new MeldeThread();
107         mt.setProcess(player_process);
108         mt.lauscherHinzufuegen(this);
109         mt.setMeldeUrl(meldeUrlStr);
110         mt.start();
111       }
a7f0a1 112       App.setPlayerProcess(player_process);
8e2038 113       antwort = "Abspielen gestartet, url: " + urlStr;
U 114     }
115     catch(IOException ex) {
116       antwort = "Fehler: " + ex.getMessage();
117     }
118     return antwort;
119   }
120     
121   /**
122    * Einen eventuell laufenden Abspielprozess beenden und den 
123    * Servlet-Kontext bereinigen.Diese Methode kann auch verwendet werden, wenn es beim normalen
124  Abspielen zu Fehlern kommt und womoeglich der Servlet-Kontext noch 
125  eine Referenz zu einem Abspielprozess enthaelt, die nicht mehr 
126  aktuell ist.
127    * 
128    * Mit der Methode tilgen kann man eine solche Referenz 
129  entfernen und gibt so das Objekt wieder frei fuer die Ausfuehrung 
130  weiterer Kommandos.
131    *
132    * @return die Antwort des Servers
133    */
cfe367 134   @Override
a7f0a1 135   public String tilgen() {
8e2038 136     String antwort; // = null;
U 137     try {
a7f0a1 138       Process o = App.getPlayerProcess();
8e2038 139       if(o == null) {
c18e1d 140         antwort = "Es ist kein Player zum Beenden vorhanden.";
U 141         //App.setPlayerProcess(null);
8e2038 142       } else {
2dd7a5 143         kommando(CMD_STOP); // setzt den Prozess der App auf null
c18e1d 144         antwort = "Player gestoppt.";
8e2038 145       }
U 146     } 
147     catch(Exception ex) {
148       antwort = "Fehler: " + ex.getMessage();
149     }
150     return antwort;
151   }
152   
153   
154   /**
155    * Dem laufenden Abspielprozess ein Kommando uebermitteln
156    * @param k  das Kommando laut 
157    * <a href="https://github.com/huceke/omxplayer/blob/master/README.md" target="_blank">Liste der Kommandos</a>
158    * @return die Antwort des Servers
159    */
cfe367 160   @Override
a7f0a1 161   public String kommando(String k) {
8e2038 162     String antwort; // = null;
U 163     try {
a7f0a1 164       //Object o = t.getAttribute(App.PI_PLAYER);
U 165       Process o = App.getPlayerProcess();
8e2038 166       if(o == null) {
c18e1d 167         //App.setPlayerProcess(null);
8e2038 168         //servletContext.removeAttribute(PI_PLAYER);
a7f0a1 169         //t.setAttribute(App.PI_PLAYER, null);
8e2038 170         antwort = "Es wird nichts abgespielt dem ein Kommando gesendet werden kann.";
U 171       } else {
a7f0a1 172         Process player_process = o;
8e2038 173         OutputStream os = player_process.getOutputStream();
U 174         Writer out = new BufferedWriter(new OutputStreamWriter(os));
175         out.write(k);
176         out.flush();
0af362 177         if(k.equals(CMD_STOP)) {
8e2038 178           out.close();
c18e1d 179           
U 180           /*
181             fuer den Fall, dass ein Stopp-Signal den Player nicht erreicht 
182             oder dort nicht funktioniert, gibt es keine Moeglichkeit festzustellen,
183             dass der Player noch spielt. Damit in einem solchen Fall der Zeiger 
184             auf den Abspielprozess nicht verloren geht, wird  der Zeiger nicht 
185             auf null gesetzt.
186           */
187           
188           //App.setPlayerProcess(null);
8e2038 189           //player_process.destroy();
U 190           //player_process = null;
a7f0a1 191           //t.setAttribute(App.PI_PLAYER, null);
8e2038 192           //servletContext.removeAttribute(PI_PLAYER);
U 193         }
194         antwort = "Kommando '" + k + "' ausgefuehrt.";
195       }
196     } 
197     catch(IOException ex) {
198       antwort = "Fehler: " + ex.getMessage();
199     }
200     return antwort;
201   }
202   
203   /* ------ Implementierung ProzessLauscher ----------------- */
204   
205   @Override
206   public void prozessBeendet(String meldeUrlStr) {
207     try {
208       HttpURLConnection conn = (HttpURLConnection) new URL(meldeUrlStr).openConnection();
209       conn.setRequestMethod("GET");
210       conn.connect();
211       int status = conn.getResponseCode();
2dd7a5 212       logger.log(Level.INFO, 
U 213               "Abspielen beendet, Meldung an {0} mit Statuscode {1} gesendet.", 
214               new Object[]{meldeUrlStr, status});
c18e1d 215           /*
U 216             fuer den Fall, dass ein Stopp-Signal den Player nicht erreicht 
217             oder dort nicht funktioniert, gibt es keine Moeglichkeit festzustellen,
218             dass der Player noch spielt. Damit in einem solchen Fall der Zeiger 
219             auf den Abspielprozess nicht verloren geht, wird  der Zeiger nicht 
220             auf null gesetzt.
221           */
222       //App.setPlayerProcess(null);
8e2038 223     } catch(IOException ex) {
U 224       logger.log(Level.INFO, ex.getMessage(), ex);
225     }
226   }
227   
228 }