use semaphore to ensure last webcam service task has completed before closing stream

This commit is contained in:
Craig Raw 2025-05-29 14:17:58 +02:00
parent 74c298fd93
commit 3fdf093a26

View file

@ -27,6 +27,8 @@ import java.awt.image.BufferedImage;
import java.awt.image.WritableRaster;
import java.util.*;
import java.util.List;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@ -34,6 +36,8 @@ import java.util.stream.Stream;
public class WebcamService extends ScheduledService<Image> {
private static final Logger log = LoggerFactory.getLogger(WebcamService.class);
private final Semaphore taskSemaphore = new Semaphore(1, true);
private List<CaptureDevice> devices;
private List<CaptureDevice> availableDevices;
private Set<WebcamResolution> resolutions;
@ -106,6 +110,7 @@ public class WebcamService extends ScheduledService<Image> {
return new Task<>() {
@Override
protected Image call() throws Exception {
taskSemaphore.acquire();
try {
if(devices == null) {
devices = capture.getDevices();
@ -207,6 +212,7 @@ public class WebcamService extends ScheduledService<Image> {
return image;
} finally {
opening.set(false);
taskSemaphore.release();
}
}
};
@ -221,12 +227,24 @@ public class WebcamService extends ScheduledService<Image> {
@Override
public boolean cancel() {
boolean cancelled = super.cancel();
try {
if(taskSemaphore.tryAcquire(1, TimeUnit.SECONDS)) {
taskSemaphore.release();
} else {
log.error("Timed out waiting for task semaphore to be available to cancel, cancelling anyway");
}
} catch(InterruptedException e) {
log.error("Interrupted while waiting for task semaphore to be available to cancel, cancelling anyway");
}
if(stream != null) {
stream.close();
opened.set(false);
}
return super.cancel();
return cancelled;
}
public void close() {