App zur Steuerung des mpv Mediaplayers auf einem Raspberry Pi über HTTP
ulrich
2021-03-25 60719cc5f0cdc13defcf73eb4a0701ee9b654289
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
8e2038 19 package de.uhilger.avdirektor.handler;
U 20
21 import de.uhilger.avdirektor.App;
22 import de.uhilger.avdirektor.MeldeThread;
23 import de.uhilger.avdirektor.ProzessLauscher;
24 import java.io.BufferedWriter;
25 import java.io.IOException;
26 import java.io.OutputStream;
27 import java.io.OutputStreamWriter;
28 import java.io.Writer;
29 import java.net.HttpURLConnection;
30 import java.net.URL;
31 import java.util.logging.Level;
32 import java.util.logging.Logger;
33
34 /**
cc2a32 35  * Methoden zur Ausfuehrung des Programmes omxplayer des Raspberry Pi 
U 36  * sowie zum Senden von Kommandos an eine laufende Instanz des 
37  * omxplayer.
38  * 
39  * Die Klasse OMXPlayer stellt als abstrakte Basisklasse ihre Methoden 
40  * den Handler-Klassen zur Verfuegung.
8e2038 41  *
U 42  * @author ulrich
43  */
44 public abstract class OMXPlayer implements ProzessLauscher {
45   
46   private static final Logger logger = Logger.getLogger(OMXPlayer.class.getName());
0c8d27 47   
0af362 48   public static final String CMD_STOP = "q";
U 49   public static final String CMD_DEC_SPEED = "1";
50   public static final String CMD_INC_SPEED = "2";
51   public static final String CMD_PREV_AUDIO = "j";
52   public static final String CMD_NEXT_AUDIO = "k";
53   public static final String CMD_PREV_CHAPTER = "i";
54   public static final String CMD_NEXT_CHAPTER = "o";
55   public static final String CMD_PREV_SUB = "n";
56   public static final String CMD_NEXT_SUB = "m";
57   public static final String CMD_TOGGLE_SUB = "s";
58   public static final String CMD_PAUSE_RESUME = "p";
59   public static final String CMD_DEC_VOL = "-";
60   public static final String CMD_INC_VOL = "+";
61   
62   public static final String PFEIL_LINKS = "5b44";
63   public static final String PFEIL_RECHTS = "5b43";
64   public static final String PFEIL_HERAUF = "5b41";
65   public static final String PFEIL_HERUNTER = "5b42";
66   
67   public static final String SP_RUECK_30 = "rueck30";
68   public static final String SP_VOR_30 = "rueck30";
69   public static final String SP_VOR_600 = "vor600";
70   public static final String SP_RUECK_600 = "rueck600";  
71
72   public static final String OPT_LOCAL_AUDIO = "-o%20local";
73   public static final String OPT_HDMI_AUDIO = "-o%20hdmi";
74   
75   public static final String F_PLAY = "play";
76   public static final String F_SEEK = "seek";
77   public static final String F_PING = "ping";
78
79   public static final String BLANK = " ";
80
8e2038 81   /**
U 82    * Einen Prozess zum Abspielen mit dem omxplayer starten
83    * @param urlStr  URL der Quelle, die abgespielt werden soll
84    * @param token
85    * @return Antwort des Servers
86    */
b6a8f0 87   /*
a7f0a1 88   public String abspielen(String urlStr, String token) {
U 89     return abspielenMitParametern(urlStr, null, token);
8e2038 90   }
b6a8f0 91   */
8e2038 92   
b6a8f0 93   /*
a7f0a1 94   public String abspielenMitRueckmeldung(String urlStr, String meldeUrlStr, String token) {
U 95     return abspielenMitParameternUndRueckmeldung(urlStr, null, meldeUrlStr, token);
8e2038 96   }
b6a8f0 97   */
8e2038 98   
U 99   /**
100    * Einen Prozess zum Abspielen mit dem omxplayer starten 
101    * und Parameter uebergeben.Moegliche Parameter fuer das Abspielen mit dem omxplayer 
102  beschreibt die Seite 
103   <a href="https://github.com/huceke/omxplayer/blob/master/README.md"target="_blank">Aufstellung der Parameter</a>.Die Zeichenkette parameter enthaelt Eintraege wie z.B.
104    * App.OPT_LOCAL_AUDIO oder App.OPT_HDMI_AUDIO.
105  Mehrere Parameter werden mit App.BLANK getrennt.
106    * @param urlStr  der URL der Quelle, die abgespielt werden soll
107    * @param parameter  die Parameter, die vom omxplayer angewendet werden sollen
108    * @param token
109    * @return Antwort des Servers
110    */
b6a8f0 111   /*
a7f0a1 112   public String abspielenMitParametern(String urlStr, String parameter, String token) {
U 113     return abspielenMitParameternUndRueckmeldung(urlStr, parameter, null, token);
8e2038 114   }
b6a8f0 115   */
8e2038 116   
b6a8f0 117   public String abspielen(String urlStr, String parameter, String meldeUrlStr, String token) {
8e2038 118     String antwort;// = null;
U 119     try {
a7f0a1 120       //Object o = t.getAttribute(App.PI_PLAYER);
U 121       Process o = App.getPlayerProcess();
8e2038 122       if(o != null) {
a7f0a1 123         tilgen();        
8e2038 124       }
U 125       StringBuilder kommando = new StringBuilder("omxplayer ");
126       if(parameter != null) {
127         kommando.append(parameter);
0af362 128         kommando.append(BLANK);
8e2038 129       }
U 130       if(urlStr.startsWith("http")) {
131         kommando.append(urlStr.replace(" ", "%20"));
132         kommando.append("?t=");
133         kommando.append(token);
134       } else {
135         /*
136           //url z.B.: Filme/H/HEAT_D2.m4v
137         
138           hier muss noch der Pfad hinzugefuegt werden, unter 
139           dem auf dem raspi die Datenquelle via NFS eingebunden ist,
140           z.B. /media/mc/
141           dieser Teil des Pfades muss in pirc als Init-Parameter oder 
142           etwas aehnliches hinterlegt sein, weil es lokal zum jeweils 
143           verwendeten raspi gehoert
144   
145         */
146         
147         String pfad = App.getInitParameter("nfs-prefix");
148         kommando.append(pfad);
149         
150         kommando.append(urlStr);
151       }
152       logger.log(Level.FINE, "kommando: {0}", kommando.toString());
153       Process player_process = Runtime.getRuntime().exec(kommando.toString());
154       if(meldeUrlStr != null) {
155         MeldeThread mt = new MeldeThread();
156         mt.setProcess(player_process);
157         mt.lauscherHinzufuegen(this);
158         mt.setMeldeUrl(meldeUrlStr);
159         mt.start();
160       }
161       //servletContext.setAttribute(App.PI_PLAYER, player_process);
a7f0a1 162       //t.setAttribute(App.PI_PLAYER, player_process);
U 163       App.setPlayerProcess(player_process);
8e2038 164       //Runtime.getRuntime().exec("killall dbus-daemon");
U 165       antwort = "Abspielen gestartet, url: " + urlStr;
166     }
167     catch(IOException ex) {
168       antwort = "Fehler: " + ex.getMessage();
169     }
170     return antwort;
171   }
172     
173   /**
174    * Einen eventuell laufenden Abspielprozess beenden und den 
175    * Servlet-Kontext bereinigen.Diese Methode kann auch verwendet werden, wenn es beim normalen
176  Abspielen zu Fehlern kommt und womoeglich der Servlet-Kontext noch 
177  eine Referenz zu einem Abspielprozess enthaelt, die nicht mehr 
178  aktuell ist.
179    * 
180    * Mit der Methode tilgen kann man eine solche Referenz 
181  entfernen und gibt so das Objekt wieder frei fuer die Ausfuehrung 
182  weiterer Kommandos.
183    *
184    * @return die Antwort des Servers
185    */
a7f0a1 186   public String tilgen() {
8e2038 187     String antwort; // = null;
U 188     try {
a7f0a1 189       //Object o = t.getAttribute(App.PI_PLAYER);
U 190       Process o = App.getPlayerProcess();
8e2038 191       if(o == null) {
a7f0a1 192         //t.setAttribute(App.PI_PLAYER, null);
U 193         App.setPlayerProcess(null);
8e2038 194         // t.removeAttribute(App.PI_PLAYER);
U 195         antwort = "Es ist kein Player zum Beenden vorhanden, aber der Servlet-Kontext wurde bereinigt.";
196       } else {
0af362 197         kommando(CMD_STOP);
8e2038 198         //t.removeAttribute(PI_PLAYER);
U 199         antwort = "Player gestoppt, Kontext bereinigt.";
200       }
201     } 
202     catch(Exception ex) {
203       antwort = "Fehler: " + ex.getMessage();
204     }
205     return antwort;
206   }
207   
208   
209   /**
210    * Dem laufenden Abspielprozess ein Kommando uebermitteln
211    * @param k  das Kommando laut 
212    * <a href="https://github.com/huceke/omxplayer/blob/master/README.md" target="_blank">Liste der Kommandos</a>
213    * @return die Antwort des Servers
214    */
a7f0a1 215   public String kommando(String k) {
8e2038 216     String antwort; // = null;
U 217     try {
a7f0a1 218       //Object o = t.getAttribute(App.PI_PLAYER);
U 219       Process o = App.getPlayerProcess();
8e2038 220       if(o == null) {
a7f0a1 221         App.setPlayerProcess(null);
8e2038 222         //servletContext.removeAttribute(PI_PLAYER);
a7f0a1 223         //t.setAttribute(App.PI_PLAYER, null);
8e2038 224         antwort = "Es wird nichts abgespielt dem ein Kommando gesendet werden kann.";
U 225       } else {
a7f0a1 226         Process player_process = o;
8e2038 227         OutputStream os = player_process.getOutputStream();
U 228         Writer out = new BufferedWriter(new OutputStreamWriter(os));
229         out.write(k);
230         out.flush();
0af362 231         if(k.equals(CMD_STOP)) {
8e2038 232           out.close();
a7f0a1 233           App.setPlayerProcess(null);
8e2038 234           //player_process.destroy();
U 235           //player_process = null;
a7f0a1 236           //t.setAttribute(App.PI_PLAYER, null);
8e2038 237           //servletContext.removeAttribute(PI_PLAYER);
U 238         }
239         antwort = "Kommando '" + k + "' ausgefuehrt.";
240       }
241     } 
242     catch(IOException ex) {
243       antwort = "Fehler: " + ex.getMessage();
244     }
245     return antwort;
246   }
247   
248   /* ------ Implementierung ProzessLauscher ----------------- */
249   
250   @Override
251   public void prozessBeendet(String meldeUrlStr) {
252     try {
253       HttpURLConnection conn = (HttpURLConnection) new URL(meldeUrlStr).openConnection();
254       conn.setRequestMethod("GET");
255       conn.connect();
256       int status = conn.getResponseCode();
257       logger.log(Level.INFO, "Abspielen beendet, Meldung an {0} mit Statuscode {1} gesendet.", new Object[]{meldeUrlStr, status});
258     } catch(IOException ex) {
259       logger.log(Level.INFO, ex.getMessage(), ex);
260     }
261   }
262   
263 }