use of net.pms.external.ExternalListener in project UniversalMediaServer by UniversalMediaServer.
the class DLNAResource method stopPlaying.
/**
* Plugin implementation. When this item is going to stop playing, it will notify all the StartStopListener
* objects available.
*
* @see StartStopListener
*/
public void stopPlaying(final String rendererId, final RendererConfiguration incomingRenderer) {
final DLNAResource self = this;
final String requestId = getRequestId(rendererId);
Runnable defer = new Runnable() {
@Override
public void run() {
long start = startTime;
try {
Thread.sleep(STOP_PLAYING_DELAY);
} catch (InterruptedException e) {
LOGGER.error("stopPlaying sleep interrupted", e);
}
synchronized (requestIdToRefcount) {
final Integer refCount = requestIdToRefcount.get(requestId);
assert refCount != null;
assert refCount > 0;
requestIdToRefcount.put(requestId, refCount - 1);
if (start != startTime) {
return;
}
Runnable r = new Runnable() {
@Override
public void run() {
if (refCount == 1) {
requestIdToRefcount.put(requestId, 0);
InetAddress rendererIp;
try {
rendererIp = InetAddress.getByName(rendererId);
RendererConfiguration renderer;
if (incomingRenderer == null) {
renderer = RendererConfiguration.getRendererConfigurationBySocketAddress(rendererIp);
} else {
renderer = incomingRenderer;
}
String rendererName = "unknown renderer";
try {
// Reset only if another item hasn't already begun playing
if (renderer.getPlayingRes() == self) {
renderer.setPlayingRes(null);
}
rendererName = renderer.getRendererName();
} catch (NullPointerException e) {
}
if (!quietPlay()) {
LOGGER.info("Stopped playing " + getName() + " on your " + rendererName);
LOGGER.debug("The full filename of which is: " + getSystemName() + " and the address of the renderer is: " + rendererId);
}
} catch (UnknownHostException ex) {
LOGGER.debug("" + ex);
}
internalStop();
for (final ExternalListener listener : ExternalFactory.getExternalListeners()) {
if (listener instanceof StartStopListener) {
// run these asynchronously for slow handlers (e.g. logging, scrobbling)
Runnable fireStartStopEvent = new Runnable() {
@Override
public void run() {
try {
((StartStopListener) listener).donePlaying(media, self);
} catch (Throwable t) {
LOGGER.error("Notification of donePlaying event failed for StartStopListener {}", listener.getClass(), t);
}
}
};
new Thread(fireStartStopEvent, "StopPlaying Event for " + listener.name()).start();
}
}
}
}
};
new Thread(r, "StopPlaying Event").start();
}
}
};
new Thread(defer, "StopPlaying Event Deferrer").start();
}
use of net.pms.external.ExternalListener in project UniversalMediaServer by UniversalMediaServer.
the class PMS method init.
/**
* Initialization procedure for UMS.
*
* @return <code>true</code> if the server has been initialized correctly.
* <code>false</code> if initialization was aborted.
* @throws Exception
*/
private boolean init() throws Exception {
// Gather and log system information from a separate thread
LogSystemInformationMode logSystemInfo = configuration.getLogSystemInformation();
if (logSystemInfo == LogSystemInformationMode.ALWAYS || logSystemInfo == LogSystemInformationMode.TRACE_ONLY && LOGGER.isTraceEnabled()) {
new SystemInformation().start();
}
// Show the language selection dialog before displayBanner();
if (!isHeadless() && (configuration.getLanguageRawString() == null || !Languages.isValid(configuration.getLanguageRawString()))) {
LanguageSelection languageDialog = new LanguageSelection(null, PMS.getLocale(), false);
languageDialog.show();
if (languageDialog.isAborted()) {
return false;
}
}
// Initialize splash screen
Splash splash = null;
if (!isHeadless()) {
splash = new Splash(configuration);
}
// Call this as early as possible
displayBanner();
// Initialize database
Tables.checkTables();
// Log registered ImageIO plugins
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("");
LOGGER.trace("Registered ImageIO reader classes:");
Iterator<ImageReaderSpi> readerIterator = IIORegistry.getDefaultInstance().getServiceProviders(ImageReaderSpi.class, true);
while (readerIterator.hasNext()) {
ImageReaderSpi reader = readerIterator.next();
LOGGER.trace("Reader class: {}", reader.getPluginClassName());
}
LOGGER.trace("");
LOGGER.trace("Registered ImageIO writer classes:");
Iterator<ImageWriterSpi> writerIterator = IIORegistry.getDefaultInstance().getServiceProviders(ImageWriterSpi.class, true);
while (writerIterator.hasNext()) {
ImageWriterSpi writer = writerIterator.next();
LOGGER.trace("Writer class: {}", writer.getPluginClassName());
}
LOGGER.trace("");
}
// Wizard
if (configuration.isRunWizard() && !isHeadless()) {
// Hide splash screen
if (splash != null) {
splash.setVisible(false);
}
// Run wizard
Wizard.run(configuration);
// Unhide splash screen
if (splash != null) {
splash.setVisible(true);
}
}
// The public VERSION field is deprecated.
// This is a temporary fix for backwards compatibility
VERSION = getVersion();
fileWatcher = new FileWatcher();
globalRepo = new GlobalIdRepo();
AutoUpdater autoUpdater = null;
if (Build.isUpdatable()) {
String serverURL = Build.getUpdateServerURL();
autoUpdater = new AutoUpdater(serverURL, getVersion());
}
registry = createSystemUtils();
// Create SleepManager
sleepManager = new SleepManager();
if (!isHeadless()) {
frame = new LooksFrame(autoUpdater, configuration);
} else {
LOGGER.info("Graphics environment not available or headless mode is forced");
LOGGER.info("Switching to console mode");
frame = new DummyFrame();
}
// Close splash screen
if (splash != null) {
splash.dispose();
splash = null;
}
/*
* we're here:
*
* main() -> createInstance() -> init()
*
* which means we haven't created the instance returned by get()
* yet, so the frame appender can't access the frame in the
* standard way i.e. PMS.get().getFrame(). we solve it by
* inverting control ("don't call us; we'll call you") i.e.
* we notify the appender when the frame is ready rather than
* e.g. making getFrame() static and requiring the frame
* appender to poll it.
*
* XXX an event bus (e.g. MBassador or Guava EventBus
* (if they fix the memory-leak issue)) notification
* would be cleaner and could support other lifecycle
* notifications (see above).
*/
FrameAppender.setFrame(frame);
configuration.addConfigurationListener(new ConfigurationListener() {
@Override
public void configurationChanged(ConfigurationEvent event) {
if ((!event.isBeforeUpdate()) && PmsConfiguration.NEED_RELOAD_FLAGS.contains(event.getPropertyName())) {
frame.setReloadable(true);
}
}
});
// Web stuff
if (configuration.useWebInterface()) {
try {
web = new RemoteWeb(configuration.getWebPort());
} catch (BindException b) {
LOGGER.error("FATAL ERROR: Unable to bind web interface on port: " + configuration.getWebPort() + ", because: " + b.getMessage());
LOGGER.info("Maybe another process is running or the hostname is wrong.");
}
}
// init Credentials
credMgr = new CredMgr(configuration.getCredFile());
// init dbs
keysDb = new UmsKeysDb();
infoDb = new InfoDb();
codes = new CodeDb();
masterCode = null;
RendererConfiguration.loadRendererConfigurations(configuration);
// Now that renderer confs are all loaded, we can start searching for renderers
UPNPHelper.getInstance().init();
// launch ChromecastMgr
jmDNS = null;
launchJmDNSRenderers();
OutputParams outputParams = new OutputParams(configuration);
// Prevent unwanted GUI buffer artifacts (and runaway timers)
outputParams.hidebuffer = true;
// Make sure buffer is destroyed
outputParams.cleanup = true;
// Initialize MPlayer and FFmpeg to let them generate fontconfig cache/s
if (!configuration.isDisableSubtitles()) {
LOGGER.info("Checking the fontconfig cache in the background, this can take two minutes or so.");
ProcessWrapperImpl mplayer = new ProcessWrapperImpl(new String[] { configuration.getMplayerPath(), "dummy" }, outputParams);
mplayer.runInNewThread();
/**
* Note: Different versions of fontconfig and bitness require
* different caches, which is why here we ask FFmpeg (64-bit
* if possible) to create a cache.
* This should result in all of the necessary caches being built.
*/
if (!Platform.isWindows() || Platform.is64Bit()) {
ProcessWrapperImpl ffmpeg = new ProcessWrapperImpl(new String[] { configuration.getFfmpegPath(), "-y", "-f", "lavfi", "-i", "nullsrc=s=720x480:d=1:r=1", "-vf", "ass=DummyInput.ass", "-target", "ntsc-dvd", "-" }, outputParams);
ffmpeg.runInNewThread();
}
}
frame.setStatusCode(0, Messages.getString("PMS.130"), "icon-status-connecting.png");
// Check the existence of VSFilter / DirectVobSub
if (registry.isAvis() && registry.getAvsPluginsDir() != null) {
LOGGER.debug("AviSynth plugins directory: " + registry.getAvsPluginsDir().getAbsolutePath());
File vsFilterDLL = new File(registry.getAvsPluginsDir(), "VSFilter.dll");
if (vsFilterDLL.exists()) {
LOGGER.debug("VSFilter / DirectVobSub was found in the AviSynth plugins directory.");
} else {
File vsFilterDLL2 = new File(registry.getKLiteFiltersDir(), "vsfilter.dll");
if (vsFilterDLL2.exists()) {
LOGGER.debug("VSFilter / DirectVobSub was found in the K-Lite Codec Pack filters directory.");
} else {
LOGGER.info("VSFilter / DirectVobSub was not found. This can cause problems when trying to play subtitled videos with AviSynth.");
}
}
}
// Check if VLC is found
String vlcVersion = registry.getVlcVersion();
String vlcPath = registry.getVlcPath();
if (vlcVersion != null && vlcPath != null) {
LOGGER.info("Found VLC version " + vlcVersion + " at: " + vlcPath);
Version vlc = new Version(vlcVersion);
Version requiredVersion = new Version("2.0.2");
if (vlc.compareTo(requiredVersion) <= 0) {
LOGGER.error("Only VLC versions 2.0.2 and above are supported");
}
}
// Check if Kerio is installed
if (registry.isKerioFirewall()) {
LOGGER.info("Detected Kerio firewall");
}
// Force use of specific DVR-MS muxer when it's installed in the right place
File dvrsMsffmpegmuxer = new File("win32/dvrms/ffmpeg_MPGMUX.exe");
if (dvrsMsffmpegmuxer.exists()) {
configuration.setFfmpegAlternativePath(dvrsMsffmpegmuxer.getAbsolutePath());
}
// Disable jaudiotagger logging
LogManager.getLogManager().readConfiguration(new ByteArrayInputStream("org.jaudiotagger.level=OFF".getBytes(StandardCharsets.US_ASCII)));
// Wrap System.err
System.setErr(new PrintStream(new SystemErrWrapper(), true, StandardCharsets.UTF_8.name()));
server = new HTTPServer(configuration.getServerPort());
/*
* XXX: keep this here (i.e. after registerExtensions and before registerPlayers) so that plugins
* can register custom players correctly (e.g. in the GUI) and/or add/replace custom formats
*
* XXX: if a plugin requires initialization/notification even earlier than
* this, then a new external listener implementing a new callback should be added
* e.g. StartupListener.registeredExtensions()
*/
try {
ExternalFactory.lookup();
} catch (Exception e) {
LOGGER.error("Error loading plugins", e);
}
// Initialize a player factory to register all players
PlayerFactory.initialize();
// Instantiate listeners that require registered players.
ExternalFactory.instantiateLateListeners();
// a static block in Player doesn't work (i.e. is called too late).
// this must always be called *after* the plugins have loaded.
// here's as good a place as any
Player.initializeFinalizeTranscoderArgsListeners();
// Any plugin-defined players are now registered, create the gui view.
frame.addEngines();
// file AFTER plugins are started
if (!isHeadless()) {
// but only if we got a GUI of course
((LooksFrame) frame).getPt().init();
}
boolean binding = false;
try {
binding = server.start();
} catch (BindException b) {
LOGGER.error("FATAL ERROR: Unable to bind on port: " + configuration.getServerPort() + ", because: " + b.getMessage());
LOGGER.info("Maybe another process is running or the hostname is wrong.");
}
new Thread("Connection Checker") {
@Override
public void run() {
try {
Thread.sleep(7000);
} catch (InterruptedException e) {
}
if (foundRenderers.isEmpty()) {
frame.setStatusCode(0, Messages.getString("PMS.0"), "icon-status-notconnected.png");
} else {
frame.setStatusCode(0, Messages.getString("PMS.18"), "icon-status-connected.png");
}
}
}.start();
if (!binding) {
return false;
}
if (web != null && web.getServer() != null) {
LOGGER.info("WEB interface is available at: " + web.getUrl());
}
// initialize the cache
if (configuration.getUseCache()) {
mediaLibrary = new MediaLibrary();
LOGGER.info("A tiny cache admin interface is available at: http://" + server.getHost() + ":" + server.getPort() + "/console/home");
}
// XXX: this must be called:
// a) *after* loading plugins i.e. plugins register root folders then RootFolder.discoverChildren adds them
// b) *after* mediaLibrary is initialized, if enabled (above)
getRootFolder(RendererConfiguration.getDefaultConf());
frame.serverReady();
ready = true;
// UPNPHelper.sendByeBye();
Runtime.getRuntime().addShutdownHook(new Thread("UMS Shutdown") {
@Override
public void run() {
try {
for (ExternalListener l : ExternalFactory.getExternalListeners()) {
l.shutdown();
}
UPNPHelper.shutDownListener();
UPNPHelper.sendByeBye();
LOGGER.debug("Forcing shutdown of all active processes");
for (Process p : currentProcesses) {
try {
p.exitValue();
} catch (IllegalThreadStateException ise) {
LOGGER.trace("Forcing shutdown of process: " + p);
ProcessUtil.destroy(p);
}
}
get().getServer().stop();
Thread.sleep(500);
} catch (InterruptedException e) {
LOGGER.debug("Caught exception", e);
}
LOGGER.info("Stopping " + PropertiesUtil.getProjectProperties().get("project.name") + " " + getVersion());
/**
* Stopping logging gracefully (flushing logs)
* No logging is available after this point
*/
ILoggerFactory iLoggerContext = LoggerFactory.getILoggerFactory();
if (iLoggerContext instanceof LoggerContext) {
((LoggerContext) iLoggerContext).stop();
} else {
LOGGER.error("Unable to shut down logging gracefully");
}
}
});
configuration.setAutoSave();
UPNPHelper.sendByeBye();
LOGGER.trace("Waiting 250 milliseconds...");
Thread.sleep(250);
UPNPHelper.sendAlive();
LOGGER.trace("Waiting 250 milliseconds...");
Thread.sleep(250);
UPNPHelper.listen();
// Initiate a library scan in case files were added to folders while UMS was closed.
if (getConfiguration().getUseCache() && getConfiguration().isScanSharedFoldersOnStartup()) {
getDatabase().scanLibrary();
}
return true;
}
use of net.pms.external.ExternalListener in project UniversalMediaServer by UniversalMediaServer.
the class PluginTab method addPlugins.
public void addPlugins() {
FormLayout layout = new FormLayout("fill:10:grow", "p, p, p, p, p, p, p, p, p, p, p, p, p, p, p, p, p, p, p, p, p, p, p, p, p, p, p, p, p, p");
pPlugins.setLayout(layout);
List<ExternalListener> externalListeners = ExternalFactory.getExternalListeners();
for (final ExternalListener listener : externalListeners) {
if (!appendPlugin(listener)) {
break;
}
}
pPlugins.setVisible(externalListeners.size() > 0);
installedPluginsSeparator.setVisible(externalListeners.size() > 0);
}
Aggregations