Java tutorial
package org.red5.stream.http.servlet; /* * RED5 Open Source Flash Server - http://www.osflash.org/red5 * * Copyright (c) 2006-2008 by respective authors (see below). All rights reserved. * * This library is free software; you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free Software * Foundation; either version 2.1 of the License, or (at your option) any later * version. * * This library is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along * with this library; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import javax.ejb.EJB; import javax.servlet.ServletException; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.io.IOUtils; import org.jboss.logging.Logger; import com.destinationradiodenver.mobileStreaming.singleton.AvailabilityService; /** * Servlet implementation class TransportSegment */ public class TransportSegment extends HttpServlet { private static final long serialVersionUID = 2077065865046683060L; private static final Logger log = Logger.getLogger(TransportSegment.class.getName()); @EJB private AvailabilityService availabilityService; /** * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response) */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } /** * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response) */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { log.errorf("Segment requested"); // http://localhost:5080/httplivestreamingstreaming/test1.ts String servletPath = request.getServletPath(); int segmentDuration = availabilityService.getSegmentTimeLimit() / 1000; int numMaxSegments = availabilityService.getNumMaxSegments(); int numExpiredSegmentsOnCDN = availabilityService.getNumExpiredSegmentsOnCDN(); /* * CDN Segment Age: * For a Origin-Pull CDN, a MPEG-TS segment should expire * once it is not longer available on the server for a cycle. * Calcuate by taking the duration of the segment, and multiplying * it by the number of max segments, and adding twice the segment * duration to that value. For example, a if a segment is 6 * seconds long, and there can only be 10 segments available * on the server at a given time, the first segment is no longer * available 66 seconds after it was first created. */ int cdnSegmentAge = (segmentDuration * numMaxSegments) + (numExpiredSegmentsOnCDN * segmentDuration); String[] path = servletPath.split("/"); /* * @param we are expecting the following servlet path: /Application/Stream/MobileProfileName/stream00000000000.ts */ String streamName = null; String mobileProfileName = null; String requestedSegment = null; String[] parts = servletPath.split("/"); log.tracef("Parts: %s", parts.length); if (!(parts.length == 4)) { log.errorf( "Servlet Request was not formatted as expected. Expected /streamName/stream.m3u8 or /streamName/mobileProfileName/stream.m3u8 , but got: %s", servletPath); response.sendError(404, "Segment not found"); return; } else { streamName = parts[1]; log.errorf("Stream Name: %s", streamName); mobileProfileName = parts[2]; log.errorf("Mobile Profile Name: %s", mobileProfileName); log.tracef("Requested Profile Name: %s", mobileProfileName); requestedSegment = path[3]; log.tracef("Requested Segment: %s", requestedSegment); } /* TODO: Define if this is appropriate for Origin-Pull CDNs. * If the same CDN requests the file again, its probably necessary. * Until proven otherwise, I am removing this code. * Maybe when I reFOSS the app I will make this tunable; * * //fail if they request the same segment * // if(tunableSessionBehavior){ * HttpSession session = ((HttpServletRequest) request).getSession(false); * if (session != null) { * String sN = (String) session.getAttribute("streamName"); * String mPN = (String) session.getAttribute("mobileProfileName"); * if (streamName.equals(sN)||mobileProfileName.equals(mPN)) { * log.info("Segment %s was already played by this requester", sN+mPN); * return; * } * session.setAttribute("stream", streamName); * session.setAttribute("mobileProfileName", mobileProfileName); * } * */ String fileNameSansExtension = requestedSegment.replace(".ts", ""); String sequenceNumberStr = fileNameSansExtension.replace("stream", ""); int sequenceNumber = Integer.valueOf(sequenceNumberStr); log.tracef("Segment sequence: %s", sequenceNumber); if (availabilityService.isAvailable(streamName, mobileProfileName)) { response.setContentType("video/MP2T"); byte[] segment = availabilityService.getSegment(streamName, mobileProfileName, sequenceNumber); if (segment != null) { InputStream iS = new ByteArrayInputStream(segment); ServletOutputStream oS = response.getOutputStream(); response.setHeader("Cache-Control", "max-age=" + cdnSegmentAge); response.setContentType("video/MP2T"); response.setContentLength(segment.length); if (IOUtils.copy(iS, oS) < 0) { log.errorf("Error serving TS: %s", servletPath); response.sendError(500, "Unable to serve segment"); } oS.flush(); oS.close(); } else { log.infof("Segment for %s was not found", streamName); } } else { //T0D0 <== done? let requester know that stream segment is not available response.sendError(404, "Segment not found"); } } }