diff --git a/resources/sounds/sounds.properties b/resources/sounds/sounds.properties
index e732a0729..28f063600 100644
--- a/resources/sounds/sounds.properties
+++ b/resources/sounds/sounds.properties
@@ -20,4 +20,6 @@ DIAL=resources/sounds/dial.wav
HANG_UP=resources/sounds/hangup.wav
CALL_SECURITY_ON=resources/sounds/zrtpSecure.wav
-CALL_SECURITY_ERROR=resources/sounds/zrtpAlert.wav
\ No newline at end of file
+CALL_SECURITY_ERROR=resources/sounds/zrtpAlert.wav
+
+WEBCAM_SNAPSHOT=resources/sounds/webcamSnapshot.wav
diff --git a/resources/sounds/webcamSnapshot.wav b/resources/sounds/webcamSnapshot.wav
new file mode 100644
index 000000000..03c038d84
Binary files /dev/null and b/resources/sounds/webcamSnapshot.wav differ
diff --git a/src/net/java/sip/communicator/impl/gui/main/presence/avatar/SelectAvatarMenu.java b/src/net/java/sip/communicator/impl/gui/main/presence/avatar/SelectAvatarMenu.java
index dcc51aded..de67720f5 100644
--- a/src/net/java/sip/communicator/impl/gui/main/presence/avatar/SelectAvatarMenu.java
+++ b/src/net/java/sip/communicator/impl/gui/main/presence/avatar/SelectAvatarMenu.java
@@ -260,7 +260,8 @@ public void run()
= GuiActivator.getRegisteredProviderForAccount(
accountID);
- if(protocolProvider != null)
+ if(protocolProvider != null
+ && protocolProvider.isRegistered())
{
OperationSetAvatar opSetAvatar
= protocolProvider
diff --git a/src/net/java/sip/communicator/impl/gui/main/presence/avatar/imagepicker/ImagePickerDialog.java b/src/net/java/sip/communicator/impl/gui/main/presence/avatar/imagepicker/ImagePickerDialog.java
index 2a1eb05e4..02e24dd03 100644
--- a/src/net/java/sip/communicator/impl/gui/main/presence/avatar/imagepicker/ImagePickerDialog.java
+++ b/src/net/java/sip/communicator/impl/gui/main/presence/avatar/imagepicker/ImagePickerDialog.java
@@ -96,8 +96,6 @@ private void initComponents(int clipperZoneWidth, int clipperZoneHeight)
this.webcamButton = new JButton(GuiActivator.getResources()
.getI18NString("service.gui.avatar.imagepicker.TAKE_PHOTO"));
- // disable it till we support it
- this.webcamButton.setEnabled(false);
this.webcamButton.addActionListener(this);
this.webcamButton.setName("webcamButton");
@@ -158,17 +156,17 @@ else if (name.equals("resetButton"))
{
this.editPanel.reset();
}
- else
+ else if (name.equals("webcamButton"))
{
-// WebcamDialog dialog = new WebcamDialog(this);
-// dialog.setVisible(true);
-// byte[] bimage = dialog.getGrabbedImage();
-//
-// if (bimage != null)
-// {
-// Image i = new ImageIcon(bimage).getImage();
-// editPanel.setImage(ImageUtils.getBufferedImage(i));
-// }
+ WebcamDialog dialog = new WebcamDialog(this);
+ dialog.setVisible(true);
+ byte[] bimage = dialog.getGrabbedImage();
+
+ if (bimage != null)
+ {
+ Image i = new ImageIcon(bimage).getImage();
+ editPanel.setImage(ImageUtils.getBufferedImage(i));
+ }
}
}
diff --git a/src/net/java/sip/communicator/impl/gui/main/presence/avatar/imagepicker/WebcamDialog.java b/src/net/java/sip/communicator/impl/gui/main/presence/avatar/imagepicker/WebcamDialog.java
index ede148e3c..19ec777ca 100644
--- a/src/net/java/sip/communicator/impl/gui/main/presence/avatar/imagepicker/WebcamDialog.java
+++ b/src/net/java/sip/communicator/impl/gui/main/presence/avatar/imagepicker/WebcamDialog.java
@@ -8,36 +8,38 @@
import java.awt.*;
import java.awt.event.*;
+import java.awt.image.*;
import javax.swing.*;
import net.java.sip.communicator.impl.gui.*;
import net.java.sip.communicator.service.audionotifier.*;
-//import net.java.sip.communicator.service.media.*;
-import net.java.sip.communicator.service.protocol.event.*;
+import net.java.sip.communicator.service.neomedia.*;
+import net.java.sip.communicator.util.*;
import net.java.sip.communicator.util.swing.*;
/**
* A dialog showing the webcam and allowing the user to grap a snapshot
*
* @author Damien Roth
+ * @author Damian Minkov
*/
public class WebcamDialog
extends SIPCommDialog
implements ActionListener
-// , VideoListener
{
+ /**
+ * The Logger used by the WebcamDialog class and its
+ * instances for logging output.
+ */
+ private static final Logger logger = Logger.getLogger(WebcamDialog.class);
+
private VideoContainer videoContainer;
- private Component videoComponent = null;
-
- private JButton cancelButton;
+
private JButton grabSnapshot;
-
+
private byte[] grabbedImage = null;
- private TransparentPanel southPanel;
-
- private TransparentPanel timerPanel;
private TimerImage[] timerImages = new TimerImage[3];
/**
@@ -66,40 +68,40 @@ private void init()
this.grabSnapshot.addActionListener(this);
this.grabSnapshot.setEnabled(false);
- this.cancelButton = new JButton(GuiActivator.getResources()
+ JButton cancelButton = new JButton(GuiActivator.getResources()
.getI18NString("service.gui.avatar.imagepicker.CANCEL"));
- this.cancelButton.setName("cancel");
- this.cancelButton.addActionListener(this);
+ cancelButton.setName("cancel");
+ cancelButton.addActionListener(this);
initAccessWebcam();
-
// Timer Panel
- this.timerPanel = new TransparentPanel();
- this.timerPanel.setLayout(new GridLayout(0, 3));
+ TransparentPanel timerPanel = new TransparentPanel();
+ timerPanel.setLayout(new GridLayout(0, timerImages.length));
TransparentPanel tp;
for (int i = 0; i < this.timerImages.length; i++)
{
- this.timerImages[i] = new TimerImage("" + (3-i));
+ this.timerImages[i] = new TimerImage("" + (timerImages.length - i));
tp = new TransparentPanel();
tp.add(this.timerImages[i], BorderLayout.CENTER);
- this.timerPanel.add(tp);
+ timerPanel.add(tp);
}
- TransparentPanel buttonsPanel = new TransparentPanel(new GridLayout(1, 2));
+ TransparentPanel buttonsPanel
+ = new TransparentPanel(new GridLayout(1, 2));
buttonsPanel.add(this.grabSnapshot);
- buttonsPanel.add(this.cancelButton);
+ buttonsPanel.add(cancelButton);
// South Panel
- this.southPanel = new TransparentPanel(new BorderLayout());
- this.southPanel.add(this.timerPanel, BorderLayout.CENTER);
- this.southPanel.add(buttonsPanel, BorderLayout.SOUTH);
+ TransparentPanel southPanel = new TransparentPanel(new BorderLayout());
+ southPanel.add(timerPanel, BorderLayout.CENTER);
+ southPanel.add(buttonsPanel, BorderLayout.SOUTH);
this.add(this.videoContainer, BorderLayout.CENTER);
- this.add(this.southPanel, BorderLayout.SOUTH);
+ this.add(southPanel, BorderLayout.SOUTH);
}
/**
@@ -107,46 +109,39 @@ private void init()
*/
private void initAccessWebcam()
{
- Dimension d = new Dimension(320, 240);
-
- // Create a container for the video
- this.videoContainer = new VideoContainer(new JLabel(
- GuiActivator.getResources()
- .getI18NString("service.gui.avatar.imagepicker.INITIALIZING"),
- JLabel.CENTER));
- this.videoContainer.setPreferredSize(d);
- this.videoContainer.setMinimumSize(d);
- this.videoContainer.setMaximumSize(d);
-
-// try
-// {
-// // Call the method in the media service
-// GuiActivator.getMediaService().createLocalVideoComponent(this);
-// } catch (MediaException e)
-// {
-// //todo: In what scenarios are exceptions thrown and how to manage them?
-// this.videoContainer = new VideoContainer(new JLabel(
-// GuiActivator.getResources()
-// .getI18NString("service.gui.avatar.imagepicker.WEBCAM_ERROR")));
-// e.printStackTrace();
-// }
+ //Call the method in the media service
+ this.videoContainer =
+ (VideoContainer)GuiActivator.getMediaService()
+ .getVideoPreviewComponent(
+ GuiActivator.getMediaService().getDefaultDevice(
+ MediaType.VIDEO,
+ MediaUseCase.CALL
+ ), 320, 240);
+ this.grabSnapshot.setEnabled(true);
}
/**
- * Grap the current image of the webcam throught the MediaService
+ * Grab the current image of the webcam through the MediaService
*/
private void grabSnapshot()
{
- // Just call the method "grabSnapshot" from the MediaService with the component
-// try
-// {
-// this.grabbedImage = GuiActivator.getMediaService()
-// .grabSnapshot(this.videoComponent);
-// }
-// catch (Exception e)
-// {
-// e.printStackTrace();
-// }
+ try
+ {
+ Robot robot = new Robot();
+ Point location = videoContainer.getLocationOnScreen();
+
+ BufferedImage bi = robot.createScreenCapture(new Rectangle(
+ location.x,
+ location.y,
+ videoContainer.getWidth(),
+ videoContainer.getHeight()));
+ this.grabbedImage = ImageUtils.toByteArray(bi);
+ }
+ catch (Throwable e)
+ {
+ logger.error("Cannot create snapshot!", e);
+ }
+
close(false);
this.setVisible(false);
}
@@ -177,41 +172,8 @@ private void playSound()
protected void close(boolean isEscaped)
{
-// try
-// {
-// if (this.videoComponent != null)
-// {
-// GuiActivator.getMediaService()
-// .disposeLocalVideoComponent(this.videoComponent);
-// this.videoComponent = null;
-// }
-// }
-// catch (MediaException e)
-// {
-// // Better manager the exception !
-// e.printStackTrace();
-// }
- }
-
- public void videoAdded(VideoEvent event)
- {
- // Here is the important part. With this event, you get the component
- // containing the video !
-
- // You need to keep it. The returned componant is the key for all
- // the other methods !
- this.videoComponent = event.getVisualComponent();
-
- // Add the component in the container
- this.videoContainer.add(this.videoComponent);
-
- this.grabSnapshot.setEnabled(true);
- }
-
- public void videoRemoved(VideoEvent event)
- {
- // In case of the video is removed elsewhere
- this.videoComponent = null;
+ this.videoContainer = null;
+ dispose();
}
public void actionPerformed(ActionEvent e)
@@ -220,21 +182,21 @@ public void actionPerformed(ActionEvent e)
if (actName.equals("grab"))
{
- if (this.videoComponent == null)
- return;
-
this.grabSnapshot.setEnabled(false);
new SnapshotTimer().start();
}
else
{
close(false);
- this.setVisible(false);
+ dispose();
}
}
-
+
+ /**
+ * This thread grabs the snapshot by counting down.
+ */
private class SnapshotTimer
- extends Thread
+ extends Thread
{
@Override
public void run()
@@ -250,7 +212,7 @@ public void run()
}
catch (InterruptedException e)
{
- e.printStackTrace();
+ logger.error("", e);
}
}
@@ -262,7 +224,10 @@ public void run()
}
}
-
+
+ /**
+ * These are the images shown as timer while grabbing the snapshot.
+ */
private class TimerImage
extends JComponent
{
diff --git a/src/net/java/sip/communicator/impl/neomedia/MediaConfiguration.java b/src/net/java/sip/communicator/impl/neomedia/MediaConfiguration.java
index 597f8f112..91ac82a52 100644
--- a/src/net/java/sip/communicator/impl/neomedia/MediaConfiguration.java
+++ b/src/net/java/sip/communicator/impl/neomedia/MediaConfiguration.java
@@ -5,20 +5,21 @@
*/
package net.java.sip.communicator.impl.neomedia;
+import java.util.*;
+
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import javax.media.*;
import javax.media.MediaException;
-import javax.media.control.*;
-import javax.media.protocol.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.*;
-import net.java.sip.communicator.impl.neomedia.codec.video.*;
import net.java.sip.communicator.impl.neomedia.device.*;
+import net.java.sip.communicator.service.neomedia.*;
+import net.java.sip.communicator.service.neomedia.device.*;
import net.java.sip.communicator.service.resources.*;
import net.java.sip.communicator.util.*;
import net.java.sip.communicator.util.swing.*;
@@ -58,12 +59,6 @@ public class MediaConfiguration
*/
private static CaptureDeviceInfo videoDeviceInPreview;
- /**
- * The Player depicting the preview of the currently selected
- * CaptureDeviceInfo.
- */
- private static Player videoPlayerInPreview;
-
/**
* Returns the audio configuration panel.
* @return the audio configuration panel
@@ -82,65 +77,6 @@ public static Component createVideoConfigPanel()
return createControls(DeviceConfigurationComboBoxModel.VIDEO);
}
- /**
- * Listens and shows the video in the video container when needed.
- * @param event the event when player has ready visual component.
- * @param videoContainer the container.
- */
- private static void controllerUpdateForPreview(ControllerEvent event,
- Container videoContainer)
- {
- if (event instanceof ConfigureCompleteEvent)
- {
- Processor player = (Processor) event.getSourceController();
-
- /*
- * Use SwScaler for the scaling since it produces an image with
- * better quality.
- */
- TrackControl[] trackControls = player.getTrackControls();
-
- if ((trackControls != null) && (trackControls.length != 0))
- try
- {
- for (TrackControl trackControl : trackControls)
- {
- SwScaler playerScaler = new SwScaler();
-
- trackControl.setCodecChain(
- new Codec[] { playerScaler });
- break;
- }
- }
- catch (UnsupportedPlugInException upiex)
- {
- logger.warn("Failed to add SwScaler to codec chain", upiex);
- }
-
- // Turn the Processor into a Player.
- try
- {
- player.setContentDescriptor(null);
- }
- catch (NotConfiguredError nce)
- {
- logger.error(
- "Failed to set ContentDescriptor of Processor",
- nce);
- }
-
- player.realize();
- }
- else if (event instanceof RealizeCompleteEvent)
- {
- Player player = (Player) event.getSourceController();
- Component video = player.getVisualComponent();
-
- showPreview(videoContainer, video, player);
- player.start();
- }
- }
-
/**
* Creates the ui controls for portaudio.
* @param portAudioPanel the panel
@@ -439,47 +375,38 @@ else if (source == downButton)
* @throws MediaException a problem getting preview.
*/
private static void createPreview(CaptureDeviceInfo device,
- final Container videoContainer)
+ final JComponent videoContainer)
throws IOException,
MediaException
{
videoContainer.removeAll();
- if (videoPlayerInPreview != null)
- disposePlayer(videoPlayerInPreview);
+
+ videoContainer.revalidate();
+ videoContainer.repaint();
if (device == null)
return;
- DataSource dataSource = Manager.createDataSource(device.getLocator());
- Dimension size = videoContainer.getPreferredSize();
-
- /*
- * Don't let the size be uselessly small just because the videoContainer
- * has too small a preferred size.
- */
- if ((size.width < 128) || (size.height < 96))
+ Iterator mDevsIter =
+ NeomediaActivator.getMediaServiceImpl()
+ .getDevices(MediaType.VIDEO, MediaUseCase.ANY)
+ .iterator();
+ while(mDevsIter.hasNext())
{
- size.width = 128;
- size.height = 96;
- }
- VideoMediaStreamImpl
- .selectVideoSize(dataSource, size.width, size.height);
-
- // A Player is documented to be created on a connected DataSource.
- dataSource.connect();
-
- Processor player = Manager.createProcessor(dataSource);
+ MediaDeviceImpl dev = (MediaDeviceImpl)mDevsIter.next();
+ if(dev.getCaptureDeviceInfo().equals(device))
+ {
+ Component c = (Component)NeomediaActivator.getMediaServiceImpl()
+ .getVideoPreviewComponent(
+ dev,
+ videoContainer.getSize().width,
+ videoContainer.getSize().height);
- videoPlayerInPreview = player;
+ videoContainer.add(c);
- player.addControllerListener(new ControllerListener()
- {
- public void controllerUpdate(ControllerEvent event)
- {
- controllerUpdateForPreview(event, videoContainer);
+ break;
}
- });
- player.configure();
+ }
}
/**
@@ -490,7 +417,7 @@ public void controllerUpdate(ControllerEvent event)
*/
private static Component createPreview(int type, final JComboBox comboBox)
{
- final Container preview;
+ final JComponent preview;
if (type == DeviceConfigurationComboBoxModel.VIDEO)
{
JLabel noPreview =
@@ -523,7 +450,7 @@ public void actionPerformed(ActionEvent event)
Exception exception;
try
- {
+ {
createPreview(device, preview);
exception = null;
}
@@ -566,7 +493,21 @@ public void hierarchyChanged(HierarchyEvent event)
& HierarchyEvent.DISPLAYABILITY_CHANGED)
!= 0)
&& comboBox.isDisplayable())
- comboBoxListener.actionPerformed(null);
+ {
+ // let current changes end their execution
+ // and after that trigger action on combobox
+ SwingUtilities.invokeLater(new Runnable(){
+ public void run()
+ {
+ comboBoxListener.actionPerformed(null);
+ }
+ });
+ }
+ else
+ {
+ if(!comboBox.isDisplayable())
+ videoDeviceInPreview = null;
+ }
}
});
} else
@@ -580,26 +521,11 @@ public void hierarchyChanged(HierarchyEvent event)
* @param noVideoComponent the container component.
* @return the video container.
*/
- private static Container createVideoContainer(Component noVideoComponent)
+ private static JComponent createVideoContainer(Component noVideoComponent)
{
return new VideoContainer(noVideoComponent);
}
- /**
- * Dispose the player used for the preview.
- * @param player the player.
- */
- private static void disposePlayer(Player player)
- {
- player.stop();
- player.deallocate();
- player.close();
-
- if ((videoPlayerInPreview != null)
- && videoPlayerInPreview.equals(player))
- videoPlayerInPreview = null;
- }
-
/**
* The mnemonic for a type.
* @param type audio or video type.
@@ -661,101 +587,4 @@ private static void move(JTable table, boolean up)
.getSelectedRow(), up);
table.getSelectionModel().setSelectionInterval(index, index);
}
-
- /**
- * Shows the preview panel.
- * @param previewContainer the container
- * @param preview the preview component.
- * @param player the player.
- */
- private static void showPreview(final Container previewContainer,
- final Component preview, final Player player)
- {
- if (!SwingUtilities.isEventDispatchThread())
- {
- SwingUtilities.invokeLater(new Runnable()
- {
- public void run()
- {
- showPreview(previewContainer, preview, player);
- }
- });
- return;
- }
-
- previewContainer.removeAll();
-
- if (preview != null)
- {
- HierarchyListener hierarchyListener = new HierarchyListener()
- {
- private Window window;
-
- private WindowListener windowListener;
-
- public void dispose()
- {
- if (windowListener != null)
- {
- if (window != null)
- {
- window.removeWindowListener(windowListener);
- window = null;
- }
- windowListener = null;
- }
- preview.removeHierarchyListener(this);
-
- disposePlayer(player);
- videoDeviceInPreview = null;
-
- /*
- * We've just disposed the player which created the preview
- * component so the preview component is of no use
- * regardless of whether the Media configuration form will
- * be redisplayed or not. And since the preview component
- * appears to be a huge object even after its player is
- * disposed, make sure to not reference it.
- */
- previewContainer.remove(preview);
- }
-
- public void hierarchyChanged(HierarchyEvent event)
- {
- if ((event.getChangeFlags()
- & HierarchyEvent.DISPLAYABILITY_CHANGED)
- == 0)
- return;
-
- if (!preview.isDisplayable())
- {
- dispose();
- return;
- }
-
- if (windowListener == null)
- {
- window = SwingUtilities.windowForComponent(preview);
- if (window != null)
- {
- windowListener = new WindowAdapter()
- {
- @Override
- public void windowClosing(WindowEvent event)
- {
- dispose();
- }
- };
- window.addWindowListener(windowListener);
- }
- }
- }
- };
- preview.addHierarchyListener(hierarchyListener);
-
- previewContainer.add(preview);
- }
- else
- disposePlayer(player);
- }
}
diff --git a/src/net/java/sip/communicator/impl/neomedia/MediaServiceImpl.java b/src/net/java/sip/communicator/impl/neomedia/MediaServiceImpl.java
index 16414ad3b..45ad7b99a 100644
--- a/src/net/java/sip/communicator/impl/neomedia/MediaServiceImpl.java
+++ b/src/net/java/sip/communicator/impl/neomedia/MediaServiceImpl.java
@@ -6,16 +6,25 @@
*/
package net.java.sip.communicator.impl.neomedia;
+import java.awt.*;
+import java.awt.event.*;
import java.util.*;
+import java.util.List;
import javax.media.*;
+import javax.media.control.*;
+import javax.media.protocol.*;
+import javax.swing.*;
import net.java.sip.communicator.impl.neomedia.codec.*;
+import net.java.sip.communicator.impl.neomedia.codec.video.*;
import net.java.sip.communicator.impl.neomedia.device.*;
import net.java.sip.communicator.impl.neomedia.format.*;
import net.java.sip.communicator.service.neomedia.*;
import net.java.sip.communicator.service.neomedia.device.*;
import net.java.sip.communicator.service.neomedia.format.*;
+import net.java.sip.communicator.util.*;
+import net.java.sip.communicator.util.swing.*;
/**
* Implements MediaService for JMF.
@@ -26,6 +35,11 @@
public class MediaServiceImpl
implements MediaService
{
+ /**
+ * The logger.
+ */
+ private static final Logger logger
+ = Logger.getLogger(MediaServiceImpl.class);
/**
* With this property video support can be disabled (enabled by default).
@@ -608,4 +622,246 @@ public Map getDynamicPayloadTypePreferences()
}
return dynamicPayloadTypePreferences;
}
+
+ /**
+ * Creates a preview component for the specified device(video device) used
+ * to show video preview from that device.
+ *
+ * @param device the video device
+ * @param preferredWidth the width we prefer for the component
+ * @param preferredHeight the height we prefer for the component
+ * @return the preview component.
+ */
+ public Object getVideoPreviewComponent(MediaDevice device
+ , int preferredWidth, int preferredHeight)
+ {
+ JLabel noPreview =
+ new JLabel(NeomediaActivator.getResources().getI18NString(
+ "impl.media.configform.NO_PREVIEW"));
+ noPreview.setHorizontalAlignment(SwingConstants.CENTER);
+ noPreview.setVerticalAlignment(SwingConstants.CENTER);
+ final JComponent videoContainer
+ = new VideoContainer(noPreview);
+
+ videoContainer.setPreferredSize(
+ new Dimension(preferredWidth, preferredHeight));
+ videoContainer.setMaximumSize(
+ new Dimension(preferredWidth, preferredHeight));
+
+ try
+ {
+ if (device == null ||
+ ((MediaDeviceImpl)device).getCaptureDeviceInfo() == null)
+ {
+ return videoContainer;
+ }
+
+ DataSource dataSource = Manager.createDataSource(
+ ((MediaDeviceImpl)device).getCaptureDeviceInfo().getLocator());
+
+ /*
+ * Don't let the size be uselessly small just because the videoContainer
+ * has too small a preferred size.
+ */
+ if ((preferredWidth < 128) || (preferredHeight < 96))
+ {
+ preferredHeight = 128;
+ preferredWidth = 96;
+ }
+ VideoMediaStreamImpl
+ .selectVideoSize(dataSource, preferredWidth, preferredHeight);
+
+ // A Player is documented to be created on a connected DataSource.
+ dataSource.connect();
+
+ Processor player = Manager.createProcessor(dataSource);
+
+ player.addControllerListener(new ControllerListener()
+ {
+ public void controllerUpdate(ControllerEvent event)
+ {
+ controllerUpdateForPreview(event, videoContainer);
+ }
+ });
+ player.configure();
+
+ return videoContainer;
+ }
+ catch(Exception e)
+ {
+ e.printStackTrace();
+ }
+
+ return null;
+ }
+
+ /**
+ * Listens and shows the video in the video container when needed.
+ * @param event the event when player has ready visual component.
+ * @param videoContainer the container.
+ */
+ private static void controllerUpdateForPreview(ControllerEvent event,
+ JComponent videoContainer)
+ {
+ if (event instanceof ConfigureCompleteEvent)
+ {
+ Processor player = (Processor) event.getSourceController();
+
+ /*
+ * Use SwScaler for the scaling since it produces an image with
+ * better quality.
+ */
+ TrackControl[] trackControls = player.getTrackControls();
+
+ if ((trackControls != null) && (trackControls.length != 0))
+ try
+ {
+ for (TrackControl trackControl : trackControls)
+ {
+ trackControl.setCodecChain(
+ new Codec[] { new SwScaler() });
+ break;
+ }
+ }
+ catch (UnsupportedPlugInException upiex)
+ {
+ logger.warn("Failed to add SwScaler to codec chain", upiex);
+ }
+
+ // Turn the Processor into a Player.
+ try
+ {
+ player.setContentDescriptor(null);
+ }
+ catch (NotConfiguredError nce)
+ {
+ logger.error(
+ "Failed to set ContentDescriptor of Processor",
+ nce);
+ }
+
+ player.realize();
+ }
+ else if (event instanceof RealizeCompleteEvent)
+ {
+ Player player = (Player) event.getSourceController();
+ Component video = player.getVisualComponent();
+
+ showPreview(videoContainer, video, player);
+ }
+ }
+
+ /**
+ * Shows the preview panel.
+ * @param previewContainer the container
+ * @param preview the preview component.
+ * @param player the player.
+ */
+ private static void showPreview(final JComponent previewContainer,
+ final Component preview, final Player player)
+ {
+ if (!SwingUtilities.isEventDispatchThread())
+ {
+ SwingUtilities.invokeLater(new Runnable()
+ {
+ public void run()
+ {
+ showPreview(previewContainer, preview, player);
+ }
+ });
+ return;
+ }
+
+ previewContainer.removeAll();
+
+ if (preview != null)
+ {
+ HierarchyListener hierarchyListener = new HierarchyListener()
+ {
+ private Window window;
+
+ private WindowListener windowListener;
+
+ public void dispose()
+ {
+ if (windowListener != null)
+ {
+ if (window != null)
+ {
+ window.removeWindowListener(windowListener);
+ window = null;
+ }
+ windowListener = null;
+ }
+ preview.removeHierarchyListener(this);
+
+ disposePlayer(player);
+
+ /*
+ * We've just disposed the player which created the preview
+ * component so the preview component is of no use
+ * regardless of whether the Media configuration form will
+ * be redisplayed or not. And since the preview component
+ * appears to be a huge object even after its player is
+ * disposed, make sure to not reference it.
+ */
+ previewContainer.remove(preview);
+ }
+
+ public void hierarchyChanged(HierarchyEvent event)
+ {
+ if ((event.getChangeFlags()
+ & HierarchyEvent.DISPLAYABILITY_CHANGED)
+ == 0)
+ return;
+
+ if (!preview.isDisplayable())
+ {
+ dispose();
+ return;
+ }
+ else
+ {
+ player.start();
+ }
+
+ if (windowListener == null)
+ {
+ window = SwingUtilities.windowForComponent(preview);
+ if (window != null)
+ {
+ windowListener = new WindowAdapter()
+ {
+ @Override
+ public void windowClosing(WindowEvent event)
+ {
+ dispose();
+ }
+ };
+ window.addWindowListener(windowListener);
+ }
+ }
+ }
+ };
+ preview.addHierarchyListener(hierarchyListener);
+
+ previewContainer.add(preview);
+
+ previewContainer.revalidate();
+ previewContainer.repaint();
+ }
+ else
+ disposePlayer(player);
+ }
+
+ /**
+ * Dispose the player used for the preview.
+ * @param player the player.
+ */
+ private static void disposePlayer(Player player)
+ {
+ player.stop();
+ player.deallocate();
+ player.close();
+ }
}
diff --git a/src/net/java/sip/communicator/impl/protocol/msn/OperationSetServerStoredAccountInfoMsnImpl.java b/src/net/java/sip/communicator/impl/protocol/msn/OperationSetServerStoredAccountInfoMsnImpl.java
index 014ce4c68..70758ae0b 100644
--- a/src/net/java/sip/communicator/impl/protocol/msn/OperationSetServerStoredAccountInfoMsnImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/msn/OperationSetServerStoredAccountInfoMsnImpl.java
@@ -34,7 +34,7 @@ public class OperationSetServerStoredAccountInfoMsnImpl
Logger.getLogger(OperationSetServerStoredAccountInfoMsnImpl.class);
/**
- * The jabber provider that created us.
+ * The msn provider that created us.
*/
private ProtocolProviderServiceMsnImpl msnProvider = null;
/**
@@ -499,14 +499,14 @@ private void assertConnected()
if (msnProvider == null)
{
throw new IllegalStateException(
- "The jabber provider must be non-null and signed on "
+ "The msn provider must be non-null and signed on "
+ "before being able to communicate.");
}
if (!msnProvider.isRegistered())
{
throw new IllegalStateException(
- "The jabber provider must be signed on before "
+ "The msn provider must be signed on before "
+ "being able to communicate.");
}
}
diff --git a/src/net/java/sip/communicator/service/neomedia/MediaService.java b/src/net/java/sip/communicator/service/neomedia/MediaService.java
index 86a6ae5f3..e923fa092 100644
--- a/src/net/java/sip/communicator/service/neomedia/MediaService.java
+++ b/src/net/java/sip/communicator/service/neomedia/MediaService.java
@@ -6,7 +6,9 @@
*/
package net.java.sip.communicator.service.neomedia;
+import java.awt.*;
import java.util.*;
+import java.util.List;
import net.java.sip.communicator.service.neomedia.device.*;
import net.java.sip.communicator.service.neomedia.format.*;
@@ -178,4 +180,16 @@ public MediaStream createMediaStream(StreamConnector connector,
* payload type number.
*/
public Map getDynamicPayloadTypePreferences();
+
+ /**
+ * Creates a preview component for the specified device(video device) used
+ * to show video preview from it.
+ *
+ * @param device the video device
+ * @param preferredWidth the width we prefer for the component
+ * @param preferredHeight the height we prefer for the component
+ * @return the preview component.
+ */
+ public Object getVideoPreviewComponent(
+ MediaDevice device, int preferredWidth, int preferredHeight);
}