Sunday, May 29, 2011

JMF Video Chat Explained - Querying Devices



These series should give you insight into the architecture and implementation of my video chat.
This time I will dive into querying devices (Webcams, Audio Cards) with the help of JMF(Java Media Framework).

Overview

  • Learn how to query media devices in JMF
Let's start

This is the window where all the magic happens. Clicking on "Query Devices" will start querying all available media devices. The question is what steps are required to perform this task?

Let's have a look at the source code:

DevicesGUI.java

     private class StartQueryingDevices implements ActionListener{

private DevicesGUI devicesGUI;

public StartQueryingDevices(DevicesGUI devicesGUI){
this.devicesGUI = devicesGUI;
}

public void actionPerformed(ActionEvent e) {
queryDevicesButton.setEnabled(false);
QueryDevicesThread qdt = new QueryDevicesThread();
qdt.addDeviceStatusListener(devicesGUI);
Thread t = new Thread(qdt);
t.start();
}

}


This inner class handles the click on the "Query Devices" Button. When clicked we create a new "QueryDevicesThread" and activate the Listener Pattern, so we get informed when the querying of devices has ended. Finally we start the thread. Let's look into the Thread.

QueryDevicesThread.java

package de.boehme.app.videochat.thread;

import java.util.logging.Logger;

import de.boehme.app.videochat.exception.ConsoleLogType;
import de.boehme.app.videochat.server.IDeviceQueryListener;

public class QueryDevicesThread implements Runnable {

private Logger log = Logger.getLogger(this.getClass().getName());

private IDeviceQueryListener deviceListener;

public void run() {

queryDevices();
deviceListener.ready();
}

private synchronized void queryDevices(){
//darf erst anfangen wenn alle anderen fertig sind
Class<?> directAudio = null;
Class<?> autoAudio = null;
Class<?> autoVideo = null;
Class<?> autoVideoPlus = null;
@SuppressWarnings("unused")
Object instanceAudio;
@SuppressWarnings("unused")
Object instanceVideo;
@SuppressWarnings("unused")
Object instanceVideoPlus;

// video... Windows
try {
autoVideo = Class.forName("VFWAuto");
} catch (Exception e) {
deviceListener.writeToConsole("No VFWAuto", ConsoleLogType.WARNING, log);
}

if (autoVideo == null) {
try {
autoVideo = Class.forName("SunVideoAuto");
} catch (Exception ee) {
deviceListener.writeToConsole("No SunVideoAuto", ConsoleLogType.WARNING, log);
}
try {
autoVideoPlus = Class.forName("SunVideoPlusAuto");
} catch (Exception ee) {
deviceListener.writeToConsole("No SunVideoPlusAuto", ConsoleLogType.WARNING, log);
}
}
// Linux??
if (autoVideo == null) {
try {
autoVideo = Class.forName("V4LAuto");
} catch (Exception eee) {
deviceListener.writeToConsole("No V4LAuto", ConsoleLogType.WARNING, log);
}
}

if (autoVideo != null)
try {
instanceVideo = autoVideo.newInstance();
} catch (InstantiationException e1) {
e1.printStackTrace();
} catch (IllegalAccessException e1) {
e1.printStackTrace();
}
if (autoVideoPlus != null)
try {
instanceVideoPlus = autoVideoPlus.newInstance();
} catch (InstantiationException e1) {
e1.printStackTrace();
} catch (IllegalAccessException e1) {
e1.printStackTrace();
}

// audio...

try {
directAudio = Class.forName("DirectSoundAuto");
} catch (Exception e) {
deviceListener.writeToConsole("No DirectSoundAuto", ConsoleLogType.WARNING, log);
}

try {
autoAudio = Class.forName("JavaSoundAuto");
} catch (Exception e) {
deviceListener.writeToConsole("No JavaSoundAuto", ConsoleLogType.WARNING, log);
}

if (directAudio != null)
try {
instanceAudio = directAudio.newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
if (autoAudio != null)
try {
instanceAudio = autoAudio.newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}

public void addDeviceStatusListener(IDeviceQueryListener deviceListener){
this.deviceListener = deviceListener;
}
}


Whats happening here? Well, when the thread is started the method "queryDevices" will be called. Note: The Method is "synchronized" because the querying of devices will take place at a different spot, namely the .dlls will do the whole work for us. Thats why we dont have any control over the process, except to choose which type of devices should get queried. This can be seen when looking at autoVideo = Class.forName("VFWAuto");. Here we will look for the Video for windows driver and call him. The same operation will happen later for different operating systems like Linux.

As the querying is finished, we call .ready() method to return to the GUI class and display the resulting devices list.

That's all.

1 comment: