Skip to content

Commit

Permalink
Merge pull request #29 from TheCacophonyProject/add-rec
Browse files Browse the repository at this point in the history
Add long recording
  • Loading branch information
hardiesoft authored Nov 6, 2024
2 parents 47bae78 + de1f70c commit 00f4aab
Show file tree
Hide file tree
Showing 5 changed files with 198 additions and 56 deletions.
4 changes: 2 additions & 2 deletions src/camera_transfer_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -721,10 +721,10 @@ fn maybe_make_test_audio_recording(

// If the user requested a test audio recording, trigger the test audio recording, and
// launch a thread to track when that recording has completed.
if recording_state.user_requested_test_audio_recording() {
if recording_state.user_requested_audio_recording() {
recording_state.sync_state_from_attiny(dbus_conn);
if !recording_state.is_recording()
&& recording_state.request_test_audio_recording_from_rp2040(dbus_conn)
&& recording_state.request_audio_recording_from_rp2040(dbus_conn)
{
let _ = restart_rp2040_channel_tx.send(true);
info!("Telling rp2040 to take test recording and restarting");
Expand Down
28 changes: 25 additions & 3 deletions src/dbus_managementd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,19 +26,39 @@ fn managementd_handler(
_env: &mut MyHandleEnv,
) -> HandleResult<()> {
if msg.dynheader.member.as_ref().unwrap() == "testaudio" {
let message = if !recording_state_ctx.is_taking_test_audio_recording() {
let message = if recording_state_ctx.is_taking_test_audio_recording() {
"Already making a test recording"
} else if recording_state_ctx.is_taking_long_audio_recording() {
"Already making a 5 minute recording"
} else {
recording_state_ctx.request_test_audio_recording();
"Asked for a test recording"
};
let mut resp = msg.dynheader.make_response();
resp.body.push_param(message)?;
Ok(Some(resp))
} else if msg.dynheader.member.as_ref().unwrap() == "longaudiorecording" {
let message = if recording_state_ctx.is_taking_long_audio_recording() {
"Already making a 5 minute recording"
} else if recording_state_ctx.is_taking_test_audio_recording() {
"Already making a 5 test recording"
} else {
"Already making a test recording"
recording_state_ctx.request_long_audio_recording();
"Asked for a 5 minute recording"
};
let mut resp = msg.dynheader.make_response();
resp.body.push_param(message)?;
Ok(Some(resp))
} else if msg.dynheader.member.as_ref().unwrap() == "audiostatus" {
let mut response = msg.dynheader.make_response();
let status = recording_state_ctx.get_audio_status();
response.body.push_param(if recording_state_ctx.is_in_audio_mode() { 1 } else { 0 })?;
response
.body
.push_param(if recording_state_ctx.is_in_audio_mode() {
1
} else {
0
})?;
response.body.push_param(status as u8)?;
Ok(Some(response))
} else if msg.dynheader.member.as_ref().unwrap() == "offloadstatus" {
Expand All @@ -65,6 +85,8 @@ pub enum AudioStatus {
WaitingToTakeTestRecording = 2,
TakingTestRecording = 3,
Recording = 4,
TakingLongRecording = 5,
WaitingToTakeLongRecording = 6,
}

pub fn setup_dbus_managementd_recording_service(recording_state: &RecordingState) {
Expand Down
106 changes: 84 additions & 22 deletions src/device_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,17 @@ fn default_activate_thermal_throttler() -> bool {
}

fn default_recording_start_time() -> AbsRelTime {
AbsRelTime { relative_time_seconds: Some(-(60 * 30)), absolute_time: None }
AbsRelTime {
relative_time_seconds: Some(-(60 * 30)),
absolute_time: None,
}
}

fn default_recording_stop_time() -> AbsRelTime {
AbsRelTime { relative_time_seconds: Some(60 * 30), absolute_time: None }
AbsRelTime {
relative_time_seconds: Some(60 * 30),
absolute_time: None,
}
}

#[derive(Debug)]
Expand Down Expand Up @@ -131,7 +137,10 @@ where
}
}
}
_ => error!("Region '{}': Must be an array of [[x, y], ...] coordinates", label),
_ => error!(
"Region '{}': Must be an array of [[x, y], ...] coordinates",
label
),
}
regions.insert(label.clone(), region);
}
Expand Down Expand Up @@ -270,7 +279,10 @@ where
if absolute_time.is_none() && relative_time_seconds.is_none() {
Err(Error::custom(format!("Failed to parse window time: {}", s)))
} else {
Ok(AbsRelTime { absolute_time, relative_time_seconds })
Ok(AbsRelTime {
absolute_time,
relative_time_seconds,
})
}
}

Expand Down Expand Up @@ -328,9 +340,15 @@ struct LocationSettings {
longitude: Option<f32>,
altitude: Option<f32>,

#[serde(deserialize_with = "timestamp_to_u64", default = "default_location_timestamp")]
#[serde(
deserialize_with = "timestamp_to_u64",
default = "default_location_timestamp"
)]
timestamp: Option<u64>,
#[serde(deserialize_with = "location_accuracy_to_f32", default = "default_location_accuracy")]
#[serde(
deserialize_with = "location_accuracy_to_f32",
default = "default_location_accuracy"
)]
accuracy: Option<f32>,
}

