All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.sarxos.webcam.ds.ipcam.IpCamDriver Maven / Gradle / Ivy

package com.github.sarxos.webcam.ds.ipcam;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.CancellationException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.github.sarxos.webcam.WebcamDevice;
import com.github.sarxos.webcam.WebcamDiscoverySupport;
import com.github.sarxos.webcam.WebcamDriver;
import com.github.sarxos.webcam.WebcamExceptionHandler;


/**
 * IP camera driver.
 *
 * @author Bartosz Firyn (sarxos)
 */
public class IpCamDriver implements WebcamDriver, WebcamDiscoverySupport {

	/**
	 * Thread factory.
	 *
	 * @author Bartosz Firyn (sarxos)
	 */
	private static class DeviceCheckThreadFactory implements ThreadFactory {

		/**
		 * Next number for created thread.
		 */
		private AtomicInteger number = new AtomicInteger();

		@Override
		public Thread newThread(Runnable r) {
			Thread t = new Thread(r, "online-check-" + number.incrementAndGet());
			t.setUncaughtExceptionHandler(WebcamExceptionHandler.getInstance());
			t.setDaemon(true);
			return t;
		}
	}

	/**
	 * Logger.
	 */
	private static final Logger LOG = LoggerFactory.getLogger(IpCamDriver.class);

	/**
	 * Thread factory.
	 */
	private static final ThreadFactory THREAD_FACTORY = new DeviceCheckThreadFactory();

	/**
	 * The callable to query single IP camera device. Callable getter will return device if it's
	 * online or null if it's offline.
	 *
	 * @author Bartosz Firyn (sarxos)
	 */
	private static class DeviceOnlineCheck implements Callable {

		/**
		 * IP camera device.
		 */
		private final IpCamDevice device;

		private final CountDownLatch latch;

		/**
		 * The callable to query single IP camera device.
		 *
		 * @param device the device to check online status
		 * @param latch the count down latch
		 */
		public DeviceOnlineCheck(IpCamDevice device, CountDownLatch latch) {
			this.device = device;
			this.latch = latch;
		}

		@Override
		public IpCamDevice call() throws Exception {
			try {
				return device.isOnline() ? device : null;
			} finally {
				latch.countDown();
			}
		}
	}

	/**
	 * Discovery scan interval in milliseconds.
	 */
	private volatile long scanInterval = 10000;

	/**
	 * Discovery scan timeout in milliseconds. This is maximum time which executor will wait for
	 * online detection to succeed.
	 */
	private volatile long scanTimeout = 10000;

	/**
	 * Is discovery scanning possible.
	 */
	private volatile boolean scanning = false;

	/**
	 * Execution service.
	 */
	private final ExecutorService executor = Executors.newCachedThreadPool(THREAD_FACTORY);

	public IpCamDriver() {
		this(null, false);
	}

	public IpCamDriver(boolean scanning) {
		this(null, scanning);
	}

	public IpCamDriver(IpCamStorage storage) {
		this(storage, false);
	}

	public IpCamDriver(IpCamStorage storage, boolean scanning) {
		if (storage != null) {
			storage.open();
		}
		this.scanning = scanning;
	}

	@Override
	public List getDevices() {

		// in case when scanning is disabled (by default) this method will
		// return all registered devices

		if (!isScanPossible()) {
			return Collections.unmodifiableList((List) IpCamDeviceRegistry.getIpCameras());
		}

		// if scanning is enabled, this method will first perform HTTP lookup
		// for every IP camera device and only online devices will be returned

		List devices = IpCamDeviceRegistry.getIpCameras();
		CountDownLatch latch = new CountDownLatch(devices.size());
		List> futures = new ArrayList>(devices.size());

		for (IpCamDevice device : devices) {
			futures.add(executor.submit(new DeviceOnlineCheck(device, latch)));
		}

		try {
			if (!latch.await(scanTimeout, TimeUnit.MILLISECONDS)) {
				for (Future future : futures) {
					if (!future.isDone()) {
						future.cancel(true);
					}
				}
			}
		} catch (InterruptedException e1) {
			return null;
		}

		List online = new ArrayList(devices.size());

		for (Future future : futures) {

			IpCamDevice device = null;
			try {
				if ((device = future.get()) != null) {
					online.add(device);
				}
			} catch (InterruptedException e) {
				LOG.debug(e.getMessage(), e);
			} catch (CancellationException e) {
				continue;
			} catch (ExecutionException e) {
				LOG.error(e.getMessage(), e);
			}
		}

		return Collections.unmodifiableList((List) online);
	}

	public void register(IpCamDevice device) {
		IpCamDeviceRegistry.register(device);
	}

	public void unregister(IpCamDevice device) {
		IpCamDeviceRegistry.unregister(device);
	}

	@Override
	public boolean isThreadSafe() {
		return true;
	}

	@Override
	public String toString() {
		return getClass().getSimpleName();
	}

	@Override
	public long getScanInterval() {
		return scanInterval;
	}

	/**
	 * Set new scan interval. Value must be given in milliseconds and shall not be negative.
	 *
	 * @param scanInterval
	 */
	public void setScanInterval(long scanInterval) {
		if (scanInterval > 0) {
			this.scanInterval = scanInterval;
		} else {
			throw new IllegalArgumentException("Scan interval for IP camera cannot be negative");
		}
	}

	@Override
	public boolean isScanPossible() {
		return scanning;
	}

	/**
	 * Set discovery scanning possible.
	 *
	 * @param scanning
	 */
	public void setScanPossible(boolean scanning) {
		this.scanning = scanning;
	}

	/**
	 * @return Scan timeout in milliseconds
	 */
	public long getScanTimeout() {
		return scanTimeout;
	}

	/**
	 * Set new scan timeout. This value cannot be less than 1000 milliseconds (which equals 1
	 * second).
	 *
	 * @param scanTimeout the scan timeout in milliseconds
	 */
	public void setScanTimeout(long scanTimeout) {
		if (scanTimeout < 1000) {
			scanTimeout = 1000;
		}
		this.scanTimeout = scanTimeout;
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy