Some portaudio fixes. Add to configuration panel option to select portaudio and the devices to use. Javasound left as default, as portaudio is not currently enabled (missing native binaries). Removed some old and unused jmf stuff like v4l, sun audio, directsound.

cusax-fix
Damian Minkov 16 years ago
parent 3932e0f779
commit b5ae6c1a91

@ -653,8 +653,10 @@
<sysproperty key="java.net.preferIPv6Addresses"
value="${java.net.preferIPv6Addresses}"/>
<!--sysproperty key="net.java.sip.communicator.SC_HOME_DIR_LOCATION"
value="${user.home}/schome"/-->
<sysproperty key="net.java.sip.communicator.SC_HOME_DIR_LOCATION"
value="${user.home}/schome"/>
<sysproperty key="net.java.sip.communicator.SC_HOME_DIR_NAME"
value="sc-2071"/>
<!-- Setting properties necessary for dependencies on native libs.-->
<sysproperty key="java.library.path"
@ -797,7 +799,7 @@
bundle-plugin-yahooaccregwizz,bundle-plugin-aimaccregwizz,
bundle-version,bundle-version-impl,bundle-shutdown-timeout,
bundle-growlnotification,bundle-swingnotification,bundle-sparkle,
bundle-audionotifier,bundle-plugin-branding,
bundle-plugin-branding,
bundle-osdependent,bundle-browserlauncher,bundle-gibberish,
bundle-gibberish-slick,bundle-plugin-gibberishaccregwizz,
bundle-plugin-call-history-form,
@ -976,6 +978,8 @@
prefix="net/java/sip/communicator/impl/media"/>
<zipfileset dir="${resources}/images/impl/media"
prefix="resources/images/impl/media"/>
<zipfileset dir="${dest}/net/java/sip/communicator/service/audionotifier"
prefix="net/java/sip/communicator/service/audionotifier"/>
<zipfileset src="${lib.win.noinst}/jmf.jar" prefix=""/>
<zipfileset src="${lib.win.noinst}/sound.jar" prefix=""/>
<zipfileset src="${lib.noinst}/jain-sdp.jar" prefix=""/>
@ -997,6 +1001,8 @@
prefix="net/java/sip/communicator/impl/media"/>
<zipfileset dir="${resources}/images/impl/media"
prefix="resources/images/impl/media"/>
<zipfileset dir="${dest}/net/java/sip/communicator/service/audionotifier"
prefix="net/java/sip/communicator/service/audionotifier"/>
<zipfileset src="${lib.lin.noinst}/jmf.jar" prefix=""/>
<zipfileset src="${lib.noinst}/jain-sdp.jar" prefix=""/>
<zipfileset src="${lib.noinst}/jspeex.jar" prefix=""/>
@ -1017,6 +1023,8 @@
prefix="net/java/sip/communicator/impl/media"/>
<zipfileset dir="${resources}/images/impl/media"
prefix="resources/images/impl/media"/>
<zipfileset dir="${dest}/net/java/sip/communicator/service/audionotifier"
prefix="net/java/sip/communicator/service/audionotifier"/>
<zipfileset src="${lib.mac.noinst}/jmf.jar" prefix=""/>
<zipfileset src="${lib.noinst}/jain-sdp.jar" prefix=""/>
<zipfileset src="${lib.noinst}/jspeex.jar" prefix=""/>

@ -130,7 +130,6 @@ felix.auto.start.60= \
reference:file:sc-bundles/callhistory.jar \
reference:file:sc-bundles/filehistory.jar \
reference:file:sc-bundles/metahistory.jar \
reference:file:sc-bundles/audionotifier.jar \
reference:file:sc-bundles/keybindings.jar \
reference:file:sc-bundles/notification.jar

@ -791,7 +791,10 @@ plugin.profiler.PLUGIN_NAME=Profiler4j
impl.media.configform.NO_DEVICE=<No Device>
impl.media.configform.TITLE=Media
impl.media.configform.AUDIO=&Audio:
impl.media.configform.AUDIO=&Audio System:
impl.media.configform.AUDIO_IN=Audio &In:
impl.media.configform.AUDIO_OUT=Audio &Out:
impl.media.configform.AUDIO_NOTIFY=&Notifications:
impl.media.configform.DOWN=&Down
impl.media.configform.ENCODINGS=&Encodings:
impl.media.configform.NO_PREVIEW=Preview

@ -166,11 +166,70 @@ Java_net_java_sip_communicator_impl_media_protocol_portaudio_PortAudio_Pa_1Write
(*env)->ReleaseByteArrayElements(env, buffer, data, 0);
if (paNoError != errorCode)
if (paNoError != errorCode && errorCode != paOutputUnderflowed)
PortAudio_throwException(env, errorCode);
/*
if(errorCode == paOutputUnderflowed)
{
printf("OutputUnderflowed\n");fflush(stdout);
}
*/
}
}
JNIEXPORT void JNICALL
Java_net_java_sip_communicator_impl_media_protocol_portaudio_PortAudio_Pa_1ReadStream
(JNIEnv *env, jclass clazz, jlong stream, jbyteArray buffer, jlong frames)
{
jbyte* data = (*env)->GetByteArrayElements(env, buffer, NULL);
PaError errorCode = Pa_ReadStream(
((PortAudioStream *) stream)->stream,
data,
frames);
(*env)->ReleaseByteArrayElements(env, buffer, data, 0);
if (paNoError != errorCode && errorCode != paInputOverflowed)
PortAudio_throwException(env, errorCode);
}
JNIEXPORT jlong JNICALL
Java_net_java_sip_communicator_impl_media_protocol_portaudio_PortAudio_Pa_1GetStreamReadAvailable
(JNIEnv *env, jclass clazz, jlong stream)
{
return Pa_GetStreamReadAvailable(((PortAudioStream *) stream)->stream);
}
JNIEXPORT jlong JNICALL
Java_net_java_sip_communicator_impl_media_protocol_portaudio_PortAudio_Pa_1GetStreamWriteAvailable
(JNIEnv *env, jclass clazz, jlong stream)
{
return Pa_GetStreamWriteAvailable(((PortAudioStream *) stream)->stream);
}
JNIEXPORT jint JNICALL
Java_net_java_sip_communicator_impl_media_protocol_portaudio_PortAudio_Pa_1GetSampleSize
(JNIEnv *env, jclass clazz, jlong format)
{
return Pa_GetSampleSize(format);
}
JNIEXPORT jboolean JNICALL
Java_net_java_sip_communicator_impl_media_protocol_portaudio_PortAudio_Pa_1IsFormatSupported
(JNIEnv *env, jclass clazz,
jlong inputParameters,
jlong outputParameters,
jdouble sampleRate)
{
if(Pa_IsFormatSupported(
(PaStreamParameters *) inputParameters,
(PaStreamParameters *) outputParameters,
sampleRate) == paFormatIsSupported)
return JNI_TRUE;
else
return JNI_FALSE;
}
JNIEXPORT jint JNICALL
Java_net_java_sip_communicator_impl_media_protocol_portaudio_PortAudio_PaDeviceInfo_1getMaxInputChannels(
JNIEnv *env, jclass clazz, jlong deviceInfo)
@ -195,6 +254,13 @@ Java_net_java_sip_communicator_impl_media_protocol_portaudio_PortAudio_PaDeviceI
return name ? (*env)->NewStringUTF(env, name) : NULL;
}
JNIEXPORT jdouble JNICALL
Java_net_java_sip_communicator_impl_media_protocol_portaudio_PortAudio_PaDeviceInfo_1getDefaultSampleRate
(JNIEnv *env, jclass clazz, jlong deviceInfo)
{
return ((PaDeviceInfo *) deviceInfo)->defaultSampleRate;
}
JNIEXPORT jlong JNICALL
Java_net_java_sip_communicator_impl_media_protocol_portaudio_PortAudio_PaStreamParameters_1new(
JNIEnv *env,
@ -211,7 +277,7 @@ Java_net_java_sip_communicator_impl_media_protocol_portaudio_PortAudio_PaStreamP
streamParameters->device = deviceIndex;
streamParameters->channelCount = channelCount;
streamParameters->sampleFormat = sampleFormat;
streamParameters->suggestedLatency = 0;
streamParameters->suggestedLatency = 0,4;
streamParameters->hostApiSpecificStreamInfo = NULL;
}
return (jlong) streamParameters;
@ -319,7 +385,7 @@ PortAudioStream_callback(
return paAbort;
}
return
return
(*env)
->CallIntMethod(
env,

@ -23,6 +23,45 @@ JNIEXPORT void JNICALL Java_net_java_sip_communicator_impl_media_protocol_portau
JNIEXPORT void JNICALL Java_net_java_sip_communicator_impl_media_protocol_portaudio_PortAudio_Pa_1WriteStream
(JNIEnv *, jclass, jlong, jbyteArray, jlong);
/*
* Class: net_java_sip_communicator_impl_media_protocol_portaudio_PortAudio
* Method: Pa_ReadStream
* Signature: (J[BJ)V
*/
JNIEXPORT void JNICALL Java_net_java_sip_communicator_impl_media_protocol_portaudio_PortAudio_Pa_1ReadStream
(JNIEnv *, jclass, jlong, jbyteArray, jlong);
/*
* Class: net_java_sip_communicator_impl_media_protocol_portaudio_PortAudio
* Method: Pa_GetStreamReadAvailable
* Signature: (J)J
*/
JNIEXPORT jlong JNICALL Java_net_java_sip_communicator_impl_media_protocol_portaudio_PortAudio_Pa_1GetStreamReadAvailable
(JNIEnv *, jclass, jlong);
/*
* Class: net_java_sip_communicator_impl_media_protocol_portaudio_PortAudio
* Method: Pa_GetStreamWriteAvailable
* Signature: (J)J
*/
JNIEXPORT jlong JNICALL Java_net_java_sip_communicator_impl_media_protocol_portaudio_PortAudio_Pa_1GetStreamWriteAvailable
(JNIEnv *, jclass, jlong);
/*
* Class: net_java_sip_communicator_impl_media_protocol_portaudio_PortAudio
* Method: Pa_GetSampleSize
* Signature: (J)I
*/
JNIEXPORT jint JNICALL Java_net_java_sip_communicator_impl_media_protocol_portaudio_PortAudio_Pa_1GetSampleSize
(JNIEnv *, jclass, jlong);
/*
* Class: net_java_sip_communicator_impl_media_protocol_portaudio_PortAudio
* Method: Pa_IsFormatSupported
* Signature: (JJD)Z
*/
JNIEXPORT jboolean JNICALL Java_net_java_sip_communicator_impl_media_protocol_portaudio_PortAudio_Pa_1IsFormatSupported
(JNIEnv *, jclass, jlong, jlong, jdouble);
/*
* Class: net_java_sip_communicator_impl_media_protocol_portaudio_PortAudio
@ -96,6 +135,14 @@ JNIEXPORT jint JNICALL Java_net_java_sip_communicator_impl_media_protocol_portau
JNIEXPORT jstring JNICALL Java_net_java_sip_communicator_impl_media_protocol_portaudio_PortAudio_PaDeviceInfo_1getName
(JNIEnv *, jclass, jlong);
/*
* Class: net_java_sip_communicator_impl_media_protocol_portaudio_PortAudio
* Method: PaDeviceInfo_getDefaultSampleRate
* Signature: (J)D
*/
JNIEXPORT jdouble JNICALL Java_net_java_sip_communicator_impl_media_protocol_portaudio_PortAudio_PaDeviceInfo_1getDefaultSampleRate
(JNIEnv *, jclass, jlong);
/*
* Class: net_java_sip_communicator_impl_media_protocol_portaudio_PortAudio
* Method: PaStreamParameters_new

@ -20,15 +20,31 @@
public class DeviceConfigurationComboBoxModel
implements ComboBoxModel
{
/**
* Encapsulates CaptureDeviceInfo
*/
public static class CaptureDevice
{
/**
* Compares two CaptureDeviceInfo
* @param a
* @param b
* @return whether a is equal to b
*/
public static boolean equals(CaptureDeviceInfo a, CaptureDeviceInfo b)
{
return (a == null) ? (b == null) : a.equals(b);
}
/**
* The encapsulated info.
*/
public final CaptureDeviceInfo info;
/**
* Creates the wrapper.
* @param info the info object we wrap.
*/
public CaptureDevice(CaptureDeviceInfo info)
{
this.info = info;
@ -43,10 +59,31 @@ public String toString()
}
}
/**
* Type of the model - audio.
*/
public static final int AUDIO = 1;
/**
* Type of the model - video.
*/
public static final int VIDEO = 2;
/**
* Audio Capture Device.
*/
public static final int AUDIO_CAPTURE = 3;
/**
* Audio playback device.
*/
public static final int AUDIO_PLAYBACK = 4;
/**
* Audio device for notification sounds.
*/
public static final int AUDIO_NOTIFY = 5;
private final DeviceConfiguration deviceConfiguration;
private CaptureDevice[] devices;
@ -56,12 +93,19 @@ public String toString()
private final int type;
/**
* Creates device combobx model
* @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 != VIDEO))
if ((type != AUDIO_CAPTURE) && (type != AUDIO_NOTIFY) &&
(type != AUDIO_PLAYBACK) &&
(type != AUDIO) && (type != VIDEO))
throw new IllegalArgumentException("type");
this.deviceConfiguration = deviceConfiguration;
@ -77,6 +121,11 @@ public void addListDataListener(ListDataListener 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 =
@ -101,12 +150,19 @@ private CaptureDevice[] getDevices()
if (devices != null)
return devices;
DeviceConfiguration deviceConfiguration = getDeviceConfiguration();
CaptureDeviceInfo[] infos;
switch (type)
{
case AUDIO:
infos = deviceConfiguration.getAvailableAudioCaptureDevices();
case AUDIO_CAPTURE:
// supply only portaudio devices, as we are in case specifying
// capture devices available only for portaudio
infos = deviceConfiguration.getAvailableAudioCaptureDevices(
DeviceConfiguration.AUDIO_SYSTEM_PORTAUDIO);
break;
case AUDIO_NOTIFY:
case AUDIO_PLAYBACK:
infos = deviceConfiguration.getAvailableAudioPlaybackDevices();
break;
case VIDEO:
infos = deviceConfiguration.getAvailableVideoCaptureDevices();
@ -125,20 +181,20 @@ private CaptureDevice[] getDevices()
return devices;
}
public Object getElementAt(int index)
{
return getDevices()[index];
}
private CaptureDevice getSelectedDevice()
{
DeviceConfiguration deviceConfiguration = getDeviceConfiguration();
CaptureDeviceInfo info;
switch (type)
{
case AUDIO:
case AUDIO_CAPTURE:
info = deviceConfiguration.getAudioCaptureDevice();
break;
case AUDIO_NOTIFY:
info = deviceConfiguration.getAudioNotifyDevice();
break;
case AUDIO_PLAYBACK:
info = deviceConfiguration.getAudioPlaybackDevice();
break;
case VIDEO:
info = deviceConfiguration.getVideoCaptureDevice();
break;
@ -154,14 +210,28 @@ private CaptureDevice getSelectedDevice()
return null;
}
public Object getElementAt(int index)
{
if(type == AUDIO)
return deviceConfiguration.getAvailableAudioSystems()[index];
else
return getDevices()[index];
}
public Object getSelectedItem()
{
return getSelectedDevice();
if(type == AUDIO)
return deviceConfiguration.getAudioSystem();
else
return getSelectedDevice();
}
public int getSize()
{
return getDevices().length;
if(type == AUDIO)
return deviceConfiguration.getAvailableAudioSystems().length;
else
return getDevices().length;
}
public void removeListDataListener(ListDataListener listener)
@ -184,9 +254,15 @@ private void setSelectedDevice(CaptureDevice device)
DeviceConfiguration deviceConfiguration = getDeviceConfiguration();
switch (type)
{
case AUDIO:
case AUDIO_CAPTURE:
deviceConfiguration.setAudioCaptureDevice(device.info);
break;
case AUDIO_NOTIFY:
deviceConfiguration.setAudioNotifyDevice(device.info);
break;
case AUDIO_PLAYBACK:
deviceConfiguration.setAudioPlaybackDevice(device.info);
break;
case VIDEO:
deviceConfiguration.setVideoCaptureDevice(device.info);
break;
@ -198,6 +274,17 @@ private void setSelectedDevice(CaptureDevice device)
public void setSelectedItem(Object item)
{
setSelectedDevice((CaptureDevice) item);
if(type == AUDIO)
{
String systemName = (String)item;
if(!systemName.equals(deviceConfiguration.getAudioSystem()))
{
deviceConfiguration.setAudioSystem(systemName, null);
fireContentsChanged(-1, -1);
}
}
else
setSelectedDevice((CaptureDevice) item);
}
}

@ -16,6 +16,7 @@
import javax.swing.event.*;
import javax.swing.table.*;
import net.java.sip.communicator.impl.media.device.*;
import net.java.sip.communicator.service.media.*;
import net.java.sip.communicator.service.resources.*;
import net.java.sip.communicator.util.*;
@ -66,6 +67,9 @@ private static MediaServiceImpl getMediaService()
*/
private Player videoPlayerInPreview;
/**
* Creates the panel.
*/
public MediaConfigurationPanel()
{
super(new GridLayout(0, 1, HGAP, VGAP));
@ -90,12 +94,71 @@ private void controllerUpdateForPreview(ControllerEvent event,
}
}
private void createPortAudioControls(Container portAudioPanel)
{
portAudioPanel.add(new JLabel(getLabelText(
DeviceConfigurationComboBoxModel.AUDIO_CAPTURE)));
JComboBox captureCombo = new JComboBox();
captureCombo.setEditable(false);
captureCombo.setModel(
new DeviceConfigurationComboBoxModel(
mediaService.getDeviceConfiguration(),
DeviceConfigurationComboBoxModel.AUDIO_CAPTURE));
portAudioPanel.add(captureCombo);
portAudioPanel.add(new JLabel(getLabelText(
DeviceConfigurationComboBoxModel.AUDIO_PLAYBACK)));
JComboBox playbackCombo = new JComboBox();
playbackCombo.setEditable(false);
playbackCombo.setModel(
new DeviceConfigurationComboBoxModel(
mediaService.getDeviceConfiguration(),
DeviceConfigurationComboBoxModel.AUDIO_PLAYBACK));
portAudioPanel.add(playbackCombo);
portAudioPanel.add(new JLabel(getLabelText(
DeviceConfigurationComboBoxModel.AUDIO_NOTIFY)));
JComboBox notifyCombo = new JComboBox();
notifyCombo.setEditable(false);
notifyCombo.setModel(
new DeviceConfigurationComboBoxModel(
mediaService.getDeviceConfiguration(),
DeviceConfigurationComboBoxModel.AUDIO_NOTIFY));
portAudioPanel.add(notifyCombo);
}
private Component createControls(int type)
{
final JComboBox comboBox = new JComboBox();
comboBox.setEditable(false);
comboBox.setModel(new DeviceConfigurationComboBoxModel(mediaService
.getDeviceConfiguration(), type));
final Container portAudioPanel =
new TransparentPanel(new GridLayout(3, 2, HGAP, VGAP));
comboBox.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent e)
{
if(e.getStateChange() == ItemEvent.SELECTED)
{
if(e.getItem().equals(
DeviceConfiguration.AUDIO_SYSTEM_PORTAUDIO))
{
createPortAudioControls(portAudioPanel);
}
else
{
portAudioPanel.removeAll();
revalidate();
repaint();
}
}
}
});
if(comboBox.getSelectedItem().equals(
DeviceConfiguration.AUDIO_SYSTEM_PORTAUDIO))
createPortAudioControls(portAudioPanel);
JLabel label = new JLabel(getLabelText(type));
label.setDisplayedMnemonic(getDisplayedMnemonic(type));
@ -111,6 +174,13 @@ private Component createControls(int type)
firstConstraints.gridx = 1;
firstConstraints.weightx = 1;
firstContainer.add(comboBox, firstConstraints);
firstConstraints.gridx = 0;
firstConstraints.gridy = 1;
firstConstraints.weightx = 1;
firstConstraints.gridwidth = 2;
firstConstraints.insets = new Insets(VGAP, 0, 0, 0);
firstContainer.add(portAudioPanel, firstConstraints);
Container secondContainer =
new TransparentPanel(new GridLayout(1, 0, HGAP, VGAP));
@ -392,6 +462,15 @@ private String getLabelText(int type)
case DeviceConfigurationComboBoxModel.AUDIO:
return MediaActivator.getResources().getI18NString(
"impl.media.configform.AUDIO");
case DeviceConfigurationComboBoxModel.AUDIO_CAPTURE:
return MediaActivator.getResources().getI18NString(
"impl.media.configform.AUDIO_IN");
case DeviceConfigurationComboBoxModel.AUDIO_NOTIFY:
return MediaActivator.getResources().getI18NString(
"impl.media.configform.AUDIO_NOTIFY");
case DeviceConfigurationComboBoxModel.AUDIO_PLAYBACK:
return MediaActivator.getResources().getI18NString(
"impl.media.configform.AUDIO_OUT");
case DeviceConfigurationComboBoxModel.VIDEO:
return MediaActivator.getResources().getI18NString(
"impl.media.configform.VIDEO");

