/* * 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.gui.main.call; import java.awt.*; import javax.swing.*; import javax.swing.event.*; import net.java.sip.communicator.plugin.desktoputil.*; import org.jitsi.service.neomedia.*; import org.jitsi.service.neomedia.event.*; /** * The volume control slider component. * * @author Yana Stamcheva * @author Vincent Lucas */ public class VolumeControlSlider extends TransparentPanel implements VolumeChangeListener { /** * The slider component. */ private final JSlider volumeSlider; /** * The VolumeControl that do the actual volume adjusting. */ private final VolumeControl volumeControl; /** * The dedicate thread to set the volume. */ private SetVolumeThread setVolumeThread = null; /** * The multiplier would just convert the float volume value coming from * the service to the int value needed for the volume control slider * component. */ private static final int MULTIPLIER = 100; /** * Creates a <tt>VolumeControlSlider</tt> for the given volumeControl * object. * * @param volumeControl the <tt>VolumeControl</tt> that do the actual volume * adjusting. */ public VolumeControlSlider( final VolumeControl volumeControl, int orientation) { super(new BorderLayout()); this.volumeControl = volumeControl; volumeControl.addVolumeChangeListener(this); setVolumeThread = new SetVolumeThread(volumeControl); volumeSlider = new JSlider(orientation, 0, 100, 50); if (orientation == JSlider.VERTICAL) volumeSlider.setPreferredSize(new Dimension(20, 100)); else volumeSlider.setPreferredSize(new Dimension(100, 20)); // Sets the minimum, maximum and default volume values for the volume // slider. volumeSlider.setMinimum((int) (volumeControl.getMinValue()*MULTIPLIER)); volumeSlider.setMaximum((int) (volumeControl.getMaxValue()*MULTIPLIER)); volumeSlider.setValue((int) (volumeControl.getVolume()*MULTIPLIER)); // Adds a change listener to the slider in order to correctly set // the volume through the VolumeControl service, on user change. volumeSlider.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent e) { JSlider source = (JSlider) e.getSource(); int volume = source.getValue(); // Set the volume to the volume control. setVolumeThread.setVolume((float) volume/MULTIPLIER); } }); this.add(volumeSlider); } /** * Event fired when volume has changed. * * @param volumeChangeEvent the volume change event. */ public void volumeChange(VolumeChangeEvent volumeChangeEvent) { int newValue = (int) (volumeChangeEvent.getLevel()*MULTIPLIER); if (volumeSlider.getValue() != newValue) volumeSlider.setValue(newValue); } /** * Returns this slider in a popup menu. * * @return this slider in a popup menu */ public JPopupMenu getPopupMenu() { SIPCommPopupMenu popupMenu = new SIPCommPopupMenu(); popupMenu.add(this); return popupMenu; } /** * Makes this Component displayable by connecting it to a native screen * resource. Starts the thread loop to change volume. */ @Override public void addNotify() { super.addNotify(); // Updates the slider level in correspodance with the system volume // level. volumeChange(new VolumeChangeEvent( volumeControl, volumeControl.getVolume(), volumeControl.getMute())); // Starts the thread loop to update the volume, as long as the slider is // shown. if(!setVolumeThread.isAlive()) { setVolumeThread = new SetVolumeThread(volumeControl); setVolumeThread.start(); } } /** * Makes this Component undisplayable by destroying it native screen * resource. Stops the thread loop to change volume. */ @Override public void removeNotify() { super.removeNotify(); // Stops the thread loop to update the volume, since the slider is // not shown anymore. if(setVolumeThread.isAlive()) { setVolumeThread.end(); } } /** * Create a dedicate thread to set the volume. */ private class SetVolumeThread extends Thread { /** * A boolean set to true if the thread must continue to loop. */ private boolean run; /** * The VolumeControl that do the actual volume adjusting. */ private final VolumeControl volumeControl; /** * The volume wished by the UI. */ private float volume; /** * The volume currently set. */ private float lastVolumeSet; /** * Create a dedicate thread to set the volume. * * @param volumeControl The VolumeControl that do the actual volume * adjusting. */ public SetVolumeThread(final VolumeControl volumeControl) { super("VolumeControlSlider: VolumeControl.setVolume"); this.run = true; this.volumeControl = volumeControl; this.lastVolumeSet = volumeControl.getVolume(); this.volume = this.lastVolumeSet; } /** * Updates and sets the volume if changed. */ @Override public void run() { while(this.run) { synchronized(this) { // Wait if there is no update yet. if(volume == lastVolumeSet) { try { this.wait(); } catch(InterruptedException iex) { } } lastVolumeSet = volume; } // Set the volume to the volume control. volumeControl.setVolume(lastVolumeSet); } } /** * Sets a new volume value. * * @param newVolume The new volume to set. */ public void setVolume(float newVolume) { synchronized(this) { volume = newVolume; // If there is a change, then wake up the tread loop.. if(volume != lastVolumeSet) { this.notify(); } } } /** * Ends the thread loop. */ public void end() { synchronized(this) { this.run = false; this.notify(); } } } }