Expand All @@ -345,7 +363,9 @@ fn timezone_offset_seconds() -> i32 {
// devices' GPS coordinates to work out correct absolute start/end recording window times.
let now = Local::now();
let local_tz = now.timezone();
local_tz.offset_from_utc_datetime(&now.naive_utc()).local_minus_utc()
local_tz
.offset_from_utc_datetime(&now.naive_utc())
.local_minus_utc()
}
#[derive(PartialEq, Clone)]
pub struct AbsRelTime {
Expand All @@ -365,7 +385,10 @@ impl Debug for AbsRelTime {
.finish();
}
if let Some(time) = relative_time {
return f.debug_struct("RelativeOffset").field("secs", &time).finish();
return f
.debug_struct("RelativeOffset")
.field("secs", &time)
.finish();
}
Err(fmt::Error::default())
}
Expand Down Expand Up @@ -469,14 +492,23 @@ pub struct AudioSettings {
deserialize_with = "deserialize_audio_mode"
)]
pub audio_mode: AudioMode,
#[serde(rename = "random-seed", default = "default_audio_seed")]
pub audio_seed: u32,
}

impl Default for AudioSettings {
fn default() -> Self {
AudioSettings { audio_mode: default_audio_mode() }
AudioSettings {
audio_mode: default_audio_mode(),
audio_seed: 0,
}
}
}

fn default_audio_seed() -> u32 {
0
}

fn default_audio_mode() -> AudioMode {
AudioMode::Disabled
}
Expand All @@ -489,7 +521,10 @@ where
if let Ok(mode) = AudioMode::from_str(&audio_mode_raw) {
Ok(mode)
} else {
Err(Error::custom(format!("Failed to parse audio mode: {}", audio_mode_raw)))
Err(Error::custom(format!(
"Failed to parse audio mode: {}",
audio_mode_raw
)))
}
}

Expand Down Expand Up @@ -572,7 +607,13 @@ impl DeviceConfig {
}

pub fn device_name(&self) -> &[u8] {
self.device_info.as_ref().unwrap().name.as_ref().unwrap().as_bytes()
self.device_info
.as_ref()
.unwrap()
.name
.as_ref()
.unwrap()
.as_bytes()
}