@ -175,13 +175,18 @@ public void initialize( DeviceConfiguration deviceConfig,
{
public void propertyChange(PropertyChangeEvent evt)
{
try
if(evt.getPropertyName().equals(
DeviceConfiguration.AUDIO_CAPTURE_DEVICE))
{
initCaptureDevices();
}
catch (MediaException e)
{
logger.error("Cannot init capture devices after change", e);
try
{
initCaptureDevices();
}
catch (MediaException e)
{
logger.error(
"Cannot init capture devices after change", e);
}
}
}
});

@ -14,6 +14,8 @@
import net.java.sip.communicator.impl.media.codec.*;
import net.java.sip.communicator.impl.media.device.*;
import net.java.sip.communicator.impl.media.notify.*;
import net.java.sip.communicator.service.audionotifier.*;
import net.java.sip.communicator.service.media.*;
import net.java.sip.communicator.service.media.event.*;
import net.java.sip.communicator.service.protocol.*;
@ -409,6 +411,9 @@ public void run()
defaultMediaControl.
initialize(deviceConfiguration, encodingConfiguration);
sdpFactory = SdpFactory.getInstance();
registerAudioNotifyService();
isStarted = true;
}
catch (Throwable ex)
@ -423,6 +428,27 @@ public void run()
}
}
private void registerAudioNotifyService()
{
//Create the audio notifier service
AudioNotifierServiceImpl audioNotifier =
new AudioNotifierServiceImpl(deviceConfiguration);
audioNotifier.setMute(
!MediaActivator.getConfigurationService()
.getBoolean(
"net.java.sip.communicator.impl.sound.isSoundEnabled",
true));
MediaActivator.getBundleContext()
.registerService(
AudioNotifierService.class.getName(),
audioNotifier,
null);
logger.info("Audio Notifier Service ...[REGISTERED]");
}
/**
* A utility method that would block until the media service has been
* started or, in case it already is started, return immediately.

@ -31,11 +31,25 @@ public class DeviceConfiguration
/**
* The name of the <code>DeviceConfiguration</code> property which
* represents the device used by <code>DeviceConfiguration</code> for video
* represents the device used by <code>DeviceConfiguration</code> for audio
* capture.
*/
public static final String AUDIO_CAPTURE_DEVICE = "AUDIO_CAPTURE_DEVICE";
/**
* The name of the <code>DeviceConfiguration</code> property which
* represents the device used by <code>DeviceConfiguration</code> for audio
* playback.
*/
public static final String AUDIO_PLAYBACK_DEVICE = "AUDIO_PLAYBACK_DEVICE";
/**
* The name of the <code>DeviceConfiguration</code> property which
* represents the device used by <code>DeviceConfiguration</code> for audio
* notify.
*/
public static final String AUDIO_NOTIFY_DEVICE = "AUDIO_NOTIFY_DEVICE";
/**
* The name of the <code>DeviceConfiguration</code> property which
* represents the device used by <code>DeviceConfiguration</code> for video
@ -43,9 +57,30 @@ public class DeviceConfiguration
*/
public static final String VIDEO_CAPTURE_DEVICE = "VIDEO_CAPTURE_DEVICE";
/**
* When audio is disabled the selected audio system is with name None.
*/
public static final String AUDIO_SYSTEM_NONE = "None";
/**
* JavaSound sound system.
*/
public static final String AUDIO_SYSTEM_JAVASOUND = "JavaSound";
/**
* PortAudio sound system.
*/
public static final String AUDIO_SYSTEM_PORTAUDIO = "PortAudio";
private static final String PROP_AUDIO_DEVICE =
"net.java.sip.communicator.impl.media.audiodev";
private static final String PROP_AUDIO_PLAYBACK_DEVICE =
"net.java.sip.communicator.impl.media.audio.playbackdev";
private static final String PROP_AUDIO_NOTIFY_DEVICE =
"net.java.sip.communicator.impl.media.audio.notifydev";
private static final String PROP_AUDIO_DEVICE_IS_DISABLED =
"net.java.sip.communicator.impl.media.audiodevIsDisabled";
@ -65,11 +100,19 @@ public class DeviceConfiguration
*/
private CaptureDeviceInfo audioCaptureDevice = null;
private CaptureDeviceInfo audioPlaybackDevice = null;
private CaptureDeviceInfo audioNotifyDevice = null;
/**
* The device that we'll be using for video capture.
*/
private CaptureDeviceInfo videoCaptureDevice;
private static Vector<String> audioSystems = new Vector<String>();
private String audioSystem = null;
/**
* Default constructor.
*/
@ -109,11 +152,15 @@ private void extractConfiguredCaptureDevices()
CaptureDeviceInfo[] audioCaptureDevices =
getAvailableAudioCaptureDevices();
if (config.getBoolean(PROP_AUDIO_DEVICE_IS_DISABLED, false))
{
audioCaptureDevice = null;
audioSystem = AUDIO_SYSTEM_NONE;
}
else if (audioCaptureDevices.length < 1)
{
logger.warn("No Audio Device was found.");
audioCaptureDevice = null;
audioSystem = AUDIO_SYSTEM_NONE;
}
else
{
@ -123,17 +170,33 @@ else if (audioCaptureDevices.length < 1)
String audioDevName = config.getString(PROP_AUDIO_DEVICE);
if(audioDevName == null)
audioCaptureDevice = audioCaptureDevices[0];
{
// the default behaviour if nothing set is to use javasound
// this will also choose the capture device
setAudioSystem(AUDIO_SYSTEM_JAVASOUND, null);
}
else
{
for (CaptureDeviceInfo captureDeviceInfo : audioCaptureDevices)
{
if (audioDevName.equals(captureDeviceInfo.getName()))
{
audioCaptureDevice = captureDeviceInfo;
setAudioSystem(getAudioSystem(captureDeviceInfo),
captureDeviceInfo);
break;
}
}
if(getAudioSystem() == null)
{
logger.warn("Computer sound config changed or " +
"there is a problem since last config was saved, " +
"will back to default javasound");
setAudioPlaybackDevice(null);
setAudioNotifyDevice(null);
setAudioCaptureDevice(null);
setAudioSystem(AUDIO_SYSTEM_JAVASOUND, null);
}
}
if (audioCaptureDevice != null)
logger.info("Found " + audioCaptureDevice.getName()
@ -221,6 +284,56 @@ public CaptureDeviceInfo[] getAvailableAudioCaptureDevices()
return audioCaptureDevices.toArray(NO_CAPTURE_DEVICES);
}
/**
* Gets the list of audio capture devices which are available through this
* <code>DeviceConfiguration</code>, amongst which is
* {@link #getAudioCaptureDevice()} and represent acceptable values
* for {@link #setAudioCaptureDevice(CaptureDeviceInfo)}
*
* @param soundSystem
* filter capture devices only from the supplied audio system.
*
* @return an array of <code>CaptureDeviceInfo</code> describing the audio
* capture devices available through this
* <code>DeviceConfiguration</code>
*/
public CaptureDeviceInfo[] getAvailableAudioCaptureDevices(String soundSystem)
{
String protocol = null;
if(soundSystem.equals(AUDIO_SYSTEM_JAVASOUND))
protocol = "javasound";
else if(soundSystem.equals(AUDIO_SYSTEM_PORTAUDIO))
protocol = "portaudio";
Vector<CaptureDeviceInfo> res = new Vector<CaptureDeviceInfo>();
if(protocol != null)
{
CaptureDeviceInfo[] all = getAvailableAudioCaptureDevices();
for(int i = 0; i < all.length; i++)
{
CaptureDeviceInfo cDeviceInfo = all[i];
if(cDeviceInfo.getLocator().getProtocol().equals(protocol))
{
res.add(cDeviceInfo);
}
}
}
return res.toArray(NO_CAPTURE_DEVICES);
}
/**
* Lists all the playback devices. These are only portaudio devices
* as we can only set particular device for playback when using portaudio.
*
* @return the devices that can be used for playback.
*/
public CaptureDeviceInfo[] getAvailableAudioPlaybackDevices()
{
return PortAudioAuto.playbackDevices;
}
/**
* Gets the list of video capture devices which are available through this
* <code>DeviceConfiguration</code>, amongst which is
@ -300,11 +413,14 @@ public void setAudioCaptureDevice(CaptureDeviceInfo device)
ConfigurationService config =
MediaActivator.getConfigurationService();
config.setProperty(PROP_AUDIO_DEVICE_IS_DISABLED,
audioCaptureDevice == null);
if (audioCaptureDevice != null)
{
config.setProperty(PROP_AUDIO_DEVICE, audioCaptureDevice
.getName());
}
else
config.setProperty(PROP_AUDIO_DEVICE, null);
firePropertyChange(AUDIO_CAPTURE_DEVICE, oldDevice, device);
}
@ -329,4 +445,327 @@ public boolean isVideoCaptureSupported()
{
return this.videoCaptureDevice != null;
}
/**
* Return the installed Audio Systems.
* @return the audio systems names.
*/
public String[] getAvailableAudioSystems()
{
return audioSystems.toArray(new String[0]);
}
/**
* Adds audio system.
* @param audioSystemName the name of the audio system.
*/
public static void addAudioSystem(String audioSystemName)
{
audioSystems.add(audioSystemName);
}
/**
* The current selected audio system.
* @return the name of the current audio system.
*/
public String getAudioSystem()
{
return audioSystem;
}
private String getAudioSystem(CaptureDeviceInfo cdi)
{
String res = null;
// Here we iterate over the available audio systems
// to be sure that the audio system
// is available and enabled on the system we are running on
if(cdi.getLocator().getProtocol().equals("javasound"))
{
Iterator<String> iter = audioSystems.iterator();
while (iter.hasNext())
{
String asName = iter.next();
if(asName.equals(AUDIO_SYSTEM_JAVASOUND))
res = asName;
}
}
else if(cdi.getLocator().getProtocol().equals("portaudio"))
{
Iterator<String> iter = audioSystems.iterator();
while (iter.hasNext())
{
String asName = iter.next();
if(asName.equals(AUDIO_SYSTEM_PORTAUDIO))
res = asName;
}
}
if(res == null)
res = AUDIO_SYSTEM_NONE;
return res;
}
/**
* Changes the current audio system.
* When javasound is selected we also change the capture device.
*
* @param name the name of the audio system.
* @param captureDevice the selected capture device, if is null we will
* choose a default one. Param used when first time initing and
* extracting config.
*/
public void setAudioSystem(String name, CaptureDeviceInfo captureDevice)
{
ConfigurationService config = MediaActivator.getConfigurationService();
audioSystem = name;
if(name.equals(AUDIO_SYSTEM_NONE))
{
setAudioCaptureDevice(null);
setAudioNotifyDevice(null);
setAudioPlaybackDevice(null);
}
else if(name.equals(AUDIO_SYSTEM_JAVASOUND))
{
setAudioNotifyDevice(null);
setAudioPlaybackDevice(null);
// as there is only one device for javasound
// lets search for it
if(captureDevice != null)
setAudioCaptureDevice(captureDevice);
else
{
CaptureDeviceInfo[] audioCaptureDevices =
getAvailableAudioCaptureDevices();
for (CaptureDeviceInfo captureDeviceInfo : audioCaptureDevices)
{
if(captureDeviceInfo.getLocator().getProtocol().
equals("javasound"))
{
setAudioCaptureDevice(captureDeviceInfo);
break;
}
}
}
// if we have inited the audiocaptureDevice, it means javasound is
// available and everything is ok
if (audioCaptureDevice != null)
{
removePortAudioRenderer();
initJavaSoundRenderer();
}
}
else if(name.equals(AUDIO_SYSTEM_PORTAUDIO))
{
// changed to portaudio, so lets clear current device selection
// as we must select them
// if this is first time call devices will be already null
// and nothing will happen
setAudioCaptureDevice(null);
setAudioNotifyDevice(null);
setAudioPlaybackDevice(null);
// we don't save anything cause it will be saved
// when the devices are stored
// if nothing is set we consider it as not configured
// so when we restart we will end up with default config
// till restart will use latest config
// capture device is not null when we are called for the
// first time, we will also extract playback devices here
if(captureDevice != null)
{
setAudioCaptureDevice(captureDevice);
String audioDevName = config.getString(PROP_AUDIO_NOTIFY_DEVICE);
if(audioDevName != null)
{
for (CaptureDeviceInfo captureDeviceInfo :
PortAudioAuto.playbackDevices)
{
if (audioDevName.equals(captureDeviceInfo.getName()))
{
this.audioNotifyDevice = captureDeviceInfo;
break;
}
}
}
audioDevName = config.getString(PROP_AUDIO_PLAYBACK_DEVICE);
if(audioDevName != null)
{
for (CaptureDeviceInfo captureDeviceInfo :
PortAudioAuto.playbackDevices)
{
if (audioDevName.equals(captureDeviceInfo.getName()))
{
this.audioPlaybackDevice = captureDeviceInfo;
setDeviceToRenderer(audioPlaybackDevice);
removeJavaSoundRenderer();
break;
}
}
}
}
// return here to prevent clearing the last config that was saved
return;
}
else
{
// not expected behaviour
logger.error("Unknown audio system! Name:" + name);
audioSystem = null;
}
config.setProperty(PROP_AUDIO_DEVICE_IS_DISABLED,
audioCaptureDevice == null);
}
/**
* Installs the PortAudio Renderer
*/
protected static void initPortAudioRenderer()
{
PlugInManager.addPlugIn(
"net.java.sip.communicator.impl.media.renderer.audio.PortAudioRenderer",
net.java.sip.communicator.impl.media.renderer.audio.
PortAudioRenderer.supportedInputFormats,
null,
PlugInManager.RENDERER);
}
private void removeJavaSoundRenderer()
{
PlugInManager.removePlugIn(
"com.sun.media.renderer.audio.JavaSoundRenderer",
PlugInManager.RENDERER);
}
private void removePortAudioRenderer()
{
PlugInManager.removePlugIn(
"net.java.sip.communicator.impl.media.renderer.audio.PortAudioRenderer",
PlugInManager.RENDERER);
}
private void initJavaSoundRenderer()
{
try
{
PlugInManager.addPlugIn(
"com.sun.media.renderer.audio.JavaSoundRenderer",
new com.sun.media.renderer.audio.JavaSoundRenderer()
.getSupportedInputFormats(),
null,
PlugInManager.RENDERER);
}
catch (Exception e)
{
// if class is missing
logger.error("Problem init javasound renderer", e);
}
}
private void setDeviceToRenderer(CaptureDeviceInfo devInfo)
{
// no need to change device to renderer it will not be used anyway
if(devInfo == null)
return;
try
{
net.java.sip.communicator.impl.media.renderer.audio.
PortAudioRenderer.setDevice(devInfo.getLocator());
}
catch (Exception e)
{
logger.error("error setting device to renderer", e);
}
}
/**
* @return the audioPlaybackDevice
*/
public CaptureDeviceInfo getAudioPlaybackDevice()
{
return audioPlaybackDevice;
}
/**
* @return the audioNotifyDevice
*/
public CaptureDeviceInfo getAudioNotifyDevice()
{
return audioNotifyDevice;
}
/**
* @param audioPlaybackDevice the audioPlaybackDevice to set
*/
public void setAudioPlaybackDevice(CaptureDeviceInfo audioPlaybackDevice)
{
if(this.audioPlaybackDevice != audioPlaybackDevice)
{
CaptureDeviceInfo oldDev = this.audioPlaybackDevice;
this.audioPlaybackDevice = audioPlaybackDevice;
setDeviceToRenderer(audioPlaybackDevice);
// we changed playback device, so we are using portaudio
// lets use it, remove javasound renderer to be sure
// its not used anymore and install the portaudio one
removeJavaSoundRenderer();
initPortAudioRenderer();
ConfigurationService config =
MediaActivator.getConfigurationService();
if (audioPlaybackDevice != null)
{
config.setProperty(PROP_AUDIO_PLAYBACK_DEVICE,
audioPlaybackDevice.getName());
config.setProperty(PROP_AUDIO_DEVICE_IS_DISABLED, false);
}
else
config.setProperty(PROP_AUDIO_PLAYBACK_DEVICE, null);
firePropertyChange(AUDIO_PLAYBACK_DEVICE,
oldDev, audioPlaybackDevice);
}
}
/**
* @param audioNotifyDevice the audioNotifyDevice to set
*/
public void setAudioNotifyDevice(CaptureDeviceInfo audioNotifyDevice)
{
if(this.audioNotifyDevice != audioNotifyDevice)
{
CaptureDeviceInfo oldDev = this.audioNotifyDevice;
this.audioNotifyDevice = audioNotifyDevice;
ConfigurationService config =
MediaActivator.getConfigurationService();
if (audioNotifyDevice != null)
{
config.setProperty(PROP_AUDIO_NOTIFY_DEVICE,
audioNotifyDevice.getName());
// atleast notify or playback must be set to consider
// portaudio for enabled
config.setProperty(PROP_AUDIO_DEVICE_IS_DISABLED, false);
}
else
config.setProperty(PROP_AUDIO_NOTIFY_DEVICE, null);
firePropertyChange(AUDIO_NOTIFY_DEVICE,
oldDev, audioNotifyDevice);
}
}
}

