Improve listener interface.

Now a structure is passed back, enabling combining the existing source
and sink listeners and adding property listeners as well.
This commit is contained in:
Peter Johnson
2016-11-04 12:46:22 -07:00
parent e07a40a16d
commit 8d2efb2838
8 changed files with 165 additions and 234 deletions

View File

@@ -75,9 +75,8 @@ typedef struct CS_VideoMode {
} CS_VideoMode;
//
// Property Functions
// Property types
//
enum CS_PropertyType {
CS_PROP_NONE = 0,
CS_PROP_BOOLEAN = 1,
@@ -86,6 +85,51 @@ enum CS_PropertyType {
CS_PROP_ENUM = 8
};
//
// Listener event types
//
enum CS_EventType {
CS_SOURCE_CREATED = 0x0001,
CS_SOURCE_DESTROYED = 0x0002,
CS_SOURCE_CONNECTED = 0x0004,
CS_SOURCE_DISCONNECTED = 0x0008,
CS_SOURCE_VIDEOMODES_UPDATED = 0x0010,
CS_SOURCE_VIDEOMODE_CHANGED = 0x0020,
CS_SINK_CREATED = 0x0100,
CS_SINK_DESTROYED = 0x0200,
CS_SINK_ENABLED = 0x0400,
CS_SINK_DISABLED = 0x0800,
CS_SOURCE_PROPERTY_CREATED = 0x1000,
CS_SOURCE_PROPERTY_VALUE_UPDATED = 0x2000,
CS_SOURCE_PROPERTY_CHOICES_UPDATED = 0x4000
};
//
// Listener event
//
struct CS_Event {
CS_EventType type;
// Valid for CS_SOURCE_* and CS_SINK_* respectively
CS_Source source;
CS_Sink sink;
// Source/sink name
const char *name;
// Fields for CS_SOURCE_VIDEOMODE_CHANGED event
CS_VideoMode mode;
// Fields for CS_SOURCE_PROPERTY_* events
CS_Property property;
CS_PropertyType propertyType;
int value;
const char* valueStr;
};
//
// Property Functions
//
enum CS_PropertyType CS_GetPropertyType(CS_Property property,
CS_Status* status);
char* CS_GetPropertyName(CS_Property property, CS_Status* status);
@@ -156,10 +200,6 @@ CS_Property CS_CreateSourceProperty(CS_Source source, const char* name,
enum CS_PropertyType type, int minimum,
int maximum, int step, int defaultValue,
int value, CS_Status* status);
CS_Property CS_CreateSourcePropertyCallback(
CS_Source source, const char* name, enum CS_PropertyType type, int minimum,
int maximum, int step, int defaultValue, int value, void* data,
void (*onChange)(void* data, CS_Property property), CS_Status* status);
void CS_SetSourceEnumPropertyChoices(CS_Source source, CS_Property property,
const char** choices, int count,
CS_Status* status);
@@ -198,33 +238,12 @@ void CS_SetSinkEnabled(CS_Sink sink, CS_Bool enabled, CS_Status* status);
//
// Listener Functions
//
enum CS_SourceEvent {
CS_SOURCE_CREATED = 0x01,
CS_SOURCE_DESTROYED = 0x02,
CS_SOURCE_CONNECTED = 0x04,
CS_SOURCE_DISCONNECTED = 0x08
};
CS_Listener CS_AddListener(void* data,
void (*callback)(void* data, const CS_Event* event),
int eventMask, int immediateNotify,
CS_Status* status);
CS_Listener CS_AddSourceListener(void* data,
void (*callback)(void* data, const char* name,
CS_Source source, int event),
int eventMask, CS_Status* status);
void CS_RemoveSourceListener(CS_Listener handle, CS_Status* status);
enum CS_SinkEvent {
CS_SINK_CREATED = 0x01,
CS_SINK_DESTROYED = 0x02,
CS_SINK_ENABLED = 0x04,
CS_SINK_DISABLED = 0x08
};
CS_Listener CS_AddSinkListener(void* data,
void (*callback)(void* data, const char* name,
CS_Sink sink, int event),
int eventMask, CS_Status* status);
void CS_RemoveSinkListener(CS_Listener handle, CS_Status* status);
void CS_RemoveListener(CS_Listener handle, CS_Status* status);
//
// Utility Functions

View File

@@ -65,10 +65,46 @@ struct VideoMode : public CS_VideoMode {
explicit operator bool() const { return pixelFormat == kUnknown; }
};
/// Listener event
struct RawEvent {
enum Type {
kSourceCreated = CS_SOURCE_CREATED,
kSourceDestroyed = CS_SOURCE_DESTROYED,
kSourceConnected = CS_SOURCE_CONNECTED,
kSourceDisconnected = CS_SOURCE_DISCONNECTED,
kSourceVideoModesUpdated = CS_SOURCE_VIDEOMODES_UPDATED,
kSourceVideoModeChanged = CS_SOURCE_VIDEOMODE_CHANGED,
kSinkCreated = CS_SINK_CREATED,
kSinkDestroyed = CS_SINK_DESTROYED,
kSinkEnabled = CS_SINK_ENABLED,
kSinkDisabled = CS_SINK_DISABLED,
kSourcePropertyCreated = CS_SOURCE_PROPERTY_CREATED,
kSourcePropertyValueUpdated = CS_SOURCE_PROPERTY_VALUE_UPDATED,
kSourcePropertyChoicesUpdated = CS_SOURCE_PROPERTY_CHOICES_UPDATED
};
Type type;
// Valid for kSource* and kSink* respectively
CS_Source sourceHandle;
CS_Sink sinkHandle;
// Source/sink name
std::string name;
// Fields for kSourceVideoModeChanged event
VideoMode mode;
// Fields for CS_SOURCE_PROPERTY_* events
CS_Property propertyHandle;
CS_PropertyType propertyType;
int value;
std::string valueStr;
};
//
// Property Functions
//
CS_PropertyType GetPropertyType(CS_Property property, CS_Status* status);
std::string GetPropertyName(CS_Property property, CS_Status* status);
llvm::StringRef GetPropertyName(CS_Property property,
@@ -144,10 +180,6 @@ CS_Property CreateSourceProperty(CS_Source source, llvm::StringRef name,
CS_PropertyType type, int minimum, int maximum,
int step, int defaultValue, int value,
CS_Status* status);
CS_Property CreateSourcePropertyCallback(
CS_Source source, llvm::StringRef name, CS_PropertyType type, int minimum,
int maximum, int step, int defaultValue, int value,
std::function<void(CS_Property property)> onChange, CS_Status* status);
void SetSourceEnumPropertyChoices(CS_Source source, CS_Property property,
llvm::ArrayRef<std::string> choices,
CS_Status* status);
@@ -193,18 +225,10 @@ void SetSinkEnabled(CS_Sink sink, bool enabled, CS_Status* status);
//
// Listener Functions
//
CS_Listener AddSourceListener(
std::function<void(llvm::StringRef name, CS_Source source, int event)>
callback,
int eventMask, CS_Status* status);
CS_Listener AddListener(std::function<void(const RawEvent& event)> callback,
int eventMask, bool immediateNotify, CS_Status* status);
void RemoveSourceListener(CS_Listener handle, CS_Status* status);
CS_Listener AddSinkListener(
std::function<void(llvm::StringRef name, CS_Sink sink, int event)> callback,
int eventMask, CS_Status* status);
void RemoveSinkListener(CS_Listener handle, CS_Status* status);
void RemoveListener(CS_Listener handle, CS_Status* status);
//
// Utility Functions

View File

@@ -18,13 +18,13 @@ namespace cs {
// Forward declarations so friend declarations work correctly
class CvSource;
class SinkListener;
class SourceListener;
class VideoEvent;
class VideoSink;
class VideoSource;
class VideoProperty {
friend class CvSource;
friend class VideoEvent;
friend class VideoSink;
friend class VideoSource;
@@ -70,6 +70,7 @@ class VideoProperty {
private:
explicit VideoProperty(CS_Property handle);
VideoProperty(CS_Property handle, Type type);
mutable CS_Status m_status;
CS_Property m_handle;
@@ -78,7 +79,7 @@ class VideoProperty {
/// A source for video that provides a sequence of frames.
class VideoSource {
friend class SourceListener;
friend class VideoEvent;
friend class VideoSink;
public:
@@ -241,21 +242,6 @@ class CvSource : public VideoSource {
int minimum, int maximum, int step,
int defaultValue, int value);
/// Create a property with a change callback.
/// @param name Property name
/// @param type Property type
/// @param minimum Minimum value
/// @param maximum Maximum value
/// @param step Step value
/// @param defaultValue Default value
/// @param value Current value
/// @param onChange Callback to call when the property value changes
/// @return Property
VideoProperty CreateProperty(
llvm::StringRef name, VideoProperty::Type type, int minimum, int maximum,
int step, int defaultValue, int value,
std::function<void(VideoProperty property)> onChange);
/// Configure enum property choices.
/// @param property Property
/// @param choices Choices
@@ -265,7 +251,7 @@ class CvSource : public VideoSource {
/// A sink for video that accepts a sequence of frames.
class VideoSink {
friend class SinkListener;
friend class VideoEvent;
public:
VideoSink() noexcept : m_handle(0) {}
@@ -372,56 +358,25 @@ class CvSink : public VideoSink {
void SetEnabled(bool enabled);
};
class SourceListener {
class VideoEvent : public RawEvent {
public:
enum Event {
kCreated = CS_SOURCE_CREATED,
kDestroyed = CS_SOURCE_DESTROYED,
kConnected = CS_SOURCE_CONNECTED,
kDisconnected = CS_SOURCE_DISCONNECTED
};
SourceListener() : m_handle(0) {}
SourceListener(
std::function<void(llvm::StringRef name, VideoSource source, int event)>
callback,
int eventMask);
SourceListener(const SourceListener&) = delete;
SourceListener& operator=(const SourceListener&) = delete;
SourceListener(SourceListener&& other) noexcept;
~SourceListener();
friend void swap(SourceListener& first, SourceListener& second) noexcept {
using std::swap;
swap(first.m_handle, second.m_handle);
}
private:
CS_Listener m_handle;
VideoSource GetSource() const;
VideoSink GetSink() const;
VideoProperty GetProperty() const;
};
class SinkListener {
class VideoListener {
public:
enum Event {
kCreated = CS_SINK_CREATED,
kDestroyed = CS_SINK_DESTROYED,
kEnabled = CS_SINK_ENABLED,
kDisabled = CS_SINK_DISABLED
};
VideoListener() : m_handle(0) {}
VideoListener(std::function<void(const VideoEvent& event)> callback,
int eventMask, bool immediateNotify);
SinkListener() : m_handle(0) {}
SinkListener(
std::function<void(llvm::StringRef name, VideoSink sink, int event)>
callback,
int eventMask);
VideoListener(const VideoListener&) = delete;
VideoListener& operator=(const VideoListener&) = delete;
VideoListener(VideoListener&& other) noexcept;
~VideoListener();
SinkListener(const SinkListener&) = delete;
SinkListener& operator=(const SinkListener&) = delete;
SinkListener(SinkListener&& other) noexcept;
~SinkListener();
friend void swap(SinkListener& first, SinkListener& second) noexcept {
friend void swap(VideoListener& first, VideoListener& second) noexcept {
using std::swap;
swap(first.m_handle, second.m_handle);
}

View File

@@ -213,18 +213,6 @@ inline VideoProperty CvSource::CreateProperty(llvm::StringRef name,
minimum, maximum, step, defaultValue, value, &m_status)};
}
inline VideoProperty CvSource::CreateProperty(
llvm::StringRef name, VideoProperty::Type type, int minimum, int maximum,
int step, int defaultValue, int value,
std::function<void(VideoProperty property)> onChange) {
m_status = 0;
return VideoProperty{CreateSourcePropertyCallback(
m_handle, name, static_cast<CS_PropertyType>(static_cast<int>(type)),
minimum, maximum, step, defaultValue, value,
[=](CS_Property property) { onChange(VideoProperty{property}); },
&m_status)};
}
inline void CvSource::SetEnumPropertyChoices(
const VideoProperty& property, llvm::ArrayRef<std::string> choices) {
m_status = 0;
@@ -310,48 +298,40 @@ inline void CvSink::SetEnabled(bool enabled) {
SetSinkEnabled(m_handle, enabled, &m_status);
}
inline SourceListener::SourceListener(
std::function<void(llvm::StringRef name, VideoSource source, int event)>
callback,
int eventMask) {
inline VideoSource VideoEvent::GetSource() const {
CS_Status status = 0;
m_handle = AddSourceListener(
[=](llvm::StringRef name, CS_Source sourceHandle, int event) {
callback(name, VideoSource{sourceHandle}, event);
},
eventMask, &status);
return VideoSource{sourceHandle == 0 ? 0 : CopySource(sourceHandle, &status)};
}
inline SourceListener::SourceListener(SourceListener&& other) noexcept
: SourceListener() {
inline VideoSink VideoEvent::GetSink() const {
CS_Status status = 0;
return VideoSink{sinkHandle == 0 ? 0 : CopySink(sinkHandle, &status)};
}
inline VideoProperty VideoEvent::GetProperty() const {
return VideoProperty{propertyHandle,
static_cast<VideoProperty::Type>(propertyType)};
}
inline VideoListener::VideoListener(
std::function<void(const VideoEvent& event)> callback, int eventMask,
bool immediateNotify) {
CS_Status status = 0;
m_handle = AddListener(
[=](const RawEvent& event) {
callback(static_cast<const VideoEvent&>(event));
},
eventMask, immediateNotify, &status);
}
inline VideoListener::VideoListener(VideoListener&& other) noexcept
: VideoListener() {
swap(*this, other);
}
inline SourceListener::~SourceListener() {
inline VideoListener::~VideoListener() {
CS_Status status = 0;
if (m_handle != 0) RemoveSourceListener(m_handle, &status);
}
inline SinkListener::SinkListener(
std::function<void(llvm::StringRef name, VideoSink sink, int event)>
callback,
int eventMask) {
CS_Status status = 0;
m_handle = AddSinkListener(
[=](llvm::StringRef name, CS_Sink sinkHandle, int event) {
callback(name, VideoSink{sinkHandle}, event);
},
eventMask, &status);
}
inline SinkListener::SinkListener(SinkListener&& other) noexcept
: SinkListener() {
swap(*this, other);
}
inline SinkListener::~SinkListener() {
CS_Status status = 0;
if (m_handle != 0) RemoveSinkListener(m_handle, &status);
if (m_handle != 0) RemoveListener(m_handle, &status);
}
} // namespace cs

View File

@@ -800,27 +800,14 @@ JNIEXPORT void JNICALL Java_edu_wpi_cameraserver_CameraServerJNI_setSinkEnabled
/*
* Class: edu_wpi_cameraserver_CameraServerJNI
* Method: removeSourceListener
* Method: removeListener
* Signature: (I)V
*/
JNIEXPORT void JNICALL Java_edu_wpi_cameraserver_CameraServerJNI_removeSourceListener
JNIEXPORT void JNICALL Java_edu_wpi_cameraserver_CameraServerJNI_removeListener
(JNIEnv *env, jclass, jint handle)
{
CS_Status status = 0;
cs::RemoveSourceListener(handle, &status);
CheckStatus(env, status);
}
/*
* Class: edu_wpi_cameraserver_CameraServerJNI
* Method: removeSinkListener
* Signature: (I)V
*/
JNIEXPORT void JNICALL Java_edu_wpi_cameraserver_CameraServerJNI_removeSinkListener
(JNIEnv *env, jclass, jint handle)
{
CS_Status status = 0;
cs::RemoveSinkListener(handle, &status);
cs::RemoveListener(handle, &status);
CheckStatus(env, status);
}

View File

@@ -156,16 +156,10 @@ public class CameraServerJNI {
//
// Listener Functions
//
//public static native int addSourceListener(void (*callback)(String name, int source,
// int event),
//public static native int addListener(void (*callback)(VideoEvent event),
// int eventMask);
public static native void removeSourceListener(int handle);
//public static native int addSinkListener(void (*callback)(String name, int sink, int event),
// int eventMask);
public static native void removeSinkListener(int handle);
public static native void removeListener(int handle);
//
// Utility Functions

View File

@@ -211,46 +211,29 @@ void CS_ReleaseSink(CS_Sink sink, CS_Status* status) {
return cs::ReleaseSink(sink, status);
}
CS_Listener CS_AddSourceListener(void* data,
void (*callback)(void* data, const char* name,
CS_Source source, int event),
int eventMask, CS_Status* status) {
return cs::AddSourceListener(
[=](llvm::StringRef name, CS_Source source, int event) {
// avoid the copy if possible
if (name[name.size()] == '\0') {
callback(data, name.data(), source, event);
} else {
llvm::SmallString<128> copy{name};
callback(data, copy.c_str(), source, event);
}
CS_Listener CS_AddListener(void* data,
void (*callback)(void* data, const CS_Event* event),
int eventMask, int immediateNotify,
CS_Status* status) {
return cs::AddListener(
[=](const cs::RawEvent& rawEvent) {
CS_Event event;
event.type = static_cast<CS_EventType>(static_cast<int>(rawEvent.type));
event.source = rawEvent.sourceHandle;
event.sink = rawEvent.sinkHandle;
event.name = rawEvent.name.c_str();
event.mode = rawEvent.mode;
event.property = rawEvent.propertyHandle;
event.propertyType = rawEvent.propertyType;
event.value = rawEvent.value;
event.valueStr = rawEvent.valueStr.c_str();
callback(data, &event);
},
eventMask, status);
eventMask, immediateNotify, status);
}
void CS_RemoveSourceListener(CS_Listener handle, CS_Status* status) {
return cs::RemoveSourceListener(handle, status);
}
CS_Listener CS_AddSinkListener(void* data,
void (*callback)(void* data, const char* name,
CS_Sink sink, int event),
int eventMask, CS_Status* status) {
return cs::AddSinkListener(
[=](llvm::StringRef name, CS_Sink sink, int event) {
// avoid the copy if possible
if (name[name.size()] == '\0') {
callback(data, name.data(), sink, event);
} else {
llvm::SmallString<128> copy{name};
callback(data, copy.c_str(), sink, event);
}
},
eventMask, status);
}
void CS_RemoveSinkListener(CS_Listener handle, CS_Status* status) {
return cs::RemoveSinkListener(handle, status);
void CS_RemoveListener(CS_Listener handle, CS_Status* status) {
return cs::RemoveListener(handle, status);
}
CS_Source* CS_EnumerateSources(int* count, CS_Status* status) {

View File

@@ -424,24 +424,13 @@ void ReleaseSink(CS_Sink sink, CS_Status* status) {
// Listener Functions
//
CS_Listener AddSourceListener(
std::function<void(llvm::StringRef name, CS_Source source, int event)>
callback,
int eventMask, CS_Status* status) {
CS_Listener AddListener(std::function<void(const RawEvent& event)> callback,
int eventMask, bool immediateNotify,
CS_Status* status) {
return 0; // TODO
}
void RemoveSourceListener(CS_Listener handle, CS_Status* status) {
// TODO
}
CS_Listener AddSinkListener(
std::function<void(llvm::StringRef name, CS_Sink sink, int event)> callback,
int eventMask, CS_Status* status) {
return 0; // TODO
}
void RemoveSinkListener(CS_Listener handle, CS_Status* status) {
void RemoveListener(CS_Listener handle, CS_Status* status) {
// TODO
}