Skip to content

Commit 6a26f33

Browse files
committed
feat: add realtime intelligence artifacts and metrics
1 parent 9f343a3 commit 6a26f33

18 files changed

+977
-7
lines changed

config.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,17 @@
3737
"everyNthFrame": 6,
3838
"minIntervalUsec": 200000,
3939
"queueDepth": 8,
40+
"snapshots": {
41+
"enabled": false,
42+
"dir": "./recordings/snapshots",
43+
"minIntervalUsec": 1000000
44+
},
45+
"clips": {
46+
"enabled": false,
47+
"dir": "./recordings/clips",
48+
"preRollUsec": 1000000,
49+
"postRollUsec": 3000000
50+
},
4051
"motion": {
4152
"gridWidth": 32,
4253
"gridHeight": 18,

config.rtsp.example.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,17 @@
3333
"everyNthFrame": 6,
3434
"minIntervalUsec": 200000,
3535
"queueDepth": 8,
36+
"snapshots": {
37+
"enabled": true,
38+
"dir": "./recordings/snapshots",
39+
"minIntervalUsec": 1000000
40+
},
41+
"clips": {
42+
"enabled": true,
43+
"dir": "./recordings/clips",
44+
"preRollUsec": 1000000,
45+
"postRollUsec": 3000000
46+
},
3647
"motion": {
3748
"gridWidth": 32,
3849
"gridHeight": 18,

packaging/config.example.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,17 @@
3737
"everyNthFrame": 6,
3838
"minIntervalUsec": 200000,
3939
"queueDepth": 8,
40+
"snapshots": {
41+
"enabled": false,
42+
"dir": "./recordings/snapshots",
43+
"minIntervalUsec": 1000000
44+
},
45+
"clips": {
46+
"enabled": false,
47+
"dir": "./recordings/clips",
48+
"preRollUsec": 1000000,
49+
"postRollUsec": 3000000
50+
},
4051
"motion": {
4152
"gridWidth": 32,
4253
"gridHeight": 18,

packaging/config.rtsp.example.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,17 @@
3737
"everyNthFrame": 6,
3838
"minIntervalUsec": 200000,
3939
"queueDepth": 8,
40+
"snapshots": {
41+
"enabled": true,
42+
"dir": "./recordings/snapshots",
43+
"minIntervalUsec": 1000000
44+
},
45+
"clips": {
46+
"enabled": true,
47+
"dir": "./recordings/clips",
48+
"preRollUsec": 1000000,
49+
"postRollUsec": 3000000
50+
},
4051
"motion": {
4152
"gridWidth": 32,
4253
"gridHeight": 18,

src/server/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ add_executable(icey-server
44
internal/httpfactory.cpp
55
internal/media.cpp
66
internal/turnserver.cpp
7+
internal/visionartifacts.cpp
78
media-server.cpp
89
)
910

src/server/internal/app.cpp

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,12 @@ bool MediaServerApp::start()
125125
if (_config.mode == Config::Mode::Record) {
126126
fs::mkdirr(_config.recordDir);
127127
}
128+
if (_config.mode == Config::Mode::Stream && _config.vision.enabled) {
129+
if (_config.vision.snapshots.enabled)
130+
fs::mkdirr(_config.vision.snapshots.dir);
131+
if (_config.vision.clips.enabled)
132+
fs::mkdirr(_config.vision.clips.dir);
133+
}
128134

129135
_startedAt = std::chrono::steady_clock::now();
130136

@@ -180,6 +186,7 @@ bool MediaServerApp::start()
180186
_config.turnExternalIP,
181187
_config.host,
182188
_config.tls.enabled(),
189+
_config.recordDir,
183190
kProductName,
184191
kServiceName,
185192
ICEY_SERVER_VERSION,
@@ -498,8 +505,31 @@ json::Value MediaServerApp::statusJson() const
498505
j["stream"]["sourceKind"] = sourceKind(_config.source);
499506
j["stream"]["loop"] = _config.loop;
500507
j["record"]["dir"] = _config.recordDir;
501-
j["intelligence"]["vision"] = _config.vision.enabled;
502-
j["intelligence"]["speech"] = _config.speech.enabled;
508+
json::Value intelligence;
509+
intelligence["vision"]["enabled"] = _config.vision.enabled;
510+
intelligence["speech"]["enabled"] = _config.speech.enabled;
511+
intelligence["vision"]["active"] = false;
512+
intelligence["speech"]["active"] = false;
513+
intelligence["vision"]["snapshotsEnabled"] = _config.vision.snapshots.enabled;
514+
intelligence["vision"]["clipsEnabled"] = _config.vision.clips.enabled;
515+
intelligence["vision"]["snapshotDir"] = _config.vision.snapshots.dir;
516+
intelligence["vision"]["clipDir"] = _config.vision.clips.dir;
517+
{
518+
std::lock_guard lock(_sessionMutex);
519+
for (const auto& [_, session] : _sessions) {
520+
if (session && session->active()) {
521+
intelligence = session->intelligenceStatus();
522+
intelligence["vision"]["enabled"] = _config.vision.enabled;
523+
intelligence["speech"]["enabled"] = _config.speech.enabled;
524+
intelligence["vision"]["snapshotsEnabled"] = _config.vision.snapshots.enabled;
525+
intelligence["vision"]["clipsEnabled"] = _config.vision.clips.enabled;
526+
intelligence["vision"]["snapshotDir"] = _config.vision.snapshots.dir;
527+
intelligence["vision"]["clipDir"] = _config.vision.clips.dir;
528+
break;
529+
}
530+
}
531+
}
532+
j["intelligence"] = std::move(intelligence);
503533
if (_startedAt != std::chrono::steady_clock::time_point{}) {
504534
const auto uptime = std::chrono::duration_cast<std::chrono::seconds>(
505535
std::chrono::steady_clock::now() - _startedAt).count();

src/server/internal/config.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,29 @@ ConfigLoadResult loadConfigResult(const std::string& path)
137137
c.vision.motionThreshold = motion.value("threshold", c.vision.motionThreshold);
138138
c.vision.motionCooldownUsec = motion.value("cooldownUsec", c.vision.motionCooldownUsec);
139139
}
140+
if (v.contains("snapshots")) {
141+
auto& snapshots = v["snapshots"];
142+
c.vision.snapshots.enabled =
143+
snapshots.value("enabled", c.vision.snapshots.enabled);
144+
c.vision.snapshots.dir =
145+
snapshots.value("dir", c.vision.snapshots.dir);
146+
c.vision.snapshots.minIntervalUsec = snapshots.value(
147+
"minIntervalUsec",
148+
c.vision.snapshots.minIntervalUsec);
149+
}
150+
if (v.contains("clips")) {
151+
auto& clips = v["clips"];
152+
c.vision.clips.enabled =
153+
clips.value("enabled", c.vision.clips.enabled);
154+
c.vision.clips.dir =
155+
clips.value("dir", c.vision.clips.dir);
156+
c.vision.clips.preRollUsec = clips.value(
157+
"preRollUsec",
158+
c.vision.clips.preRollUsec);
159+
c.vision.clips.postRollUsec = clips.value(
160+
"postRollUsec",
161+
c.vision.clips.postRollUsec);
162+
}
140163
}
141164
if (intelligence.contains("speech")) {
142165
auto& s = intelligence["speech"];
@@ -161,6 +184,12 @@ ConfigLoadResult loadConfigResult(const std::string& path)
161184

162185
c.source = resolvePathFromConfig(path, c.source, true);
163186
c.recordDir = resolvePathFromConfig(path, c.recordDir);
187+
if (c.vision.snapshots.dir.empty())
188+
c.vision.snapshots.dir = fs::makePath(c.recordDir, "snapshots");
189+
if (c.vision.clips.dir.empty())
190+
c.vision.clips.dir = fs::makePath(c.recordDir, "clips");
191+
c.vision.snapshots.dir = resolvePathFromConfig(path, c.vision.snapshots.dir);
192+
c.vision.clips.dir = resolvePathFromConfig(path, c.vision.clips.dir);
164193
c.webRoot = resolvePathFromConfig(path, c.webRoot);
165194
c.tls.certFile = resolvePathFromConfig(path, c.tls.certFile);
166195
c.tls.keyFile = resolvePathFromConfig(path, c.tls.keyFile);

src/server/internal/config.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,21 @@ struct Config
3030

3131
struct VisionConfig
3232
{
33+
struct SnapshotConfig
34+
{
35+
bool enabled = false;
36+
std::string dir;
37+
int64_t minIntervalUsec = 1000000;
38+
};
39+
40+
struct ClipConfig
41+
{
42+
bool enabled = false;
43+
std::string dir;
44+
int64_t preRollUsec = 1000000;
45+
int64_t postRollUsec = 3000000;
46+
};
47+
3348
bool enabled = false;
3449
uint32_t everyNthFrame = 6;
3550
int64_t minIntervalUsec = 200000;
@@ -39,6 +54,8 @@ struct Config
3954
uint32_t motionWarmupFrames = 2;
4055
float motionThreshold = 0.08f;
4156
int64_t motionCooldownUsec = 500000;
57+
SnapshotConfig snapshots;
58+
ClipConfig clips;
4259
};
4360

4461
struct SpeechConfig

src/server/internal/httpfactory.cpp

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,12 @@ constexpr const char* kDemoTurnCredential = "icey";
1616
class StaticFileResponder : public http::ServerResponder
1717
{
1818
public:
19-
StaticFileResponder(http::ServerConnection& conn, const std::string& webRoot)
19+
StaticFileResponder(http::ServerConnection& conn,
20+
const std::string& webRoot,
21+
const std::string& artifactRoot)
2022
: http::ServerResponder(conn)
2123
, _webRoot(webRoot)
24+
, _artifactRoot(artifactRoot)
2225
{
2326
}
2427

@@ -35,7 +38,14 @@ class StaticFileResponder : public http::ServerResponder
3538
return;
3639
}
3740

38-
std::string filePath = _webRoot + path;
41+
std::string basePath = _webRoot;
42+
std::string localPath = path;
43+
if (path.rfind("/artifacts/", 0) == 0) {
44+
basePath = _artifactRoot;
45+
localPath = path.substr(std::string("/artifacts").size());
46+
}
47+
48+
std::string filePath = basePath + localPath;
3949
std::ifstream file(filePath, std::ios::binary | std::ios::ate);
4050
if (!file.is_open()) {
4151
response.setStatus(http::StatusCode::NotFound);
@@ -75,6 +85,7 @@ class StaticFileResponder : public http::ServerResponder
7585
}
7686

7787
std::string _webRoot;
88+
std::string _artifactRoot;
7889
};
7990

8091
} // namespace
@@ -95,7 +106,8 @@ std::unique_ptr<http::ServerResponder> HttpFactory::createResponder(
95106
if (uri.substr(0, 5) == "/api/")
96107
return createApiResponder(conn);
97108

98-
return std::make_unique<StaticFileResponder>(conn, _webRoot);
109+
return std::make_unique<StaticFileResponder>(
110+
conn, _webRoot, _runtimeConfig.artifactRoot);
99111
}
100112

101113

src/server/internal/httpfactory.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ class HttpFactory : public http::ServerConnectionFactory
2424
std::string turnExternalIP;
2525
std::string host;
2626
bool enableTls = false;
27+
std::string artifactRoot;
2728
std::string product = kProductName;
2829
std::string service = kServiceName;
2930
std::string version;

0 commit comments

Comments
 (0)