@ -1,111 +0,0 @@
/*
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*
* File based on:
* @(#)DirectSoundAuto.java 1.3 01/03/13
* Copyright (c) 1999-2001 Sun Microsystems, Inc. All Rights Reserved.
*/
package net.java.sip.communicator.impl.media.device;
import java.util.*;
import javax.media.*;
import javax.media.format.*;
import net.java.sip.communicator.util.*;
public class DirectSoundAuto {
private static final Logger logger = Logger.getLogger(DirectSoundAuto.class);
private static final String detectClass = "com.sun.media.protocol.dsound.DSound";
CaptureDeviceInfo[] devices = null;
public static void main(String[] args) {
new DirectSoundAuto();
System.exit(0);
}
private boolean supports(AudioFormat af) {
try {
com.sun.media.protocol.dsound.DSound ds;
ds = new com.sun.media.protocol.dsound.DSound(af, 1024);
ds.open();
ds.close();
} catch (Exception e) {
logger.error(e);
return false;
}
return true;
}
@SuppressWarnings("unchecked") //legacy JMF code.
public DirectSoundAuto() {
boolean supported = false;
// instance JavaSoundDetector to check is javasound's capture is availabe
try {
Class.forName(detectClass);
supported = true;
} catch (Throwable t) {
supported = false;
// t.printStackTrace();
}
logger.info("DirectSound Capture Supported = " + supported);
if (supported) {
// It's there, start to register JavaSound with CaptureDeviceManager
Vector<CaptureDeviceInfo> devices
= (Vector<CaptureDeviceInfo>)CaptureDeviceManager
.getDeviceList(null).clone();
// remove the old direct sound capturers
String name;
Enumeration<CaptureDeviceInfo> enumeration = devices.elements();
while (enumeration.hasMoreElements()) {
CaptureDeviceInfo cdi = enumeration.nextElement();
name = cdi.getName();
if (name.startsWith(com.sun.media.protocol.dsound.DataSource.NAME))
CaptureDeviceManager.removeDevice(cdi);
}
int LE = AudioFormat.LITTLE_ENDIAN;
int SI = AudioFormat.SIGNED;
int US = AudioFormat.UNSIGNED;
int UN = AudioFormat.NOT_SPECIFIED;
float [] Rates = new float[] {
48000, 44100, 32000, 22050, 16000, 11025, 8000
};
Vector<AudioFormat> formats = new Vector<AudioFormat>(4);
for (int rateIndex = 0; rateIndex < Rates.length; rateIndex++) {
float rate = Rates[rateIndex];
AudioFormat af;
af = new AudioFormat(AudioFormat.LINEAR, rate, 16, 2, LE, SI);
if (supports(af)) formats.addElement(af);
af = new AudioFormat(AudioFormat.LINEAR, rate, 16, 1, LE, SI);
if (supports(af)) formats.addElement(af);
af = new AudioFormat(AudioFormat.LINEAR, rate, 8, 2, UN, US);
if (supports(af)) formats.addElement(af);
af = new AudioFormat(AudioFormat.LINEAR, rate, 8, 1, UN, US);
if (supports(af)) formats.addElement(af);
}
AudioFormat [] formatArray = new AudioFormat[formats.size()];
for (int fa = 0; fa < formatArray.length; fa++)
formatArray[fa] = formats.elementAt(fa);
CaptureDeviceInfo cdi = new CaptureDeviceInfo(
com.sun.media.protocol.dsound.DataSource.NAME,
new MediaLocator("dsound://"),
formatArray);
CaptureDeviceManager.addDevice(cdi);
try {
CaptureDeviceManager.commit();
logger.info("DirectSoundAuto: Committed ok");
} catch (java.io.IOException ioe) {
logger.error("DirectSoundAuto: error committing cdm");
}
}
}
}

@ -1,357 +0,0 @@
/*
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*
* File based on:
* @(#)JMFInit.java 1.14 03/04/30
* Copyright (c) 1996-2002 Sun Microsystems, Inc. All rights reserved.
*/
package net.java.sip.communicator.impl.media.device;
import java.io.*;
import java.util.*;
import javax.media.*;
import javax.media.format.*;
import net.java.sip.communicator.util.*;
public class JMFInit
implements Runnable {
private static final Logger logger = Logger.getLogger(JMFInit.class);
public JMFInit() {
// try {
// Registry.commit();
// }
// catch (Exception e) {
// logger.error("Failed to commit to JMFRegistry!", e );
// }
Thread detectThread = new Thread(this);
detectThread.run();
/*
int slept = 0;
while (!done && slept < 60 * 1000 * 2) {
try {
Thread.currentThread().sleep(500);
}
catch (InterruptedException ie) {
}
slept += 500;
}
if (!done) {
console.error("Detection is taking too long! Aborting!");
message("Detection is taking too long! Aborting!");
}
try {
Thread.currentThread().sleep(2000);
}
catch (InterruptedException ie) {
}
*/
}
/**
* Detect all capture devices
*/
public void run() {
detectDirectAudio();
detectS8DirectAudio();
detectCaptureDevices();
}
private void detectCaptureDevices() {
// check if JavaSound capture is available
logger.info("Looking for Audio capturer");
Class<?> dsauto = null;
try {
dsauto = Class.forName(
"net.java.sip.communicator.impl.media.device.DirectSoundAuto");
dsauto.newInstance();
logger.info("Finished detecting DirectSound capturer");
}
catch (ThreadDeath td) {
throw td;
}
catch (Throwable t) {
logger.warn("DirectSound capturer detection failed!", t);
}
Class<?> jsauto = null;
try {
jsauto = Class.forName(
"net.java.sip.communicator.impl.media.device.JavaSoundAuto");
jsauto.newInstance();
logger.info("Finished detecting JavaSound capturer");
}
catch (ThreadDeath td) {
throw td;
}
catch (Throwable t) {
logger.warn("JavaSound capturer detection failed!", t);
}
// Check if VFWAuto or SunVideoAuto is available
logger.info("Looking for video capture devices");
Class<?> auto = null;
Class<?> autoPlus = null;
try {
auto = Class.forName(
"net.java.sip.communicator.impl.media.device.VFWAuto");
}
catch (Exception e) {
logger.warn("VFWAuto capturer detection failed!", e);
}
if (auto == null) {
try {
auto = Class.forName(
"net.java.sip.communicator.impl.media.device.SunVideoAuto");
}
catch (Exception ee) {
logger.warn("SunVideoAuto capturer detection failed!", ee);
}
try {
autoPlus = Class.forName(
"net.java.sip.communicator.impl.media.device.SunVideoPlusAuto");
}
catch (Exception ee) {
logger.warn("SunVideoPlusAuto capturer detection failed!", ee);
}
}
if (auto == null) {
try {
auto = Class.forName(
"net.java.sip.communicator.impl.media.device.V4LAuto");
}
catch (Exception ee) {
logger.warn("V4lAuto capturer detection failed!", ee);
}
}
try {
auto.newInstance();
if (autoPlus != null) {
autoPlus.newInstance();
}
logger.info("Finished detecting video capture devices");
}
catch (ThreadDeath td) {
throw td;
}
catch (Throwable t) {
logger.error("Capture device detection failed!", t);
}
}
@SuppressWarnings("unchecked") //legacy JMF code.
private void detectDirectAudio() {
Class<?> cls;
int plType = PlugInManager.RENDERER;
String dar = "com.sun.media.renderer.audio.DirectAudioRenderer";
try {
// Check if this is the Windows Performance Pack - hack
cls = Class.forName(
"net.java.sip.communicator.impl.media.device.VFWAuto");
// Check if DS capture is supported, otherwise fail DS renderer
// since NT doesn't have capture
cls = Class.forName("com.sun.media.protocol.dsound.DSound");
// Find the renderer class and instantiate it.
cls = Class.forName(dar);
Renderer rend = (Renderer) cls.newInstance();
try {
// Set the format and open the device
AudioFormat af = new AudioFormat(AudioFormat.LINEAR,
44100, 16, 2);
rend.setInputFormat(af);
rend.open();
Format[] inputFormats = rend.getSupportedInputFormats();
// Register the device
PlugInManager.addPlugIn(dar, inputFormats, new Format[0],
plType);
// Move it to the top of the list
Vector<String> rendList =
PlugInManager.getPlugInList(null, null, plType);
int listSize = rendList.size();
if (rendList.elementAt(listSize - 1).equals(dar)) {
rendList.removeElementAt(listSize - 1);
rendList.insertElementAt(dar, 0);
PlugInManager.setPlugInList(rendList, plType);
PlugInManager.commit();
//System.err.println("registered");
}
rend.close();
}
catch (Throwable t) {
//System.err.println("Error " + t);
}
}
catch (Throwable tt) {
}
}
private void detectS8DirectAudio() {
try
{
new S8DirectAudioAuto();
}
catch (Throwable tt)
{
}
}
/**
* Runs JMFInit the first time the application is started so that capture
* devices are properly detected and initialized by JMF.
*/
public static void setupJMF()
{
try
{
logger.logEntry();
// .jmf is the place where we store the jmf.properties file used
// by JMF. if the directory does not exist or it does not contain
// a jmf.properties file, or if the jmf.properties file has 0 length
// then this is the first time we're running and should detect capture
// devices
String homeDir = System.getProperty("user.home");
File jmfDir = new File(homeDir, ".jmf");
String classpath = System.getProperty("java.class.path");
classpath += System.getProperty("path.separator") +
jmfDir.getAbsolutePath();
System.setProperty("java.class.path", classpath);
if (!jmfDir.exists())
jmfDir.mkdir();
File jmfProperties = new File(jmfDir, "jmf.properties");
if (!jmfProperties.exists()) {
try {
jmfProperties.createNewFile();
}
catch (IOException ex) {
logger.error(
"Failed to create jmf.properties - " +
jmfProperties.getAbsolutePath());
}
}
//if we're running on linux checkout that libjmutil.so is where it
//should be and put it there.
// runLinuxPreInstall();
if (jmfProperties.length() == 0) {
new JMFInit();
}
}
finally
{
logger.logExit();
}
}
// private static void runLinuxPreInstall()
// {
// try {
// logger.logEntry();
//
// if (Utils.getProperty("os.name") == null
// || !Utils.getProperty("os.name").equalsIgnoreCase("Linux"))
// return;
//
// try {
// System.loadLibrary("jmv4l");
// console.debug("Successfully loaded libjmv4l.so");
// }
// catch (UnsatisfiedLinkError err) {
// console.debug("Failed to load libjmv4l.so. Will try and copy libjmutil.so", err);
//
// String destinationPathStr = Utils.getProperty("java.home")
// + File.separator + "lib"
// + File.separator + "i386";
// String libjmutilFileStr = "libjmutil.so";
//
// try {
// InputStream libIS =
// MediaManager.class.getClassLoader().
// getResourceAsStream(libjmutilFileStr);
// File outFile = new File(destinationPathStr
// +File.separator + libjmutilFileStr);
//
// //Check if file is already there - Ben Asselstine
// if (outFile.exists()) {
// //if we're here then libjmutil is already where it should be
// // but yet we failed to load libjmv4l.
// //so notify log and bail out
// console.error(
// "An error occurred while trying to load JMF. This "
// +"error is probably due to a JMF installation problem. "
// +"Please copy libjmutil.so to a location contained by "
// + "$LD_LIBRARY_PATH and try again!",
// err);
// return;
//
// }
//
// outFile.createNewFile();
//
// console.debug("jmutil");
//
// FileOutputStream fileOS = new FileOutputStream(outFile);
// int available = libIS.available();
// byte[] bytes = new byte[libIS.available()];
// int read = 0;
// int i = 0;
// for (i = 0; i<available ; i++)
// {
// bytes[i] = (byte)libIS.read();
// }
//
// console.debug("Read " + i + " bytes out of " + available );
//
// fileOS.write(bytes, 0, bytes.length);
// console.debug("Wrote " + available + " bytes.");
// bytes = null;
// libIS.close();
// fileOS.close();
// }
// catch (IOException exc) {
// if( exc.getMessage() != null
// && exc.getMessage().toLowerCase().indexOf("permission denied") != -1)
// console.showError("Permission denied!",
// "Because of insufficient permissions SIP Communicator has failed "
// + "to copy a required library to\n\n\t"
// + destinationPathStr + "!\n\nPlease run the application as root or "
// + "manually copy the " +libjmutilFileStr
// + " file to the above location!\n");
// exc.printStackTrace();
// }
// }
// /** @todo check whether we have a permissions problem and alert the
// * user that they should be running as root */
// catch(Throwable t)
// {
// console.debug("Error while loading");
// }
// }
// finally {
// console.logExit();
// }
// }
public static void start() {
setupJMF();
}
}

@ -15,6 +15,10 @@
import net.java.sip.communicator.util.*;
/**
* Detects javasound and registers capture devices.
* @author damencho
*/
public class JavaSoundAuto {
private static final Logger logger = Logger.getLogger(JavaSoundAuto.class);
@ -74,6 +78,9 @@ public JavaSoundAuto() {
}
}
// now add it as available audio system to DeviceConfiguration
DeviceConfiguration.addAudioSystem(
DeviceConfiguration.AUDIO_SYSTEM_JAVASOUND);
}
}
}

@ -130,20 +130,6 @@ private void detectCaptureDevices()
{
logger.info("Looking for Audio capturer");
// Issues #693 and #524:
// Disable DirectSound since it fails on multiple installations
//
// //First check if DirectSound capture is available
// try
// {
//
// new DirectSoundAuto();
// }
// catch (Throwable exc)
// {
// logger.debug("No direct sound detected: " + exc.getMessage());
// }
// check if JavaSound capture is available
try
{
@ -163,14 +149,20 @@ private void detectCaptureDevices()
{
logger.debug("No FMJ javasound detected: " + exc.getMessage());
}
// try
// {
// new PortAudioAuto();
// }
// catch (Throwable exc)
// {
// logger.info("No JMF portaudio detected: " + exc.getMessage());
// }
try
{
new PortAudioAuto();
}
catch (Throwable exc)
{
logger.info("No portaudio detected: " + exc.getMessage());
}
// after javasound and portaudio eventually add them to available
// audio systems, lets add option None, in order to be able to
// disable audio
DeviceConfiguration.addAudioSystem(
DeviceConfiguration.AUDIO_SYSTEM_NONE);
// video is enabled by default
// if video is disabled skip device detection
@ -330,17 +322,6 @@ private void detectDirectAudio()
}
}
private void detectS8DirectAudio()
{
try
{
new S8DirectAudioAuto();
}
catch (Throwable tt)
{
}
}
/**
* Runs JMFInit the first time the application is started so that capture
* devices are properly detected and initialized by JMF.
@ -404,18 +385,6 @@ public static void setupJMF()
}
setupRenderers();
// Enables Portaudio Renderer and makes it default by removing
// javasound renderer
// PlugInManager.addPlugIn(
// "net.java.sip.communicator.impl.media.renderer.audio.PortAudioRenderer",
// net.java.sip.communicator.impl.media.renderer.audio.PortAudioRenderer.supportedInputFormats,
// null,
// PlugInManager.RENDERER);
//
// PlugInManager.removePlugIn(
// "com.sun.media.renderer.audio.JavaSoundRenderer",
// PlugInManager.RENDERER);
}
@SuppressWarnings("unchecked") //legacy JMF code.
@ -483,9 +452,4 @@ public static void detectAndConfigureCaptureDevices()
{
setupJMF();
}
public static void main(String[] args)
{
detectAndConfigureCaptureDevices();
}
}

@ -6,28 +6,71 @@
*/
package net.java.sip.communicator.impl.media.device;
import java.util.*;
import javax.media.*;
import net.java.sip.communicator.impl.media.protocol.portaudio.*;
/**
* Creates Portaudio capture devices.
* Creates Portaudio capture devices by enumarating all the
* host devices that has input channels.
*
* @author Damian Minkov
*/
public class PortAudioAuto
{
/**
* An array of the devices that can be used for playback.
*/
public static CaptureDeviceInfo[] playbackDevices = null;
PortAudioAuto() throws Exception
{
Format[] formats = new Format[1];
// if PortAudio has a problem initializing like missing native
// components it will trow exception here and PortAudio rendering will
// not be inited.
PortAudio.initialize();
int deviceCount = PortAudio.Pa_GetDeviceCount();
int deviceIndex = 0;
Vector<CaptureDeviceInfo> playbackDevVector =
new Vector<CaptureDeviceInfo>();
for (; deviceIndex < deviceCount; deviceIndex++)
{
long deviceInfo = PortAudio.Pa_GetDeviceInfo(deviceIndex);
int maxInputChannels =
PortAudio.PaDeviceInfo_getMaxInputChannels(deviceInfo);
int maxOutputChannels =
PortAudio.PaDeviceInfo_getMaxOutputChannels(deviceInfo);
formats[0] = PortAudioStream.audioFormat;
CaptureDeviceInfo jmfInfo =
new CaptureDeviceInfo(
PortAudio.PaDeviceInfo_getName(deviceInfo),
new MediaLocator(
PortAudioStream.LOCATOR_PREFIX + deviceIndex),
PortAudioStream.getFormats());
CaptureDeviceInfo jmfInfo =
new CaptureDeviceInfo("portaudio:1",
new MediaLocator("portaudio:#" + 1), formats);
if(maxInputChannels > 0)
{
CaptureDeviceManager.addDevice(jmfInfo);
}
CaptureDeviceManager.addDevice(jmfInfo);
if(maxOutputChannels > 0)
{
playbackDevVector.add(jmfInfo);
}
}
playbackDevices = playbackDevVector.toArray(new CaptureDeviceInfo[0]);
CaptureDeviceManager.commit();
// Enables Portaudio Renderer
DeviceConfiguration.initPortAudioRenderer();
// now add it as available audio system to DeviceConfiguration
DeviceConfiguration.addAudioSystem(
DeviceConfiguration.AUDIO_SYSTEM_PORTAUDIO);
}
}

