/*
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*
* File based on:
* @(#)JMFInit.java 1.14 03/04/30
* Copyright (c) 1996-2002 Sun Microsystems, Inc. All rights reserved.
*/
package net.java.sip.communicator.impl.media.device;
import java.io.*;
import java.util.*;
import javax.media.*;
import javax.media.format.*;
import net.java.sip.communicator.impl.media.*;
import net.java.sip.communicator.service.fileaccess.*;
import net.java.sip.communicator.util.*;
import com.sun.media.util.*;
/**
* Probes for available capture and playback devices and initializes the
* jmf.properties accordingly.
*
* @author Emil Ivov
* @author Ken Larson
* @author Lubomir Marinov
*/
public class JmfDeviceDetector
{
private static final Logger logger = Logger.getLogger(JmfDeviceDetector.class);
/**
* The JMF property that specifies whether we'd have the right to capture
* when run from webstart or an applet.
*/
private static final String PROP_ALLOW_CAPTURE_FROM_APPLETS
= "secure.allowCaptureFromApplets";
/**
* The JMF property that specifies whether we'd have the right to save
* files when run from webstart or an applet.
*/
private static final String PROP_ALLOW_SAVE_FILE_FROM_APPLETS
= "secure.allowSaveFileFromApplets";
/**
* The JMF registry property that specifies that have initilized the
* currently valid repository.
*/
private static final String PROP_REGISTRY_AUTHOR
= "registry.author";
/**
* The value of the JMF registry property that determines whether we have
* initilized the currentl repository.
*/
private static final String PROP_REGISTRY_AUTHOR_VALUE
= "sip-communicator.org";
/**
* The name of the file that the JMF registry uses for storing and loading
* jmf properties.
*/
private static final String JMF_PROPERTIES_FILE_NAME = "jmf.properties";
/**
* Default constructor - does nothing.
*/
public JmfDeviceDetector()
{
}
/**
* Detect all capture devices
*/
private void initialize()
{
if (FMJConditionals.USE_JMF_INTERNAL_REGISTRY)
{
// This uses JMF internals:
// see if the registry has already been "tagged" by us, skip auto-detection if
// it has.
// This was probably done because JMF auto-detection is very slow, especially
// for video devices. FMJ does this quickly, so there is no need for this
// kind of workaround (besides the fact that these internal functions are not
// implemented in FMJ).
String author = (String)Registry.get(PROP_REGISTRY_AUTHOR);
if(author != null)
{
return;
}
Registry.set(PROP_ALLOW_CAPTURE_FROM_APPLETS, new Boolean(true));
Registry.set(PROP_ALLOW_SAVE_FILE_FROM_APPLETS, new Boolean(true));
Registry.set(PROP_REGISTRY_AUTHOR, PROP_REGISTRY_AUTHOR_VALUE);
try
{
Registry.commit();
}
catch (Exception exc)
{
logger.error(
"Failed to initially commit JMFRegistry. Ignoring err."
, exc);
}
}
detectDirectAudio();
detectS8DirectAudio();
detectCaptureDevices();
}
/**
* Detect all existing capture devices and record them into the JMF
* repository.
*/
private void detectCaptureDevices()
{
logger.info("Looking for Audio capturer");
// check if JavaSound capture is available
try
{
new JavaSoundAuto();
}
catch (Throwable exc)
{
logger.debug("No JMF javasound detected: " + exc.getMessage());
}
// check if we have FMJJavaSoundAuto capture is available
try
{
new FMJJavaSoundAuto();
}
catch (Throwable exc)
{
logger.debug("No FMJ javasound detected: " + exc.getMessage());
}
// video is enabled by default
// if video is disabled skip device detection
if(MediaActivator.
getConfigurationService().getBoolean(
MediaServiceImpl.DISABLE_VIDEO_SUPPORT_PROPERTY_NAME, false))
return;
// Try to configgure capture devices for any operating system.
//those that do not apply will silently fail.
logger.info("Looking for video capture devices");
/* int nDevices = 0;
//Windows
try
{
VFWAuto vfwAuto = new VFWAuto();
vfwAuto.autoDetectDevices();
logger.info("Detected "
+ nDevices
+" VFW video capture device(s).");
}
catch (Throwable exc)
{
logger.debug("No VFW video detected: " + exc.getMessage());
}
//SunVideo
try
{
SunVideoAuto sunVideoAuto = new SunVideoAuto();
nDevices = sunVideoAuto.autoDetectDevices();
logger.info("Detected "
+ nDevices
+" SUN Video capture device(s).");
}
catch (Throwable exc)
{
logger.debug("No SUN Video detected: " + exc.getMessage());
}
//SunVideoPlus
try
{
SunVideoPlusAuto sunVideoAutoPlus = new SunVideoPlusAuto();
nDevices = sunVideoAutoPlus.autoDetectDevices();
logger.info("Detected "
+ nDevices
+ " SUN Video Plus device(s).");
}
catch (Throwable exc)
{
logger.debug("No SUN Video Plus detected: " + exc.getMessage());
}
//Linux
try
{
V4LAuto v4lAuto = new V4LAuto();
nDevices = v4lAuto.autoDetectDevices();
logger.info("Detected "
+ nDevices
+" V4L video capture device.");
}
catch (Throwable exc)
{
logger.debug("No V4l video detected: " + exc.getMessage());
}
*/
//FMJ
try
{
new FMJCivilVideoAuto();
}
catch (Throwable exc)
{
logger.debug("No FMJ CIVIL video detected: " + exc.getMessage(), exc);
}
}
/**
* Will try to detect direct audio devices.
*/
private void detectDirectAudio()
{
Class<?> cls;
int plType = PlugInManager.RENDERER;
String dar = "com.sun.media.renderer.audio.DirectAudioRenderer";
try
{
// Check if this is the Windows Performance Pack - hack
cls = Class.forName(
"net.java.sip.communicator.impl.media.device.VFWAuto");
// Check if DS capture is supported, otherwise fail DS renderer
// since NT doesn't have capture
cls = Class.forName("com.sun.media.protocol.dsound.DSound");
// Find the renderer class and instantiate it.
cls = Class.forName(dar);
Renderer rend = (Renderer) cls.newInstance();
try
{
// Set the format and open the device
AudioFormat af = new AudioFormat(AudioFormat.LINEAR,
44100, 16, 2);
rend.setInputFormat(af);
rend.open();
Format[] inputFormats = rend.getSupportedInputFormats();
// Register the device
PlugInManager.addPlugIn(dar, inputFormats, new Format[0],
plType);
// Move it to the top of the list
Vector rendList =
PlugInManager.getPlugInList(null, null, plType);
int listSize = rendList.size();
if (rendList.elementAt(listSize - 1).equals(dar))
{
rendList.removeElementAt(listSize - 1);
rendList.insertElementAt(dar, 0);
PlugInManager.setPlugInList(rendList, plType);
PlugInManager.commit();
//System.err.println("registered");
}
rend.close();
}
catch (Throwable throwable)
{
logger.debug("Detection for direct audio failed.", throwable);
}
}
catch (Throwable tt)
{
logger.debug("Detection for direct audio failed.", tt);
}
}
private void detectS8DirectAudio()
{
try
{
new S8DirectAudioAuto();
}
catch (Throwable tt)
{
}
}
/**
* Runs JMFInit the first time the application is started so that capture
* devices are properly detected and initialized by JMF.
*/
public static void setupJMF()
{
logger.logEntry();
try
{
// we'll be storing our jmf.properties file inside the
//sip-communicator directory. If it does not exist - we created it.
//If the jmf.properties file has 0 length then this is the first
//time we're running and should detect capture devices
File jmfPropsFile = null;
try
{
FileAccessService faService
= MediaActivator.getFileAccessService();
if(faService != null)
{
jmfPropsFile = faService.
getPrivatePersistentFile(JMF_PROPERTIES_FILE_NAME);
}
//small hack for when running from outside oscar
else
{
jmfPropsFile
= new File(System.getProperty("user.home")
+ File.separator
+ ".sip-communicator/jmf.properties");
}
//force reinitialization
if(jmfPropsFile.exists())
jmfPropsFile.delete();
jmfPropsFile.createNewFile();
}
catch (Exception exc)
{
throw new RuntimeException(
"Failed to create the jmf.properties file.", exc);
}
String classpath = System.getProperty("java.class.path");
classpath = jmfPropsFile.getParentFile().getAbsolutePath()
+ System.getProperty("path.separator")
+ classpath;
System.setProperty("java.class.path", classpath);
/** @todo run this only if necessary and in parallel. Right now
* we're running detection no matter what. We should be more
* intelligent and detect somehow whether new devices are present
* before we run our detection tests.*/
JmfDeviceDetector detector = new JmfDeviceDetector();
detector.initialize();
}
finally
{
logger.logExit();
}
setupRenderers();
}
private static void setupRenderers()
{
if (isWindowsVista())
{
/*
* DDRenderer will cause Windows Vista to switch its theme from Aero
* to Vista Basic so try to pick up a different Renderer.
*/
Vector renderers =
PlugInManager.getPlugInList(null, null, PlugInManager.RENDERER);
if (renderers.contains("com.sun.media.renderer.video.GDIRenderer"))
{
PlugInManager.removePlugIn(
"com.sun.media.renderer.video.DDRenderer",
PlugInManager.RENDERER);
}
}
else if(!isLinux32())
{
Vector renderers =
PlugInManager.getPlugInList(null, null, PlugInManager.RENDERER);
if (renderers.contains("com.sun.media.renderer.video.LightWeightRenderer") ||
renderers.contains("com.sun.media.renderer.video.AWTRenderer"))
{
// remove xlib renderer cause its native one and jmf is supported
// only on 32bit machines
PlugInManager.removePlugIn(
"com.sun.media.renderer.video.XLibRenderer",
PlugInManager.RENDERER);
}
}
}
private static boolean isWindowsVista()
{
String osName = System.getProperty("os.name");
/*
* TODO We're currently checking for Vista only but it may make sense to
* check for a version of Windows greater than or equal to Vista.
*/
return (osName != null) && (osName.indexOf("Windows") != -1)
&& (osName.indexOf("Vista") != -1);
}
private static boolean isLinux32()
{
String osName = System.getProperty("os.name");
String arch = System.getProperty("sun.arch.data.model");
return (osName != null) && (arch != null) && (osName.indexOf("Linux") != -1)
&& (arch.indexOf("32") != -1);
}
/**
* Detect all devices and complete
*/
public static void detectAndConfigureCaptureDevices()
{
setupJMF();
}
public static void main(String[] args)
{
detectAndConfigureCaptureDevices();
}
}