mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-19 00:41:43 +00:00
cscore: Change impl to only one singleton (#1398)
This avoids a number of shutdown use-after-free races by controlling the destruction order. It also is a prerequisite to making the internal interfaces mockable for unit testing.
This commit is contained in:
@@ -13,6 +13,7 @@
|
||||
#include <wpi/SmallString.h>
|
||||
|
||||
#include "Handle.h"
|
||||
#include "Instance.h"
|
||||
#include "Log.h"
|
||||
#include "Notifier.h"
|
||||
#include "c_util.h"
|
||||
@@ -20,14 +21,17 @@
|
||||
|
||||
using namespace cs;
|
||||
|
||||
CvSinkImpl::CvSinkImpl(const wpi::Twine& name) : SinkImpl{name} {
|
||||
CvSinkImpl::CvSinkImpl(const wpi::Twine& name, wpi::Logger& logger,
|
||||
Notifier& notifier, Telemetry& telemetry)
|
||||
: SinkImpl{name, logger, notifier, telemetry} {
|
||||
m_active = true;
|
||||
// m_thread = std::thread(&CvSinkImpl::ThreadMain, this);
|
||||
}
|
||||
|
||||
CvSinkImpl::CvSinkImpl(const wpi::Twine& name,
|
||||
CvSinkImpl::CvSinkImpl(const wpi::Twine& name, wpi::Logger& logger,
|
||||
Notifier& notifier, Telemetry& telemetry,
|
||||
std::function<void(uint64_t time)> processFrame)
|
||||
: SinkImpl{name} {}
|
||||
: SinkImpl{name, logger, notifier, telemetry} {}
|
||||
|
||||
CvSinkImpl::~CvSinkImpl() { Stop(); }
|
||||
|
||||
@@ -119,24 +123,28 @@ void CvSinkImpl::ThreadMain() {
|
||||
namespace cs {
|
||||
|
||||
CS_Sink CreateCvSink(const wpi::Twine& name, CS_Status* status) {
|
||||
auto sink = std::make_shared<CvSinkImpl>(name);
|
||||
auto handle = Sinks::GetInstance().Allocate(CS_SINK_CV, sink);
|
||||
Notifier::GetInstance().NotifySink(name, handle, CS_SINK_CREATED);
|
||||
auto& inst = Instance::GetInstance();
|
||||
auto sink = std::make_shared<CvSinkImpl>(name, inst.logger, inst.notifier,
|
||||
inst.telemetry);
|
||||
auto handle = inst.sinks.Allocate(CS_SINK_CV, sink);
|
||||
inst.notifier.NotifySink(name, handle, CS_SINK_CREATED);
|
||||
return handle;
|
||||
}
|
||||
|
||||
CS_Sink CreateCvSinkCallback(const wpi::Twine& name,
|
||||
std::function<void(uint64_t time)> processFrame,
|
||||
CS_Status* status) {
|
||||
auto sink = std::make_shared<CvSinkImpl>(name, processFrame);
|
||||
auto handle = Sinks::GetInstance().Allocate(CS_SINK_CV, sink);
|
||||
Notifier::GetInstance().NotifySink(name, handle, CS_SINK_CREATED);
|
||||
auto& inst = Instance::GetInstance();
|
||||
auto sink = std::make_shared<CvSinkImpl>(name, inst.logger, inst.notifier,
|
||||
inst.telemetry, processFrame);
|
||||
auto handle = inst.sinks.Allocate(CS_SINK_CV, sink);
|
||||
inst.notifier.NotifySink(name, handle, CS_SINK_CREATED);
|
||||
return handle;
|
||||
}
|
||||
|
||||
void SetSinkDescription(CS_Sink sink, const wpi::Twine& description,
|
||||
CS_Status* status) {
|
||||
auto data = Sinks::GetInstance().Get(sink);
|
||||
auto data = Instance::GetInstance().sinks.Get(sink);
|
||||
if (!data || data->kind != CS_SINK_CV) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return;
|
||||
@@ -145,7 +153,7 @@ void SetSinkDescription(CS_Sink sink, const wpi::Twine& description,
|
||||
}
|
||||
|
||||
uint64_t GrabSinkFrame(CS_Sink sink, cv::Mat& image, CS_Status* status) {
|
||||
auto data = Sinks::GetInstance().Get(sink);
|
||||
auto data = Instance::GetInstance().sinks.Get(sink);
|
||||
if (!data || data->kind != CS_SINK_CV) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return 0;
|
||||
@@ -155,7 +163,7 @@ uint64_t GrabSinkFrame(CS_Sink sink, cv::Mat& image, CS_Status* status) {
|
||||
|
||||
uint64_t GrabSinkFrameTimeout(CS_Sink sink, cv::Mat& image, double timeout,
|
||||
CS_Status* status) {
|
||||
auto data = Sinks::GetInstance().Get(sink);
|
||||
auto data = Instance::GetInstance().sinks.Get(sink);
|
||||
if (!data || data->kind != CS_SINK_CV) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return 0;
|
||||
@@ -164,7 +172,7 @@ uint64_t GrabSinkFrameTimeout(CS_Sink sink, cv::Mat& image, double timeout,
|
||||
}
|
||||
|
||||
std::string GetSinkError(CS_Sink sink, CS_Status* status) {
|
||||
auto data = Sinks::GetInstance().Get(sink);
|
||||
auto data = Instance::GetInstance().sinks.Get(sink);
|
||||
if (!data || data->kind != CS_SINK_CV) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return std::string{};
|
||||
@@ -174,7 +182,7 @@ std::string GetSinkError(CS_Sink sink, CS_Status* status) {
|
||||
|
||||
wpi::StringRef GetSinkError(CS_Sink sink, wpi::SmallVectorImpl<char>& buf,
|
||||
CS_Status* status) {
|
||||
auto data = Sinks::GetInstance().Get(sink);
|
||||
auto data = Instance::GetInstance().sinks.Get(sink);
|
||||
if (!data || data->kind != CS_SINK_CV) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return wpi::StringRef{};
|
||||
@@ -183,7 +191,7 @@ wpi::StringRef GetSinkError(CS_Sink sink, wpi::SmallVectorImpl<char>& buf,
|
||||
}
|
||||
|
||||
void SetSinkEnabled(CS_Sink sink, bool enabled, CS_Status* status) {
|
||||
auto data = Sinks::GetInstance().Get(sink);
|
||||
auto data = Instance::GetInstance().sinks.Get(sink);
|
||||
if (!data || data->kind != CS_SINK_CV) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return;
|
||||
|
||||
@@ -8,20 +8,17 @@
|
||||
#ifndef CSCORE_CVSINKIMPL_H_
|
||||
#define CSCORE_CVSINKIMPL_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
#include <wpi/NetworkAcceptor.h>
|
||||
#include <wpi/NetworkStream.h>
|
||||
#include <wpi/SmallVector.h>
|
||||
#include <wpi/StringRef.h>
|
||||
#include <opencv2/core/core.hpp>
|
||||
#include <wpi/Twine.h>
|
||||
#include <wpi/raw_istream.h>
|
||||
#include <wpi/raw_ostream.h>
|
||||
#include <wpi/raw_socket_ostream.h>
|
||||
#include <wpi/condition_variable.h>
|
||||
|
||||
#include "Frame.h"
|
||||
#include "SinkImpl.h"
|
||||
|
||||
namespace cs {
|
||||
@@ -30,8 +27,10 @@ class SourceImpl;
|
||||
|
||||
class CvSinkImpl : public SinkImpl {
|
||||
public:
|
||||
explicit CvSinkImpl(const wpi::Twine& name);
|
||||
CvSinkImpl(const wpi::Twine& name,
|
||||
CvSinkImpl(const wpi::Twine& name, wpi::Logger& logger, Notifier& notifier,
|
||||
Telemetry& telemetry);
|
||||
CvSinkImpl(const wpi::Twine& name, wpi::Logger& logger, Notifier& notifier,
|
||||
Telemetry& telemetry,
|
||||
std::function<void(uint64_t time)> processFrame);
|
||||
~CvSinkImpl() override;
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <wpi/timestamp.h>
|
||||
|
||||
#include "Handle.h"
|
||||
#include "Instance.h"
|
||||
#include "Log.h"
|
||||
#include "Notifier.h"
|
||||
#include "c_util.h"
|
||||
@@ -21,8 +22,10 @@
|
||||
|
||||
using namespace cs;
|
||||
|
||||
CvSourceImpl::CvSourceImpl(const wpi::Twine& name, const VideoMode& mode)
|
||||
: SourceImpl{name} {
|
||||
CvSourceImpl::CvSourceImpl(const wpi::Twine& name, wpi::Logger& logger,
|
||||
Notifier& notifier, Telemetry& telemetry,
|
||||
const VideoMode& mode)
|
||||
: SourceImpl{name, logger, notifier, telemetry} {
|
||||
m_mode = mode;
|
||||
m_videoModes.push_back(m_mode);
|
||||
}
|
||||
@@ -37,7 +40,7 @@ bool CvSourceImpl::SetVideoMode(const VideoMode& mode, CS_Status* status) {
|
||||
m_mode = mode;
|
||||
m_videoModes[0] = mode;
|
||||
}
|
||||
Notifier::GetInstance().NotifySourceVideoMode(*this, mode);
|
||||
m_notifier.NotifySourceVideoMode(*this, mode);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -105,8 +108,8 @@ int CvSourceImpl::CreateProperty(const wpi::Twine& name, CS_PropertyKind kind,
|
||||
prop.defaultValue = defaultValue;
|
||||
value = prop.value;
|
||||
});
|
||||
Notifier::GetInstance().NotifySourceProperty(
|
||||
*this, CS_SOURCE_PROPERTY_CREATED, name, ndx, kind, value, wpi::Twine{});
|
||||
m_notifier.NotifySourceProperty(*this, CS_SOURCE_PROPERTY_CREATED, name, ndx,
|
||||
kind, value, wpi::Twine{});
|
||||
return ndx;
|
||||
}
|
||||
|
||||
@@ -132,29 +135,30 @@ void CvSourceImpl::SetEnumPropertyChoices(int property,
|
||||
return;
|
||||
}
|
||||
prop->enumChoices = choices;
|
||||
Notifier::GetInstance().NotifySourceProperty(
|
||||
*this, CS_SOURCE_PROPERTY_CHOICES_UPDATED, prop->name, property,
|
||||
CS_PROP_ENUM, prop->value, wpi::Twine{});
|
||||
m_notifier.NotifySourceProperty(*this, CS_SOURCE_PROPERTY_CHOICES_UPDATED,
|
||||
prop->name, property, CS_PROP_ENUM,
|
||||
prop->value, wpi::Twine{});
|
||||
}
|
||||
|
||||
namespace cs {
|
||||
|
||||
CS_Source CreateCvSource(const wpi::Twine& name, const VideoMode& mode,
|
||||
CS_Status* status) {
|
||||
auto source = std::make_shared<CvSourceImpl>(name, mode);
|
||||
auto handle = Sources::GetInstance().Allocate(CS_SOURCE_CV, source);
|
||||
auto& notifier = Notifier::GetInstance();
|
||||
notifier.NotifySource(name, handle, CS_SOURCE_CREATED);
|
||||
auto& inst = Instance::GetInstance();
|
||||
auto source = std::make_shared<CvSourceImpl>(name, inst.logger, inst.notifier,
|
||||
inst.telemetry, mode);
|
||||
auto handle = inst.sources.Allocate(CS_SOURCE_CV, source);
|
||||
inst.notifier.NotifySource(name, handle, CS_SOURCE_CREATED);
|
||||
// Generate initial events here so they come after the source created event
|
||||
source->Start(); // causes a property event
|
||||
notifier.NotifySource(name, handle, CS_SOURCE_CONNECTED);
|
||||
notifier.NotifySource(name, handle, CS_SOURCE_VIDEOMODES_UPDATED);
|
||||
notifier.NotifySourceVideoMode(*source, mode);
|
||||
inst.notifier.NotifySource(name, handle, CS_SOURCE_CONNECTED);
|
||||
inst.notifier.NotifySource(name, handle, CS_SOURCE_VIDEOMODES_UPDATED);
|
||||
inst.notifier.NotifySourceVideoMode(*source, mode);
|
||||
return handle;
|
||||
}
|
||||
|
||||
void PutSourceFrame(CS_Source source, cv::Mat& image, CS_Status* status) {
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
auto data = Instance::GetInstance().sources.Get(source);
|
||||
if (!data || data->kind != CS_SOURCE_CV) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return;
|
||||
@@ -164,7 +168,7 @@ void PutSourceFrame(CS_Source source, cv::Mat& image, CS_Status* status) {
|
||||
|
||||
void NotifySourceError(CS_Source source, const wpi::Twine& msg,
|
||||
CS_Status* status) {
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
auto data = Instance::GetInstance().sources.Get(source);
|
||||
if (!data || data->kind != CS_SOURCE_CV) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return;
|
||||
@@ -173,7 +177,7 @@ void NotifySourceError(CS_Source source, const wpi::Twine& msg,
|
||||
}
|
||||
|
||||
void SetSourceConnected(CS_Source source, bool connected, CS_Status* status) {
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
auto data = Instance::GetInstance().sources.Get(source);
|
||||
if (!data || data->kind != CS_SOURCE_CV) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return;
|
||||
@@ -183,7 +187,7 @@ void SetSourceConnected(CS_Source source, bool connected, CS_Status* status) {
|
||||
|
||||
void SetSourceDescription(CS_Source source, const wpi::Twine& description,
|
||||
CS_Status* status) {
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
auto data = Instance::GetInstance().sources.Get(source);
|
||||
if (!data || data->kind != CS_SOURCE_CV) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return;
|
||||
@@ -195,7 +199,7 @@ CS_Property CreateSourceProperty(CS_Source source, const wpi::Twine& name,
|
||||
CS_PropertyKind kind, int minimum, int maximum,
|
||||
int step, int defaultValue, int value,
|
||||
CS_Status* status) {
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
auto data = Instance::GetInstance().sources.Get(source);
|
||||
if (!data || data->kind != CS_SOURCE_CV) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return -1;
|
||||
@@ -210,7 +214,7 @@ CS_Property CreateSourcePropertyCallback(
|
||||
CS_Source source, const wpi::Twine& name, CS_PropertyKind kind, int minimum,
|
||||
int maximum, int step, int defaultValue, int value,
|
||||
std::function<void(CS_Property property)> onChange, CS_Status* status) {
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
auto data = Instance::GetInstance().sources.Get(source);
|
||||
if (!data || data->kind != CS_SOURCE_CV) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return -1;
|
||||
@@ -224,7 +228,7 @@ CS_Property CreateSourcePropertyCallback(
|
||||
void SetSourceEnumPropertyChoices(CS_Source source, CS_Property property,
|
||||
wpi::ArrayRef<std::string> choices,
|
||||
CS_Status* status) {
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
auto data = Instance::GetInstance().sources.Get(source);
|
||||
if (!data || data->kind != CS_SOURCE_CV) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return;
|
||||
@@ -237,7 +241,7 @@ void SetSourceEnumPropertyChoices(CS_Source source, CS_Property property,
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return;
|
||||
}
|
||||
auto data2 = Sources::GetInstance().Get(Handle{i, Handle::kSource});
|
||||
auto data2 = Instance::GetInstance().sources.Get(Handle{i, Handle::kSource});
|
||||
if (!data2 || data->source.get() != data2->source.get()) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return;
|
||||
|
||||
@@ -14,13 +14,18 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <opencv2/core/core.hpp>
|
||||
#include <wpi/ArrayRef.h>
|
||||
#include <wpi/Twine.h>
|
||||
|
||||
#include "SourceImpl.h"
|
||||
|
||||
namespace cs {
|
||||
|
||||
class CvSourceImpl : public SourceImpl {
|
||||
public:
|
||||
CvSourceImpl(const wpi::Twine& name, const VideoMode& mode);
|
||||
CvSourceImpl(const wpi::Twine& name, wpi::Logger& logger, Notifier& notifier,
|
||||
Telemetry& telemetry, const VideoMode& mode);
|
||||
~CvSourceImpl() override;
|
||||
|
||||
void Start();
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <opencv2/highgui/highgui.hpp>
|
||||
#include <opencv2/imgproc/imgproc.hpp>
|
||||
|
||||
#include "Instance.h"
|
||||
#include "Log.h"
|
||||
#include "SourceImpl.h"
|
||||
|
||||
@@ -450,9 +451,11 @@ Image* Frame::GetImageImpl(int width, int height,
|
||||
if (!cur || cur->Is(width, height, pixelFormat, requiredJpegQuality))
|
||||
return cur;
|
||||
|
||||
DEBUG4("converting image from "
|
||||
<< cur->width << "x" << cur->height << " type " << cur->pixelFormat
|
||||
<< " to " << width << "x" << height << " type " << pixelFormat);
|
||||
WPI_DEBUG4(Instance::GetInstance().logger,
|
||||
"converting image from " << cur->width << "x" << cur->height
|
||||
<< " type " << cur->pixelFormat << " to "
|
||||
<< width << "x" << height << " type "
|
||||
<< pixelFormat);
|
||||
|
||||
// If the source image is a JPEG, we need to decode it before we can do
|
||||
// anything else with it. Note that if the destination format is JPEG, we
|
||||
|
||||
@@ -8,20 +8,10 @@
|
||||
#ifndef CSCORE_HANDLE_H_
|
||||
#define CSCORE_HANDLE_H_
|
||||
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include <wpi/StringRef.h>
|
||||
|
||||
#include "UnlimitedHandleResource.h"
|
||||
#include "cscore_c.h"
|
||||
|
||||
namespace cs {
|
||||
|
||||
class SinkImpl;
|
||||
class SourceImpl;
|
||||
|
||||
// Handle data layout:
|
||||
// Bits 0-15: Handle index
|
||||
// Bits 16-23: Parent index (property only)
|
||||
@@ -74,59 +64,6 @@ class Handle {
|
||||
CS_Handle m_handle;
|
||||
};
|
||||
|
||||
struct SourceData {
|
||||
SourceData(CS_SourceKind kind_, std::shared_ptr<SourceImpl> source_)
|
||||
: kind{kind_}, refCount{0}, source{source_} {}
|
||||
|
||||
CS_SourceKind kind;
|
||||
std::atomic_int refCount;
|
||||
std::shared_ptr<SourceImpl> source;
|
||||
};
|
||||
|
||||
class Sources
|
||||
: public UnlimitedHandleResource<Handle, SourceData, Handle::kSource> {
|
||||
public:
|
||||
static Sources& GetInstance() {
|
||||
static Sources instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
std::pair<CS_Source, std::shared_ptr<SourceData>> Find(
|
||||
const SourceImpl& source) {
|
||||
return FindIf(
|
||||
[&](const SourceData& data) { return data.source.get() == &source; });
|
||||
}
|
||||
|
||||
private:
|
||||
Sources() = default;
|
||||
};
|
||||
|
||||
struct SinkData {
|
||||
explicit SinkData(CS_SinkKind kind_, std::shared_ptr<SinkImpl> sink_)
|
||||
: kind{kind_}, refCount{0}, sourceHandle{0}, sink{sink_} {}
|
||||
|
||||
CS_SinkKind kind;
|
||||
std::atomic_int refCount;
|
||||
std::atomic<CS_Source> sourceHandle;
|
||||
std::shared_ptr<SinkImpl> sink;
|
||||
};
|
||||
|
||||
class Sinks : public UnlimitedHandleResource<Handle, SinkData, Handle::kSink> {
|
||||
public:
|
||||
static Sinks& GetInstance() {
|
||||
static Sinks instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
std::pair<CS_Sink, std::shared_ptr<SinkData>> Find(const SinkImpl& sink) {
|
||||
return FindIf(
|
||||
[&](const SinkData& data) { return data.sink.get() == &sink; });
|
||||
}
|
||||
|
||||
private:
|
||||
Sinks() = default;
|
||||
};
|
||||
|
||||
} // namespace cs
|
||||
|
||||
#endif // CSCORE_HANDLE_H_
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <wpi/timestamp.h>
|
||||
|
||||
#include "Handle.h"
|
||||
#include "Instance.h"
|
||||
#include "JpegUtil.h"
|
||||
#include "Log.h"
|
||||
#include "Notifier.h"
|
||||
@@ -21,8 +22,10 @@
|
||||
|
||||
using namespace cs;
|
||||
|
||||
HttpCameraImpl::HttpCameraImpl(const wpi::Twine& name, CS_HttpCameraKind kind)
|
||||
: SourceImpl{name}, m_kind{kind} {}
|
||||
HttpCameraImpl::HttpCameraImpl(const wpi::Twine& name, CS_HttpCameraKind kind,
|
||||
wpi::Logger& logger, Notifier& notifier,
|
||||
Telemetry& telemetry)
|
||||
: SourceImpl{name, logger, notifier, telemetry}, m_kind{kind} {}
|
||||
|
||||
HttpCameraImpl::~HttpCameraImpl() {
|
||||
m_active = false;
|
||||
@@ -106,8 +109,8 @@ wpi::HttpConnection* HttpCameraImpl::DeviceStreamConnect(
|
||||
}
|
||||
|
||||
// Try to connect
|
||||
auto stream = wpi::TCPConnector::connect(req.host.c_str(), req.port,
|
||||
Logger::GetInstance(), 1);
|
||||
auto stream =
|
||||
wpi::TCPConnector::connect(req.host.c_str(), req.port, m_logger, 1);
|
||||
|
||||
if (!m_active || !stream) return nullptr;
|
||||
|
||||
@@ -268,8 +271,8 @@ void HttpCameraImpl::SettingsThreadMain() {
|
||||
|
||||
void HttpCameraImpl::DeviceSendSettings(wpi::HttpRequest& req) {
|
||||
// Try to connect
|
||||
auto stream = wpi::TCPConnector::connect(req.host.c_str(), req.port,
|
||||
Logger::GetInstance(), 1);
|
||||
auto stream =
|
||||
wpi::TCPConnector::connect(req.host.c_str(), req.port, m_logger, 1);
|
||||
|
||||
if (!m_active || !stream) return;
|
||||
|
||||
@@ -332,9 +335,9 @@ void HttpCameraImpl::CreateProperty(const wpi::Twine& name,
|
||||
name, httpParam, viaSettings, kind, minimum, maximum, step, defaultValue,
|
||||
value));
|
||||
|
||||
Notifier::GetInstance().NotifySourceProperty(
|
||||
*this, CS_SOURCE_PROPERTY_CREATED, name, m_propertyData.size() + 1, kind,
|
||||
value, wpi::Twine{});
|
||||
m_notifier.NotifySourceProperty(*this, CS_SOURCE_PROPERTY_CREATED, name,
|
||||
m_propertyData.size() + 1, kind, value,
|
||||
wpi::Twine{});
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@@ -350,12 +353,12 @@ void HttpCameraImpl::CreateEnumProperty(
|
||||
enumChoices.clear();
|
||||
for (const auto& choice : choices) enumChoices.emplace_back(choice);
|
||||
|
||||
Notifier::GetInstance().NotifySourceProperty(
|
||||
*this, CS_SOURCE_PROPERTY_CREATED, name, m_propertyData.size() + 1,
|
||||
CS_PROP_ENUM, value, wpi::Twine{});
|
||||
Notifier::GetInstance().NotifySourceProperty(
|
||||
*this, CS_SOURCE_PROPERTY_CHOICES_UPDATED, name,
|
||||
m_propertyData.size() + 1, CS_PROP_ENUM, value, wpi::Twine{});
|
||||
m_notifier.NotifySourceProperty(*this, CS_SOURCE_PROPERTY_CREATED, name,
|
||||
m_propertyData.size() + 1, CS_PROP_ENUM,
|
||||
value, wpi::Twine{});
|
||||
m_notifier.NotifySourceProperty(*this, CS_SOURCE_PROPERTY_CHOICES_UPDATED,
|
||||
name, m_propertyData.size() + 1, CS_PROP_ENUM,
|
||||
value, wpi::Twine{});
|
||||
}
|
||||
|
||||
std::unique_ptr<PropertyImpl> HttpCameraImpl::CreateEmptyProperty(
|
||||
@@ -466,19 +469,21 @@ namespace cs {
|
||||
|
||||
CS_Source CreateHttpCamera(const wpi::Twine& name, const wpi::Twine& url,
|
||||
CS_HttpCameraKind kind, CS_Status* status) {
|
||||
auto& inst = Instance::GetInstance();
|
||||
std::shared_ptr<HttpCameraImpl> source;
|
||||
switch (kind) {
|
||||
case CS_HTTP_AXIS:
|
||||
source = std::make_shared<AxisCameraImpl>(name);
|
||||
source = std::make_shared<AxisCameraImpl>(name, inst.logger,
|
||||
inst.notifier, inst.telemetry);
|
||||
break;
|
||||
default:
|
||||
source = std::make_shared<HttpCameraImpl>(name, kind);
|
||||
source = std::make_shared<HttpCameraImpl>(name, kind, inst.logger,
|
||||
inst.notifier, inst.telemetry);
|
||||
break;
|
||||
}
|
||||
if (!source->SetUrls(url.str(), status)) return 0;
|
||||
auto handle = Sources::GetInstance().Allocate(CS_SOURCE_HTTP, source);
|
||||
auto& notifier = Notifier::GetInstance();
|
||||
notifier.NotifySource(name, handle, CS_SOURCE_CREATED);
|
||||
auto handle = inst.sources.Allocate(CS_SOURCE_HTTP, source);
|
||||
inst.notifier.NotifySource(name, handle, CS_SOURCE_CREATED);
|
||||
source->Start();
|
||||
return handle;
|
||||
}
|
||||
@@ -486,21 +491,22 @@ CS_Source CreateHttpCamera(const wpi::Twine& name, const wpi::Twine& url,
|
||||
CS_Source CreateHttpCamera(const wpi::Twine& name,
|
||||
wpi::ArrayRef<std::string> urls,
|
||||
CS_HttpCameraKind kind, CS_Status* status) {
|
||||
auto& inst = Instance::GetInstance();
|
||||
if (urls.empty()) {
|
||||
*status = CS_EMPTY_VALUE;
|
||||
return 0;
|
||||
}
|
||||
auto source = std::make_shared<HttpCameraImpl>(name, kind);
|
||||
auto source = std::make_shared<HttpCameraImpl>(name, kind, inst.logger,
|
||||
inst.notifier, inst.telemetry);
|
||||
if (!source->SetUrls(urls, status)) return 0;
|
||||
auto handle = Sources::GetInstance().Allocate(CS_SOURCE_HTTP, source);
|
||||
auto& notifier = Notifier::GetInstance();
|
||||
notifier.NotifySource(name, handle, CS_SOURCE_CREATED);
|
||||
auto handle = inst.sources.Allocate(CS_SOURCE_HTTP, source);
|
||||
inst.notifier.NotifySource(name, handle, CS_SOURCE_CREATED);
|
||||
source->Start();
|
||||
return handle;
|
||||
}
|
||||
|
||||
CS_HttpCameraKind GetHttpCameraKind(CS_Source source, CS_Status* status) {
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
auto data = Instance::GetInstance().sources.Get(source);
|
||||
if (!data || data->kind != CS_SOURCE_HTTP) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return CS_HTTP_UNKNOWN;
|
||||
@@ -514,7 +520,7 @@ void SetHttpCameraUrls(CS_Source source, wpi::ArrayRef<std::string> urls,
|
||||
*status = CS_EMPTY_VALUE;
|
||||
return;
|
||||
}
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
auto data = Instance::GetInstance().sources.Get(source);
|
||||
if (!data || data->kind != CS_SOURCE_HTTP) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return;
|
||||
@@ -524,7 +530,7 @@ void SetHttpCameraUrls(CS_Source source, wpi::ArrayRef<std::string> urls,
|
||||
|
||||
std::vector<std::string> GetHttpCameraUrls(CS_Source source,
|
||||
CS_Status* status) {
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
auto data = Instance::GetInstance().sources.Get(source);
|
||||
if (!data || data->kind != CS_SOURCE_HTTP) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return std::vector<std::string>{};
|
||||
|
||||
@@ -30,7 +30,8 @@ namespace cs {
|
||||
|
||||
class HttpCameraImpl : public SourceImpl {
|
||||
public:
|
||||
HttpCameraImpl(const wpi::Twine& name, CS_HttpCameraKind kind);
|
||||
HttpCameraImpl(const wpi::Twine& name, CS_HttpCameraKind kind,
|
||||
wpi::Logger& logger, Notifier& notifier, Telemetry& telemetry);
|
||||
~HttpCameraImpl() override;
|
||||
|
||||
void Start();
|
||||
@@ -140,8 +141,9 @@ class HttpCameraImpl : public SourceImpl {
|
||||
|
||||
class AxisCameraImpl : public HttpCameraImpl {
|
||||
public:
|
||||
explicit AxisCameraImpl(const wpi::Twine& name)
|
||||
: HttpCameraImpl{name, CS_HTTP_AXIS} {}
|
||||
AxisCameraImpl(const wpi::Twine& name, wpi::Logger& logger,
|
||||
Notifier& notifier, Telemetry& telemetry)
|
||||
: HttpCameraImpl{name, CS_HTTP_AXIS, logger, notifier, telemetry} {}
|
||||
#if 0
|
||||
void SetProperty(int property, int value, CS_Status* status) override;
|
||||
void SetStringProperty(int property, const wpi::Twine& value,
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#include "Log.h"
|
||||
#include "Instance.h"
|
||||
|
||||
#include <wpi/Path.h>
|
||||
#include <wpi/SmallString.h>
|
||||
@@ -38,8 +38,27 @@ static void def_log_func(unsigned int level, const char* file,
|
||||
wpi::errs() << oss.str();
|
||||
}
|
||||
|
||||
Logger::Logger() { SetDefaultLogger(); }
|
||||
Instance::Instance() : telemetry(notifier), network_listener(logger, notifier) {
|
||||
SetDefaultLogger();
|
||||
}
|
||||
|
||||
Logger::~Logger() {}
|
||||
Instance::~Instance() {}
|
||||
|
||||
void Logger::SetDefaultLogger() { SetLogger(def_log_func); }
|
||||
Instance& Instance::GetInstance() {
|
||||
static Instance inst;
|
||||
return inst;
|
||||
}
|
||||
|
||||
void Instance::SetDefaultLogger() { logger.SetLogger(def_log_func); }
|
||||
|
||||
std::pair<CS_Source, std::shared_ptr<SourceData>> Instance::FindSource(
|
||||
const SourceImpl& source) {
|
||||
return sources.FindIf(
|
||||
[&](const SourceData& data) { return data.source.get() == &source; });
|
||||
}
|
||||
|
||||
std::pair<CS_Sink, std::shared_ptr<SinkData>> Instance::FindSink(
|
||||
const SinkImpl& sink) {
|
||||
return sinks.FindIf(
|
||||
[&](const SinkData& data) { return data.sink.get() == &sink; });
|
||||
}
|
||||
75
cscore/src/main/native/cpp/Instance.h
Normal file
75
cscore/src/main/native/cpp/Instance.h
Normal file
@@ -0,0 +1,75 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef CSCORE_INSTANCE_H_
|
||||
#define CSCORE_INSTANCE_H_
|
||||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include <wpi/EventLoopRunner.h>
|
||||
#include <wpi/Logger.h>
|
||||
|
||||
#include "Log.h"
|
||||
#include "NetworkListener.h"
|
||||
#include "Notifier.h"
|
||||
#include "SinkImpl.h"
|
||||
#include "SourceImpl.h"
|
||||
#include "Telemetry.h"
|
||||
#include "UnlimitedHandleResource.h"
|
||||
|
||||
namespace cs {
|
||||
|
||||
struct SourceData {
|
||||
SourceData(CS_SourceKind kind_, std::shared_ptr<SourceImpl> source_)
|
||||
: kind{kind_}, refCount{0}, source{source_} {}
|
||||
|
||||
CS_SourceKind kind;
|
||||
std::atomic_int refCount;
|
||||
std::shared_ptr<SourceImpl> source;
|
||||
};
|
||||
|
||||
struct SinkData {
|
||||
explicit SinkData(CS_SinkKind kind_, std::shared_ptr<SinkImpl> sink_)
|
||||
: kind{kind_}, refCount{0}, sourceHandle{0}, sink{sink_} {}
|
||||
|
||||
CS_SinkKind kind;
|
||||
std::atomic_int refCount;
|
||||
std::atomic<CS_Source> sourceHandle;
|
||||
std::shared_ptr<SinkImpl> sink;
|
||||
};
|
||||
|
||||
class Instance {
|
||||
public:
|
||||
Instance(const Instance&) = delete;
|
||||
Instance& operator=(const Instance&) = delete;
|
||||
~Instance();
|
||||
|
||||
static Instance& GetInstance();
|
||||
|
||||
UnlimitedHandleResource<Handle, SourceData, Handle::kSource> sources;
|
||||
UnlimitedHandleResource<Handle, SinkData, Handle::kSink> sinks;
|
||||
|
||||
wpi::Logger logger;
|
||||
Notifier notifier;
|
||||
Telemetry telemetry;
|
||||
NetworkListener network_listener;
|
||||
wpi::EventLoopRunner event_loop;
|
||||
|
||||
std::pair<CS_Sink, std::shared_ptr<SinkData>> FindSink(const SinkImpl& sink);
|
||||
std::pair<CS_Source, std::shared_ptr<SourceData>> FindSource(
|
||||
const SourceImpl& source);
|
||||
|
||||
void SetDefaultLogger();
|
||||
|
||||
private:
|
||||
Instance();
|
||||
};
|
||||
|
||||
} // namespace cs
|
||||
|
||||
#endif // CSCORE_INSTANCE_H_
|
||||
@@ -10,34 +10,18 @@
|
||||
|
||||
#include <wpi/Logger.h>
|
||||
|
||||
namespace cs {
|
||||
|
||||
class Logger : public wpi::Logger {
|
||||
public:
|
||||
static Logger& GetInstance() {
|
||||
static Logger instance;
|
||||
return instance;
|
||||
}
|
||||
~Logger();
|
||||
|
||||
void SetDefaultLogger();
|
||||
|
||||
private:
|
||||
Logger();
|
||||
};
|
||||
|
||||
#define LOG(level, x) WPI_LOG(cs::Logger::GetInstance(), level, x)
|
||||
#define LOG(level, x) WPI_LOG(m_logger, level, x)
|
||||
|
||||
#undef ERROR
|
||||
#define ERROR(x) WPI_ERROR(cs::Logger::GetInstance(), x)
|
||||
#define WARNING(x) WPI_WARNING(cs::Logger::GetInstance(), x)
|
||||
#define INFO(x) WPI_INFO(cs::Logger::GetInstance(), x)
|
||||
#define ERROR(x) WPI_ERROR(m_logger, x)
|
||||
#define WARNING(x) WPI_WARNING(m_logger, x)
|
||||
#define INFO(x) WPI_INFO(m_logger, x)
|
||||
|
||||
#define DEBUG(x) WPI_DEBUG(cs::Logger::GetInstance(), x)
|
||||
#define DEBUG1(x) WPI_DEBUG1(cs::Logger::GetInstance(), x)
|
||||
#define DEBUG2(x) WPI_DEBUG2(cs::Logger::GetInstance(), x)
|
||||
#define DEBUG3(x) WPI_DEBUG3(cs::Logger::GetInstance(), x)
|
||||
#define DEBUG4(x) WPI_DEBUG4(cs::Logger::GetInstance(), x)
|
||||
#define DEBUG(x) WPI_DEBUG(m_logger, x)
|
||||
#define DEBUG1(x) WPI_DEBUG1(m_logger, x)
|
||||
#define DEBUG2(x) WPI_DEBUG2(m_logger, x)
|
||||
#define DEBUG3(x) WPI_DEBUG3(m_logger, x)
|
||||
#define DEBUG4(x) WPI_DEBUG4(m_logger, x)
|
||||
|
||||
#define SERROR(x) ERROR(GetName() << ": " << x)
|
||||
#define SWARNING(x) WARNING(GetName() << ": " << x)
|
||||
@@ -49,6 +33,4 @@ class Logger : public wpi::Logger {
|
||||
#define SDEBUG3(x) DEBUG3(GetName() << ": " << x)
|
||||
#define SDEBUG4(x) DEBUG4(GetName() << ": " << x)
|
||||
|
||||
} // namespace cs
|
||||
|
||||
#endif // CSCORE_LOG_H_
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <wpi/raw_socket_ostream.h>
|
||||
|
||||
#include "Handle.h"
|
||||
#include "Instance.h"
|
||||
#include "JpegUtil.h"
|
||||
#include "Log.h"
|
||||
#include "Notifier.h"
|
||||
@@ -73,7 +74,8 @@ static const char* endRootPage = "</div></body></html>";
|
||||
|
||||
class MjpegServerImpl::ConnThread : public wpi::SafeThread {
|
||||
public:
|
||||
explicit ConnThread(const wpi::Twine& name) : m_name(name.str()) {}
|
||||
explicit ConnThread(const wpi::Twine& name, wpi::Logger& logger)
|
||||
: m_name(name.str()), m_logger(logger) {}
|
||||
|
||||
void Main();
|
||||
|
||||
@@ -97,6 +99,7 @@ class MjpegServerImpl::ConnThread : public wpi::SafeThread {
|
||||
|
||||
private:
|
||||
std::string m_name;
|
||||
wpi::Logger& m_logger;
|
||||
|
||||
wpi::StringRef GetName() { return m_name; }
|
||||
|
||||
@@ -548,10 +551,11 @@ void MjpegServerImpl::ConnThread::SendJSON(wpi::raw_ostream& os,
|
||||
os.flush();
|
||||
}
|
||||
|
||||
MjpegServerImpl::MjpegServerImpl(const wpi::Twine& name,
|
||||
MjpegServerImpl::MjpegServerImpl(const wpi::Twine& name, wpi::Logger& logger,
|
||||
Notifier& notifier, Telemetry& telemetry,
|
||||
const wpi::Twine& listenAddress, int port,
|
||||
std::unique_ptr<wpi::NetworkAcceptor> acceptor)
|
||||
: SinkImpl{name},
|
||||
: SinkImpl{name, logger, notifier, telemetry},
|
||||
m_listenAddress(listenAddress.str()),
|
||||
m_port(port),
|
||||
m_acceptor{std::move(acceptor)} {
|
||||
@@ -865,7 +869,7 @@ void MjpegServerImpl::ServerThreadMain() {
|
||||
}
|
||||
|
||||
// Start it if not already started
|
||||
it->Start(GetName());
|
||||
it->Start(GetName(), m_logger);
|
||||
|
||||
auto nstreams =
|
||||
std::count_if(m_connThreads.begin(), m_connThreads.end(),
|
||||
@@ -909,20 +913,21 @@ namespace cs {
|
||||
CS_Sink CreateMjpegServer(const wpi::Twine& name,
|
||||
const wpi::Twine& listenAddress, int port,
|
||||
CS_Status* status) {
|
||||
auto& inst = Instance::GetInstance();
|
||||
wpi::SmallString<128> listenAddressBuf;
|
||||
auto sink = std::make_shared<MjpegServerImpl>(
|
||||
name, listenAddress, port,
|
||||
name, inst.logger, inst.notifier, inst.telemetry, listenAddress, port,
|
||||
std::unique_ptr<wpi::NetworkAcceptor>(new wpi::TCPAcceptor(
|
||||
port,
|
||||
listenAddress.toNullTerminatedStringRef(listenAddressBuf).data(),
|
||||
Logger::GetInstance())));
|
||||
auto handle = Sinks::GetInstance().Allocate(CS_SINK_MJPEG, sink);
|
||||
Notifier::GetInstance().NotifySink(name, handle, CS_SINK_CREATED);
|
||||
inst.logger)));
|
||||
auto handle = inst.sinks.Allocate(CS_SINK_MJPEG, sink);
|
||||
inst.notifier.NotifySink(name, handle, CS_SINK_CREATED);
|
||||
return handle;
|
||||
}
|
||||
|
||||
std::string GetMjpegServerListenAddress(CS_Sink sink, CS_Status* status) {
|
||||
auto data = Sinks::GetInstance().Get(sink);
|
||||
auto data = Instance::GetInstance().sinks.Get(sink);
|
||||
if (!data || data->kind != CS_SINK_MJPEG) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return std::string{};
|
||||
@@ -931,7 +936,7 @@ std::string GetMjpegServerListenAddress(CS_Sink sink, CS_Status* status) {
|
||||
}
|
||||
|
||||
int GetMjpegServerPort(CS_Sink sink, CS_Status* status) {
|
||||
auto data = Sinks::GetInstance().Get(sink);
|
||||
auto data = Instance::GetInstance().sinks.Get(sink);
|
||||
if (!data || data->kind != CS_SINK_MJPEG) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return 0;
|
||||
|
||||
@@ -31,8 +31,10 @@ class SourceImpl;
|
||||
|
||||
class MjpegServerImpl : public SinkImpl {
|
||||
public:
|
||||
MjpegServerImpl(const wpi::Twine& name, const wpi::Twine& listenAddress,
|
||||
int port, std::unique_ptr<wpi::NetworkAcceptor> acceptor);
|
||||
MjpegServerImpl(const wpi::Twine& name, wpi::Logger& logger,
|
||||
Notifier& notifier, Telemetry& telemetry,
|
||||
const wpi::Twine& listenAddress, int port,
|
||||
std::unique_ptr<wpi::NetworkAcceptor> acceptor);
|
||||
~MjpegServerImpl() override;
|
||||
|
||||
void Stop();
|
||||
|
||||
@@ -8,23 +8,25 @@
|
||||
#ifndef CSCORE_NETWORKLISTENER_H_
|
||||
#define CSCORE_NETWORKLISTENER_H_
|
||||
|
||||
#include <wpi/Logger.h>
|
||||
#include <wpi/SafeThread.h>
|
||||
|
||||
namespace cs {
|
||||
|
||||
class Notifier;
|
||||
|
||||
class NetworkListener {
|
||||
public:
|
||||
static NetworkListener& GetInstance() {
|
||||
static NetworkListener instance;
|
||||
return instance;
|
||||
}
|
||||
NetworkListener(wpi::Logger& logger, Notifier& notifier)
|
||||
: m_logger(logger), m_notifier(notifier) {}
|
||||
~NetworkListener();
|
||||
|
||||
void Start();
|
||||
void Stop();
|
||||
|
||||
private:
|
||||
NetworkListener() = default;
|
||||
wpi::Logger& m_logger;
|
||||
Notifier& m_notifier;
|
||||
|
||||
class Thread;
|
||||
wpi::SafeThreadOwner<Thread> m_owner;
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "Handle.h"
|
||||
#include "Instance.h"
|
||||
#include "SinkImpl.h"
|
||||
#include "SourceImpl.h"
|
||||
|
||||
@@ -157,7 +158,7 @@ void Notifier::NotifySource(const wpi::Twine& name, CS_Source source,
|
||||
}
|
||||
|
||||
void Notifier::NotifySource(const SourceImpl& source, CS_EventKind kind) {
|
||||
auto handleData = Sources::GetInstance().Find(source);
|
||||
auto handleData = Instance::GetInstance().FindSource(source);
|
||||
NotifySource(source.GetName(), handleData.first, kind);
|
||||
}
|
||||
|
||||
@@ -166,7 +167,7 @@ void Notifier::NotifySourceVideoMode(const SourceImpl& source,
|
||||
auto thr = m_owner.GetThread();
|
||||
if (!thr) return;
|
||||
|
||||
auto handleData = Sources::GetInstance().Find(source);
|
||||
auto handleData = Instance::GetInstance().FindSource(source);
|
||||
|
||||
thr->m_notifications.emplace(source.GetName(), handleData.first, mode);
|
||||
thr->m_cond.notify_one();
|
||||
@@ -179,7 +180,7 @@ void Notifier::NotifySourceProperty(const SourceImpl& source, CS_EventKind kind,
|
||||
auto thr = m_owner.GetThread();
|
||||
if (!thr) return;
|
||||
|
||||
auto handleData = Sources::GetInstance().Find(source);
|
||||
auto handleData = Instance::GetInstance().FindSource(source);
|
||||
|
||||
thr->m_notifications.emplace(
|
||||
propertyName, handleData.first, static_cast<RawEvent::Kind>(kind),
|
||||
@@ -198,7 +199,7 @@ void Notifier::NotifySink(const wpi::Twine& name, CS_Sink sink,
|
||||
}
|
||||
|
||||
void Notifier::NotifySink(const SinkImpl& sink, CS_EventKind kind) {
|
||||
auto handleData = Sinks::GetInstance().Find(sink);
|
||||
auto handleData = Instance::GetInstance().FindSink(sink);
|
||||
NotifySink(sink.GetName(), handleData.first, kind);
|
||||
}
|
||||
|
||||
@@ -221,7 +222,7 @@ void Notifier::NotifySinkProperty(const SinkImpl& sink, CS_EventKind kind,
|
||||
auto thr = m_owner.GetThread();
|
||||
if (!thr) return;
|
||||
|
||||
auto handleData = Sinks::GetInstance().Find(sink);
|
||||
auto handleData = Instance::GetInstance().FindSink(sink);
|
||||
|
||||
thr->m_notifications.emplace(
|
||||
propertyName, handleData.first, static_cast<RawEvent::Kind>(kind),
|
||||
|
||||
@@ -23,10 +23,7 @@ class Notifier {
|
||||
friend class NotifierTest;
|
||||
|
||||
public:
|
||||
static Notifier& GetInstance() {
|
||||
static Notifier instance;
|
||||
return instance;
|
||||
}
|
||||
Notifier();
|
||||
~Notifier();
|
||||
|
||||
void Start();
|
||||
@@ -62,8 +59,6 @@ class Notifier {
|
||||
void NotifyTelemetryUpdated();
|
||||
|
||||
private:
|
||||
Notifier();
|
||||
|
||||
class Thread;
|
||||
wpi::SafeThreadOwner<Thread> m_owner;
|
||||
|
||||
|
||||
@@ -7,12 +7,18 @@
|
||||
|
||||
#include "SinkImpl.h"
|
||||
|
||||
#include "Instance.h"
|
||||
#include "Notifier.h"
|
||||
#include "SourceImpl.h"
|
||||
|
||||
using namespace cs;
|
||||
|
||||
SinkImpl::SinkImpl(const wpi::Twine& name) : m_name{name.str()} {}
|
||||
SinkImpl::SinkImpl(const wpi::Twine& name, wpi::Logger& logger,
|
||||
Notifier& notifier, Telemetry& telemetry)
|
||||
: m_logger(logger),
|
||||
m_notifier(notifier),
|
||||
m_telemetry(telemetry),
|
||||
m_name{name.str()} {}
|
||||
|
||||
SinkImpl::~SinkImpl() {
|
||||
if (m_source) {
|
||||
@@ -37,7 +43,7 @@ void SinkImpl::Enable() {
|
||||
++m_enabledCount;
|
||||
if (m_enabledCount == 1) {
|
||||
if (m_source) m_source->EnableSink();
|
||||
Notifier::GetInstance().NotifySink(*this, CS_SINK_ENABLED);
|
||||
m_notifier.NotifySink(*this, CS_SINK_ENABLED);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,7 +52,7 @@ void SinkImpl::Disable() {
|
||||
--m_enabledCount;
|
||||
if (m_enabledCount == 0) {
|
||||
if (m_source) m_source->DisableSink();
|
||||
Notifier::GetInstance().NotifySink(*this, CS_SINK_DISABLED);
|
||||
m_notifier.NotifySink(*this, CS_SINK_DISABLED);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,11 +61,11 @@ void SinkImpl::SetEnabled(bool enabled) {
|
||||
if (enabled && m_enabledCount == 0) {
|
||||
if (m_source) m_source->EnableSink();
|
||||
m_enabledCount = 1;
|
||||
Notifier::GetInstance().NotifySink(*this, CS_SINK_ENABLED);
|
||||
m_notifier.NotifySink(*this, CS_SINK_ENABLED);
|
||||
} else if (!enabled && m_enabledCount > 0) {
|
||||
if (m_source) m_source->DisableSink();
|
||||
m_enabledCount = 0;
|
||||
Notifier::GetInstance().NotifySink(*this, CS_SINK_DISABLED);
|
||||
m_notifier.NotifySink(*this, CS_SINK_DISABLED);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,15 +103,14 @@ wpi::StringRef SinkImpl::GetError(wpi::SmallVectorImpl<char>& buf) const {
|
||||
}
|
||||
|
||||
void SinkImpl::NotifyPropertyCreated(int propIndex, PropertyImpl& prop) {
|
||||
auto& notifier = Notifier::GetInstance();
|
||||
notifier.NotifySinkProperty(*this, CS_SINK_PROPERTY_CREATED, prop.name,
|
||||
propIndex, prop.propKind, prop.value,
|
||||
prop.valueStr);
|
||||
m_notifier.NotifySinkProperty(*this, CS_SINK_PROPERTY_CREATED, prop.name,
|
||||
propIndex, prop.propKind, prop.value,
|
||||
prop.valueStr);
|
||||
// also notify choices updated event for enum types
|
||||
if (prop.propKind == CS_PROP_ENUM)
|
||||
notifier.NotifySinkProperty(*this, CS_SINK_PROPERTY_CHOICES_UPDATED,
|
||||
prop.name, propIndex, prop.propKind, prop.value,
|
||||
wpi::Twine{});
|
||||
m_notifier.NotifySinkProperty(*this, CS_SINK_PROPERTY_CHOICES_UPDATED,
|
||||
prop.name, propIndex, prop.propKind,
|
||||
prop.value, wpi::Twine{});
|
||||
}
|
||||
|
||||
void SinkImpl::UpdatePropertyValue(int property, bool setString, int value,
|
||||
@@ -119,10 +124,11 @@ void SinkImpl::UpdatePropertyValue(int property, bool setString, int value,
|
||||
prop->SetValue(value);
|
||||
|
||||
// Only notify updates after we've notified created
|
||||
if (m_properties_cached)
|
||||
Notifier::GetInstance().NotifySinkProperty(
|
||||
*this, CS_SINK_PROPERTY_VALUE_UPDATED, prop->name, property,
|
||||
prop->propKind, prop->value, prop->valueStr);
|
||||
if (m_properties_cached) {
|
||||
m_notifier.NotifySinkProperty(*this, CS_SINK_PROPERTY_VALUE_UPDATED,
|
||||
prop->name, property, prop->propKind,
|
||||
prop->value, prop->valueStr);
|
||||
}
|
||||
}
|
||||
|
||||
void SinkImpl::SetSourceImpl(std::shared_ptr<SourceImpl> source) {}
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include <wpi/Logger.h>
|
||||
#include <wpi/StringRef.h>
|
||||
#include <wpi/Twine.h>
|
||||
#include <wpi/mutex.h>
|
||||
@@ -20,10 +21,13 @@
|
||||
namespace cs {
|
||||
|
||||
class Frame;
|
||||
class Notifier;
|
||||
class Telemetry;
|
||||
|
||||
class SinkImpl : public PropertyContainer {
|
||||
public:
|
||||
explicit SinkImpl(const wpi::Twine& name);
|
||||
explicit SinkImpl(const wpi::Twine& name, wpi::Logger& logger,
|
||||
Notifier& notifier, Telemetry& telemetry);
|
||||
virtual ~SinkImpl();
|
||||
SinkImpl(const SinkImpl& queue) = delete;
|
||||
SinkImpl& operator=(const SinkImpl& queue) = delete;
|
||||
@@ -55,6 +59,11 @@ class SinkImpl : public PropertyContainer {
|
||||
|
||||
virtual void SetSourceImpl(std::shared_ptr<SourceImpl> source);
|
||||
|
||||
protected:
|
||||
wpi::Logger& m_logger;
|
||||
Notifier& m_notifier;
|
||||
Telemetry& m_telemetry;
|
||||
|
||||
private:
|
||||
std::string m_name;
|
||||
std::string m_description;
|
||||
|
||||
@@ -21,7 +21,12 @@ using namespace cs;
|
||||
|
||||
static constexpr size_t kMaxImagesAvail = 32;
|
||||
|
||||
SourceImpl::SourceImpl(const wpi::Twine& name) : m_name{name.str()} {
|
||||
SourceImpl::SourceImpl(const wpi::Twine& name, wpi::Logger& logger,
|
||||
Notifier& notifier, Telemetry& telemetry)
|
||||
: m_logger(logger),
|
||||
m_notifier(notifier),
|
||||
m_telemetry(telemetry),
|
||||
m_name{name.str()} {
|
||||
m_frame = Frame{*this, wpi::StringRef{}, 0};
|
||||
}
|
||||
|
||||
@@ -53,9 +58,9 @@ wpi::StringRef SourceImpl::GetDescription(
|
||||
void SourceImpl::SetConnected(bool connected) {
|
||||
bool wasConnected = m_connected.exchange(connected);
|
||||
if (wasConnected && !connected)
|
||||
Notifier::GetInstance().NotifySource(*this, CS_SOURCE_DISCONNECTED);
|
||||
m_notifier.NotifySource(*this, CS_SOURCE_DISCONNECTED);
|
||||
else if (!wasConnected && connected)
|
||||
Notifier::GetInstance().NotifySource(*this, CS_SOURCE_CONNECTED);
|
||||
m_notifier.NotifySource(*this, CS_SOURCE_CONNECTED);
|
||||
}
|
||||
|
||||
uint64_t SourceImpl::GetCurFrameTime() {
|
||||
@@ -215,9 +220,8 @@ void SourceImpl::PutFrame(VideoMode::PixelFormat pixelFormat, int width,
|
||||
|
||||
void SourceImpl::PutFrame(std::unique_ptr<Image> image, Frame::Time time) {
|
||||
// Update telemetry
|
||||
Telemetry::GetInstance().RecordSourceFrames(*this, 1);
|
||||
Telemetry::GetInstance().RecordSourceBytes(*this,
|
||||
static_cast<int>(image->size()));
|
||||
m_telemetry.RecordSourceFrames(*this, 1);
|
||||
m_telemetry.RecordSourceBytes(*this, static_cast<int>(image->size()));
|
||||
|
||||
// Update frame
|
||||
{
|
||||
@@ -241,15 +245,14 @@ void SourceImpl::PutError(const wpi::Twine& msg, Frame::Time time) {
|
||||
}
|
||||
|
||||
void SourceImpl::NotifyPropertyCreated(int propIndex, PropertyImpl& prop) {
|
||||
auto& notifier = Notifier::GetInstance();
|
||||
notifier.NotifySourceProperty(*this, CS_SOURCE_PROPERTY_CREATED, prop.name,
|
||||
propIndex, prop.propKind, prop.value,
|
||||
prop.valueStr);
|
||||
m_notifier.NotifySourceProperty(*this, CS_SOURCE_PROPERTY_CREATED, prop.name,
|
||||
propIndex, prop.propKind, prop.value,
|
||||
prop.valueStr);
|
||||
// also notify choices updated event for enum types
|
||||
if (prop.propKind == CS_PROP_ENUM)
|
||||
notifier.NotifySourceProperty(*this, CS_SOURCE_PROPERTY_CHOICES_UPDATED,
|
||||
prop.name, propIndex, prop.propKind,
|
||||
prop.value, wpi::Twine{});
|
||||
m_notifier.NotifySourceProperty(*this, CS_SOURCE_PROPERTY_CHOICES_UPDATED,
|
||||
prop.name, propIndex, prop.propKind,
|
||||
prop.value, wpi::Twine{});
|
||||
}
|
||||
|
||||
void SourceImpl::UpdatePropertyValue(int property, bool setString, int value,
|
||||
@@ -263,10 +266,11 @@ void SourceImpl::UpdatePropertyValue(int property, bool setString, int value,
|
||||
prop->SetValue(value);
|
||||
|
||||
// Only notify updates after we've notified created
|
||||
if (m_properties_cached)
|
||||
Notifier::GetInstance().NotifySourceProperty(
|
||||
*this, CS_SOURCE_PROPERTY_VALUE_UPDATED, prop->name, property,
|
||||
prop->propKind, prop->value, prop->valueStr);
|
||||
if (m_properties_cached) {
|
||||
m_notifier.NotifySourceProperty(*this, CS_SOURCE_PROPERTY_VALUE_UPDATED,
|
||||
prop->name, property, prop->propKind,
|
||||
prop->value, prop->valueStr);
|
||||
}
|
||||
}
|
||||
|
||||
void SourceImpl::ReleaseImage(std::unique_ptr<Image> image) {
|
||||
|
||||
@@ -15,23 +15,29 @@
|
||||
#include <vector>
|
||||
|
||||
#include <wpi/ArrayRef.h>
|
||||
#include <wpi/Logger.h>
|
||||
#include <wpi/StringRef.h>
|
||||
#include <wpi/Twine.h>
|
||||
#include <wpi/condition_variable.h>
|
||||
#include <wpi/mutex.h>
|
||||
|
||||
#include "Frame.h"
|
||||
#include "Handle.h"
|
||||
#include "Image.h"
|
||||
#include "PropertyContainer.h"
|
||||
#include "cscore_cpp.h"
|
||||
|
||||
namespace cs {
|
||||
|
||||
class Notifier;
|
||||
class Telemetry;
|
||||
|
||||
class SourceImpl : public PropertyContainer {
|
||||
friend class Frame;
|
||||
|
||||
public:
|
||||
explicit SourceImpl(const wpi::Twine& name);
|
||||
SourceImpl(const wpi::Twine& name, wpi::Logger& logger, Notifier& notifier,
|
||||
Telemetry& telemetry);
|
||||
virtual ~SourceImpl();
|
||||
SourceImpl(const SourceImpl& oth) = delete;
|
||||
SourceImpl& operator=(const SourceImpl& oth) = delete;
|
||||
@@ -146,6 +152,10 @@ class SourceImpl : public PropertyContainer {
|
||||
// Current video mode
|
||||
mutable VideoMode m_mode;
|
||||
|
||||
wpi::Logger& m_logger;
|
||||
Notifier& m_notifier;
|
||||
Telemetry& m_telemetry;
|
||||
|
||||
private:
|
||||
void ReleaseImage(std::unique_ptr<Image> image);
|
||||
std::unique_ptr<Frame::Impl> AllocFrameImpl();
|
||||
|
||||
@@ -14,15 +14,20 @@
|
||||
#include <wpi/timestamp.h>
|
||||
|
||||
#include "Handle.h"
|
||||
#include "Instance.h"
|
||||
#include "Notifier.h"
|
||||
#include "SourceImpl.h"
|
||||
#include "cscore_cpp.h"
|
||||
|
||||
using namespace cs;
|
||||
|
||||
class Telemetry::Thread : public wpi::SafeThread {
|
||||
public:
|
||||
explicit Thread(Notifier& notifier) : m_notifier(notifier) {}
|
||||
|
||||
void Main();
|
||||
|
||||
Notifier& m_notifier;
|
||||
wpi::DenseMap<std::pair<CS_Handle, int>, int64_t> m_user;
|
||||
wpi::DenseMap<std::pair<CS_Handle, int>, int64_t> m_current;
|
||||
double m_period = 0.0;
|
||||
@@ -41,11 +46,9 @@ int64_t Telemetry::Thread::GetValue(CS_Handle handle, CS_TelemetryKind kind,
|
||||
return it->getSecond();
|
||||
}
|
||||
|
||||
Telemetry::Telemetry() {}
|
||||
|
||||
Telemetry::~Telemetry() {}
|
||||
|
||||
void Telemetry::Start() { m_owner.Start(); }
|
||||
void Telemetry::Start() { m_owner.Start(m_notifier); }
|
||||
|
||||
void Telemetry::Stop() { m_owner.Stop(); }
|
||||
|
||||
@@ -74,7 +77,7 @@ void Telemetry::Thread::Main() {
|
||||
prevTime = curTime;
|
||||
|
||||
// notify
|
||||
Notifier::GetInstance().NotifyTelemetryUpdated();
|
||||
m_notifier.NotifyTelemetryUpdated();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,7 +120,7 @@ double Telemetry::GetAverageValue(CS_Handle handle, CS_TelemetryKind kind,
|
||||
void Telemetry::RecordSourceBytes(const SourceImpl& source, int quantity) {
|
||||
auto thr = m_owner.GetThread();
|
||||
if (!thr) return;
|
||||
auto handleData = Sources::GetInstance().Find(source);
|
||||
auto handleData = Instance::GetInstance().FindSource(source);
|
||||
thr->m_current[std::make_pair(Handle{handleData.first, Handle::kSource},
|
||||
static_cast<int>(CS_SOURCE_BYTES_RECEIVED))] +=
|
||||
quantity;
|
||||
@@ -126,7 +129,7 @@ void Telemetry::RecordSourceBytes(const SourceImpl& source, int quantity) {
|
||||
void Telemetry::RecordSourceFrames(const SourceImpl& source, int quantity) {
|
||||
auto thr = m_owner.GetThread();
|
||||
if (!thr) return;
|
||||
auto handleData = Sources::GetInstance().Find(source);
|
||||
auto handleData = Instance::GetInstance().FindSource(source);
|
||||
thr->m_current[std::make_pair(Handle{handleData.first, Handle::kSource},
|
||||
static_cast<int>(CS_SOURCE_FRAMES_RECEIVED))] +=
|
||||
quantity;
|
||||
|
||||
@@ -14,16 +14,14 @@
|
||||
|
||||
namespace cs {
|
||||
|
||||
class Notifier;
|
||||
class SourceImpl;
|
||||
|
||||
class Telemetry {
|
||||
friend class TelemetryTest;
|
||||
|
||||
public:
|
||||
static Telemetry& GetInstance() {
|
||||
static Telemetry instance;
|
||||
return instance;
|
||||
}
|
||||
explicit Telemetry(Notifier& notifier) : m_notifier(notifier) {}
|
||||
~Telemetry();
|
||||
|
||||
void Start();
|
||||
@@ -41,7 +39,7 @@ class Telemetry {
|
||||
void RecordSourceFrames(const SourceImpl& source, int quantity);
|
||||
|
||||
private:
|
||||
Telemetry();
|
||||
Notifier& m_notifier;
|
||||
|
||||
class Thread;
|
||||
wpi::SafeThreadOwner<Thread> m_owner;
|
||||
|
||||
@@ -163,20 +163,6 @@ UnlimitedHandleResource<THandle, TStruct, typeValue, TMutex>::FindIf(F func) {
|
||||
return std::make_pair(0, nullptr);
|
||||
}
|
||||
|
||||
template <typename THandle, typename TStruct, int typeValue,
|
||||
typename TMutex = wpi::mutex>
|
||||
class StaticUnlimitedHandleResource
|
||||
: public UnlimitedHandleResource<THandle, TStruct, typeValue, TMutex> {
|
||||
public:
|
||||
static StaticUnlimitedHandleResource& GetInstance() {
|
||||
static StaticUnlimitedHandleResource instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
private:
|
||||
StaticUnlimitedHandleResource() = default;
|
||||
};
|
||||
|
||||
} // namespace cs
|
||||
|
||||
#endif // CSCORE_UNLIMITEDHANDLERESOURCE_H_
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <wpi/hostname.h>
|
||||
|
||||
#include "Handle.h"
|
||||
#include "Instance.h"
|
||||
#include "Log.h"
|
||||
#include "NetworkListener.h"
|
||||
#include "Notifier.h"
|
||||
@@ -27,7 +28,7 @@ static std::shared_ptr<PropertyContainer> GetPropertyContainer(
|
||||
Handle handle{propertyHandle};
|
||||
if (handle.IsType(Handle::kProperty)) {
|
||||
int i = handle.GetParentIndex();
|
||||
auto data = Sources::GetInstance().Get(Handle{i, Handle::kSource});
|
||||
auto data = Instance::GetInstance().sources.Get(Handle{i, Handle::kSource});
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return nullptr;
|
||||
@@ -35,7 +36,7 @@ static std::shared_ptr<PropertyContainer> GetPropertyContainer(
|
||||
container = data->source;
|
||||
} else if (handle.IsType(Handle::kSinkProperty)) {
|
||||
int i = handle.GetParentIndex();
|
||||
auto data = Sinks::GetInstance().Get(Handle{i, Handle::kSink});
|
||||
auto data = Instance::GetInstance().sinks.Get(Handle{i, Handle::kSink});
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return nullptr;
|
||||
@@ -159,7 +160,7 @@ std::vector<std::string> GetEnumPropertyChoices(CS_Property property,
|
||||
//
|
||||
|
||||
CS_SourceKind GetSourceKind(CS_Source source, CS_Status* status) {
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
auto data = Instance::GetInstance().sources.Get(source);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return CS_SOURCE_UNKNOWN;
|
||||
@@ -168,7 +169,7 @@ CS_SourceKind GetSourceKind(CS_Source source, CS_Status* status) {
|
||||
}
|
||||
|
||||
std::string GetSourceName(CS_Source source, CS_Status* status) {
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
auto data = Instance::GetInstance().sources.Get(source);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return std::string{};
|
||||
@@ -178,7 +179,7 @@ std::string GetSourceName(CS_Source source, CS_Status* status) {
|
||||
|
||||
wpi::StringRef GetSourceName(CS_Source source, wpi::SmallVectorImpl<char>& buf,
|
||||
CS_Status* status) {
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
auto data = Instance::GetInstance().sources.Get(source);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return wpi::StringRef{};
|
||||
@@ -187,7 +188,7 @@ wpi::StringRef GetSourceName(CS_Source source, wpi::SmallVectorImpl<char>& buf,
|
||||
}
|
||||
|
||||
std::string GetSourceDescription(CS_Source source, CS_Status* status) {
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
auto data = Instance::GetInstance().sources.Get(source);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return std::string{};
|
||||
@@ -199,7 +200,7 @@ std::string GetSourceDescription(CS_Source source, CS_Status* status) {
|
||||
wpi::StringRef GetSourceDescription(CS_Source source,
|
||||
wpi::SmallVectorImpl<char>& buf,
|
||||
CS_Status* status) {
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
auto data = Instance::GetInstance().sources.Get(source);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return wpi::StringRef{};
|
||||
@@ -208,7 +209,7 @@ wpi::StringRef GetSourceDescription(CS_Source source,
|
||||
}
|
||||
|
||||
uint64_t GetSourceLastFrameTime(CS_Source source, CS_Status* status) {
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
auto data = Instance::GetInstance().sources.Get(source);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return 0;
|
||||
@@ -219,7 +220,7 @@ uint64_t GetSourceLastFrameTime(CS_Source source, CS_Status* status) {
|
||||
void SetSourceConnectionStrategy(CS_Source source,
|
||||
CS_ConnectionStrategy strategy,
|
||||
CS_Status* status) {
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
auto data = Instance::GetInstance().sources.Get(source);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return;
|
||||
@@ -228,7 +229,7 @@ void SetSourceConnectionStrategy(CS_Source source,
|
||||
}
|
||||
|
||||
bool IsSourceConnected(CS_Source source, CS_Status* status) {
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
auto data = Instance::GetInstance().sources.Get(source);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return false;
|
||||
@@ -237,7 +238,7 @@ bool IsSourceConnected(CS_Source source, CS_Status* status) {
|
||||
}
|
||||
|
||||
bool IsSourceEnabled(CS_Source source, CS_Status* status) {
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
auto data = Instance::GetInstance().sources.Get(source);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return false;
|
||||
@@ -247,7 +248,7 @@ bool IsSourceEnabled(CS_Source source, CS_Status* status) {
|
||||
|
||||
CS_Property GetSourceProperty(CS_Source source, const wpi::Twine& name,
|
||||
CS_Status* status) {
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
auto data = Instance::GetInstance().sources.Get(source);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return 0;
|
||||
@@ -263,7 +264,7 @@ CS_Property GetSourceProperty(CS_Source source, const wpi::Twine& name,
|
||||
wpi::ArrayRef<CS_Property> EnumerateSourceProperties(
|
||||
CS_Source source, wpi::SmallVectorImpl<CS_Property>& vec,
|
||||
CS_Status* status) {
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
auto data = Instance::GetInstance().sources.Get(source);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return 0;
|
||||
@@ -276,7 +277,7 @@ wpi::ArrayRef<CS_Property> EnumerateSourceProperties(
|
||||
}
|
||||
|
||||
VideoMode GetSourceVideoMode(CS_Source source, CS_Status* status) {
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
auto data = Instance::GetInstance().sources.Get(source);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return VideoMode{};
|
||||
@@ -286,7 +287,7 @@ VideoMode GetSourceVideoMode(CS_Source source, CS_Status* status) {
|
||||
|
||||
bool SetSourceVideoMode(CS_Source source, const VideoMode& mode,
|
||||
CS_Status* status) {
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
auto data = Instance::GetInstance().sources.Get(source);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return false;
|
||||
@@ -296,7 +297,7 @@ bool SetSourceVideoMode(CS_Source source, const VideoMode& mode,
|
||||
|
||||
bool SetSourcePixelFormat(CS_Source source, VideoMode::PixelFormat pixelFormat,
|
||||
CS_Status* status) {
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
auto data = Instance::GetInstance().sources.Get(source);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return false;
|
||||
@@ -306,7 +307,7 @@ bool SetSourcePixelFormat(CS_Source source, VideoMode::PixelFormat pixelFormat,
|
||||
|
||||
bool SetSourceResolution(CS_Source source, int width, int height,
|
||||
CS_Status* status) {
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
auto data = Instance::GetInstance().sources.Get(source);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return false;
|
||||
@@ -315,7 +316,7 @@ bool SetSourceResolution(CS_Source source, int width, int height,
|
||||
}
|
||||
|
||||
bool SetSourceFPS(CS_Source source, int fps, CS_Status* status) {
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
auto data = Instance::GetInstance().sources.Get(source);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return false;
|
||||
@@ -325,7 +326,7 @@ bool SetSourceFPS(CS_Source source, int fps, CS_Status* status) {
|
||||
|
||||
std::vector<VideoMode> EnumerateSourceVideoModes(CS_Source source,
|
||||
CS_Status* status) {
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
auto data = Instance::GetInstance().sources.Get(source);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return std::vector<VideoMode>{};
|
||||
@@ -336,13 +337,14 @@ std::vector<VideoMode> EnumerateSourceVideoModes(CS_Source source,
|
||||
wpi::ArrayRef<CS_Sink> EnumerateSourceSinks(CS_Source source,
|
||||
wpi::SmallVectorImpl<CS_Sink>& vec,
|
||||
CS_Status* status) {
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
auto& inst = Instance::GetInstance();
|
||||
auto data = inst.sources.Get(source);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return wpi::ArrayRef<CS_Sink>{};
|
||||
}
|
||||
vec.clear();
|
||||
Sinks::GetInstance().ForEach([&](CS_Sink sinkHandle, const SinkData& data) {
|
||||
inst.sinks.ForEach([&](CS_Sink sinkHandle, const SinkData& data) {
|
||||
if (source == data.sourceHandle.load()) vec.push_back(sinkHandle);
|
||||
});
|
||||
return vec;
|
||||
@@ -350,7 +352,7 @@ wpi::ArrayRef<CS_Sink> EnumerateSourceSinks(CS_Source source,
|
||||
|
||||
CS_Source CopySource(CS_Source source, CS_Status* status) {
|
||||
if (source == 0) return 0;
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
auto data = Instance::GetInstance().sources.Get(source);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return 0;
|
||||
@@ -361,16 +363,16 @@ CS_Source CopySource(CS_Source source, CS_Status* status) {
|
||||
|
||||
void ReleaseSource(CS_Source source, CS_Status* status) {
|
||||
if (source == 0) return;
|
||||
auto& inst = Sources::GetInstance();
|
||||
auto data = inst.Get(source);
|
||||
auto& inst = Instance::GetInstance();
|
||||
auto data = inst.sources.Get(source);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return;
|
||||
}
|
||||
if (data->refCount-- == 0) {
|
||||
Notifier::GetInstance().NotifySource(data->source->GetName(), source,
|
||||
CS_SOURCE_DESTROYED);
|
||||
inst.Free(source);
|
||||
inst.notifier.NotifySource(data->source->GetName(), source,
|
||||
CS_SOURCE_DESTROYED);
|
||||
inst.sources.Free(source);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -379,7 +381,7 @@ void ReleaseSource(CS_Source source, CS_Status* status) {
|
||||
//
|
||||
|
||||
void SetCameraBrightness(CS_Source source, int brightness, CS_Status* status) {
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
auto data = Instance::GetInstance().sources.Get(source);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return;
|
||||
@@ -388,7 +390,7 @@ void SetCameraBrightness(CS_Source source, int brightness, CS_Status* status) {
|
||||
}
|
||||
|
||||
int GetCameraBrightness(CS_Source source, CS_Status* status) {
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
auto data = Instance::GetInstance().sources.Get(source);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return 0;
|
||||
@@ -397,7 +399,7 @@ int GetCameraBrightness(CS_Source source, CS_Status* status) {
|
||||
}
|
||||
|
||||
void SetCameraWhiteBalanceAuto(CS_Source source, CS_Status* status) {
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
auto data = Instance::GetInstance().sources.Get(source);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return;
|
||||
@@ -406,7 +408,7 @@ void SetCameraWhiteBalanceAuto(CS_Source source, CS_Status* status) {
|
||||
}
|
||||
|
||||
void SetCameraWhiteBalanceHoldCurrent(CS_Source source, CS_Status* status) {
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
auto data = Instance::GetInstance().sources.Get(source);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return;
|
||||
@@ -416,7 +418,7 @@ void SetCameraWhiteBalanceHoldCurrent(CS_Source source, CS_Status* status) {
|
||||
|
||||
void SetCameraWhiteBalanceManual(CS_Source source, int value,
|
||||
CS_Status* status) {
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
auto data = Instance::GetInstance().sources.Get(source);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return;
|
||||
@@ -425,7 +427,7 @@ void SetCameraWhiteBalanceManual(CS_Source source, int value,
|
||||
}
|
||||
|
||||
void SetCameraExposureAuto(CS_Source source, CS_Status* status) {
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
auto data = Instance::GetInstance().sources.Get(source);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return;
|
||||
@@ -434,7 +436,7 @@ void SetCameraExposureAuto(CS_Source source, CS_Status* status) {
|
||||
}
|
||||
|
||||
void SetCameraExposureHoldCurrent(CS_Source source, CS_Status* status) {
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
auto data = Instance::GetInstance().sources.Get(source);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return;
|
||||
@@ -443,7 +445,7 @@ void SetCameraExposureHoldCurrent(CS_Source source, CS_Status* status) {
|
||||
}
|
||||
|
||||
void SetCameraExposureManual(CS_Source source, int value, CS_Status* status) {
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
auto data = Instance::GetInstance().sources.Get(source);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return;
|
||||
@@ -456,7 +458,7 @@ void SetCameraExposureManual(CS_Source source, int value, CS_Status* status) {
|
||||
//
|
||||
|
||||
CS_SinkKind GetSinkKind(CS_Sink sink, CS_Status* status) {
|
||||
auto data = Sinks::GetInstance().Get(sink);
|
||||
auto data = Instance::GetInstance().sinks.Get(sink);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return CS_SINK_UNKNOWN;
|
||||
@@ -465,7 +467,7 @@ CS_SinkKind GetSinkKind(CS_Sink sink, CS_Status* status) {
|
||||
}
|
||||
|
||||
std::string GetSinkName(CS_Sink sink, CS_Status* status) {
|
||||
auto data = Sinks::GetInstance().Get(sink);
|
||||
auto data = Instance::GetInstance().sinks.Get(sink);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return std::string{};
|
||||
@@ -475,7 +477,7 @@ std::string GetSinkName(CS_Sink sink, CS_Status* status) {
|
||||
|
||||
wpi::StringRef GetSinkName(CS_Sink sink, wpi::SmallVectorImpl<char>& buf,
|
||||
CS_Status* status) {
|
||||
auto data = Sinks::GetInstance().Get(sink);
|
||||
auto data = Instance::GetInstance().sinks.Get(sink);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return wpi::StringRef{};
|
||||
@@ -484,7 +486,7 @@ wpi::StringRef GetSinkName(CS_Sink sink, wpi::SmallVectorImpl<char>& buf,
|
||||
}
|
||||
|
||||
std::string GetSinkDescription(CS_Sink sink, CS_Status* status) {
|
||||
auto data = Sinks::GetInstance().Get(sink);
|
||||
auto data = Instance::GetInstance().sinks.Get(sink);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return std::string{};
|
||||
@@ -495,7 +497,7 @@ std::string GetSinkDescription(CS_Sink sink, CS_Status* status) {
|
||||
|
||||
wpi::StringRef GetSinkDescription(CS_Sink sink, wpi::SmallVectorImpl<char>& buf,
|
||||
CS_Status* status) {
|
||||
auto data = Sinks::GetInstance().Get(sink);
|
||||
auto data = Instance::GetInstance().sinks.Get(sink);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return wpi::StringRef{};
|
||||
@@ -505,7 +507,7 @@ wpi::StringRef GetSinkDescription(CS_Sink sink, wpi::SmallVectorImpl<char>& buf,
|
||||
|
||||
CS_Property GetSinkProperty(CS_Sink sink, const wpi::Twine& name,
|
||||
CS_Status* status) {
|
||||
auto data = Sinks::GetInstance().Get(sink);
|
||||
auto data = Instance::GetInstance().sinks.Get(sink);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return 0;
|
||||
@@ -520,7 +522,7 @@ CS_Property GetSinkProperty(CS_Sink sink, const wpi::Twine& name,
|
||||
|
||||
wpi::ArrayRef<CS_Property> EnumerateSinkProperties(
|
||||
CS_Sink sink, wpi::SmallVectorImpl<CS_Property>& vec, CS_Status* status) {
|
||||
auto data = Sinks::GetInstance().Get(sink);
|
||||
auto data = Instance::GetInstance().sinks.Get(sink);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return 0;
|
||||
@@ -532,7 +534,7 @@ wpi::ArrayRef<CS_Property> EnumerateSinkProperties(
|
||||
}
|
||||
|
||||
void SetSinkSource(CS_Sink sink, CS_Source source, CS_Status* status) {
|
||||
auto data = Sinks::GetInstance().Get(sink);
|
||||
auto data = Instance::GetInstance().sinks.Get(sink);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return;
|
||||
@@ -540,7 +542,7 @@ void SetSinkSource(CS_Sink sink, CS_Source source, CS_Status* status) {
|
||||
if (source == 0) {
|
||||
data->sink->SetSource(nullptr);
|
||||
} else {
|
||||
auto sourceData = Sources::GetInstance().Get(source);
|
||||
auto sourceData = Instance::GetInstance().sources.Get(source);
|
||||
if (!sourceData) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return;
|
||||
@@ -548,12 +550,12 @@ void SetSinkSource(CS_Sink sink, CS_Source source, CS_Status* status) {
|
||||
data->sink->SetSource(sourceData->source);
|
||||
}
|
||||
data->sourceHandle.store(source);
|
||||
Notifier::GetInstance().NotifySinkSourceChanged(data->sink->GetName(), sink,
|
||||
source);
|
||||
Instance::GetInstance().notifier.NotifySinkSourceChanged(
|
||||
data->sink->GetName(), sink, source);
|
||||
}
|
||||
|
||||
CS_Source GetSinkSource(CS_Sink sink, CS_Status* status) {
|
||||
auto data = Sinks::GetInstance().Get(sink);
|
||||
auto data = Instance::GetInstance().sinks.Get(sink);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return 0;
|
||||
@@ -563,7 +565,7 @@ CS_Source GetSinkSource(CS_Sink sink, CS_Status* status) {
|
||||
|
||||
CS_Property GetSinkSourceProperty(CS_Sink sink, const wpi::Twine& name,
|
||||
CS_Status* status) {
|
||||
auto data = Sinks::GetInstance().Get(sink);
|
||||
auto data = Instance::GetInstance().sinks.Get(sink);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return 0;
|
||||
@@ -573,7 +575,7 @@ CS_Property GetSinkSourceProperty(CS_Sink sink, const wpi::Twine& name,
|
||||
|
||||
CS_Sink CopySink(CS_Sink sink, CS_Status* status) {
|
||||
if (sink == 0) return 0;
|
||||
auto data = Sinks::GetInstance().Get(sink);
|
||||
auto data = Instance::GetInstance().sinks.Get(sink);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return 0;
|
||||
@@ -584,16 +586,15 @@ CS_Sink CopySink(CS_Sink sink, CS_Status* status) {
|
||||
|
||||
void ReleaseSink(CS_Sink sink, CS_Status* status) {
|
||||
if (sink == 0) return;
|
||||
auto& inst = Sinks::GetInstance();
|
||||
auto data = inst.Get(sink);
|
||||
auto& inst = Instance::GetInstance();
|
||||
auto data = inst.sinks.Get(sink);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return;
|
||||
}
|
||||
if (data->refCount-- == 0) {
|
||||
Notifier::GetInstance().NotifySink(data->sink->GetName(), sink,
|
||||
CS_SINK_DESTROYED);
|
||||
inst.Free(sink);
|
||||
inst.notifier.NotifySink(data->sink->GetName(), sink, CS_SINK_DESTROYED);
|
||||
inst.sinks.Free(sink);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -602,22 +603,22 @@ void ReleaseSink(CS_Sink sink, CS_Status* status) {
|
||||
//
|
||||
|
||||
void SetListenerOnStart(std::function<void()> onStart) {
|
||||
Notifier::GetInstance().SetOnStart(onStart);
|
||||
Instance::GetInstance().notifier.SetOnStart(onStart);
|
||||
}
|
||||
|
||||
void SetListenerOnExit(std::function<void()> onExit) {
|
||||
Notifier::GetInstance().SetOnExit(onExit);
|
||||
Instance::GetInstance().notifier.SetOnExit(onExit);
|
||||
}
|
||||
|
||||
CS_Listener AddListener(std::function<void(const RawEvent& event)> callback,
|
||||
int eventMask, bool immediateNotify,
|
||||
CS_Status* status) {
|
||||
int uid = Notifier::GetInstance().AddListener(callback, eventMask);
|
||||
auto& inst = Instance::GetInstance();
|
||||
int uid = inst.notifier.AddListener(callback, eventMask);
|
||||
if ((eventMask & CS_NETWORK_INTERFACES_CHANGED) != 0) {
|
||||
// start network interface event listener
|
||||
NetworkListener::GetInstance().Start();
|
||||
if (immediateNotify)
|
||||
Notifier::GetInstance().NotifyNetworkInterfacesChanged();
|
||||
inst.network_listener.Start();
|
||||
if (immediateNotify) inst.notifier.NotifyNetworkInterfacesChanged();
|
||||
}
|
||||
if (immediateNotify) {
|
||||
// TODO
|
||||
@@ -631,7 +632,7 @@ void RemoveListener(CS_Listener handle, CS_Status* status) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return;
|
||||
}
|
||||
Notifier::GetInstance().RemoveListener(uid);
|
||||
Instance::GetInstance().notifier.RemoveListener(uid);
|
||||
}
|
||||
|
||||
bool NotifierDestroyed() { return Notifier::destroyed(); }
|
||||
@@ -640,37 +641,39 @@ bool NotifierDestroyed() { return Notifier::destroyed(); }
|
||||
// Telemetry Functions
|
||||
//
|
||||
void SetTelemetryPeriod(double seconds) {
|
||||
Telemetry::GetInstance().Start();
|
||||
Telemetry::GetInstance().SetPeriod(seconds);
|
||||
auto& inst = Instance::GetInstance();
|
||||
inst.telemetry.Start();
|
||||
inst.telemetry.SetPeriod(seconds);
|
||||
}
|
||||
|
||||
double GetTelemetryElapsedTime() {
|
||||
return Telemetry::GetInstance().GetElapsedTime();
|
||||
return Instance::GetInstance().telemetry.GetElapsedTime();
|
||||
}
|
||||
|
||||
int64_t GetTelemetryValue(CS_Handle handle, CS_TelemetryKind kind,
|
||||
CS_Status* status) {
|
||||
return Telemetry::GetInstance().GetValue(handle, kind, status);
|
||||
return Instance::GetInstance().telemetry.GetValue(handle, kind, status);
|
||||
}
|
||||
|
||||
double GetTelemetryAverageValue(CS_Handle handle, CS_TelemetryKind kind,
|
||||
CS_Status* status) {
|
||||
return Telemetry::GetInstance().GetAverageValue(handle, kind, status);
|
||||
return Instance::GetInstance().telemetry.GetAverageValue(handle, kind,
|
||||
status);
|
||||
}
|
||||
|
||||
//
|
||||
// Logging Functions
|
||||
//
|
||||
void SetLogger(LogFunc func, unsigned int min_level) {
|
||||
Logger& logger = Logger::GetInstance();
|
||||
auto& logger = Instance::GetInstance().logger;
|
||||
logger.SetLogger(func);
|
||||
logger.set_min_level(min_level);
|
||||
}
|
||||
|
||||
void SetDefaultLogger(unsigned int min_level) {
|
||||
Logger& logger = Logger::GetInstance();
|
||||
logger.SetDefaultLogger();
|
||||
logger.set_min_level(min_level);
|
||||
auto& inst = Instance::GetInstance();
|
||||
inst.SetDefaultLogger();
|
||||
inst.logger.set_min_level(min_level);
|
||||
}
|
||||
|
||||
//
|
||||
@@ -679,12 +682,12 @@ void SetDefaultLogger(unsigned int min_level) {
|
||||
|
||||
wpi::ArrayRef<CS_Source> EnumerateSourceHandles(
|
||||
wpi::SmallVectorImpl<CS_Source>& vec, CS_Status* status) {
|
||||
return Sources::GetInstance().GetAll(vec);
|
||||
return Instance::GetInstance().sources.GetAll(vec);
|
||||
}
|
||||
|
||||
wpi::ArrayRef<CS_Sink> EnumerateSinkHandles(wpi::SmallVectorImpl<CS_Sink>& vec,
|
||||
CS_Status* status) {
|
||||
return Sinks::GetInstance().GetAll(vec);
|
||||
return Instance::GetInstance().sinks.GetAll(vec);
|
||||
}
|
||||
|
||||
std::string GetHostname() { return wpi::GetHostname(); }
|
||||
|
||||
@@ -27,8 +27,12 @@ using namespace cs;
|
||||
|
||||
class NetworkListener::Thread : public wpi::SafeThread {
|
||||
public:
|
||||
Thread(wpi::Logger& logger, Notifier& notifier)
|
||||
: m_logger(logger), m_notifier(notifier) {}
|
||||
void Main();
|
||||
|
||||
wpi::Logger& m_logger;
|
||||
Notifier& m_notifier;
|
||||
#ifdef __linux__
|
||||
int m_command_fd = -1;
|
||||
#endif
|
||||
@@ -36,10 +40,7 @@ class NetworkListener::Thread : public wpi::SafeThread {
|
||||
|
||||
NetworkListener::~NetworkListener() { Stop(); }
|
||||
|
||||
void NetworkListener::Start() {
|
||||
auto thr = m_owner.GetThread();
|
||||
if (!thr) m_owner.Start();
|
||||
}
|
||||
void NetworkListener::Start() { m_owner.Start(m_logger, m_notifier); }
|
||||
|
||||
void NetworkListener::Stop() {
|
||||
// Wake up thread
|
||||
@@ -125,7 +126,7 @@ void NetworkListener::Thread::Main() {
|
||||
if (nh->nlmsg_type == NLMSG_DONE) break;
|
||||
if (nh->nlmsg_type == RTM_NEWLINK || nh->nlmsg_type == RTM_DELLINK ||
|
||||
nh->nlmsg_type == RTM_NEWADDR || nh->nlmsg_type == RTM_DELADDR) {
|
||||
Notifier::GetInstance().NotifyNetworkInterfacesChanged();
|
||||
m_notifier.NotifyNetworkInterfacesChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include <wpi/timestamp.h>
|
||||
|
||||
#include "Handle.h"
|
||||
#include "Instance.h"
|
||||
#include "JpegUtil.h"
|
||||
#include "Log.h"
|
||||
#include "Notifier.h"
|
||||
@@ -209,14 +210,17 @@ static std::string GetDescriptionImpl(const char* cpath) {
|
||||
return std::string{};
|
||||
}
|
||||
|
||||
UsbCameraImpl::UsbCameraImpl(const wpi::Twine& name, const wpi::Twine& path)
|
||||
: SourceImpl{name},
|
||||
UsbCameraImpl::UsbCameraImpl(const wpi::Twine& name, wpi::Logger& logger,
|
||||
Notifier& notifier, Telemetry& telemetry,
|
||||
const wpi::Twine& path)
|
||||
: SourceImpl{name, logger, notifier, telemetry},
|
||||
m_path{path.str()},
|
||||
m_fd{-1},
|
||||
m_command_fd{eventfd(0, 0)},
|
||||
m_active{true} {
|
||||
SetDescription(GetDescriptionImpl(m_path.c_str()));
|
||||
SetQuirks();
|
||||
|
||||
CreateProperty(kPropConnectVerbose, [] {
|
||||
return std::make_unique<UsbCameraProperty>(kPropConnectVerbose,
|
||||
kPropConnectVerboseId,
|
||||
@@ -640,7 +644,7 @@ CS_StatusValue UsbCameraImpl::DeviceCmdSetMode(
|
||||
DeviceConnect();
|
||||
}
|
||||
if (wasStreaming) DeviceStreamOn();
|
||||
Notifier::GetInstance().NotifySourceVideoMode(*this, newMode);
|
||||
m_notifier.NotifySourceVideoMode(*this, newMode);
|
||||
lock.lock();
|
||||
} else if (newMode.fps != m_mode.fps) {
|
||||
m_mode = newMode;
|
||||
@@ -650,7 +654,7 @@ CS_StatusValue UsbCameraImpl::DeviceCmdSetMode(
|
||||
if (wasStreaming) DeviceStreamOff();
|
||||
DeviceSetFPS();
|
||||
if (wasStreaming) DeviceStreamOn();
|
||||
Notifier::GetInstance().NotifySourceVideoMode(*this, newMode);
|
||||
m_notifier.NotifySourceVideoMode(*this, newMode);
|
||||
lock.lock();
|
||||
}
|
||||
|
||||
@@ -886,7 +890,7 @@ void UsbCameraImpl::DeviceCacheMode() {
|
||||
if (formatChanged) DeviceSetMode();
|
||||
if (fpsChanged) DeviceSetFPS();
|
||||
|
||||
Notifier::GetInstance().NotifySourceVideoMode(*this, m_mode);
|
||||
m_notifier.NotifySourceVideoMode(*this, m_mode);
|
||||
}
|
||||
|
||||
void UsbCameraImpl::DeviceCacheProperty(
|
||||
@@ -1068,7 +1072,7 @@ void UsbCameraImpl::DeviceCacheVideoModes() {
|
||||
std::lock_guard<wpi::mutex> lock(m_mutex);
|
||||
m_videoModes.swap(modes);
|
||||
}
|
||||
Notifier::GetInstance().NotifySource(*this, CS_SOURCE_VIDEOMODES_UPDATED);
|
||||
m_notifier.NotifySource(*this, CS_SOURCE_VIDEOMODES_UPDATED);
|
||||
}
|
||||
|
||||
CS_StatusValue UsbCameraImpl::SendAndWait(Message&& msg) const {
|
||||
@@ -1259,9 +1263,11 @@ CS_Source CreateUsbCameraDev(const wpi::Twine& name, int dev,
|
||||
|
||||
CS_Source CreateUsbCameraPath(const wpi::Twine& name, const wpi::Twine& path,
|
||||
CS_Status* status) {
|
||||
auto source = std::make_shared<UsbCameraImpl>(name, path);
|
||||
auto handle = Sources::GetInstance().Allocate(CS_SOURCE_USB, source);
|
||||
Notifier::GetInstance().NotifySource(name, handle, CS_SOURCE_CREATED);
|
||||
auto& inst = Instance::GetInstance();
|
||||
auto source = std::make_shared<UsbCameraImpl>(
|
||||
name, inst.logger, inst.notifier, inst.telemetry, path);
|
||||
auto handle = inst.sources.Allocate(CS_SOURCE_USB, source);
|
||||
inst.notifier.NotifySource(name, handle, CS_SOURCE_CREATED);
|
||||
// Start thread after the source created event to ensure other events
|
||||
// come after it.
|
||||
source->Start();
|
||||
@@ -1269,7 +1275,7 @@ CS_Source CreateUsbCameraPath(const wpi::Twine& name, const wpi::Twine& path,
|
||||
}
|
||||
|
||||
std::string GetUsbCameraPath(CS_Source source, CS_Status* status) {
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
auto data = Instance::GetInstance().sources.Get(source);
|
||||
if (!data || data->kind != CS_SOURCE_USB) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return std::string{};
|
||||
@@ -1300,7 +1306,7 @@ std::vector<UsbCameraInfo> EnumerateUsbCameras(CS_Status* status) {
|
||||
closedir(dp);
|
||||
} else {
|
||||
// *status = ;
|
||||
ERROR("Could not open /dev");
|
||||
WPI_ERROR(Instance::GetInstance().logger, "Could not open /dev");
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
@@ -31,9 +31,13 @@
|
||||
|
||||
namespace cs {
|
||||
|
||||
class Notifier;
|
||||
class Telemetry;
|
||||
|
||||
class UsbCameraImpl : public SourceImpl {
|
||||
public:
|
||||
UsbCameraImpl(const wpi::Twine& name, const wpi::Twine& path);
|
||||
UsbCameraImpl(const wpi::Twine& name, wpi::Logger& logger, Notifier& notifier,
|
||||
Telemetry& telemetry, const wpi::Twine& path);
|
||||
~UsbCameraImpl() override;
|
||||
|
||||
void Start();
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <wpi/raw_istream.h>
|
||||
#include <wpi/raw_ostream.h>
|
||||
|
||||
#include "Instance.h"
|
||||
#include "Log.h"
|
||||
|
||||
namespace cs {
|
||||
@@ -150,8 +151,9 @@ int CheckedIoctl(int fd, unsigned long req, void* data, // NOLINT(runtime/int)
|
||||
if (!quiet && retval < 0) {
|
||||
wpi::SmallString<64> localfile{file};
|
||||
localfile.push_back('\0');
|
||||
ERROR("ioctl " << name << " failed at " << basename(localfile.data()) << ":"
|
||||
<< line << ": " << std::strerror(errno));
|
||||
WPI_ERROR(Instance::GetInstance().logger,
|
||||
"ioctl " << name << " failed at " << basename(localfile.data())
|
||||
<< ":" << line << ": " << std::strerror(errno));
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user