@ -1,62 +0,0 @@
package net.java.sip.communicator.impl.media.device;
import java.util.*;
import javax.media.*;
import com.sun.media.*;
/**
* Probes for JMF Solaris 8 direct audio.
*
* @author Emil Ivov
* @author Ken Larson
*/
public class S8DirectAudioAuto
{
@SuppressWarnings("unchecked") //legacy JMF code.
public S8DirectAudioAuto() throws Exception
{
Class<?> cls;
int plType = PlugInManager.RENDERER;
String dar = "com.sun.media.renderer.audio.DirectAudioRenderer";
// Check if this is the solaris Performance Pack - hack
cls = Class.forName(
"net.java.sip.communicator.impl.media.device.SunVideoAuto");
// Find the renderer class and instantiate it.
cls = Class.forName(dar);
Renderer rend = (Renderer) cls.newInstance();
if (rend instanceof ExclusiveUse &&
! ( (ExclusiveUse) rend).isExclusive())
{
// sol8+, DAR supports mixing
Vector<String> rendList = PlugInManager.getPlugInList(null, null,
plType);
int listSize = rendList.size();
boolean found = false;
String rname = null;
for (int i = 0; i < listSize; i++)
{
rname = rendList.elementAt(i);
if (rname.equals(dar))
{ // DAR is in the registry
found = true;
rendList.removeElementAt(i);
break;
}
}
if (found)
{
rendList.insertElementAt(dar, 0);
PlugInManager.setPlugInList(rendList, plType);
PlugInManager.commit();
}
}
}
}

@ -1,206 +0,0 @@
/*
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*
* File based on:
* @(#)SunVideoAuto.java 1.8 01/03/13
* Copyright (c) 1999-2001 Sun Microsystems, Inc. All Rights Reserved.
*/
package net.java.sip.communicator.impl.media.device;
import java.io.*;
import java.util.*;
import javax.media.*;
import javax.media.format.*;
import java.awt.*;
import net.java.sip.communicator.util.*;
import com.sun.media.protocol.sunvideo.*;
public class SunVideoAuto
{
private static final Logger logger = Logger.getLogger(SunVideoAuto.class);
private static String DEVICE_PREFIX = "/dev/rtvc";
private static String PROTOCOL = "sunvideo";
private static String LOCATOR_PREFIX = PROTOCOL + "://";
CaptureDeviceInfo [] devices = null;
int currentID = -1;
XILCapture xilCap;
Vector<Format> formats = null;
int [] ports = { 1, 2, 0 }; // most likely ports for a device
int [] scales = { 2, 4, 1 }; // supported scales / sizes
/**
* Default constructor. Does nothing.
*/
public SunVideoAuto()
{
}
/**
* Removes from the CaptureDeviceManager all currently detected vfw devices
* and runs a new detection loop to rediscover those that are currently
* available.
*
* @return the number of devices detected.
*/
@SuppressWarnings("unchecked") //legacy JMF code.
public int autoDetectDevices()
{
Vector<CaptureDeviceInfo> devices
= (Vector) CaptureDeviceManager.getDeviceList(null).clone();
Enumeration<CaptureDeviceInfo> enumeration = devices.elements();
while (enumeration.hasMoreElements()) {
CaptureDeviceInfo cdi = enumeration.nextElement();
String devName = cdi.getLocator().getProtocol();
if (devName.equals(PROTOCOL))
CaptureDeviceManager.removeDevice(cdi);
}
int nDevices = 0;
for (int i = 0; i < 7; i++) {
File fl = new File(DEVICE_PREFIX + i);
if (fl.exists()) {
doDevice(i);
nDevices++;
}
}
try {
CaptureDeviceManager.commit();
} catch (java.io.IOException ioe) {
logger.error("SunVideoAuto: error committing cdm", ioe);
return 0;
}
return nDevices;
}
private void addFormat(Format fin)
{
Enumeration<Format> enumeration = formats.elements();
while (enumeration.hasMoreElements()) {
Format format = enumeration.nextElement();
if (format.equals(fin))
return;
}
//System.err.println("New format = " + fin);
formats.addElement(fin);
}
private void doDevice(int index)
{
xilCap = new XILCapture(null);
formats = new Vector<Format>();
//boolean gotPort = false;
if (!xilCap.connect(index)) {
dummyDevice(index);
return;
}
for (int i = 0; i < ports.length; i++) {
if (xilCap.setPort(ports[i])) {
getJpegFormats();
getRGBFormats();
}
}
xilCap.disconnect();
if (formats.size() > 0)
addDevice(index);
else
dummyDevice(index);
}
private void getRGBFormats()
{
if (!xilCap.setCompress("RGB"))
return;
for (int i = 0; i < scales.length; i++) {
xilCap.setScale(scales[i]);
// To get the real values, start the device
if (xilCap.start()) {
Dimension size = new Dimension(xilCap.getWidth(),
xilCap.getHeight());
int stride = xilCap.getLineStride();
int maxbuf = stride * size.width;
addFormat(new RGBFormat(size, maxbuf, byte[].class,
15f,
24,
3, 2, 1, 3, stride,
Format.FALSE,
Format.NOT_SPECIFIED));
}
xilCap.stop();
}
}
private void getJpegFormats() {
if (!xilCap.setCompress("Jpeg"))
return;
for (int i = 0; i < scales.length; i++) {
xilCap.setScale(scales[i]);
// To get the real values, start the device
if (xilCap.start()) {
Dimension size = new Dimension(xilCap.getWidth(),
xilCap.getHeight());
// approximate the max for high quality
int maxbuf = 3 * size.width * size.height;
addFormat(new VideoFormat(VideoFormat.JPEG, size, maxbuf,
byte[].class, 15f));
}
xilCap.stop();
}
}
private void dummyDevice(int index)
{
// Can't get to the device, use the barest formats
addFormat(new VideoFormat(VideoFormat.JPEG));
addFormat(new RGBFormat());
addDevice(index);
}
private void addDevice(int index)
{
String name = "SunVideo device " + index;
String locator = LOCATOR_PREFIX + index;
Format [] farray = new Format[formats.size()];
Enumeration<Format> enumeration = formats.elements();
int i = 0;
while (enumeration.hasMoreElements()) {
Format format = enumeration.nextElement();
farray[i++] = format;
}
CaptureDeviceInfo cdi = new CaptureDeviceInfo(name,
new MediaLocator(locator), farray);
CaptureDeviceManager.addDevice(cdi);
}
public static void main(String [] args)
{
SunVideoAuto sunVideoAuto = new SunVideoAuto();
sunVideoAuto.autoDetectDevices();
System.exit(0);
}
}

