package org.red5.service.httpstream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.util.concurrent.atomic.AtomicReference; import org.apache.commons.io.IOUtils; import org.jboss.logging.Logger; import org.red5.service.httpstream.model.MobileProfile; import com.destinationradiodenver.mobileStreaming.singleton.AvailabilityService; public class SegmentConsumer implements Runnable { private static final Logger log = Logger.getLogger(SegmentConsumer.class); private String streamName; private MobileProfile mobileProfile; private String pipePath; private final AtomicReference<Thread> currentThread = new AtomicReference<Thread>(); private boolean interruptMe; private AvailabilityService availabilityService; public String getCurrentPipePath(int intSwitch){ //FFMPEG will write first to /path/to/named/pipe0.ts and then to pipe1.ts, as it wraps every other segment int current = -1; if(intSwitch<0) current = 0; if(intSwitch>0) current = 1; String actualPath = getPipePath()+current; actualPath += ".ts"; log.tracef("actual path to pipe: %s", actualPath); return actualPath; } @Override public void run() { currentThread.set(Thread.currentThread()); log.errorf("Running SegmentConsumer"); int intSwitch = -1; int negOne = -1; while(!isInterruptMe()){ try { File actualPipe = new File(getCurrentPipePath(intSwitch)); log.tracef("opening FIS"); FileInputStream reader = new FileInputStream(actualPipe); log.tracef("opened"); //byte[] array = IOUtils.toByteArray(reader); ByteArrayOutputStream oS = new ByteArrayOutputStream(); log.tracef("new BAOS"); byte[] b = new byte[1024]; int bytesRead = 0; log.tracef("before open"); log.tracef("ready to open"); while ((bytesRead = reader.read(b)) != -1) { log.tracef("reading"); oS.write(b, 0, bytesRead); } log.tracef("finish"); byte[] array = oS.toByteArray(); log.tracef("Copied FIS TO BAOS"); IOUtils.closeQuietly(reader); log.tracef("FIS closed"); log.tracef("converted to byte array"); getAvailabilityService().update(getStreamName(), array); log.tracef("notified and sent"); /*TODO: Determine if we need to sleep for any amount of time. * because * accessing the named pipe should be blocking until the segment is * done writing to the pipe. Once its done, we should instantly try to * open the pipe again (FFMPEG is faster than Java, I would think). If * we do indeed need to wait for a bit, let's play with the code below. * while(!(Application.transcoderReady(getPipePath()))){ try { log.tracef("not ready to open"); Thread.sleep(100); } catch (InterruptedException e1) { } } * try { * Thread.sleep(500); * } catch (InterruptedException e) { * log.errorf("interrupted: %s", e); * } */ intSwitch = intSwitch*negOne; } catch (FileNotFoundException e) { log.errorf("FNF - Could not open FileInputStream, sleeping: %s", getCurrentPipePath(intSwitch)); //we might still be setting up the pipe //wait half a second for it to come up try { Thread.sleep(500); } catch (InterruptedException e1) { log.errorf("Interrupt: %s", e1); } } catch (IOException e) { log.errorf("couldn't read byte array: %s", getCurrentPipePath(intSwitch)); currentThread.get().interrupt(); } } } public MobileProfile getMobileProfile() { return mobileProfile; } private String getPipePath() { return pipePath; } public void setStreamName(String streamName) { this.streamName = streamName; } public String getStreamName() { return streamName; } public void setPipePath(String path) { this.pipePath = path; } public void setMobileProfile(MobileProfile mP) { mobileProfile = mP; } public boolean isInterruptMe() { return interruptMe; } public void setInterruptMe(boolean interruptMe) { this.interruptMe = interruptMe; } public AvailabilityService getAvailabilityService() { return availabilityService; } public void setAvailabilityService(AvailabilityService availabilityService) { this.availabilityService = availabilityService; } }