/* * 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.beans.*; import java.util.*; import javax.media.*; import javax.swing.*; import javax.swing.event.*; import org.jitsi.impl.neomedia.device.*; import org.jitsi.service.neomedia.*; /** * Implements ComboBoxModel for a specific DeviceConfiguration * so that the latter may be displayed and manipulated in the user interface as * a combo box. * * @author Lyubomir Marinov * @author Damian Minkov */ public class DeviceConfigurationComboBoxModel implements ComboBoxModel, ListModel, PropertyChangeListener { /** * Type of the model - audio. */ public static final int AUDIO = 1; /** * Audio Capture Device. */ public static final int AUDIO_CAPTURE = 3; /** * Audio device for notification sounds. */ public static final int AUDIO_NOTIFY = 5; /** * Audio playback device. */ public static final int AUDIO_PLAYBACK = 4; /** * Type of the model - video. */ public static final int VIDEO = 2; private AudioSystem[] audioSystems; /** * The current device configuration. */ private final DeviceConfiguration deviceConfiguration; /** * All the devices. */ private CaptureDevice[] devices; /** * The ListDataListeners registered with this instance. */ private final List listeners = new ArrayList(); /** * The type of the media for this combo. */ private final int type; /** * Creates device combobox model * @param parent the parent component * @param deviceConfiguration the current device configuration * @param type the device - audio/video */ public DeviceConfigurationComboBoxModel( DeviceConfiguration deviceConfiguration, int type) { if (deviceConfiguration == null) throw new IllegalArgumentException("deviceConfiguration"); if ((type != AUDIO) && (type != AUDIO_CAPTURE) && (type != AUDIO_NOTIFY) && (type != AUDIO_PLAYBACK) && (type != VIDEO)) throw new IllegalArgumentException("type"); this.deviceConfiguration = deviceConfiguration; this.type = type; if (type == AUDIO || type == AUDIO_CAPTURE || type == AUDIO_NOTIFY || type == AUDIO_PLAYBACK) { deviceConfiguration.addPropertyChangeListener(this); } } public void addListDataListener(ListDataListener listener) { if (listener == null) throw new IllegalArgumentException("listener"); if (!listeners.contains(listener)) listeners.add(listener); } /** * Change of the content. * @param index0 from index. * @param index1 to index. */ protected void fireContentsChanged(int index0, int index1) { ListDataListener[] listeners = this.listeners.toArray( new ListDataListener[this.listeners.size()]); ListDataEvent event = new ListDataEvent( this, ListDataEvent.CONTENTS_CHANGED, index0, index1); for (ListDataListener listener : listeners) listener.contentsChanged(event); } private AudioSystem[] getAudioSystems() { if (type != AUDIO) throw new IllegalStateException("type"); audioSystems = deviceConfiguration.getAvailableAudioSystems(); return audioSystems; } /** * Extracts the devices for the current type. * @return the devices. */ private CaptureDevice[] getDevices() { if (type == AUDIO) throw new IllegalStateException("type"); if (devices != null) return devices; AudioSystem audioSystem; List infos = null; switch (type) { case AUDIO_CAPTURE: audioSystem = deviceConfiguration.getAudioSystem(); infos = (audioSystem == null) ? null : audioSystem.getDevices(AudioSystem.DataFlow.CAPTURE); break; case AUDIO_NOTIFY: audioSystem = deviceConfiguration.getAudioSystem(); infos = (audioSystem == null) ? null : audioSystem.getDevices(AudioSystem.DataFlow.NOTIFY); break; case AUDIO_PLAYBACK: audioSystem = deviceConfiguration.getAudioSystem(); infos = (audioSystem == null) ? null : audioSystem.getDevices(AudioSystem.DataFlow.PLAYBACK); break; case VIDEO: infos = deviceConfiguration.getAvailableVideoCaptureDevices( MediaUseCase.CALL); break; default: throw new IllegalStateException("type"); } final int deviceCount = (infos == null) ? 0 : infos.size(); devices = new CaptureDevice[deviceCount + 1]; if (deviceCount > 0) { for (int i = 0; i < deviceCount; i++) devices[i] = new CaptureDevice(infos.get(i)); } devices[deviceCount] = new CaptureDevice(null); return devices; } public Object getElementAt(int index) { if (type == AUDIO) return getAudioSystems()[index]; else return getDevices()[index]; } /** * Extracts the devices selected by the configuration. * @return CaptureDevice selected */ private CaptureDevice getSelectedDevice() { AudioSystem audioSystem; CaptureDeviceInfo info; switch (type) { case AUDIO_CAPTURE: audioSystem = deviceConfiguration.getAudioSystem(); info = (audioSystem == null) ? null : audioSystem.getSelectedDevice(AudioSystem.DataFlow.CAPTURE); break; case AUDIO_NOTIFY: audioSystem = deviceConfiguration.getAudioSystem(); info = (audioSystem == null) ? null : audioSystem.getSelectedDevice(AudioSystem.DataFlow.NOTIFY); break; case AUDIO_PLAYBACK: audioSystem = deviceConfiguration.getAudioSystem(); info = (audioSystem == null) ? null : audioSystem.getSelectedDevice(AudioSystem.DataFlow.PLAYBACK); break; case VIDEO: info = deviceConfiguration.getVideoCaptureDevice(MediaUseCase.ANY); break; default: throw new IllegalStateException("type"); } for (CaptureDevice device : getDevices()) { if (device.equals(info)) return device; } return null; } public Object getSelectedItem() { if (type == AUDIO) return deviceConfiguration.getAudioSystem(); else return getSelectedDevice(); } public int getSize() { if (type == AUDIO) return getAudioSystems().length; else return getDevices().length; } /** * Notifies this instance about changes in the values of the properties of * {@link #deviceConfiguration} so that this instance keeps itself * up-to-date with respect to the list of devices. * * @param ev a PropertyChangeEvent which describes the name of the * property whose value has changed and the old and new values of that * property */ public void propertyChange(final PropertyChangeEvent ev) { if (DeviceConfiguration.PROP_AUDIO_SYSTEM_DEVICES.equals( ev.getPropertyName())) { if (SwingUtilities.isEventDispatchThread()) { audioSystems = null; devices = null; fireContentsChanged(0, getSize() - 1); } else { SwingUtilities.invokeLater( new Runnable() { public void run() { propertyChange(ev); } }); } } } public void removeListDataListener(ListDataListener listener) { if (listener == null) throw new IllegalArgumentException("listener"); listeners.remove(listener); } /** * Selects and saves the new choice. * @param device the device we choose. */ private void setSelectedDevice(CaptureDevice device) { // We cannot clear the selection of DeviceConfiguration. if (device == null) return; CaptureDevice selectedDevice = getSelectedDevice(); if (selectedDevice != device) { AudioSystem audioSystem; switch (type) { case AUDIO_CAPTURE: audioSystem = deviceConfiguration.getAudioSystem(); if (audioSystem != null) { audioSystem.setDevice( AudioSystem.DataFlow.CAPTURE, ((CaptureDeviceInfo2) device.info), true); } break; case AUDIO_NOTIFY: audioSystem = deviceConfiguration.getAudioSystem(); if (audioSystem != null) { audioSystem.setDevice( AudioSystem.DataFlow.NOTIFY, ((CaptureDeviceInfo2) device.info), true); } break; case AUDIO_PLAYBACK: audioSystem = deviceConfiguration.getAudioSystem(); if (audioSystem != null) { audioSystem.setDevice( AudioSystem.DataFlow.PLAYBACK, ((CaptureDeviceInfo2) device.info), true); } break; case VIDEO: deviceConfiguration.setVideoCaptureDevice(device.info, true); break; } fireContentsChanged(-1, -1); } } public void setSelectedItem(Object item) { if (type == AUDIO) { AudioSystem audioSystem = (AudioSystem) item; if(!audioSystem.equals(deviceConfiguration.getAudioSystem())) { deviceConfiguration.setAudioSystem(audioSystem, true); fireContentsChanged(-1, -1); } } else setSelectedDevice((CaptureDevice) item); } /** * Encapsulates a CaptureDeviceInfo for the purposes of its display * in the user interface. */ public static class CaptureDevice { /** * The encapsulated info. */ public final CaptureDeviceInfo info; /** * Creates the wrapper. * @param info the info object we wrap. */ public CaptureDevice(CaptureDeviceInfo info) { this.info = info; } /** * Determines whether the CaptureDeviceInfo encapsulated by * this instance is equal (by value) to a specific * CaptureDeviceInfo. * * @param cdi the CaptureDeviceInfo to be determined whether it * is equal (by value) to the CaptureDeviceInfo encapsulated by * this instance * @return true if the CaptureDeviceInfo encapsulated * by this instance is equal (by value) to the specified cdi; * otherwise, false */ public boolean equals(CaptureDeviceInfo cdi) { return (info == null) ? (cdi == null) : info.equals(cdi); } /** * Gets a human-readable String representation of this * instance. * * @return a String value which is a human-readable * representation of this instance */ @Override public String toString() { String s; if(info == null) { s = NeomediaActivator.getResources().getI18NString( "impl.media.configform.NO_DEVICE"); } else { s = info.getName(); if(info instanceof CaptureDeviceInfo2) { String transportType = ((CaptureDeviceInfo2) info).getTransportType(); if(transportType != null) s += " (" + transportType + ")"; } } return s; } } }