cscore: Add connection strategy to sources (#1252)

By default, sources automatically manage their connection based on whether
any sinks are connected.  This change allows the user to keep a connection
open or force it closed regardless of the number of connected sinks.
This commit is contained in:
Peter Johnson
2018-07-29 21:18:45 -07:00
committed by GitHub
parent 7bd3f9f0bd
commit 0a0d9245e2
12 changed files with 222 additions and 11 deletions

View File

@@ -69,13 +69,12 @@ void HttpCameraImpl::StreamThreadMain() {
// sleep between retries
std::this_thread::sleep_for(std::chrono::milliseconds(250));
// disconnect if no one is listening
if (m_numSinksEnabled == 0) {
// disconnect if not enabled
if (!IsEnabled()) {
std::unique_lock<wpi::mutex> lock(m_mutex);
if (m_streamConn) m_streamConn->stream->close();
// Wait for a sink to enable
m_sinkEnabledCond.wait(
lock, [=] { return !m_active || m_numSinksEnabled != 0; });
// Wait for enable
m_sinkEnabledCond.wait(lock, [=] { return !m_active || IsEnabled(); });
if (!m_active) return;
}
@@ -185,8 +184,8 @@ void HttpCameraImpl::DeviceStream(wpi::raw_istream& is,
int numErrors = 0;
// streaming loop
while (m_active && !is.has_error() && m_numSinksEnabled > 0 &&
numErrors < 3 && !m_streamSettingsUpdated) {
while (m_active && !is.has_error() && IsEnabled() && numErrors < 3 &&
!m_streamSettingsUpdated) {
if (!FindMultipartBoundary(is, boundary, nullptr)) break;
// Read the next two characters after the boundary (normally \r\n)

View File

@@ -41,6 +41,15 @@ class SourceImpl : public PropertyContainer {
void SetDescription(const wpi::Twine& description);
wpi::StringRef GetDescription(wpi::SmallVectorImpl<char>& buf) const;
void SetConnectionStrategy(CS_ConnectionStrategy strategy) {
m_strategy = static_cast<int>(strategy);
}
bool IsEnabled() const {
return m_strategy == CS_CONNECTION_KEEP_OPEN ||
(m_strategy == CS_CONNECTION_AUTO_MANAGE && m_numSinksEnabled > 0);
}
// User-visible connection status
void SetConnected(bool connected);
bool IsConnected() const { return m_connected; }
@@ -130,7 +139,6 @@ class SourceImpl : public PropertyContainer {
virtual void NumSinksEnabledChanged() = 0;
std::atomic_int m_numSinks{0};
std::atomic_int m_numSinksEnabled{0};
protected:
// Cached video modes (protected with m_mutex)
@@ -146,6 +154,9 @@ class SourceImpl : public PropertyContainer {
std::string m_name;
std::string m_description;
std::atomic_int m_strategy{CS_CONNECTION_AUTO_MANAGE};
std::atomic_int m_numSinksEnabled{0};
wpi::mutex m_frameMutex;
wpi::condition_variable m_frameCv;

View File

@@ -309,10 +309,10 @@ void UsbCameraImpl::CameraThreadMain() {
}
}
// Turn off streaming if no one is listening, and turn it on if there is.
if (m_streaming && m_numSinksEnabled == 0) {
// Turn off streaming if not enabled, and turn it on if enabled
if (m_streaming && !IsEnabled()) {
DeviceStreamOff();
} else if (!m_streaming && m_numSinksEnabled > 0) {
} else if (!m_streaming && IsEnabled()) {
DeviceStreamOn();
}

View File

@@ -99,10 +99,20 @@ uint64_t CS_GetSourceLastFrameTime(CS_Source source, CS_Status* status) {
return cs::GetSourceLastFrameTime(source, status);
}
void CS_SetSourceConnectionStrategy(CS_Source source,
CS_ConnectionStrategy strategy,
CS_Status* status) {
cs::SetSourceConnectionStrategy(source, strategy, status);
}
CS_Bool CS_IsSourceConnected(CS_Source source, CS_Status* status) {
return cs::IsSourceConnected(source, status);
}
CS_Bool CS_IsSourceEnabled(CS_Source source, CS_Status* status) {
return cs::IsSourceEnabled(source, status);
}
CS_Property CS_GetSourceProperty(CS_Source source, const char* name,
CS_Status* status) {
return cs::GetSourceProperty(source, name, status);

View File

@@ -222,6 +222,17 @@ uint64_t GetSourceLastFrameTime(CS_Source source, CS_Status* status) {
return data->source->GetCurFrameTime();
}
void SetSourceConnectionStrategy(CS_Source source,
CS_ConnectionStrategy strategy,
CS_Status* status) {
auto data = Sources::GetInstance().Get(source);
if (!data) {
*status = CS_INVALID_HANDLE;
return;
}
data->source->SetConnectionStrategy(strategy);
}
bool IsSourceConnected(CS_Source source, CS_Status* status) {
auto data = Sources::GetInstance().Get(source);
if (!data) {
@@ -231,6 +242,15 @@ bool IsSourceConnected(CS_Source source, CS_Status* status) {
return data->source->IsConnected();
}
bool IsSourceEnabled(CS_Source source, CS_Status* status) {
auto data = Sources::GetInstance().Get(source);
if (!data) {
*status = CS_INVALID_HANDLE;
return false;
}
return data->source->IsEnabled();
}
CS_Property GetSourceProperty(CS_Source source, const wpi::Twine& name,
CS_Status* status) {
auto data = Sources::GetInstance().Get(source);

View File

@@ -599,6 +599,21 @@ Java_edu_wpi_cscore_CameraServerJNI_getSourceLastFrameTime
return val;
}
/*
* Class: edu_wpi_cscore_CameraServerJNI
* Method: setSourceConnectionStrategy
* Signature: (II)V
*/
JNIEXPORT void JNICALL
Java_edu_wpi_cscore_CameraServerJNI_setSourceConnectionStrategy
(JNIEnv* env, jclass, jint source, jint strategy)
{
CS_Status status = 0;
cs::SetSourceConnectionStrategy(
source, static_cast<CS_ConnectionStrategy>(strategy), &status);
CheckStatus(env, status);
}
/*
* Class: edu_wpi_cscore_CameraServerJNI
* Method: isSourceConnected
@@ -614,6 +629,21 @@ Java_edu_wpi_cscore_CameraServerJNI_isSourceConnected
return val;
}
/*
* Class: edu_wpi_cscore_CameraServerJNI
* Method: isSourceEnabled
* Signature: (I)Z
*/
JNIEXPORT jboolean JNICALL
Java_edu_wpi_cscore_CameraServerJNI_isSourceEnabled
(JNIEnv* env, jclass, jint source)
{
CS_Status status = 0;
auto val = cs::IsSourceEnabled(source, &status);
CheckStatus(env, status);
return val;
}
/*
* Class: edu_wpi_cscore_CameraServerJNI
* Method: getSourceProperty