/*
* Jitsi, the OpenSource Java VoIP and Instant Messaging client.
*
* Copyright @ 2015 Atlassian Pty Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.java.sip.communicator.impl.neomedia;
import java.util.*;
import net.java.sip.communicator.impl.neomedia.codec.video.h264.*;
import net.java.sip.communicator.service.gui.*;
import net.java.sip.communicator.service.notification.*;
import net.java.sip.communicator.service.resources.*;
import net.java.sip.communicator.util.*;
import org.jitsi.impl.neomedia.*;
import org.jitsi.service.audionotifier.*;
import org.jitsi.service.configuration.*;
import org.jitsi.service.fileaccess.*;
import org.jitsi.service.libjitsi.*;
import org.jitsi.service.neomedia.*;
import org.jitsi.service.packetlogging.*;
import org.jitsi.service.resources.*;
import org.osgi.framework.*;
/**
* Implements <tt>BundleActivator</tt> for the neomedia bundle.
*
* @author Martin Andre
* @author Emil Ivov
* @author Lyubomir Marinov
* @author Boris Grozev
*/
public class NeomediaActivator
implements BundleActivator
{
/**
* Indicates if the audio configuration form should be disabled, i.e.
* not visible to the user.
*/
private static final String AUDIO_CONFIG_DISABLED_PROP
= "net.java.sip.communicator.impl.neomedia.AUDIO_CONFIG_DISABLED";
/**
* The audio configuration form used to define the capture/notify/playback
* audio devices.
*/
private static ConfigurationForm audioConfigurationForm;
/**
* The audio notifier service.
*/
private static AudioNotifierService audioNotifierService;
/**
* The context in which the one and only <tt>NeomediaActivator</tt> instance
* has started executing.
*/
private static BundleContext bundleContext;
/**
* Indicates if the call recording config form should be disabled, i.e.
* not visible to the user.
*/
private static final String CALL_RECORDING_CONFIG_DISABLED_PROP
= "net.java.sip.communicator.impl.neomedia.callrecordingconfig.DISABLED";
/**
* The <tt>ConfigurationService</tt> registered in {@link #bundleContext}
* and used by the <tt>NeomediaActivator</tt> instance to read and write
* configuration properties.
*/
private static ConfigurationService configurationService;
/**
* The name of the notification pop-up event displayed when the device
* configration has changed.
*/
public static final String DEVICE_CONFIGURATION_HAS_CHANGED
= "DeviceConfigurationChanged";
/**
* The <tt>FileAccessService</tt> registered in {@link #bundleContext} and
* used by the <tt>NeomediaActivator</tt> instance to safely access files.
*/
private static FileAccessService fileAccessService;
/**
* Indicates if the H.264 configuration form should be disabled, i.e.
* not visible to the user.
*/
private static final String H264_CONFIG_DISABLED_PROP
= "net.java.sip.communicator.impl.neomedia.h264config.DISABLED";
/**
* A {@link MediaConfigurationService} instance.
*/
private static MediaConfigurationImpl mediaConfiguration;
/**
* The one and only <tt>MediaServiceImpl</tt> instance registered in
* {@link #bundleContext} by the <tt>NeomediaActivator</tt> instance.
*/
private static MediaServiceImpl mediaServiceImpl;
/**
* The name of the notification pop-up event displayed when a new device
* is selected (for audio in, audio out or notifications).
*/
public static final String NEW_SELECTED_DEVICE
= "NewSelectedDevice";
/**
* The notifcation service to pop-up messages.
*/
private static NotificationService notificationService;
/**
* The OSGi <tt>PacketLoggingService</tt> of {@link #mediaServiceImpl} in
* {@link #bundleContext} and used for debugging.
*/
private static PacketLoggingService packetLoggingService = null;
/**
* The <tt>ResourceManagementService</tt> registered in
* {@link #bundleContext} and representing the resources such as
* internationalized and localized text and images used by the neomedia
* bundle.
*/
private static ResourceManagementService resources;
/**
* Indicates if the video configuration form should be disabled, i.e.
* not visible to the user.
*/
private static final String VIDEO_CONFIG_DISABLED_PROP
= "net.java.sip.communicator.impl.neomedia.VIDEO_CONFIG_DISABLED";
/**
* A listener to the click on the popup message concerning video device
* configuration changes.
* Disabled until video hotplug is not available.
*/
//private VideoDeviceConfigurationListener
// videoDeviceConfigurationPropertyChangeListener;
/**
* The video configuration form.
*/
private static ConfigurationForm videoConfigurationForm;
/**
* Indicates if the ZRTP configuration form should be disabled, i.e.
* not visible to the user.
*/
private static final String ZRTP_CONFIG_DISABLED_PROP
= "net.java.sip.communicator.impl.neomedia.zrtpconfig.DISABLED";
/**
* Returns the audio configuration form used to define the
* capture/notify/playback audio devices.
*
* @return The audio configuration form used to define the
* capture/notify/playback audio devices.
*/
public static ConfigurationForm getAudioConfigurationForm()
{
return audioConfigurationForm;
}
/**
* Returns the <tt>AudioService</tt> obtained from the bundle
* context.
* @return the <tt>AudioService</tt> obtained from the bundle
* context
*/
public static AudioNotifierService getAudioNotifierService()
{
if(audioNotifierService == null)
{
audioNotifierService
= ServiceUtils.getService(
bundleContext,
AudioNotifierService.class);
}
return audioNotifierService;
}
/**
* Returns the context in which the one and only <tt>NeomediaActivator</tt>
* instance has started executing.
*
* @return The context in which the one and only <tt>NeomediaActivator</tt>
* instance has started executing.
*/
public static BundleContext getBundleContext()
{
return bundleContext;
}
/**
* Returns a reference to a ConfigurationService implementation currently
* registered in the bundle context or null if no such implementation was
* found.
*
* @return a currently valid implementation of the ConfigurationService.
*/
public static ConfigurationService getConfigurationService()
{
if (configurationService == null)
{
configurationService
= ServiceUtils.getService(
bundleContext,
ConfigurationService.class);
}
return configurationService;
}
/**
* Returns a reference to a FileAccessService implementation
* currently registered in the bundle context or null if no such
* implementation was found.
*
* @return a currently valid implementation of the
* FileAccessService .
*/
public static FileAccessService getFileAccessService()
{
if (fileAccessService == null)
{
fileAccessService
= ServiceUtils.getService(
bundleContext,
FileAccessService.class);
}
return fileAccessService;
}
public static MediaConfigurationService getMediaConfiguration()
{
return mediaConfiguration;
}
/**
* Gets the <tt>MediaService</tt> implementation instance registered by the
* neomedia bundle.
*
* @return the <tt>MediaService</tt> implementation instance registered by
* the neomedia bundle
*/
public static MediaServiceImpl getMediaServiceImpl()
{
return mediaServiceImpl;
}
/**
* Returns the <tt>NotificationService</tt> obtained from the bundle
* context.
*
* @return The <tt>NotificationService</tt> obtained from the bundle
* context.
*/
public static NotificationService getNotificationService()
{
if(notificationService == null)
{
// Get the notification service implementation
ServiceReference notifReference = bundleContext
.getServiceReference(NotificationService.class.getName());
notificationService = (NotificationService) bundleContext
.getService(notifReference);
if(notificationService != null)
{
// Register a popup message for a device configuration changed
// notification.
notificationService.registerDefaultNotificationForEvent(
DEVICE_CONFIGURATION_HAS_CHANGED,
net.java.sip.communicator.service.notification.NotificationAction.ACTION_POPUP_MESSAGE,
"Device configuration has changed",
null);
// Register a popup message for a new device selected for audio
// in, audio out or notifications.
notificationService.registerDefaultNotificationForEvent(
NEW_SELECTED_DEVICE,
net.java.sip.communicator.service.notification.NotificationAction.ACTION_POPUP_MESSAGE,
"New selected device",
null);
}
}
return notificationService;
}
/**
* Returns a reference to the <tt>PacketLoggingService</tt> implementation
* currently registered in the bundle context or null if no such
* implementation was found.
*
* @return a reference to a <tt>PacketLoggingService</tt> implementation
* currently registered in the bundle context or null if no such
* implementation was found.
*/
public static PacketLoggingService getPacketLogging()
{
if (packetLoggingService == null)
{
packetLoggingService
= ServiceUtils.getService(
bundleContext,
PacketLoggingService.class);
}
return packetLoggingService;
}
/**
* Gets the <tt>ResourceManagementService</tt> instance which represents the
* resources such as internationalized and localized text and images used by
* the neomedia bundle.
*
* @return the <tt>ResourceManagementService</tt> instance which represents
* the resources such as internationalized and localized text and images
* used by the neomedia bundle
*/
public static ResourceManagementService getResources()
{
if (resources == null)
{
resources
= ResourceManagementServiceUtils.getService(bundleContext);
}
return resources;
}
/**
* Returns the video configuration form.
*
* @return The video configuration form.
*/
public static ConfigurationForm getVideoConfigurationForm()
{
return videoConfigurationForm;
}
/**
* A listener to the click on the popup message concerning audio device
* configuration changes.
*/
private AudioDeviceConfigurationListener
audioDeviceConfigurationPropertyChangeListener;
/**
* The <tt>Logger</tt> used by the <tt>NeomediaActivator</tt> class and its
* instances for logging output.
*/
private final Logger logger = Logger.getLogger(NeomediaActivator.class);
/**
* Starts the execution of the neomedia bundle in the specified context.
*
* @param bundleContext the context in which the neomedia bundle is to start
* executing
* @throws Exception if an error occurs while starting the execution of the
* neomedia bundle in the specified context
*/
public void start(BundleContext bundleContext)
throws Exception
{
if (logger.isDebugEnabled())
logger.debug("Started.");
NeomediaActivator.bundleContext = bundleContext;
// MediaService
mediaServiceImpl = (MediaServiceImpl) LibJitsi.getMediaService();
bundleContext.registerService(
MediaService.class.getName(),
mediaServiceImpl,
null);
if (logger.isDebugEnabled())
logger.debug("Media Service ... [REGISTERED]");
mediaConfiguration = new MediaConfigurationImpl();
bundleContext.registerService(
MediaConfigurationService.class.getName(),
getMediaConfiguration(),
null);
if (logger.isDebugEnabled())
logger.debug("Media Configuration ... [REGISTERED]");
ConfigurationService cfg = NeomediaActivator.getConfigurationService();
Dictionary<String, String> mediaProps = new Hashtable<String, String>();
mediaProps.put( ConfigurationForm.FORM_TYPE,
ConfigurationForm.GENERAL_TYPE);
// If the audio configuration form is disabled don't register it.
if ((cfg == null) || !cfg.getBoolean(AUDIO_CONFIG_DISABLED_PROP, false))
{
audioConfigurationForm
= new LazyConfigurationForm(
AudioConfigurationPanel.class.getName(),
getClass().getClassLoader(),
"plugin.mediaconfig.AUDIO_ICON",
"impl.neomedia.configform.AUDIO",
3);
bundleContext.registerService(
ConfigurationForm.class.getName(),
audioConfigurationForm,
mediaProps);
// Initializes and registers the changed audio device configuration
// event at the notification service.
if (audioDeviceConfigurationPropertyChangeListener == null)
{
getNotificationService();
audioDeviceConfigurationPropertyChangeListener
= new AudioDeviceConfigurationListener(
audioConfigurationForm);
mediaServiceImpl
.getDeviceConfiguration()
.addPropertyChangeListener(
audioDeviceConfigurationPropertyChangeListener);
}
}
// If the video configuration form is disabled don't register it.
if ((cfg == null) || !cfg.getBoolean(VIDEO_CONFIG_DISABLED_PROP, false))
{
videoConfigurationForm
= new LazyConfigurationForm(
VideoConfigurationPanel.class.getName(),
getClass().getClassLoader(),
"plugin.mediaconfig.VIDEO_ICON",
"impl.neomedia.configform.VIDEO",
4);
bundleContext.registerService(
ConfigurationForm.class.getName(),
videoConfigurationForm,
mediaProps);
// Initializes and registers the changed video device configuration
// event at the notification service.
// Disabled until video hotplug is not available.
/*if (videoDeviceConfigurationPropertyChangeListener == null)
{
getNotificationService();
videoDeviceConfigurationPropertyChangeListener
= new VideoDeviceConfigurationListener(
videoConfigurationForm);
mediaServiceImpl
.getDeviceConfiguration()
.addPropertyChangeListener(
videoDeviceConfigurationPropertyChangeListener);
}*/
}
// H.264
// If the H.264 configuration form is disabled don't register it.
if ((cfg == null) || !cfg.getBoolean(H264_CONFIG_DISABLED_PROP, false))
{
Dictionary<String, String> h264Props
= new Hashtable<String, String>();
h264Props.put(
ConfigurationForm.FORM_TYPE,
ConfigurationForm.ADVANCED_TYPE);
bundleContext.registerService(
ConfigurationForm.class.getName(),
new LazyConfigurationForm(
ConfigurationPanel.class.getName(),
getClass().getClassLoader(),
"plugin.mediaconfig.VIDEO_ICON",
"impl.neomedia.configform.H264",
-1,
true),
h264Props);
}
// ZRTP
// If the ZRTP configuration form is disabled don't register it.
if ((cfg == null) || !cfg.getBoolean(ZRTP_CONFIG_DISABLED_PROP, false))
{
Dictionary<String, String> securityProps
= new Hashtable<String, String>();
securityProps.put( ConfigurationForm.FORM_TYPE,
ConfigurationForm.SECURITY_TYPE);
bundleContext.registerService(
ConfigurationForm.class.getName(),
new LazyConfigurationForm(
SecurityConfigForm.class.getName(),
getClass().getClassLoader(),
"impl.media.security.zrtp.CONF_ICON",
"impl.media.security.zrtp.TITLE",
0),
securityProps);
}
//we use the nist-sdp stack to make parse sdp and we need to set the
//following property to make sure that it would accept java generated
//IPv6 addresses that contain address scope zones.
System.setProperty("gov.nist.core.STRIP_ADDR_SCOPES", "true");
// AudioNotifierService
AudioNotifierService audioNotifierService
= LibJitsi.getAudioNotifierService();
audioNotifierService.setMute(
(cfg == null)
|| !cfg.getBoolean(
"net.java.sip.communicator"
+ ".impl.sound.isSoundEnabled",
true));
bundleContext.registerService(
AudioNotifierService.class.getName(),
audioNotifierService,
null);
if (logger.isInfoEnabled())
logger.info("Audio Notifier Service ...[REGISTERED]");
// Call Recording
// If the call recording configuration form is disabled don't continue.
if ((cfg == null)
|| !(cfg.getBoolean(CALL_RECORDING_CONFIG_DISABLED_PROP, false)
|| cfg.getBoolean("net.java.sip.communicator" +
".impl.gui.main.call.HIDE_CALL_RECORD_BUTTON",
false)))
{
Dictionary<String, String> callRecordingProps
= new Hashtable<String, String>();
callRecordingProps.put(
ConfigurationForm.FORM_TYPE,
ConfigurationForm.ADVANCED_TYPE);
bundleContext.registerService(
ConfigurationForm.class.getName(),
new LazyConfigurationForm(
CallRecordingConfigForm.class.getName(),
getClass().getClassLoader(),
null,
"plugin.callrecordingconfig.CALL_RECORDING_CONFIG",
1100,
true),
callRecordingProps);
}
}
/**
* Stops the execution of the neomedia bundle in the specified context.
*
* @param bundleContext the context in which the neomedia bundle is to stop
* executing
* @throws Exception if an error occurs while stopping the execution of the
* neomedia bundle in the specified context
*/
public void stop(BundleContext bundleContext)
throws Exception
{
try
{
if(audioDeviceConfigurationPropertyChangeListener != null)
{
mediaServiceImpl
.getDeviceConfiguration()
.removePropertyChangeListener(
audioDeviceConfigurationPropertyChangeListener);
audioDeviceConfigurationPropertyChangeListener.dispose();
audioDeviceConfigurationPropertyChangeListener = null;
}
// Disabled until video hotplug is available.
/*
if(videoDeviceConfigurationPropertyChangeListener != null)
{
mediaServiceImpl
.getDeviceConfiguration()
.removePropertyChangeListener(
videoDeviceConfigurationPropertyChangeListener);
videoDeviceConfigurationPropertyChangeListener.dispose();
videoDeviceConfigurationPropertyChangeListener = null;
}
*/
}
finally
{
configurationService = null;
fileAccessService = null;
mediaServiceImpl = null;
resources = null;
}
}
}