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); }