private Entry createEntry(MediaFile file, Player player) { return new Entry(file, transcodingService.getSuffix(player, file, null)); }
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { TransferStatus status = null; PlayQueueInputStream in = null; Player player = playerService.getPlayer(request, response, false, true); User user = securityService.getUserByName(player.getUsername()); try { if (!user.isStreamRole()) { response.sendError( HttpServletResponse.SC_FORBIDDEN, "Streaming is forbidden for user " + user.getUsername()); return null; } // If "playlist" request parameter is set, this is a Podcast request. In that case, create a // separate // play queue (in order to support multiple parallel Podcast streams). Integer playlistId = ServletRequestUtils.getIntParameter(request, "playlist"); boolean isPodcast = playlistId != null; if (isPodcast) { PlayQueue playQueue = new PlayQueue(); playQueue.addFiles(false, playlistService.getFilesInPlaylist(playlistId)); player.setPlayQueue(playQueue); Util.setContentLength(response, playQueue.length()); LOG.info("Incoming Podcast request for playlist " + playlistId); } String contentType = StringUtil.getMimeType(request.getParameter("suffix")); response.setContentType(contentType); String preferredTargetFormat = request.getParameter("format"); Integer maxBitRate = ServletRequestUtils.getIntParameter(request, "maxBitRate"); if (Integer.valueOf(0).equals(maxBitRate)) { maxBitRate = null; } VideoTranscodingSettings videoTranscodingSettings = null; // Is this a request for a single file (typically from the embedded Flash player)? // In that case, create a separate playlist (in order to support multiple parallel streams). // Also, enable partial download (HTTP byte range). MediaFile file = getSingleFile(request); boolean isSingleFile = file != null; LongRange range = null; if (isSingleFile) { PlayQueue playQueue = new PlayQueue(); playQueue.addFiles(true, file); player.setPlayQueue(playQueue); if (!file.isVideo()) { response.setIntHeader("ETag", file.getId()); // response.setHeader("Accept-Ranges", "bytes"); } TranscodingService.Parameters parameters = transcodingService.getParameters( file, player, maxBitRate, preferredTargetFormat, null, false); long fileLength = getFileLength(parameters); boolean isConversion = parameters.isDownsample() || parameters.isTranscode(); boolean estimateContentLength = ServletRequestUtils.getBooleanParameter(request, "estimateContentLength", false); boolean isHls = ServletRequestUtils.getBooleanParameter(request, "hls", false); range = getRange(request, file); if (range != null) { LOG.info("Got range: " + range); // response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT); // Util.setContentLength(response, fileLength - // range.getMinimumLong()); // long firstBytePos = range.getMinimumLong(); // long lastBytePos = fileLength - 1; // response.setHeader("Content-Range", "bytes " + firstBytePos + "-" + // lastBytePos + "/" + fileLength); /// if (isConversion) { response.setHeader("Accept-Ranges", "none"); } else { response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT); long maxLength = fileLength; if (maxLength > range.getMaximumLong()) maxLength = range.getMaximumLong() + 1; Util.setContentLength(response, Math.max(maxLength - range.getMinimumLong(), 0)); long firstBytePos = range.getMinimumLong(); long lastBytePos = maxLength - 1; response.setHeader( "Content-Range", "bytes " + firstBytePos + "-" + lastBytePos + "/" + fileLength); } /// } else if (!isHls && (!isConversion || estimateContentLength)) { Util.setContentLength(response, fileLength); } if (isHls) { response.setContentType(StringUtil.getMimeType("ts")); // HLS is always MPEG TS. } else { String transcodedSuffix = transcodingService.getSuffix(player, file, preferredTargetFormat); response.setContentType(StringUtil.getMimeType(transcodedSuffix)); } if (file.isVideo() || isHls) { videoTranscodingSettings = createVideoTranscodingSettings(file, request); } } if (request.getMethod().equals("HEAD")) { return null; } // Terminate any other streams to this player. if (!isPodcast && !isSingleFile) { for (TransferStatus streamStatus : statusService.getStreamStatusesForPlayer(player)) { if (streamStatus.isActive()) { streamStatus.terminate(); } } } status = statusService.createStreamStatus(player); in = new PlayQueueInputStream( player, status, maxBitRate, preferredTargetFormat, videoTranscodingSettings, transcodingService, audioScrobblerService, mediaFileService, searchService); OutputStream out = RangeOutputStream.wrap(response.getOutputStream(), range); // Enabled SHOUTcast, if requested. boolean isShoutCastRequested = "1".equals(request.getHeader("icy-metadata")); if (isShoutCastRequested && !isSingleFile) { response.setHeader("icy-metaint", "" + ShoutCastOutputStream.META_DATA_INTERVAL); response.setHeader("icy-notice1", "This stream is served using FutureSonic"); response.setHeader("icy-notice2", "FutureSonic - Free media streamer - sonic.lt"); response.setHeader("icy-name", "FutureSonic"); response.setHeader("icy-genre", "Mixed"); response.setHeader("icy-url", "http://sonic.lt/"); out = new ShoutCastOutputStream(out, player.getPlayQueue(), settingsService); } final int BUFFER_SIZE = 2048; byte[] buf = new byte[BUFFER_SIZE]; while (true) { // Check if stream has been terminated. if (status.terminated()) { return null; } if (player.getPlayQueue().getStatus() == PlayQueue.Status.STOPPED) { if (isPodcast || isSingleFile) { break; } else { sendDummy(buf, out); } } else { int n = in.read(buf); if (n == -1) { if (isPodcast || isSingleFile) { break; } else { sendDummy(buf, out); } } else { out.write(buf, 0, n); } } } } finally { if (status != null) { securityService.updateUserByteCounts(user, status.getBytesTransfered(), 0L, 0L); statusService.removeStreamStatus(status); } IOUtils.closeQuietly(in); } return null; }