/**
* BigBlueButton open source conferencing system - http://www.bigbluebutton.org/
*
* Copyright (c) 2012 BigBlueButton Inc. and by respective authors (see below).
*
* This program 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 3.0 of the License, or (at your option) any later
* version.
*
* BigBlueButton 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 BigBlueButton; if not, see <http://www.gnu.org/licenses/>.
*
*/
package org.bigbluebutton.deskshare.server.recorder;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import org.apache.mina.core.buffer.IoBuffer;
import org.bigbluebutton.deskshare.server.recorder.event.RecordErrorEvent;
import org.bigbluebutton.deskshare.server.recorder.event.RecordStartedEvent;
import org.bigbluebutton.deskshare.server.recorder.event.RecordStoppedEvent;
import org.bigbluebutton.deskshare.server.recorder.event.RecordUpdateEvent;
import org.bigbluebutton.deskshare.server.session.FlvEncodeException;
import org.bigbluebutton.deskshare.server.session.ScreenVideoFlvEncoder;
import org.bigbluebutton.deskshare.server.util.StackTraceUtil;
import org.red5.logging.Red5LoggerFactory;
import org.slf4j.Logger;
public class FileRecorder implements Recorder {
final private Logger log = Red5LoggerFactory.getLogger(FileRecorder.class, "deskshare");
private BlockingQueue<IoBuffer> screenQueue = new LinkedBlockingQueue<IoBuffer>();
private final Executor exec = Executors.newSingleThreadExecutor();
private Runnable capturedScreenSender;
private volatile boolean sendCapturedScreen = false;
private FileOutputStream fo;
private ScreenVideoFlvEncoder svf = new ScreenVideoFlvEncoder();
private String flvFilename = "/tmp/screenvideostream.flv";
private final String session;
private final RecordStatusListeners listeners = new RecordStatusListeners();
public FileRecorder(String name, String recordingPath) {
session = name;
flvFilename = recordingPath + "/" + name + "-" + genTimestamp() + ".flv";
}
private Long genTimestamp() {
return TimeUnit.NANOSECONDS.toMillis(System.nanoTime());
}
public void addListener(RecordStatusListener l) {
listeners.addListener(l);
}
public void removeListener(RecordStatusListener l) {
listeners.removeListener(l);
}
public void record(IoBuffer frame) {
try {
screenQueue.put(frame);
} catch (InterruptedException e) {
log.info("InterruptedException while putting event into queue.");
}
}
public void start() {
try {
fo = new FileOutputStream(flvFilename);
fo.write(svf.encodeHeader());
} catch (FileNotFoundException e1) {
log.error(StackTraceUtil.getStackTrace(e1));
RecordErrorEvent event = new RecordErrorEvent(session);
event.setReason("Failed to create recording output.");
listeners.notifyListeners(event);
} catch (IOException e) {
log.error(StackTraceUtil.getStackTrace(e));
RecordErrorEvent event = new RecordErrorEvent(session);
event.setReason("Cannot record to recording output.");
listeners.notifyListeners(event);
}
sendCapturedScreen = true;
log.info("Starting stream");
capturedScreenSender = new Runnable() {
public void run() {
while (sendCapturedScreen) {
try {
IoBuffer frame = screenQueue.take();
recordFrameToFile(frame);
} catch (InterruptedException e) {
log.error("InterruptedExeption while taking event.");
RecordErrorEvent event = new RecordErrorEvent(session);
event.setReason("Cannot record to recording output.");
listeners.notifyListeners(event);
}
}
}
};
exec.execute(capturedScreenSender);
RecordStartedEvent event = new RecordStartedEvent(session);
event.setFile(flvFilename);
listeners.notifyListeners(event);
}
private void recordFrameToFile(IoBuffer frame) {
try {
fo.write(svf.encodeFlvData(frame.array()));
RecordUpdateEvent event = new RecordUpdateEvent(session);
listeners.notifyListeners(event);
} catch (IOException e) {
log.error(StackTraceUtil.getStackTrace(e));
RecordErrorEvent event = new RecordErrorEvent(session);
event.setReason("Cannot record to recording output.");
listeners.notifyListeners(event);
} catch (FlvEncodeException e) {
log.error(StackTraceUtil.getStackTrace(e));
RecordErrorEvent event = new RecordErrorEvent(session);
event.setReason("Cannot record to recording output.");
listeners.notifyListeners(event);
}
}
public void stop() {
try {
log.info("Closing stream");
fo.close();
svf = null;
} catch (IOException e) {
log.error(StackTraceUtil.getStackTrace(e));
RecordErrorEvent event = new RecordErrorEvent(session);
event.setReason("Cannot record to recording output.");
listeners.notifyListeners(event);
}
RecordStoppedEvent event = new RecordStoppedEvent(session);
event.setFile(flvFilename);
listeners.notifyListeners(event);
}
}