@ -1,456 +0,0 @@
/*
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*
* File based on:
* @(#)SunVideoPlusAuto.java 1.6 01/03/13
* Copyright (c) 1999-2001 Sun Microsystems, Inc. All Rights Reserved.
*/
package net.java.sip.communicator.impl.media.device;
import java.io.*;
import java.util.*;
import javax.media.*;
import javax.media.format.*;
import javax.media.protocol.*;
import java.awt.*;
import com.sun.media.protocol.sunvideoplus.*;
import net.java.sip.communicator.util.*;
/**
* SIP Communicator modifications.
* @author Emil Ivov
*/
public class SunVideoPlusAuto
{
private static final Logger logger
= Logger.getLogger(SunVideoPlusAuto.class);
private static String DEVICE_PREFIX = "/dev/o1k";
private static String PROTOCOL = "sunvideoplus";
private static String LOCATOR_PREFIX = PROTOCOL + "://";
private static boolean DO_PAL = false;
int currentID = -1;
/**
* Removes from the CaptureDeviceManager all currently detected sun video
* devices and runs a new detection loop to rediscover those that are
* currently available.
*
* @return the number of devices detected.
*/
@SuppressWarnings("unchecked") //legacy JMF code.
public int autoDetectDevices()
{
/*
* First remove any old entries
*/
Vector<CaptureDeviceInfo> devices = (Vector) CaptureDeviceManager.
getDeviceList(null).clone();
Enumeration<CaptureDeviceInfo> enumeration = devices.elements();
while (enumeration.hasMoreElements())
{
CaptureDeviceInfo cdi = enumeration.nextElement();
String devName = cdi.getLocator().getProtocol();
if (devName.equals(PROTOCOL))
CaptureDeviceManager.removeDevice(cdi);
}
int nDevices = 0;
for (int i = 0; i < 10; i++)
{
File fl = new File(DEVICE_PREFIX + i);
if (fl.exists())
{
if (DO_PAL)
{
generalDevice(i, "PAL");
// If generating PAL, do both
// Garbage collect to release the PAL datasource
// otherwise it sometimes hangs before completing NTSC
System.gc();
generalDevice(i, "NTSC");
}
else
{
generalDevice(i, null);
}
// No longer generate specific configurations,
// let capture preview handle selection.
// doDevice(i);
nDevices++;
}
}
try
{
CaptureDeviceManager.commit();
}
catch (java.io.IOException ioe)
{
logger.error("SunVideoPlusAuto: error committing cdm", ioe);
return 0;
}
return nDevices;
}
protected void generalDevice(int id, String signal)
{
// Add the general device
javax.media.protocol.DataSource dsource = null;
String url = LOCATOR_PREFIX + id;
if (signal != null)
url += "////" + signal.toLowerCase();
try
{
dsource = Manager.createDataSource(new MediaLocator(url));
}
catch (Exception ex)
{
}
if (dsource != null && dsource instanceof
com.sun.media.protocol.sunvideoplus.DataSource)
{
CaptureDeviceInfo cdi = ( (CaptureDevice) dsource).
getCaptureDeviceInfo();
if (cdi != null)
{
String name = cdi.getName();
if (signal == null)
{
CaptureDeviceManager.addDevice(cdi);
}
else
{
name = cdi.getName() + " (" + signal + ")";
CaptureDeviceManager.addDevice(new CaptureDeviceInfo(name,
cdi.getLocator(), cdi.getFormats()));
}
System.err.println("CaptureDeviceInfo = "
+ name + " "
+ cdi.getLocator());
}
dsource.disconnect();
}
}
protected void doDevice(int id)
{
currentID = id;
FormatSetup fd = new FormatSetup(currentID);
Vector<CaptureDeviceInfo> cdiv = fd.getDeviceInfo();
if (cdiv != null && cdiv.size() > 0)
{
for (int i = 0; i < cdiv.size(); i++)
{
CaptureDeviceInfo cdi = cdiv.elementAt(i);
// At the moment, the name and locator are identical
System.err.println("CaptureDeviceInfo = "
+ cdi.getName());
// System.err.println("CaptureDeviceInfo = "
// + cdi.getName() + " "
// + cdi.getLocator());
}
}
}
static class FormatSetup
{
int id;
boolean fullVideo = false;
boolean anyVideo = true;
String sAnalog, sPort, sVideoFormat, sSize;
Hashtable<String, Format> videoFormats = new Hashtable<String, Format>();
OPICapture opiVidCap = null;
public FormatSetup(int id)
{
this.id = id;
opiVidCap = new OPICapture(null);
if (!opiVidCap.connect(id))
{
throw new Error("Unable to connect to device");
}
}
private void addVideoFormat(Format fin)
{
String sVideo = sPort + "/" + sVideoFormat + "/"
+ sSize + "/"
+ sAnalog;
System.err.println("New format " + sVideo + " = " + fin);
videoFormats.put(sVideo, fin);
}
public void mydispose()
{
opiVidCap.disconnect();
System.err.println("Disconnected driver");
}
public void doFormat()
{
if (anyVideo)
{
doVideoFormats();
}
}
public void doVideoFormats()
{
if (!anyVideo)
{
// add a dummy format entry
videoFormats.put("off", new VideoFormat(VideoFormat.RGB));
}
sAnalog = "ntsc";
if (DO_PAL)
sAnalog = "pal";
if (!opiVidCap.setSignal(sAnalog))
{
System.err.println("Video analog signal not recognized");
return;
}
int port = 1;
if (!opiVidCap.setPort(port))
{
System.err.println("Video source not recognized on port");
return;
}
sPort = "" + port;
opiVidCap.setScale(2);
sSize = "cif";
getVideoFormats();
}
private void getVideoFormats()
{
sVideoFormat = "h261";
getH261Format();
sVideoFormat = "h263";
getH263Format();
sVideoFormat = "jpeg";
getJpegFormat();
sVideoFormat = "rgb";
getRGBFormat();
sVideoFormat = "yuv";
getYUVFormat();
}
private void getRGBFormat()
{
if (!opiVidCap.setCompress("RGB"))
return;
/*
* If sizes are wanted, the only valid sizes are
* NTSC
* fcif (640 x 480)
* cif (320 x 240)
* qcif (160 x 120)
* PAL
* fcif (768 x 576)
* cif (384 x 288)
* qcif (192 x 144)
*/
Dimension size = new Dimension(opiVidCap.getWidth(),
opiVidCap.getHeight());
addVideoFormat(new RGBFormat(size, Format.NOT_SPECIFIED,
Format.byteArray,
Format.NOT_SPECIFIED,
16,
0xF800, 0x7E0, 0x1F, 2,
Format.NOT_SPECIFIED,
Format.FALSE,
Format.NOT_SPECIFIED));
}
private void getYUVFormat()
{
if (!opiVidCap.setCompress("YUV"))
return;
/*
* If sizes are wanted, the only valid sizes are
* NTSC
* fcif (640 x 480)
* cif (320 x 240)
* qcif (160 x 120)
* PAL
* fcif (768 x 576)
* cif (384 x 288)
* qcif (192 x 144)
*
* The capture stream is actually interleaved YVYU format.
* This is defined in the offset values below.
*/
Dimension size = new Dimension(opiVidCap.getWidth(),
opiVidCap.getHeight());
addVideoFormat(new YUVFormat(size, Format.NOT_SPECIFIED,
Format.byteArray,
Format.NOT_SPECIFIED,
YUVFormat.YUV_YUYV,
Format.NOT_SPECIFIED,
Format.NOT_SPECIFIED,
0, 3, 1));
}
private void getJpegFormat()
{
if (!opiVidCap.setCompress("Jpeg"))
return;
/*
* If sizes are wanted, the only valid sizes are
* NTSC
* cif (320 x 240)
* qcif (160 x 120)
* PAL
* cif (384 x 288)
* qcif (192 x 144)
*/
Dimension size = new Dimension(opiVidCap.getWidth(),
opiVidCap.getHeight());
addVideoFormat(new VideoFormat(VideoFormat.JPEG, size,
Format.NOT_SPECIFIED,
Format.byteArray,
Format.NOT_SPECIFIED));
}
private void getH261Format()
{
if (!opiVidCap.setCompress("H261"))
return;
/*
* If sizes are wanted, the only valid sizes are
* cif (352 x 288)
* qcif (176 x 144)
*/
Dimension size = new Dimension(opiVidCap.getWidth(),
opiVidCap.getHeight());
addVideoFormat(new VideoFormat(VideoFormat.H261, size,
Format.NOT_SPECIFIED,
Format.byteArray,
Format.NOT_SPECIFIED));
}
private void getH263Format()
{
if (!opiVidCap.setCompress("H263"))
return;
/*
* If sizes are wanted, the only valid sizes are
* cif (352 x 288)
* qcif (176 x 144)
*/
Dimension size = new Dimension(opiVidCap.getWidth(),
opiVidCap.getHeight());
addVideoFormat(new VideoFormat(VideoFormat.H263, size,
Format.NOT_SPECIFIED,
Format.byteArray,
Format.NOT_SPECIFIED));
}
public void issueError(String err)
{
System.err.println(err);
Toolkit.getDefaultToolkit().beep();
}
public Enumeration<String> sortedFormats(Hashtable<String, Format> formats)
{
Vector<String> sorted = new Vector<String>();
keyloop:for (Enumeration<String> en = formats.keys();
en.hasMoreElements(); )
{
String key = en.nextElement();
for (int i = 0; i < sorted.size(); i++)
{
if (key.compareTo( sorted.elementAt(i)) < 0)
{
sorted.insertElementAt(key, i);
continue keyloop;
}
}
sorted.addElement(key);
}
return sorted.elements();
}
public Vector<CaptureDeviceInfo> getDeviceInfo()
{
doFormat();
mydispose();
String locatorPrefix = LOCATOR_PREFIX + id;
Vector<CaptureDeviceInfo> devices = new Vector<CaptureDeviceInfo>();
if (anyVideo)
{
for (Enumeration<String> ve = sortedFormats(videoFormats);
ve.hasMoreElements(); )
{
String vKey = ve.nextElement();
Format vForm = videoFormats.get(vKey);
Format[] farray = null;
farray = new Format[1];
farray[0] = vForm;
String name = locatorPrefix + "/" + vKey;
CaptureDeviceInfo cdi = new CaptureDeviceInfo(name,
new MediaLocator(name), farray);
CaptureDeviceManager.addDevice(cdi);
devices.addElement(cdi);
}
}
return devices;
}
}
public static void setPALSignal(boolean pal)
{
DO_PAL = pal;
}
public static void main(String[] args)
{
if (args.length > 0)
{
if (args.length > 1)
{
System.err.println(
"Usage: java SunVideoPlusAuto [ ntsc | pal ]");
System.exit(1);
}
if (args[0].equalsIgnoreCase("ntsc"))
{
SunVideoPlusAuto.setPALSignal(false);
}
else if (args[0].equalsIgnoreCase("pal"))
{
SunVideoPlusAuto.setPALSignal(true);
}
else
{
System.err.println(
"Usage: java SunVideoPlusAuto [ ntsc | pal ]");
System.exit(1);
}
}
SunVideoPlusAuto sunVideoPlus = new SunVideoPlusAuto();
sunVideoPlus.autoDetectDevices();
System.exit(0);
}
}

@ -1,110 +0,0 @@
/*
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*
* File based on:
* @(#)V4LAuto.java 1.2 01/03/13
* Copyright (c) 1999-2001 Sun Microsystems, Inc. All Rights Reserved.
*/
package net.java.sip.communicator.impl.media.device;
import java.util.*;
import javax.media.*;
import net.java.sip.communicator.util.*;
import com.sun.media.protocol.v4l.*;
/**
* Probes for video capture devices present on linux systems.
* @author Emil Ivov
*/
public class V4LAuto {
private static final Logger logger = Logger.getLogger(V4LAuto.class);
/**
* Removes from the CaptureDeviceManager all currently detected devices and
* runs a new detection loop to rediscover those that are currently
* available.
*
* @return the number of devices detected.
*/
@SuppressWarnings("unchecked") //JMF legacy code
public int autoDetectDevices()
{
Vector<CaptureDeviceInfo> devices
= (Vector) CaptureDeviceManager.getDeviceList(null).clone();
Enumeration<CaptureDeviceInfo> enumeration = devices.elements();
while (enumeration.hasMoreElements())
{
CaptureDeviceInfo cdi = enumeration.nextElement();
String name = cdi.getName();
if (name.startsWith("v4l:"))
CaptureDeviceManager.removeDevice(cdi);
}
int nDevices = 0;
for (int i = 0; i < 10; i++)
{
CaptureDeviceInfo cdi = autoDetect(i);
if (cdi != null)
nDevices++;
}
return nDevices;
}
/**
* Runs a device query for the capture card with the specified card number
* and returns its corresponding CaptureDeviceInfo or null if detection
* failed or nos such card exists.
* @param cardNo the index of the card to discover.
* @return the CaptureDeviceInfo corresponsing to the newly discovered
* device.
*/
protected CaptureDeviceInfo autoDetect(int cardNo)
{
CaptureDeviceInfo cdi = null;
try
{
cdi = new V4LDeviceQuery();
((V4LDeviceQuery)cdi).sendQuery(cardNo);
if ( cdi.getFormats() != null
&& cdi.getFormats().length > 0)
{
// Commit it to disk. Its a new device
if (CaptureDeviceManager.addDevice(cdi))
{
logger.info("Added device " + cdi);
CaptureDeviceManager.commit();
}
}
}
catch (Throwable thr)
{
logger.debug("No device for index "
+ cardNo + ". "
+ thr.getMessage());
if (thr instanceof ThreadDeath)
throw (ThreadDeath)thr;
}
return cdi;
}
/**
* Test method, present for testing only.
* @param args String[]
*/
public static void main(String [] args)
{
V4LAuto auto = new V4LAuto();
auto.autoDetectDevices();
System.exit(0);
}
}

@ -1,72 +0,0 @@
/*
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*
* File based on:
* @(#)VFWAuto.java 1.2 01/03/13
* Copyright (c) 1999-2001 Sun Microsystems, Inc. All Rights Reserved.
*/
package net.java.sip.communicator.impl.media.device;
import java.util.*;
import javax.media.*;
import com.sun.media.protocol.vfw.*;
import net.java.sip.communicator.util.*;
/**
* SIP Communicator modifications
* @author Emil Ivov
*/
public class VFWAuto
{
private static final Logger logger
= Logger.getLogger(VFWAuto.class);
/**
* Removes from the CaptureDeviceManager all currently detected vfw devices
* and runs a new detection loop to rediscover those that are currently
* available.
*
* @return the number of devices detected.
*/
@SuppressWarnings("unchecked") // jmf legacy code
public int autoDetectDevices()
{
Vector<CaptureDeviceInfo> devices
= (Vector) CaptureDeviceManager.getDeviceList(null).clone();
Enumeration<CaptureDeviceInfo> devicesEnum = devices.elements();
while (devicesEnum.hasMoreElements())
{
CaptureDeviceInfo cdi = devicesEnum.nextElement();
String name = cdi.getName();
if (name.startsWith("vfw:"))
CaptureDeviceManager.removeDevice(cdi);
}
int nDevices = 0;
for (int i = 0; i < 10; i++)
{
String name = VFWCapture.capGetDriverDescriptionName(i);
if (name != null && name.length() > 1)
{
logger.debug("Found device " + name);
logger.debug("Querying device. Please wait...");
com.sun.media.protocol.vfw.VFWSourceStream.autoDetect(i);
nDevices++;
}
}
return nDevices;
}
public static void main(String [] args)
{
VFWAuto vfwAuto = new VFWAuto();
vfwAuto.autoDetectDevices();
System.exit(0);
}
}

@ -41,4 +41,5 @@ Export-Package: net.java.sip.communicator.service.media,
net.java.sip.communicator.service.media.event,
net.java.sip.communicator.impl.media,
net.java.sip.communicator.impl.media.device,
net.java.sip.communicator.service.audionotifier
Metadata-Location: /net/java/sip/communicator/impl/media/media.metadata.xml

@ -0,0 +1,159 @@
/*
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package net.java.sip.communicator.impl.media.notify;
import java.net.*;
import java.util.*;
import net.java.sip.communicator.impl.media.*;
import net.java.sip.communicator.impl.media.device.*;
import net.java.sip.communicator.service.audionotifier.*;
/**
* The implementation of the AudioNotifierService.
*
* @author Yana Stamcheva
*/
public class AudioNotifierServiceImpl
implements AudioNotifierService
{
private static final Map<String, SCAudioClipImpl> audioClips =
new HashMap<String, SCAudioClipImpl>();
private boolean isMute;
/**
* Device config to look for notify device.
*/
private DeviceConfiguration deviceConfiguration;
/**
* Creates audio notify service.
* @param deviceConfiguration the device configuration.
*/
public AudioNotifierServiceImpl(DeviceConfiguration deviceConfiguration)
{
this.deviceConfiguration = deviceConfiguration;
}
/**
* Creates an SCAudioClip from the given URI and adds it to the list of
* available audio-s.
*
* @param uri the path where the audio file could be found
*/
public SCAudioClipImpl createAudio(String uri)
{
SCAudioClipImpl audioClip;
synchronized (audioClips)
{
if(audioClips.containsKey(uri))
{
audioClip = audioClips.get(uri);
}
else
{
URL url =
MediaActivator.getResources().getSoundURLForPath(uri);
if (url == null)
{
// Not found by the class loader. Perhaps it's a local file.
try
{
url = new URL(uri);
}
catch (MalformedURLException e)
{
//logger.error("The given uri could not be parsed.", e);
return null;
}
}
try
{
if(getDeviceConfiguration().getAudioSystem().equals(
DeviceConfiguration.AUDIO_SYSTEM_JAVASOUND))
{
audioClip = new JMFAudioClipImpl(url, this);
}
else if(getDeviceConfiguration().getAudioSystem().equals(
DeviceConfiguration.AUDIO_SYSTEM_PORTAUDIO))
{
audioClip = new PortAudioClipImpl(url, this);
}
else
return null;
}
catch (Throwable e)
{
// Cannot create audio to play
return null;
}
audioClips.put(uri, audioClip);
}
}
return audioClip;
}
/**
* Removes the given audio from the list of available audio clips.
*
* @param audioClip the audio to destroy
*/
public void destroyAudio(SCAudioClip audioClip)
{
synchronized (audioClips) {
audioClips.remove(audioClip);
}
}
/**
* Enables or disables the sound in the application. If FALSE, we try to
* restore all looping sounds if any.
*
* @param isMute when TRUE disables the sound, otherwise enables the sound.
*/
public void setMute(boolean isMute)
{
this.isMute = isMute;
for (SCAudioClipImpl audioClip : audioClips.values())
{
if (isMute)
{
audioClip.internalStop();
}
else if (audioClip.isLooping())
{
audioClip.playInLoop(audioClip.getLoopInterval());
}
}
}
/**
* Returns TRUE if the sound is currently disabled, FALSE otherwise.
* @return TRUE if the sound is currently disabled, FALSE otherwise
*/
public boolean isMute()
{
return isMute;
}
/**
* The device configuration.
*
* @return the deviceConfiguration
*/
public DeviceConfiguration getDeviceConfiguration()
{
return deviceConfiguration;
}
}