pub fn lat_lng(&self) -> (f32, f32) {
Expand Down Expand Up @@ -614,7 +655,11 @@ impl DeviceConfig {

pub fn is_continuous_recorder(&self) -> bool {
self.recording_settings.constant_recorder
|| (self.recording_window.start_recording.absolute_time.is_some()
|| (self
.recording_window
.start_recording
.absolute_time
.is_some()
&& self.recording_window.stop_recording.absolute_time.is_some()
&& self.recording_window.start_recording == self.recording_window.stop_recording)
}
Expand Down Expand Up @@ -675,11 +720,17 @@ impl DeviceConfig {
start_offset = 86_400 + start_offset;
}
let (window_start, window_end) = if !is_absolute_start || !is_absolute_end {
let location =
self.location.as_ref().expect("Relative recording windows require a location");
let location = self
.location
.as_ref()
.expect("Relative recording windows require a location");
let (lat, lng) = (
location.latitude.expect("Relative recording windows require a valid latitude"),
location.longitude.expect("Relative recording windows require a valid longitude"),
location
.latitude
.expect("Relative recording windows require a valid latitude"),
location
.longitude
.expect("Relative recording windows require a valid longitude"),
);
let altitude = location.altitude;
let yesterday_utc = *now_utc - Duration::days(1);
Expand All @@ -692,9 +743,13 @@ impl DeviceConfig {
.unwrap();
let yesterday_sunset =
yesterday_sunset.naive_utc() + Duration::seconds(start_offset as i64);
let (today_sunrise, today_sunset) =
sun_times(now_utc.date(), lat as f64, lng as f64, altitude.unwrap_or(0.0) as f64)
.unwrap();
let (today_sunrise, today_sunset) = sun_times(
now_utc.date(),
lat as f64,
lng as f64,
altitude.unwrap_or(0.0) as f64,
)
.unwrap();
let today_sunrise = today_sunrise.naive_utc() + Duration::seconds(end_offset as i64);
let today_sunset = today_sunset.naive_utc() + Duration::seconds(start_offset as i64);
let tomorrow_utc = *now_utc + Duration::days(1);
Expand Down Expand Up @@ -829,6 +884,8 @@ impl DeviceConfig {
buf.write_u32::<LittleEndian>(device_id).unwrap();
let audio_mode: u8 = self.audio_info.audio_mode.clone().into();
buf.write_u8(audio_mode).unwrap();
buf.write_u32::<LittleEndian>(self.audio_info.audio_seed)
.unwrap();
let (latitude, longitude) = self.lat_lng();
buf.write_f32::<LittleEndian>(latitude).unwrap();
buf.write_f32::<LittleEndian>(longitude).unwrap();
Expand Down Expand Up @@ -860,8 +917,10 @@ impl DeviceConfig {
buf.write_i32::<LittleEndian>(start_seconds_offset).unwrap();
buf.write_u8(if end_is_abs { 1 } else { 0 }).unwrap();
buf.write_i32::<LittleEndian>(end_seconds_offset).unwrap();
buf.write_u8(if self.is_continuous_recorder() { 1 } else { 0 }).unwrap();
buf.write_u8(if self.use_low_power_mode() { 1 } else { 0 }).unwrap();
buf.write_u8(if self.is_continuous_recorder() { 1 } else { 0 })
.unwrap();
buf.write_u8(if self.use_low_power_mode() { 1 } else { 0 })
.unwrap();

let device_name = self.device_name();
let device_name_length = device_name.len().min(63);
Expand Down Expand Up @@ -911,7 +970,10 @@ pub fn watch_local_config_file_changes(
// Add a path to be watched. All files and directories at that path and
// below will be monitored for changes.
watcher
.watch(Path::new("/etc/cacophony/config.toml"), RecursiveMode::NonRecursive)
.watch(
Path::new("/etc/cacophony/config.toml"),
RecursiveMode::NonRecursive,
)
.map_err(|e| {
error!("File watcher setup error: {e}");
process::exit(1);
Expand Down
43 changes: 30 additions & 13 deletions src/frame_socket_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,9 @@ pub fn spawn_frame_socket_server_thread(
recording_state: &RecordingState,
) {
let recording_state = recording_state.clone();
let _ = thread::Builder::new().name("frame-socket".to_string()).spawn_with_priority(
ThreadPriority::Max,
move |result| {
let _ = thread::Builder::new()
.name("frame-socket".to_string())
.spawn_with_priority(ThreadPriority::Max, move |result| {
let address = get_socket_address(serve_frames_via_wifi);
let management_address = "/var/spool/managementd".to_string();
// Spawn a thread which can output the frames, converted to rgb grayscale
Expand All @@ -63,8 +63,10 @@ pub fn spawn_frame_socket_server_thread(

let mut reconnects = 0;
let mut prev_frame_num = None;
let mut sockets: [(String, bool, Option<SocketStream>); 2] =
[(address, serve_frames_via_wifi, None), (management_address, false, None)];
let mut sockets: [(String, bool, Option<SocketStream>); 2] = [
(address, serve_frames_via_wifi, None),
(management_address, false, None),
];
loop {
restart_rp2040_if_requested(
&restart_rp2040_channel_rx,
Expand Down Expand Up @@ -92,8 +94,10 @@ pub fn spawn_frame_socket_server_thread(
*stream = stream_connection;
}

let connections =
sockets.iter().filter(|(_, _, stream)| stream.is_some()).count();
let connections = sockets
.iter()
.filter(|(_, _, stream)| stream.is_some())
.count();
if connections == 0 {
sleep(Duration::from_millis(1000));
continue;
Expand All @@ -112,8 +116,7 @@ pub fn spawn_frame_socket_server_thread(
);
}
}
},
);
});
}

fn handle_payload_from_frame_acquire_thread(
Expand All @@ -136,7 +139,11 @@ fn handle_payload_from_frame_acquire_thread(
}),
camera_file_transfer_in_progress: false,
}) => {
let model = if radiometry_enabled { "lepton3.5" } else { "lepton3" };
let model = if radiometry_enabled {
"lepton3.5"
} else {
"lepton3"
};
let header = format!(
"ResX: 160\n\
ResX: 160\n\
Expand All @@ -151,7 +158,9 @@ fn handle_payload_from_frame_acquire_thread(
for (_, _, stream) in sockets.iter_mut().filter(|(_, use_wifi, stream)| {
stream.is_some() && !use_wifi && !stream.as_ref().unwrap().sent_header
}) {
let stream = stream.as_mut().expect("Never fails, because we filtered already.");
let stream = stream
.as_mut()
.expect("Never fails, because we filtered already.");
if stream.write_all(header.as_bytes()).is_err() {
warn!("Failed sending header info");
}
Expand Down Expand Up @@ -181,7 +190,11 @@ fn handle_payload_from_frame_acquire_thread(
if !sent {
warn!(
"Send to {} failed",
if *use_wifi { "tc2-frames server" } else { address }
if *use_wifi {
"tc2-frames server"
} else {
address
}
);
let _ = stream.take().expect("Never fails").shutdown().is_ok();
}
Expand Down Expand Up @@ -227,7 +240,11 @@ fn handle_payload_from_frame_acquire_thread(
{
info!(
"Shutting down socket '{}'",
if *use_wifi { "tc2-frames server" } else { address }
if *use_wifi {
"tc2-frames server"
} else {
address
}
);
let _ = stream.take().unwrap().shutdown().is_ok();
}
Expand Down
Loading

0 comments on commit 00f4aab

Please sign in to comment.