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:
Peter Johnson
2018-10-31 20:22:58 -07:00
committed by GitHub
parent 1dec0393a1
commit e27d6d7bb8
28 changed files with 433 additions and 356 deletions

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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();

View File

@@ -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

View File

@@ -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_

View File

@@ -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>{};

View File

@@ -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,

View File

@@ -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; });
}

View 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_

View File

@@ -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_

View File

@@ -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;

View File

@@ -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();

View File

@@ -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;

View File

@@ -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),

View File

@@ -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;

View File

@@ -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) {}

View File

@@ -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;

View File

@@ -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) {

View File

@@ -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();

View File

@@ -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;

View File

@@ -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;

View File

@@ -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_

View File

@@ -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(); }

View File

@@ -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();
}
}
}

View File

@@ -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;
}

View File

@@ -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();

View File

@@ -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;
}