@ -0,0 +1,201 @@
/*
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package net.java.sip.communicator.impl.media.notify;
import java.applet.*;
import java.awt.event.*;
import java.io.*;
import java.lang.reflect.*;
import java.net.*;
import java.security.*;
import javax.swing.*;
import net.java.sip.communicator.service.audionotifier.*;
/**
* Implementation of SCAudioClip.
*
* @author Yana Stamcheva
*/
public class JMFAudioClipImpl
extends SCAudioClipImpl
implements ActionListener
{
private static Constructor<AudioClip> acConstructor = null;
private final Timer playAudioTimer = new Timer(1000, null);
private final AudioClip audioClip;
private final AudioNotifierService audioNotifier;
/**
* Creates the audio clip and initialize the listener used from the
* loop timer.
*
* @param url the url pointing to the audio file
* @param audioNotifier the audio notify service
* @throws IOException cannot audio clip with supplied url.
*/
public JMFAudioClipImpl(URL url, AudioNotifierService audioNotifier)
throws IOException
{
this.audioClip = createAppletAudioClip(url.openStream());
this.audioNotifier = audioNotifier;
this.playAudioTimer.addActionListener(this);
}
/**
* Plays this audio.
*/
public void play()
{
if ((audioClip != null) && !audioNotifier.isMute())
audioClip.play();
}
/**
* Plays this audio in loop.
*
* @param interval the loop interval
*/
public void playInLoop(int interval)
{
if(!audioNotifier.isMute())
{
if(interval == 0)
audioClip.loop();
else
{
//first play the audio and then start the timer and wait
audioClip.play();
playAudioTimer.setDelay(interval);
playAudioTimer.setRepeats(true);
playAudioTimer.start();
}
}
setLoopInterval(interval);
setIsLooping(true);
}
/**
* Stops this audio.
*/
public void stop()
{
if (audioClip != null)
audioClip.stop();
if (isLooping())
{
playAudioTimer.stop();
setIsLooping(false);
}
}
/**
* Stops this audio without setting the isLooping property in the case of
* a looping audio. The AudioNotifier uses this method to stop the audio
* when setMute(true) is invoked. This allows us to restore all looping
* audios when the sound is restored by calling setMute(false).
*/
public void internalStop()
{
if (audioClip != null)
audioClip.stop();
if (isLooping())
playAudioTimer.stop();
}
/**
* Creates an AppletAudioClip.
*
* @param inputstream the audio input stream
* @throws IOException
*/
private static AudioClip createAppletAudioClip(InputStream inputstream)
throws IOException
{
if (acConstructor == null)
{
try
{
acConstructor
= AccessController.doPrivileged(
new PrivilegedExceptionAction<Constructor<AudioClip>>()
{
public Constructor<AudioClip> run()
throws ClassNotFoundException,
NoSuchMethodException,
SecurityException
{
return createAcConstructor();
}
});
}
catch (PrivilegedActionException paex)
{
throw
new IOException(
"Failed to get AudioClip constructor: "
+ paex.getException());
}
}
try
{
return acConstructor.newInstance(inputstream);
}
catch (Exception ex)
{
throw new IOException("Failed to construct the AudioClip: " + ex);
}
}
@SuppressWarnings("unchecked")
private static Constructor<AudioClip> createAcConstructor()
throws ClassNotFoundException,
NoSuchMethodException,
SecurityException
{
Class<?> class1;
try
{
class1
= Class.forName(
"com.sun.media.sound.JavaSoundAudioClip",
true,
ClassLoader.getSystemClassLoader());
}
catch (ClassNotFoundException cnfex)
{
class1
= Class.forName("sun.audio.SunAudioClip", true, null);
}
return
(Constructor<AudioClip>) class1.getConstructor(InputStream.class);
}
/**
* Plays an audio clip. Used in the playAudioTimer to play an audio in loop.
* @param e the event.
*/
public void actionPerformed(ActionEvent e)
{
if (audioClip != null)
{
audioClip.stop();
audioClip.play();
}
}
}

@ -0,0 +1,204 @@
/*
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package net.java.sip.communicator.impl.media.notify;
import java.io.*;
import java.net.*;
import javax.sound.sampled.*;
import net.java.sip.communicator.impl.media.protocol.portaudio.*;
import net.java.sip.communicator.impl.media.device.*;
import net.java.sip.communicator.util.*;
/**
* Implementation of SCAudioClip using PortAudio.
*
* @author Damian Minkov
*/
public class PortAudioClipImpl
extends SCAudioClipImpl
implements PropertyChangeListener
{
private static final Logger logger
= Logger.getLogger(PortAudioClipImpl.class);
private final AudioNotifierServiceImpl audioNotifier;
private Thread playThread = new Thread(new PlayThread());
private boolean started = false;
private long portAudioStream = 0;
private URL url = null;
/**
* Creates the audio clip and initialize the listener used from the
* loop timer.
*
* @param url the url pointing to the audio file
* @param audioNotifier the audio notify service
* @throws IOException cannot audio clip with supplied url.
*/
public PortAudioClipImpl(URL url, AudioNotifierServiceImpl audioNotifier)
throws IOException
{
this.audioNotifier = audioNotifier;
this.url = url;
audioNotifier.getDeviceConfiguration().addPropertyChangeListener(this);
}
/**
* Plays this audio.
*/
public void play()
{
if ((url != null) && !audioNotifier.isMute())
{
started = true;
playThread.start();
}
}
/**
* Plays this audio in loop.
*
* @param interval the loop interval
*/
public void playInLoop(int interval)
{
setLoopInterval(interval);
setIsLooping(true);
if(!audioNotifier.isMute())
{
started = true;
playThread.start();
}
}
/**
* Stops this audio.
*/
public void stop()
{
if (url != null)
started = false;
setIsLooping(false);
}
/**
* Stops this audio without setting the isLooping property in the case of
* a looping audio. The AudioNotifier uses this method to stop the audio
* when setMute(true) is invoked. This allows us to restore all looping
* audios when the sound is restored by calling setMute(false).
*/
public void internalStop()
{
if (url != null)
started = false;
}
/**
* Notified when device configuration has changed.
* @param evt the event of the change
*/
public void propertyChange(PropertyChangeEvent evt)
{
if(evt.getPropertyName().equals(
DeviceConfiguration.AUDIO_NOTIFY_DEVICE))
{
// make the stream 0, to be sure next time the new
// device will be used
portAudioStream = 0;
}
}
private class PlayThread
implements Runnable
{
byte[] buffer = new byte[1024];
public void run()
{
try
{
while(true)
{
if (portAudioStream == 0)
{
long streamParameters
= PortAudio.PaStreamParameters_new(
PortAudioStream.getDeviceIndexFromLocator(
audioNotifier.getDeviceConfiguration().
getAudioNotifyDevice().getLocator()),
2,
PortAudio.SAMPLE_FORMAT_INT16);
portAudioStream
= PortAudio.Pa_OpenStream(
0,
streamParameters,
48000,
PortAudio.FRAMES_PER_BUFFER_UNSPECIFIED,
PortAudio.STREAM_FLAGS_NO_FLAG,
null);
PortAudio.Pa_StartStream(portAudioStream);
}
AudioInputStream audioStream =
AudioSystem.getAudioInputStream(url);
if(!started)
{
PortAudio.Pa_CloseStream(portAudioStream);
return;
}
int read = 0;
while((read = audioStream.read(buffer)) != -1)
{
PortAudio.Pa_WriteStream(
portAudioStream,
buffer,
buffer.length/audioStream.getFormat().getFrameSize());
}
if(!isLooping())
{
PortAudio.Pa_CloseStream(portAudioStream);
break;
}
else
{
Thread.sleep(getLoopInterval());
}
}
}
catch (PortAudioException e)
{
logger.error(
"Cannot open portaudio device for notifications", e);
}
catch (IOException e)
{
logger.error("Error reading from audio resource", e);
}
catch (InterruptedException e)
{
logger.error("Cannot wait the interval between plays", e);
}
catch (UnsupportedAudioFileException e)
{
logger.error("Unknown file format", e);
}
}
}
}

@ -0,0 +1,94 @@
/*
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package net.java.sip.communicator.impl.media.notify;
import net.java.sip.communicator.service.audionotifier.*;
/**
* Common properties impl for SCAudioClip.
*
* @author Damian Minkov
*/
public abstract class SCAudioClipImpl
implements SCAudioClip
{
private boolean isLooping;
private int loopInterval;
private boolean isInvalid;
/**
* Returns TRUE if this audio is invalid, FALSE otherwise.
*
* @return TRUE if this audio is invalid, FALSE otherwise
*/
public boolean isInvalid()
{
return isInvalid;
}
/**
* Marks this audio as invalid or not.
*
* @param isInvalid TRUE to mark this audio as invalid, FALSE otherwise
*/
public void setInvalid(boolean isInvalid)
{
this.setIsInvalid(isInvalid);
}
/**
* Returns TRUE if this audio is currently playing in loop, FALSE otherwise.
* @return TRUE if this audio is currently playing in loop, FALSE otherwise.
*/
public boolean isLooping()
{
return isLooping;
}
/**
* Returns the loop interval if this audio is looping.
* @return the loop interval if this audio is looping
*/
public int getLoopInterval()
{
return loopInterval;
}
/**
* @param isLooping the isLooping to set
*/
public void setIsLooping(boolean isLooping)
{
this.isLooping = isLooping;
}
/**
* @param loopInterval the loopInterval to set
*/
public void setLoopInterval(int loopInterval)
{
this.loopInterval = loopInterval;
}
/**
* @param isInvalid the isInvalid to set
*/
public void setIsInvalid(boolean isInvalid)
{
this.isInvalid = isInvalid;
}
/**
* Stops this audio without setting the isLooping property in the case of
* a looping audio. The AudioNotifier uses this method to stop the audio
* when setMute(true) is invoked. This allows us to restore all looping
* audios when the sound is restored by calling setMute(false).
*/
public abstract void internalStop();
}

@ -12,10 +12,12 @@
import javax.media.protocol.*;
/**
* Portaudio datasource.
*
* @author Damian Minkov
*/
public class DataSource
extends PushBufferDataSource
extends PullBufferDataSource
{
private boolean connected = false;
@ -27,6 +29,7 @@ public class DataSource
/**
* Connect the datasource
* @throws IOException if we cannot initialize portaudio.
*/
public void connect()
throws IOException
@ -80,7 +83,9 @@ public String getContentType()
/**
* Return required control from the Control[] array
* if exists, that is
* if exists.
* @param controlType the control we are interested in.
* @return the object that implements the control, or null.
*/
public Object getControl(String controlType)
{
@ -101,7 +106,7 @@ public Object getControl(String controlType)
/**
* Gives control information to the caller
*
* @return the collection of object controls.
*/
public Object[] getControls()
{
@ -120,22 +125,35 @@ public Time getDuration()
}
/**
* Returns an array of PushBufferStream containing all the streams
* Returns an array of PullBufferStream containing all the streams
* i.e. only one in our case : only sound.
*
* If no stream actually exists, instantiate one on the fly.
*
* @return Array of one stream
*/
public PushBufferStream[] getStreams()
public PullBufferStream[] getStreams()
{
if (streams == null)
streams = new PortAudioStream[] { new PortAudioStream() };
try
{
if (streams == null)
streams = new PortAudioStream[]
{new PortAudioStream(getLocator())};
}
catch (Exception e)
{
e.printStackTrace();
// if we cannot parse desired device we will not open a stream
// so there is no stream returned
streams = new PortAudioStream[0];
}
return streams;
}
/**
* Start the datasource and the underlying stream
* @throws IOException
*/
public void start()
throws IOException
@ -146,21 +164,14 @@ public void start()
if (!connected)
throw new IOException("DataSource must be connected");
try
{
streams[0].start();
}
catch (PortAudioException paex)
{
IOException ioex = new IOException();
ioex.initCause(paex);
throw ioex;
}
streams[0].start();
started = true;
}
/**
* Stop the datasource and it's underlying stream
* @throws IOException
*/
public void stop()
throws IOException
@ -168,16 +179,8 @@ public void stop()
if (!started)
return;
try
{
streams[0].stop();
}
catch (PortAudioException paex)
{
IOException ioex = new IOException();
ioex.initCause(paex);
throw ioex;
}
streams[0].stop();
started = false;
}
}

