mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-19 00:41:43 +00:00
[cscore] Add USB camera change event (#3123)
This commit is contained in:
@@ -26,7 +26,8 @@ public class VideoEvent {
|
||||
kTelemetryUpdated(0x8000),
|
||||
kSinkPropertyCreated(0x10000),
|
||||
kSinkPropertyValueUpdated(0x20000),
|
||||
kSinkPropertyChoicesUpdated(0x40000);
|
||||
kSinkPropertyChoicesUpdated(0x40000),
|
||||
kUsbCamerasChanged(0x80000);
|
||||
|
||||
private final int value;
|
||||
|
||||
@@ -84,6 +85,8 @@ public class VideoEvent {
|
||||
return Kind.kSinkPropertyValueUpdated;
|
||||
case 0x40000:
|
||||
return Kind.kSinkPropertyChoicesUpdated;
|
||||
case 0x80000:
|
||||
return Kind.kUsbCamerasChanged;
|
||||
default:
|
||||
return Kind.kUnknown;
|
||||
}
|
||||
|
||||
@@ -36,7 +36,10 @@ static void def_log_func(unsigned int level, const char* file,
|
||||
wpi::errs() << oss.str();
|
||||
}
|
||||
|
||||
Instance::Instance() : telemetry(notifier), networkListener(logger, notifier) {
|
||||
Instance::Instance()
|
||||
: telemetry(notifier),
|
||||
networkListener(logger, notifier),
|
||||
usbCameraListener(logger, notifier) {
|
||||
SetDefaultLogger();
|
||||
}
|
||||
|
||||
@@ -52,6 +55,7 @@ void Instance::Shutdown() {
|
||||
m_sinks.FreeAll();
|
||||
m_sources.FreeAll();
|
||||
networkListener.Stop();
|
||||
usbCameraListener.Stop();
|
||||
telemetry.Stop();
|
||||
notifier.Stop();
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "SourceImpl.h"
|
||||
#include "Telemetry.h"
|
||||
#include "UnlimitedHandleResource.h"
|
||||
#include "UsbCameraListener.h"
|
||||
|
||||
namespace cs {
|
||||
|
||||
@@ -54,6 +55,7 @@ class Instance {
|
||||
Notifier notifier;
|
||||
Telemetry telemetry;
|
||||
NetworkListener networkListener;
|
||||
UsbCameraListener usbCameraListener;
|
||||
|
||||
private:
|
||||
UnlimitedHandleResource<Handle, SourceData, Handle::kSource> m_sources;
|
||||
|
||||
@@ -94,3 +94,7 @@ void Notifier::NotifyNetworkInterfacesChanged() {
|
||||
void Notifier::NotifyTelemetryUpdated() {
|
||||
Send(UINT_MAX, RawEvent::kTelemetryUpdated);
|
||||
}
|
||||
|
||||
void Notifier::NotifyUsbCamerasChanged() {
|
||||
Send(UINT_MAX, RawEvent::kUsbCamerasChanged);
|
||||
}
|
||||
|
||||
@@ -83,6 +83,7 @@ class Notifier : public wpi::CallbackManager<Notifier, impl::NotifierThread> {
|
||||
const wpi::Twine& valueStr);
|
||||
void NotifyNetworkInterfacesChanged();
|
||||
void NotifyTelemetryUpdated();
|
||||
void NotifyUsbCamerasChanged();
|
||||
};
|
||||
|
||||
} // namespace cs
|
||||
|
||||
31
cscore/src/main/native/cpp/UsbCameraListener.h
Normal file
31
cscore/src/main/native/cpp/UsbCameraListener.h
Normal file
@@ -0,0 +1,31 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
#ifndef CSCORE_USBCAMERALISTENER_H_
|
||||
#define CSCORE_USBCAMERALISTENER_H_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <wpi/Logger.h>
|
||||
|
||||
namespace cs {
|
||||
|
||||
class Notifier;
|
||||
|
||||
class UsbCameraListener {
|
||||
public:
|
||||
UsbCameraListener(wpi::Logger& logger, Notifier& notifier);
|
||||
~UsbCameraListener();
|
||||
|
||||
void Start();
|
||||
void Stop();
|
||||
|
||||
private:
|
||||
class Impl;
|
||||
std::unique_ptr<Impl> m_impl;
|
||||
};
|
||||
|
||||
} // namespace cs
|
||||
|
||||
#endif // CSCORE_USBCAMERALISTENER_H_
|
||||
@@ -718,6 +718,13 @@ static void StartBackground(int eventMask, bool immediateNotify) {
|
||||
inst.notifier.NotifyNetworkInterfacesChanged();
|
||||
}
|
||||
}
|
||||
if ((eventMask & CS_USB_CAMERAS_CHANGED) != 0) {
|
||||
// start network interface event listener
|
||||
inst.usbCameraListener.Start();
|
||||
if (immediateNotify) {
|
||||
inst.notifier.NotifyUsbCamerasChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CS_Listener AddListener(std::function<void(const RawEvent& event)> callback,
|
||||
|
||||
@@ -170,7 +170,8 @@ enum CS_EventKind {
|
||||
CS_TELEMETRY_UPDATED = 0x8000,
|
||||
CS_SINK_PROPERTY_CREATED = 0x10000,
|
||||
CS_SINK_PROPERTY_VALUE_UPDATED = 0x20000,
|
||||
CS_SINK_PROPERTY_CHOICES_UPDATED = 0x40000
|
||||
CS_SINK_PROPERTY_CHOICES_UPDATED = 0x40000,
|
||||
CS_USB_CAMERAS_CHANGED = 0x80000
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -116,7 +116,8 @@ struct RawEvent {
|
||||
kTelemetryUpdated = CS_TELEMETRY_UPDATED,
|
||||
kSinkPropertyCreated = CS_SINK_PROPERTY_CREATED,
|
||||
kSinkPropertyValueUpdated = CS_SINK_PROPERTY_VALUE_UPDATED,
|
||||
kSinkPropertyChoicesUpdated = CS_SINK_PROPERTY_CHOICES_UPDATED
|
||||
kSinkPropertyChoicesUpdated = CS_SINK_PROPERTY_CHOICES_UPDATED,
|
||||
kUsbCamerasChanged = CS_USB_CAMERAS_CHANGED
|
||||
};
|
||||
|
||||
RawEvent() = default;
|
||||
|
||||
55
cscore/src/main/native/linux/UsbCameraListener.cpp
Normal file
55
cscore/src/main/native/linux/UsbCameraListener.cpp
Normal file
@@ -0,0 +1,55 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
#include "UsbCameraListener.h"
|
||||
|
||||
#include <wpi/EventLoopRunner.h>
|
||||
#include <wpi/uv/FsEvent.h>
|
||||
#include <wpi/uv/Timer.h>
|
||||
|
||||
#include "Notifier.h"
|
||||
|
||||
using namespace cs;
|
||||
|
||||
class UsbCameraListener::Impl {
|
||||
public:
|
||||
explicit Impl(Notifier& notifier) : m_notifier(notifier) {}
|
||||
|
||||
Notifier& m_notifier;
|
||||
|
||||
std::unique_ptr<wpi::EventLoopRunner> m_runner;
|
||||
};
|
||||
|
||||
UsbCameraListener::UsbCameraListener(wpi::Logger& logger, Notifier& notifier)
|
||||
: m_impl(std::make_unique<Impl>(notifier)) {}
|
||||
|
||||
UsbCameraListener::~UsbCameraListener() = default;
|
||||
|
||||
void UsbCameraListener::Start() {
|
||||
if (!m_impl->m_runner) {
|
||||
m_impl->m_runner = std::make_unique<wpi::EventLoopRunner>();
|
||||
m_impl->m_runner->ExecAsync([impl = m_impl.get()](wpi::uv::Loop& loop) {
|
||||
auto refreshTimer = wpi::uv::Timer::Create(loop);
|
||||
refreshTimer->timeout.connect([notifier = &impl->m_notifier] {
|
||||
notifier->NotifyUsbCamerasChanged();
|
||||
});
|
||||
refreshTimer->Unreference();
|
||||
|
||||
auto devEvents = wpi::uv::FsEvent::Create(loop);
|
||||
devEvents->fsEvent.connect([refreshTimer](const char* fn, int flags) {
|
||||
if (wpi::StringRef(fn).startswith("video")) {
|
||||
refreshTimer->Start(wpi::uv::Timer::Time(200));
|
||||
}
|
||||
});
|
||||
devEvents->Start("/dev");
|
||||
devEvents->Unreference();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void UsbCameraListener::Stop() {
|
||||
if (m_impl->m_runner) {
|
||||
m_impl->m_runner.reset();
|
||||
}
|
||||
}
|
||||
17
cscore/src/main/native/osx/UsbCameraListener.cpp
Normal file
17
cscore/src/main/native/osx/UsbCameraListener.cpp
Normal file
@@ -0,0 +1,17 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
#include "UsbCameraListener.h"
|
||||
|
||||
using namespace cs;
|
||||
|
||||
class UsbCameraListener::Impl {};
|
||||
|
||||
UsbCameraListener::UsbCameraListener(wpi::Logger& logger, Notifier& notifier) {}
|
||||
|
||||
UsbCameraListener::~UsbCameraListener() = default;
|
||||
|
||||
void UsbCameraListener::Start() {}
|
||||
|
||||
void UsbCameraListener::Stop() {}
|
||||
72
cscore/src/main/native/windows/UsbCameraListener.cpp
Normal file
72
cscore/src/main/native/windows/UsbCameraListener.cpp
Normal file
@@ -0,0 +1,72 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
#include "UsbCameraListener.h"
|
||||
|
||||
#include "Notifier.h"
|
||||
#include "WindowsMessagePump.h"
|
||||
|
||||
#include <dbt.h> // NOLINT(build/include_order)
|
||||
|
||||
#define IDT_TIMER1 1001
|
||||
|
||||
using namespace cs;
|
||||
|
||||
class UsbCameraListener::Impl {
|
||||
public:
|
||||
explicit Impl(Notifier& notifier) : m_notifier{notifier} {}
|
||||
|
||||
void Start() {
|
||||
m_messagePump = std::make_unique<WindowsMessagePump>(
|
||||
[this](HWND hwnd, UINT uiMsg, WPARAM wParam, LPARAM lParam) {
|
||||
return this->PumpMain(hwnd, uiMsg, wParam, lParam);
|
||||
});
|
||||
}
|
||||
|
||||
void Stop() { m_messagePump = nullptr; }
|
||||
|
||||
LRESULT PumpMain(HWND hwnd, UINT uiMsg, WPARAM wParam, LPARAM lParam) {
|
||||
switch (uiMsg) {
|
||||
case WM_CLOSE:
|
||||
KillTimer(hwnd, IDT_TIMER1);
|
||||
break;
|
||||
case WM_TIMER:
|
||||
if (wParam == IDT_TIMER1) {
|
||||
KillTimer(hwnd, IDT_TIMER1);
|
||||
m_notifier.NotifyUsbCamerasChanged();
|
||||
}
|
||||
break;
|
||||
case WM_DEVICECHANGE:
|
||||
PDEV_BROADCAST_HDR parameter =
|
||||
reinterpret_cast<PDEV_BROADCAST_HDR>(lParam);
|
||||
if (wParam == DBT_DEVICEARRIVAL &&
|
||||
parameter->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE) {
|
||||
SetTimer(hwnd, IDT_TIMER1, 200, nullptr);
|
||||
} else if (wParam == DBT_DEVICEREMOVECOMPLETE &&
|
||||
parameter->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE) {
|
||||
SetTimer(hwnd, IDT_TIMER1, 200, nullptr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
Notifier& m_notifier;
|
||||
std::unique_ptr<cs::WindowsMessagePump> m_messagePump;
|
||||
};
|
||||
|
||||
UsbCameraListener::UsbCameraListener(wpi::Logger& logger, Notifier& notifier)
|
||||
: m_impl{std::make_unique<Impl>(notifier)} {}
|
||||
|
||||
UsbCameraListener::~UsbCameraListener() {
|
||||
Stop();
|
||||
}
|
||||
|
||||
void UsbCameraListener::Start() {
|
||||
m_impl->Start();
|
||||
}
|
||||
|
||||
void UsbCameraListener::Stop() {
|
||||
m_impl->Stop();
|
||||
}
|
||||
Reference in New Issue
Block a user