49class PhysiologyServiceImpl final :
public Physiology::CallbackService {
51 explicit PhysiologyServiceImpl(
53 double preprocessed_data_buffer_duration_s = 0.2,
54 std::optional<bool> enable_phasic_bp = std::nullopt,
55 std::optional<bool> enable_eda = std::nullopt,
56 std::optional<bool> use_full_range_face_detection = std::nullopt,
57 std::optional<bool> use_full_pose_landmarks = std::nullopt,
58 std::optional<bool> enable_pose_landmark_segmentation = std::nullopt,
59 std::optional<bool> enable_micromotion = std::nullopt,
60 bool use_camera =
false,
61 int camera_device_index = 0,
62 const std::string& input_video_path =
"",
63 const std::string& input_video_time_path =
"",
64 int interframe_delay_ms = 20,
65 bool start_with_recording_on =
false,
66 bool exit_on_input_video_completion =
false,
67 uint16_t physiology_core_port_number = 50052,
68 bool physiology_core_manual_control =
false,
69 int physiology_core_connection_timeout_ms = 50000,
70 const std::string& venv_directory =
"",
72 const int log_buffer_size = 1000,
73 int64_t test_physiology_core_seed = -1,
74 std::unique_ptr<ipc::IpcStreamWriter<TIntegrationMode>> ipc_stream_writer =
nullptr,
75 std::optional<std::string> video_output_directory = std::nullopt,
76 bool enable_camera_tuning =
true,
78 std::chrono::seconds camera_tuning_cooldown_seconds = std::chrono::seconds(10),
79 bool camera_tuning_recheck_on_recovery = false
82 ~PhysiologyServiceImpl()
override;
84 using BackgroundContainer =
86 presage::platform_independence::DeviceType::Cpu,
87 smartspectra::container::settings::OperationMode::Continuous,
96 using BackgroundContainerSettings =
typename BackgroundContainer::SettingsType;
98 grpc::ServerUnaryReactor* StartCore(
99 grpc::CallbackServerContext* context,
100 const ::google::protobuf::Empty* request,
101 ::google::protobuf::Empty* response
104 grpc::ServerUnaryReactor* StartEdgeGraph(
105 grpc::CallbackServerContext* context,
106 const ::google::protobuf::Empty* request,
107 ::google::protobuf::Empty* response
111 grpc::CallbackServerContext* context,
112 const ::google::protobuf::Empty* request,
113 ::google::protobuf::Empty* response
116 grpc::ServerUnaryReactor* WaitUntilGraphIsIdle(
117 grpc::CallbackServerContext* context,
118 const ::google::protobuf::Empty* request,
119 ::google::protobuf::Empty* response
122 grpc::ServerUnaryReactor* SetRecording(
123 grpc::CallbackServerContext* context,
124 const ::google::protobuf::BoolValue* request,
125 ::google::protobuf::Empty* response
128 grpc::ServerReadReactor<presage::smartspectra::FrameWithTimestamp>* AddFrameWithTimestamp(
129 grpc::CallbackServerContext* context,
130 google::protobuf::Empty* response
133 grpc::ServerWriteReactor<physiology::StatusValue>* GetStatusCode(
134 grpc::CallbackServerContext* context,
135 const google::protobuf::Empty* request
138 grpc::ServerUnaryReactor* GetStatusDescription(
139 grpc::CallbackServerContext* context,
140 const physiology::StatusValue* request,
141 google::protobuf::StringValue* response
144 grpc::ServerUnaryReactor* GetStatusHint(
145 grpc::CallbackServerContext* context,
146 const physiology::StatusValue* request,
147 google::protobuf::StringValue* response
150 grpc::ServerWriteReactor<presage::physiology::MetricsBuffer>* GetCoreMetrics(
151 grpc::CallbackServerContext* context,
152 const google::protobuf::Empty* request
155 grpc::ServerWriteReactor<presage::physiology::MetricsBuffer>* GetMetrics(
156 grpc::CallbackServerContext* context,
157 const google::protobuf::Empty* request
160 grpc::ServerWriteReactor<presage::physiology::Metrics>* GetEdgeMetrics(
161 grpc::CallbackServerContext* context,
162 const google::protobuf::Empty* request
165 grpc::ServerUnaryReactor* StopCore(
166 grpc::CallbackServerContext* context,
167 const ::google::protobuf::Empty* request,
168 ::google::protobuf::Empty* response
172 grpc::CallbackServerContext* context,
173 const ::google::protobuf::Empty* request,
174 ::google::protobuf::Empty* response
178 grpc::CallbackServerContext* context,
179 const ::google::protobuf::Empty* request,
180 ::google::protobuf::Empty* response
183 grpc::ServerUnaryReactor* ResetProcessing(
184 grpc::CallbackServerContext* context,
185 const ::google::protobuf::Empty* request,
186 ::google::protobuf::Empty* response
189 grpc::ServerUnaryReactor* CheckHealth(
190 grpc::CallbackServerContext* context,
191 const ::google::protobuf::Empty* request,
192 ::google::protobuf::StringValue* response
195 grpc::ServerUnaryReactor* IsPhysiologyCoreUp(
196 grpc::CallbackServerContext* context,
197 const ::google::protobuf::Empty* request,
198 ::google::protobuf::BoolValue* response
201 grpc::ServerUnaryReactor* IsEdgeGraphRunning(
202 grpc::CallbackServerContext* context,
203 const ::google::protobuf::Empty* request,
204 ::google::protobuf::BoolValue* response
207 grpc::ServerUnaryReactor* IsPreprocessingRunning(
208 grpc::CallbackServerContext* context,
209 const ::google::protobuf::Empty* request,
210 ::google::protobuf::BoolValue* response
213 grpc::ServerWriteReactor<::presage::smartspectra::LogEntry>* StreamLogs(
214 grpc::CallbackServerContext* context,
215 const google::protobuf::Empty* request
218 absl::Status AutoStartIfRequested();
219 void SetOnInputVideoCompletionCallback(std::function<
void()> callback);
222 template<
typename TProv
iderWithContainer>
223 TProviderWithContainer* GenericHookToProvider(std::shared_ptr<TProviderWithContainer>& provider);
225 absl::Status StartCoreServer();
227 absl::Status StartCoreClient();
229 absl::Status StopCoreServer();
231 absl::Status BuildAndStartContainer();
233 absl::Status StopAndDestroyContainer();
235 absl::Status VerifyVenv();
236 absl::Status PublishRecordingStateToRedis(
bool recording);
238 absl::Status HandleStatusForTuning(
239 const presage::physiology::StatusValue& status_output,
240 presage::physiology::StatusCode previous_status_code
246 static bool StatusRequiresImmediateRetune(presage::physiology::StatusCode status);
247 static bool StatusShouldRetuneAfterRecovery(presage::physiology::StatusCode status);
251 const uint16_t physiology_core_port_number;
252 const bool physiology_core_manual_control;
253 const int64_t test_physiology_core_seed;
254 const int physiology_core_connection_timeout_ms;
257 std::shared_ptr<BackgroundContainer> container;
258 std::shared_ptr<TFrameWithTimestampRecorder> frame_with_timestamp_recorder;
259 std::shared_ptr<TStatusCodeProvider> status_code_provider;
260 std::shared_ptr<TMetricsProvider> metrics_provider;
261 std::shared_ptr<TEdgeMetricsProvider> edge_metrics_provider;
262 std::mutex preprocessing_construction_mutex;
263 std::condition_variable preprocessing_construction_condition;
266 const BackgroundContainerSettings container_settings;
267 reproc::options physiology_core_process_options;
268 reproc::process physiology_core_process;
269 bool physiology_core_started =
false;
270 std::shared_ptr<grpc::Channel> channel;
271 std::unique_ptr<presage::physiology::PhysiologyCore::Stub> core_stub =
nullptr;
272 std::filesystem::path venv_directory;
273 bool venv_verified =
false;
282 std::thread core_log_thread;
283 std::atomic<bool> core_log_thread_shutdown =
false;
286 const bool use_camera;
287 const std::string input_video_path;
288 const std::string input_video_time_path;
289 const bool local_input_enabled;
290 const bool start_with_recording_on;
291 const bool exit_on_input_video_completion;
292 bool recording_auto_started =
false;
293 const int camera_device_index;
294 std::mutex local_input_thread_mutex;
295 std::thread local_input_thread;
296 std::atomic<bool> local_input_thread_shutdown =
false;
297 std::shared_ptr<video_source::VideoSource> local_input_source;
298 std::function<void()> input_video_completion_callback;
299 std::mutex input_video_completion_callback_mutex;
302 std::unique_ptr<ipc::IpcStreamWriter<TIntegrationMode>> ipc_stream_writer;
305 std::shared_ptr<video_source::CameraTuner> camera_tuner;
307 std::atomic<bool> camera_tuning_enabled =
false;
308 std::atomic<bool> is_recording =
false;
309 std::atomic<bool> is_tuning_camera =
false;
310 std::chrono::steady_clock::time_point last_camera_tuning_time;
311 std::chrono::seconds camera_tuning_cooldown_duration;
312 const bool camera_tuning_recheck_on_recovery_;
313 std::mutex camera_tuning_mutex;
314 std::atomic<int64_t> latest_status_change_timestamp_us_{0};
315 std::atomic<presage::physiology::StatusCode> latest_status_code_{presage::physiology::StatusCode::PROCESSING_NOT_STARTED};
316 std::mutex pending_status_mutex_;
317 std::optional<presage::physiology::StatusValue> pending_status_after_tuning_;
320 std::optional<absl::Status> last_camera_error_;
321 std::mutex camera_error_mutex_;