/*
* 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 extends CaptureDeviceInfo> 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;
}
}
}