@ -66,12 +66,29 @@ public static native void Pa_WriteStream(
long frames)
throws PortAudioException;
public static native void Pa_ReadStream(
long stream, byte[] buffer, long frames)
throws PortAudioException;
public static native long Pa_GetStreamReadAvailable(long stream);
public static native long Pa_GetStreamWriteAvailable(long stream);
public static native int Pa_GetSampleSize(long format);
public static native boolean Pa_IsFormatSupported(
long inputParameters,
long outputParameters,
double sampleRate);
public static native int PaDeviceInfo_getMaxInputChannels(long deviceInfo);
public static native int PaDeviceInfo_getMaxOutputChannels(long deviceInfo);
public static native String PaDeviceInfo_getName(long deviceInfo);
public static native double PaDeviceInfo_getDefaultSampleRate(long deviceInfo);
public static native long PaStreamParameters_new(
int deviceIndex,
int channelCount,

@ -14,22 +14,28 @@
import javax.media.format.*;
import javax.media.protocol.*;
import net.java.sip.communicator.util.*;
/**
* @author Damian Minkov
*/
public class PortAudioStream
implements PushBufferStream,
PortAudioStreamCallback
implements PullBufferStream
{
// private static final Logger logger
// = Logger.getLogger(PortAudioStream.class);
private static final Logger logger =
Logger.getLogger(PortAudioStream.class);
/**
* The locatro prefix used when creating or parsing MediaLocators.
*/
public static final String LOCATOR_PREFIX = "portaudio:#";
private final static ContentDescriptor cd =
new ContentDescriptor(ContentDescriptor.RAW);
private BufferTransferHandler transferHandler;
private Control[] controls = new Control[0];
public static AudioFormat audioFormat = new AudioFormat(
private static AudioFormat audioFormat = new AudioFormat(
AudioFormat.LINEAR,
44100,
16,
@ -40,53 +46,47 @@ public class PortAudioStream
Format.NOT_SPECIFIED,
Format.byteArray);
private boolean started;
private long stream = 0;
private ByteBuffer bufferToProcess = null;
private int seqNo = 0;
private int sampleSize = 1;
final private int deviceIndex;
/**
* Returns the supported formats by this stream.
* @return supported formats
* Creates new stream.
* @param locator the locator to extract the device index from it.
*/
public Format getFormat()
public PortAudioStream(MediaLocator locator)
{
return audioFormat;
this.deviceIndex = getDeviceIndexFromLocator(locator);
}
/**
*
* @param buffer
* @throws IOException
* Return the formats supported by the datasource stream
* corresponding the maximum input channels.
*
* @return the supported formats.
*/
public void read(Buffer buffer)
throws IOException
public static Format[] getFormats()
{
byte[] barr = new byte[bufferToProcess.remaining()];
bufferToProcess.get(barr);
buffer.setTimeStamp(System.nanoTime());
buffer.setData(barr);
buffer.setSequenceNumber(seqNo);
buffer.setLength(barr.length);
buffer.setFlags(0);
buffer.setHeader(null);
seqNo++;
return new Format[]{audioFormat};
}
/**
*
* @param transferHandler
* Returns the supported format by this stream.
* @return supported formats
*/
public void setTransferHandler(BufferTransferHandler transferHandler)
public Format getFormat()
{
this.transferHandler = transferHandler;
return audioFormat;
}
/**
* We are providing access to raw data
* @return RAW content descriptor.
*/
public ContentDescriptor getContentDescriptor()
{
@ -95,6 +95,7 @@ public ContentDescriptor getContentDescriptor()
/**
* We are streaming.
* @return unknown content length.
*/
public long getContentLength()
{
@ -103,7 +104,7 @@ public long getContentLength()
/**
* The stream never ends.
*
* @return true if the end of the stream has been reached.
*/
public boolean endOfStream()
{
@ -112,7 +113,7 @@ public boolean endOfStream()
/**
* Gives control information to the caller
*
* @return no controls currently supported.
*/
public Object[] getControls()
{
@ -121,7 +122,10 @@ public Object[] getControls()
/**
* Return required control from the Control[] array
* if exists, that is
* if exists
*
* @param controlType the control class name.
* @return the object that implements the control, or null.
*/
public Object getControl(String controlType)
{
@ -145,96 +149,130 @@ public Object getControl(String controlType)
}
}
public void finishedCallback()
{
}
/**
* Starts the stream operation
*/
void start()
throws PortAudioException
{
if (this.stream != 0)
throw new IllegalStateException("stream");
long stream = createStream();
try
{
PortAudio.Pa_StartStream(stream);
this.stream = stream;
}
catch (PortAudioException startException)
synchronized (this)
{
this.started = true;
try
{
PortAudio.Pa_CloseStream(stream);
PortAudio.Pa_StartStream(getStream());
}
catch (PortAudioException closeException)
catch (PortAudioException paex)
{
/*
* We couldn't start the stream so we're closing it just to free
* the native resources but if that fails as well, we cannot do
* anything about it. Besides, we have to rethrow the exception
* which was thrown on start.
*/
paex.printStackTrace();
}
throw startException;
}
}
void stop()
throws PortAudioException
{
if (stream != 0)
synchronized (this)
{
PortAudio.Pa_CloseStream(stream);
stream = 0;
this.started = false;
try
{
PortAudio.Pa_CloseStream(getStream());
stream = 0;
}
catch (PortAudioException paex)
{
paex.printStackTrace();
}
}
}
private long createStream()
private long getStream()
throws PortAudioException
{
int deviceCount = PortAudio.Pa_GetDeviceCount();
int deviceIndex = 0;
for (; deviceIndex < deviceCount; deviceIndex++)
if (stream == 0)
{
long deviceInfo = PortAudio.Pa_GetDeviceInfo(deviceIndex);
if ((PortAudio.PaDeviceInfo_getMaxInputChannels(deviceInfo) == 2)
&& (PortAudio.PaDeviceInfo_getMaxOutputChannels(deviceInfo) == 0)
&& PortAudio.PaDeviceInfo_getName(deviceInfo)
.contains("Analog"))
break;
long streamParameters
= PortAudio.PaStreamParameters_new(
deviceIndex,
audioFormat.getChannels(),
PortAudio.SAMPLE_FORMAT_INT16);
stream
= PortAudio.Pa_OpenStream(
streamParameters,
0,
audioFormat.getSampleRate(),
PortAudio.FRAMES_PER_BUFFER_UNSPECIFIED,
PortAudio.STREAM_FLAGS_NO_FLAG,
null);
sampleSize =
PortAudio.Pa_GetSampleSize(PortAudio.SAMPLE_FORMAT_INT16);
}
long streamParameters
= PortAudio.PaStreamParameters_new(
deviceIndex,
1,
PortAudio.SAMPLE_FORMAT_INT16);
return
PortAudio.Pa_OpenStream(
streamParameters,
0,
44100,
PortAudio.FRAMES_PER_BUFFER_UNSPECIFIED,
PortAudio.STREAM_FLAGS_NO_FLAG,
this);
return stream;
}
public int callback(ByteBuffer input, ByteBuffer output)
/**
* Query if the next read will block.
* @return true if a read will block.
*/
public boolean willReadBlock()
{
bufferToProcess = input;
try
{
return PortAudio.Pa_GetStreamReadAvailable(getStream()) == 0;
}
catch (PortAudioException ex)
{
logger.error("Cannot get read available", ex);
return true;
}
}
if (transferHandler != null)
transferHandler.transferData(this);
/**
* Block and read a buffer from the stream.
* @param buffer should be non-null.
* @throws IOException Thrown if an error occurs while reading.
*/
public synchronized void read(Buffer buffer)
throws IOException
{
if(!this.started)
return;
return RESULT_CONTINUE;
try
{
int canread =
(int)PortAudio.Pa_GetStreamReadAvailable(getStream());
if(canread < 1)
canread = 512;
byte[] bytebuff = new byte[canread*sampleSize];
PortAudio.Pa_ReadStream(getStream(), bytebuff, canread);
buffer.setTimeStamp(System.nanoTime());
buffer.setData(bytebuff);
buffer.setSequenceNumber(seqNo);
buffer.setLength(bytebuff.length);
buffer.setFlags(0);
buffer.setHeader(null);
seqNo++;
}
catch (PortAudioException e)
{
logger.error("", e);
}
}
/**
* Extracts the device index from the locator.
* @param locator the locator containing the device index.
* @return the extracted device index.
*/
public static int getDeviceIndexFromLocator(MediaLocator locator)
{
return Integer.parseInt(locator.toExternalForm().replace(
PortAudioStream.LOCATOR_PREFIX, ""));
}
}

@ -12,6 +12,7 @@
import net.java.sip.communicator.impl.media.protocol.portaudio.*;
/**
* Portaudio renderer.
*
* @author Damian Minkov
*/
@ -22,41 +23,55 @@ public class PortAudioRenderer
Logger.getLogger(PortAudioRenderer.class);
private static final String name = "PortAudio Renderer";
public static Format[] supportedInputFormats = new Format[]
{
new AudioFormat(
private static AudioFormat audioFormat =
new AudioFormat(
AudioFormat.LINEAR,
44100,
48000,
16,
1,
2,
AudioFormat.LITTLE_ENDIAN,
AudioFormat.SIGNED,
16,
Format.NOT_SPECIFIED,
Format.byteArray)
Format.byteArray);
/**
* The supported input formats.
*/
public static Format[] supportedInputFormats = new Format[]
{
audioFormat
};
protected Object [] controls = new Object[0];
private Object [] controls = new Object[0];
private AudioFormat inputFormat;
private long stream = 0;
public PortAudioRenderer()
{
try
{
PortAudio.initialize();
}
catch (PortAudioException e)
{
logger.error("Cannot Initialize portaudio", e);
}
}
boolean started = false;
private WriterThread writerThread = null;
private final Object bufferSync = new Object();
private byte[] buffer = null;
private static int deviceIndex = -1;
/**
* Lists the input formats supported by this Renderer.
* @return An array of Format objects that represent
* the input formats supported by this Renderer.
*/
public Format[] getSupportedInputFormats()
{
return supportedInputFormats;
return new Format[]{audioFormat};
}
/**
* Sets the Format of the input data.
* @param format the format to set.
* @return The Format that was set.
*/
public Format setInputFormat(Format format)
{
if(!(format instanceof AudioFormat))
@ -69,10 +84,16 @@ public Format setInputFormat(Format format)
return inputFormat;
}
/**
* Initiates the rendering process.
* When start is called, the renderer begins rendering
* any data available in its internal buffers.
*/
public void start()
{
try
{
{
started = true;
PortAudio.Pa_StartStream(stream);
}
catch (PortAudioException e)
@ -81,34 +102,52 @@ public void start()
}
}
/**
* Halts the rendering process.
*/
public void stop()
{
try
synchronized(bufferSync)
{
PortAudio.Pa_CloseStream(stream);
}
catch (PortAudioException e)
{
logger.error("Closing portaudio stream failed", e);
try
{
PortAudio.Pa_CloseStream(stream);
writerThread = null;
started = false;
}
catch (PortAudioException e)
{
logger.error("Closing portaudio stream failed", e);
}
}
}
/**
* Processes the data and renders it
* to the output device represented by this Renderer.
* @param inputBuffer the input data.
* @return BUFFER_PROCESSED_OK if the processing is successful.
*/
public int process(Buffer inputBuffer)
{
try
synchronized(bufferSync)
{
byte[] buff = new byte[inputBuffer.getLength()];
System.arraycopy(
(byte[])inputBuffer.getData(),
inputBuffer.getOffset(),
buff,
0,
buff.length);
PortAudio.Pa_WriteStream(stream, buff, buff.length/2);
System.arraycopy(
(byte[])inputBuffer.getData(),
inputBuffer.getOffset(),
buff,
0,
buff.length);
buffer = buff;
bufferSync.notifyAll();
}
catch (PortAudioException e)
if(writerThread == null)
{
logger.error("Error write to device!", e);
writerThread = new WriterThread();
writerThread.start();
}
return BUFFER_PROCESSED_OK;
@ -116,12 +155,18 @@ public int process(Buffer inputBuffer)
/**
* Returns the name of the pluging.
* @return A String that contains the descriptive name of the plug-in.
*/
public String getName()
{
return name;
}
/**
* Opens the device and stream that we will use to render data.
* @throws ResourceUnavailableException If required resources cannot
* be opened/created.
*/
public void open()
throws ResourceUnavailableException
{
@ -129,31 +174,17 @@ public void open()
{
if (stream == 0)
{
int deviceCount = PortAudio.Pa_GetDeviceCount();
int deviceIndex = 0;
for (; deviceIndex < deviceCount; deviceIndex++)
{
long deviceInfo = PortAudio.Pa_GetDeviceInfo(deviceIndex);
if ((PortAudio.PaDeviceInfo_getMaxOutputChannels(deviceInfo) == 2)
&& (PortAudio.PaDeviceInfo_getMaxInputChannels(deviceInfo) == 2)
&& PortAudio.PaDeviceInfo_getName(deviceInfo)
.contains("Analog"))
break;
}
long streamParameters
= PortAudio.PaStreamParameters_new(
deviceIndex,
1,
audioFormat.getChannels(),
PortAudio.SAMPLE_FORMAT_INT16);
stream
= PortAudio.Pa_OpenStream(
0,
streamParameters,
44100,
audioFormat.getSampleRate(),
PortAudio.FRAMES_PER_BUFFER_UNSPECIFIED,
PortAudio.STREAM_FLAGS_NO_FLAG,
null);
@ -166,14 +197,14 @@ public void open()
}
/**
*
* Closes the plug-in.
*/
public void close()
{
}
/**
*
* Resets the state of the plug-in.
*/
public void reset()
{
@ -181,7 +212,7 @@ public void reset()
/**
* Gives control information to the caller
*
* @return the collection of object controls.
*/
public Object[] getControls()
{
@ -190,7 +221,9 @@ public Object[] getControls()
/**
* Return required control from the Control[] array
* if exists, that is
* if exists.
* @param controlType the control we are interested in.
* @return the object that implements the control, or null.
*/
public Object getControl(String controlType)
{
@ -213,4 +246,60 @@ public Object getControl(String controlType)
return null;
}
}
/**
* Used to set the device index used by the renderer common for all
* instances of it.
* @param locator the locator containing the device index.
*/
public static void setDevice(MediaLocator locator)
{
deviceIndex = PortAudioStream.getDeviceIndexFromLocator(locator);
}
/**
* Writes data to the portaudio stream. If there is no data for
* particular time write some silence so we wont hear some cracks in
* the sound.
*/
private class WriterThread
extends Thread
{
public WriterThread()
{
setName("Portaudio Renderer");
}
public void run()
{
while(true)
{
try
{
synchronized(bufferSync)
{
// put some silence if there is no data
if(buffer == null)
{
buffer = new byte[1024];
}
PortAudio.Pa_WriteStream(
stream, buffer, buffer.length/4);
buffer = null;
bufferSync.wait(90);
}
if(!started)
return;
}
catch (Exception e)
{
logger.error("writing to stream", e);
}
}
}
}
}

Loading…
Cancel
Save