package net.pms.remote; import com.sun.net.httpserver.Headers; import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpHandler; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import net.pms.PMS; import net.pms.configuration.FormatConfiguration; import net.pms.configuration.RendererConfiguration; import net.pms.configuration.WebRender; import net.pms.dlna.*; import net.pms.encoders.FFMpegVideo; import net.pms.encoders.FFmpegAudio; import net.pms.encoders.FFmpegWebVideo; import net.pms.util.FileUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class RemoteMediaHandler implements HttpHandler { private static final Logger LOGGER = LoggerFactory.getLogger(RemoteMediaHandler.class); private RemoteWeb parent; private String path; private RendererConfiguration render; private boolean flash; public RemoteMediaHandler(RemoteWeb parent) { this(parent, "media/", null); } public RemoteMediaHandler(RemoteWeb parent, boolean flash) { this(parent, "fmedia/", null); this.flash = flash; } public RemoteMediaHandler(RemoteWeb parent, String path, RendererConfiguration render) { this.flash = false; this.parent = parent; this.path = path; this.render = render; } @Override public void handle(HttpExchange t) throws IOException { if (RemoteUtil.deny(t)) { throw new IOException("Access denied"); } RootFolder root = parent.getRoot(RemoteUtil.userName(t), t); if (root == null) { throw new IOException("Unknown root"); } Headers h = t.getRequestHeaders(); for (String h1 : h.keySet()) { LOGGER.debug("key " + h1 + "=" + h.get(h1)); } String id = RemoteUtil.getId(path, t); id = RemoteUtil.strip(id); RendererConfiguration r = render; if (render == null) { r = root.getDefaultRenderer(); } DLNAResource dlna = root.getDLNAResource(id, r); if (dlna == null) { // another error LOGGER.debug("media unkonwn"); throw new IOException("Bad id"); } if (!dlna.isCodeValid(dlna)) { LOGGER.debug("coded object with invalid code"); throw new IOException("Bad code"); } DLNAMediaSubtitle sid = null; String mime = root.getDefaultRenderer().getMimeType(dlna.mimeType(), dlna.getMedia()); //DLNAResource dlna = res.get(0); WebRender render = (WebRender) r; DLNAMediaInfo m = dlna.getMedia(); if (m == null) { m = new DLNAMediaInfo(); dlna.setMedia(m); } if (mime.equals(FormatConfiguration.MIMETYPE_AUTO) && m.getMimeType() != null) { mime = m.getMimeType(); } int code = 200; dlna.setDefaultRenderer(r); if (dlna.getFormat().isVideo()) { if (flash) { mime = "video/flash"; } else if (!RemoteUtil.directmime(mime) || RemoteUtil.transMp4(mime, m)) { mime = render != null ? render.getVideoMimeType() : RemoteUtil.transMime(); if (FileUtil.isUrl(dlna.getSystemName())) { dlna.setPlayer(new FFmpegWebVideo()); } else { dlna.setPlayer(new FFMpegVideo()); } //code = 206; } if ( PMS.getConfiguration().getWebSubs() && dlna.getMediaSubtitle() != null && dlna.getMediaSubtitle().isExternal() ) { // fetched on the side sid = dlna.getMediaSubtitle(); dlna.setMediaSubtitle(null); } } if (!RemoteUtil.directmime(mime) && dlna.getFormat().isAudio()) { dlna.setPlayer(new FFmpegAudio()); code = 206; } m.setMimeType(mime); Range.Byte range = RemoteUtil.parseRange(t.getRequestHeaders(), dlna.length()); LOGGER.debug("dumping media " + mime + " " + dlna); InputStream in = dlna.getInputStream(range, root.getDefaultRenderer()); if(range.getEnd() == 0) { // For web resources actual length may be unknown until we open the stream range.setEnd(dlna.length()); } Headers hdr = t.getResponseHeaders(); hdr.add("Content-Type", mime); hdr.add("Accept-Ranges", "bytes"); if (range != null) { long end = range.getEnd(); long start = range.getStart(); String rStr = start + "-" + end + "/*" ; hdr.add("Content-Range", "bytes " + rStr); if (start != 0) { code = 206; } } hdr.add("Server", PMS.get().getServerName()); hdr.add("Connection", "keep-alive"); t.sendResponseHeaders(code, 0); OutputStream os = t.getResponseBody(); render.start(dlna); if (sid != null) { dlna.setMediaSubtitle(sid); } RemoteUtil.dump(in, os, render); } }