App zur Steuerung des mpv Mediaplayers auf einem Raspberry Pi über HTTP
ulrich
2021-04-24 229976b4c8a0a11a30efabbb8ada5bdd0cbba8cd
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 = " ";
0af362 55   public static final String CMD_DEC_SPEED = "1";
U 56   public static final String CMD_DEC_VOL = "-";
cfe367 57   public static final String CMD_INC_SPEED = "2";
0af362 58   public static final String CMD_INC_VOL = "+";
cfe367 59   public static final String CMD_NEXT_AUDIO = "k";
U 60   public static final String CMD_NEXT_CHAPTER = "o";
61   public static final String CMD_NEXT_SUB = "m";
62   public static final String CMD_PAUSE_RESUME = "p";
63   public static final String CMD_PREV_AUDIO = "j";
64   public static final String CMD_PREV_CHAPTER = "i";
65   public static final String CMD_PREV_SUB = "n";
66   public static final String CMD_STOP = "q";
67   public static final String CMD_TOGGLE_SUB = "s";
68   public static final String F_PING = "ping";
0af362 69   public static final String F_PLAY = "play";
2dd7a5 70   public static final String F_PLAY_ON = "playon";
0af362 71   public static final String F_SEEK = "seek";
cfe367 72   public static final String OPT_HDMI_AUDIO = "-o%20hdmi";
U 73   public static final String OPT_LOCAL_AUDIO = "-o%20local";
74   public static final String PFEIL_HERAUF = "5b41";
75   public static final String PFEIL_HERUNTER = "5b42";
76   public static final String PFEIL_LINKS = "5b44";
77   public static final String PFEIL_RECHTS = "5b43";
78   public static final String SP_RUECK_30 = "rueck30";
79   public static final String SP_RUECK_600 = "rueck600";
80   public static final String SP_VOR_30 = "rueck30";
81   public static final String SP_VOR_600 = "vor600";
0af362 82
cfe367 83   @Override
b6a8f0 84   public String abspielen(String urlStr, String parameter, String meldeUrlStr, String token) {
8e2038 85     String antwort;// = null;
U 86     try {
a7f0a1 87       Process o = App.getPlayerProcess();
8e2038 88       if(o != null) {
a7f0a1 89         tilgen();        
8e2038 90       }
2dd7a5 91       List<String> kommando = new ArrayList();
6ff352 92       kommando.add(NAME);
2dd7a5 93       kommando.addAll(Arrays.asList(parameter.split(BLANK)));
8e2038 94       if(urlStr.startsWith("http")) {
2dd7a5 95         kommando.add(urlStr.replace(" ", "%20"));
8e2038 96       } else {
2dd7a5 97         kommando.add(App.getInitParameter("nfs-prefix") + urlStr);        
U 98       }      
99       logger.log(Level.FINE, "parameter: {0}", parameter);
8e2038 100       logger.log(Level.FINE, "kommando: {0}", kommando.toString());
2dd7a5 101       ProcessBuilder pb = new ProcessBuilder(kommando);
U 102       pb.directory(new File(System.getProperty("omx.wd")));
103       Process player_process = pb.start();
8e2038 104       if(meldeUrlStr != null) {
U 105         MeldeThread mt = new MeldeThread();
106         mt.setProcess(player_process);
107         mt.lauscherHinzufuegen(this);
108         mt.setMeldeUrl(meldeUrlStr);
109         mt.start();
110       }
a7f0a1 111       App.setPlayerProcess(player_process);
8e2038 112       antwort = "Abspielen gestartet, url: " + urlStr;
U 113     }
114     catch(IOException ex) {
115       antwort = "Fehler: " + ex.getMessage();
116     }
117     return antwort;
118   }
119     
120   /**
121    * Einen eventuell laufenden Abspielprozess beenden und den 
122    * Servlet-Kontext bereinigen.Diese Methode kann auch verwendet werden, wenn es beim normalen
123  Abspielen zu Fehlern kommt und womoeglich der Servlet-Kontext noch 
124  eine Referenz zu einem Abspielprozess enthaelt, die nicht mehr 
125  aktuell ist.
126    * 
127    * Mit der Methode tilgen kann man eine solche Referenz 
128  entfernen und gibt so das Objekt wieder frei fuer die Ausfuehrung 
129  weiterer Kommandos.
130    *
131    * @return die Antwort des Servers
132    */
cfe367 133   @Override
a7f0a1 134   public String tilgen() {
8e2038 135     String antwort; // = null;
U 136     try {
a7f0a1 137       Process o = App.getPlayerProcess();
8e2038 138       if(o == null) {
c18e1d 139         antwort = "Es ist kein Player zum Beenden vorhanden.";
U 140         //App.setPlayerProcess(null);
8e2038 141       } else {
2dd7a5 142         kommando(CMD_STOP); // setzt den Prozess der App auf null
c18e1d 143         antwort = "Player gestoppt.";
8e2038 144       }
U 145     } 
146     catch(Exception ex) {
147       antwort = "Fehler: " + ex.getMessage();
148     }
149     return antwort;
150   }
151   
152   
153   /**
154    * Dem laufenden Abspielprozess ein Kommando uebermitteln
155    * @param k  das Kommando laut 
156    * <a href="https://github.com/huceke/omxplayer/blob/master/README.md" target="_blank">Liste der Kommandos</a>
157    * @return die Antwort des Servers
158    */
cfe367 159   @Override
a7f0a1 160   public String kommando(String k) {
8e2038 161     String antwort; // = null;
U 162     try {
a7f0a1 163       //Object o = t.getAttribute(App.PI_PLAYER);
U 164       Process o = App.getPlayerProcess();
8e2038 165       if(o == null) {
c18e1d 166         //App.setPlayerProcess(null);
8e2038 167         //servletContext.removeAttribute(PI_PLAYER);
a7f0a1 168         //t.setAttribute(App.PI_PLAYER, null);
8e2038 169         antwort = "Es wird nichts abgespielt dem ein Kommando gesendet werden kann.";
U 170       } else {
a7f0a1 171         Process player_process = o;
8e2038 172         OutputStream os = player_process.getOutputStream();
U 173         Writer out = new BufferedWriter(new OutputStreamWriter(os));
174         out.write(k);
175         out.flush();
0af362 176         if(k.equals(CMD_STOP)) {
8e2038 177           out.close();
c18e1d 178           
U 179           /*
180             fuer den Fall, dass ein Stopp-Signal den Player nicht erreicht 
181             oder dort nicht funktioniert, gibt es keine Moeglichkeit festzustellen,
182             dass der Player noch spielt. Damit in einem solchen Fall der Zeiger 
183             auf den Abspielprozess nicht verloren geht, wird  der Zeiger nicht 
184             auf null gesetzt.
185           */
186           
187           //App.setPlayerProcess(null);
8e2038 188           //player_process.destroy();
U 189           //player_process = null;
a7f0a1 190           //t.setAttribute(App.PI_PLAYER, null);
8e2038 191           //servletContext.removeAttribute(PI_PLAYER);
U 192         }
193         antwort = "Kommando '" + k + "' ausgefuehrt.";
194       }
195     } 
196     catch(IOException ex) {
197       antwort = "Fehler: " + ex.getMessage();
198     }
199     return antwort;
200   }
201   
202   /* ------ Implementierung ProzessLauscher ----------------- */
203   
204   @Override
205   public void prozessBeendet(String meldeUrlStr) {
206     try {
207       HttpURLConnection conn = (HttpURLConnection) new URL(meldeUrlStr).openConnection();
208       conn.setRequestMethod("GET");
209       conn.connect();
210       int status = conn.getResponseCode();
2dd7a5 211       logger.log(Level.INFO, 
U 212               "Abspielen beendet, Meldung an {0} mit Statuscode {1} gesendet.", 
213               new Object[]{meldeUrlStr, status});
c18e1d 214           /*
U 215             fuer den Fall, dass ein Stopp-Signal den Player nicht erreicht 
216             oder dort nicht funktioniert, gibt es keine Moeglichkeit festzustellen,
217             dass der Player noch spielt. Damit in einem solchen Fall der Zeiger 
218             auf den Abspielprozess nicht verloren geht, wird  der Zeiger nicht 
219             auf null gesetzt.
220           */
221       //App.setPlayerProcess(null);
8e2038 222     } catch(IOException ex) {
U 223       logger.log(Level.INFO, ex.getMessage(), ex);
224     }
225   }
226   
227 }