com.reelfx.controller.LinuxController.java Source code

Java tutorial

Introduction

Here is the source code for com.reelfx.controller.LinuxController.java

Source

package com.reelfx.controller;

import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.io.FileUtils;
import org.apache.log4j.Logger;

import com.reelfx.Applet;
import com.reelfx.model.AudioRecorder;
import com.reelfx.model.PostProcessor;
import com.reelfx.model.ScreenRecorder;
import com.reelfx.view.PostOptions;
import com.reelfx.view.RecordControls;
import com.reelfx.view.util.MessageNotification;
import com.reelfx.view.util.ViewNotifications;

/**
 * 
 * @author Daniel Dixon (http://www.danieldixon.com)
 *
 * 
 *    Copyright (C) 2010  ReelFX Creative Studios (http://www.reelfx.com)
 *
 *   This program is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation, either version 3 of the License, or
 *    (at your option) any later version.
 *    
 *    This program 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 General Public License for more details.
 *    
 *    You should have received a copy of the GNU General Public License
 *    along with this program.  If not, see <http://www.gnu.org/licenses/>
 *
 */
public class LinuxController extends AbstractController {

    public static File MERGED_OUTPUT_FILE = new File(
            Applet.BASE_FOLDER.getAbsolutePath() + File.separator + "screen_capture_temp.mov");
    private static Logger logger = Logger.getLogger(LinuxController.class);

    private AudioRecorder audio;
    private boolean recordingDone = false;
    private long audioStart, videoStart;

    public LinuxController() {
        super();
    }

    @Override
    public void setupExtensions() {
        //super.setupExtensions();
        try {
            if (!Applet.BIN_FOLDER.exists()) {
                // delete any old versions
                for (File file : Applet.BASE_FOLDER.listFiles()) {
                    if (file.getName().startsWith("bin") && file.isDirectory()) {
                        FileUtils.deleteDirectory(file);
                        if (file.exists())
                            throw new Exception("Could not delete the old native extentions!");
                    }
                }
                // download an install the new one
                String url = Applet.HOST_URL + File.separator + Applet.getBinFolderName() + ".jar?"
                        + Math.random() * 10000;
                Applet.copyFolderFromRemoteJar(new URL(url), Applet.getBinFolderName());
                if (!Applet.BIN_FOLDER.exists()) {
                    logger.info("Could not find native extensions at " + url + ". Trying next code base url...");
                    url = Applet.CODE_BASE.toString() + File.separator + Applet.getBinFolderName() + ".jar?"
                            + Math.random() * 10000;
                    Applet.copyFolderFromRemoteJar(new URL(url), Applet.getBinFolderName());
                    if (!Applet.BIN_FOLDER.exists()) {
                        logger.info("Could not find native extensions at " + url
                                + ". Trying next document base url...");
                        url = Applet.DOCUMENT_BASE.toString() + File.separator + Applet.getBinFolderName() + ".jar?"
                                + Math.random() * 10000;
                        Applet.copyFolderFromRemoteJar(new URL(url), Applet.getBinFolderName());
                        if (!Applet.BIN_FOLDER.exists()) {
                            throw new IOException(
                                    "Did not copy Linux extensions to the execution directory! Last url: " + url);
                        }
                    }
                }
                Runtime.getRuntime().exec("chmod 755 " + Applet.BIN_FOLDER + File.separator + "ffmpeg").waitFor();
                Runtime.getRuntime().exec("chmod 755 " + Applet.BIN_FOLDER + File.separator + "ffplay").waitFor();
            }
            logger.info("Have access to execution folder: " + Applet.BIN_FOLDER.getAbsolutePath());
            setReadyStateBasedOnPriorRecording();
        } catch (Exception e) { // possibilities: MalformedURL, InterriptedException, IOException
            Applet.sendViewNotification(ViewNotifications.FATAL, new MessageNotification("Error with install",
                    "Sorry, an error occurred while installing the native extensions. Please contact an admin."));
            logger.error("Could not install native extensions", e);
        }
    }

    @Override
    public void prepareForRecording() {
        super.prepareForRecording();
        recordingDone = false;
        screen = new ScreenRecorder();
        screen.addProcessListener(this);
    }

    @Override
    public void startRecording(AudioRecorder selectedAudio) {
        deleteOutput();
        AudioRecorder.deleteOutput();
        if (selectedAudio != null) {
            audio = selectedAudio;
            audio.addProcessListener(this);
            audio.startRecording();
        } else {
            logger.info("No audio source specified.");
            audio = null;
        }
        // start up ffmpeg
        screen.start();
    }

    @Override
    public void stopRecording() {
        if (audio != null)
            audio.stopRecording();
        else
            recordingDone = true; // if no audio, queue the post process
        logger.info("About to stop screen recording...");
        screen.stopRecording();
        super.stopRecording(); // call after (has nothing but GUI updates)
    }

    public void processUpdate(int event, Object body) {
        super.processUpdate(event, body);
        switch (event) {

        case AudioRecorder.RECORDING_STARTED:
            audioStart = Calendar.getInstance().getTimeInMillis();
            break;
        case ScreenRecorder.RECORDING_STARTED:
            videoStart = Calendar.getInstance().getTimeInMillis();
            break;

        case ScreenRecorder.RECORDING_COMPLETE:
        case AudioRecorder.RECORDING_COMPLETE:
            if (recordingDone) {
                // merge the video and audio file together (ffmpeg does this pretty quickly)
                deleteOutput();
                if (postProcess != null)
                    postProcess.removeAllProcessListeners();
                postProcess = new PostProcessor();
                Map<Integer, String> opts = new HashMap<Integer, String>();
                opts.put(PostProcessor.MERGE_AUDIO_VIDEO, null);
                if (audioStart > videoStart) {
                    long ms = videoStart - audioStart;
                    float s = ((float) ms) / 1000f;
                    logger.info("Video delay: " + ms + " ms " + s + " s");
                    opts.put(PostProcessor.OFFSET_VIDEO, s + "");
                } else if (videoStart > audioStart) {
                    long ms = audioStart - videoStart;
                    float s = ((float) ms) / 1000f;
                    logger.info("Audio delay: " + ms + " ms " + s + " s");
                    opts.put(PostProcessor.OFFSET_AUDIO, s + "");
                }
                //postProcess.setSilent(true); // no need to notify UI for this encoding
                postProcess.encodingOptions(opts);
                postProcess.addProcessListener(this);
                postProcess.saveToComputer(MERGED_OUTPUT_FILE);
            } else {
                recordingDone = true;
            }
            break;

        case PostProcessor.ENCODING_COMPLETE:
            Applet.sendViewNotification(ViewNotifications.POST_OPTIONS,
                    new MessageNotification("", "What would you like to do with your new screen recording?"));
            break;
        }
    }

    public void deleteRecording() {
        deleteOutput();
        super.deleteRecording();
    }

    public static void deleteOutput() {
        AccessController.doPrivileged(new PrivilegedAction<Object>() {

            @Override
            public Object run() {
                try {
                    if (MERGED_OUTPUT_FILE.exists() && !MERGED_OUTPUT_FILE.delete())
                        throw new Exception("Can't delete the old preview file on Linux!");
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return null;
            }
        });
    }
}