Skip to content

Commit da00877

Browse files
committed
feat(recording): add presentation minize events to layout.xml
- Include the info when presentation is minimized by presenter with push layout on: <?xml version="1.0" encoding="UTF-8"?> <recording id="layout_swap_events"> <event timestamp="0.0" show_screenshare="false"/> <event timestamp="6.0" show_screenshare="true"/> <event timestamp="12.7" show_screenshare="false"/> <event timestamp="19.7" show_presentation="true"/> <event timestamp="21.6" show_presentation="false"/> <event timestamp="24.8" show_presentation="true"/> <event timestamp="29.9" show_presentation="false"/> </recording>
1 parent 3f5d66f commit da00877

2 files changed

Lines changed: 75 additions & 33 deletions

File tree

record-and-playback/core/lib/recordandplayback/generators/events.rb

Lines changed: 58 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1167,17 +1167,20 @@ def self.screenshare_has_audio?(events, deskshare_dir)
11671167
return false
11681168
end
11691169

1170-
# Get a list of times when the "screenshare as content" flag is changed
1170+
# Generic function to get a list of times when a specific state changes
11711171
#
11721172
# The returned times account for recording start/stop events, and have timestamps relative to the start of the
11731173
# recording.
11741174
#
11751175
# @param events [Nokogiri::XML::Document] The parsed events.xml document
11761176
# @param start_time [Integer] The recording segment start timestamp (ms)
11771177
# @param end_time [Integer] The recording segment end timestamp (ms)
1178-
# @return [Array<Hash>] An array of events, each with a timestamp and the screenshareAsContent flag
1179-
def self.get_screenshare_as_content_events(events, start_time, end_time)
1180-
BigBlueButton.logger.info('Getting Screenshare as Content Events')
1178+
# @param target_module [String] The module name of the event to track
1179+
# @param target_eventname [String] The event name to track
1180+
# @param compare_keys [Array<Symbol>] Optional list of keys to compare for state changes. If nil, all keys are compared.
1181+
# @return [Array<Hash>] An array of events, each with a timestamp and the extracted state
1182+
def self.get_events(events, start_time, end_time, target_module, target_eventname, compare_keys = nil)
1183+
BigBlueButton.logger.info("Getting #{target_eventname} Events")
11811184

11821185
initial_timestamp = first_event_timestamp(events)
11831186
start_time -= initial_timestamp
@@ -1188,25 +1191,32 @@ def self.get_screenshare_as_content_events(events, start_time, end_time)
11881191
# Recordings without status events are assumed to have been recorded from the beginning
11891192
record = events.at_xpath('/recording/event[@eventname="RecordStatusEvent"]').nil?
11901193

1191-
screenshare_content_events = []
1194+
extracted_events = []
1195+
current_state = nil
11921196

11931197
events.xpath('/recording/event').each do |event|
11941198
timestamp = event[:timestamp].to_i - initial_timestamp
11951199
break if timestamp >= end_time
11961200

11971201
case [event[:module], event[:eventname]]
1198-
when %w[PARTICIPANT SetScreenshareAsContentEvent]
1199-
screenshare_as_content = event.at_xpath('screenshareAsContent')&.content == 'true'
1202+
when [target_module, target_eventname]
1203+
current_state = yield(event)
12001204

12011205
# Don't emit events during unrecorded sections of the meeting. An event will be emitted when recording resumes
12021206
next unless timestamp >= start_time && record
1207+
12031208
# Don't emit an event if the previous event has the same state
1204-
next if screenshare_content_events.dig(-1, :screenshareAsContent) == screenshare_as_content
1209+
if extracted_events.last
1210+
last_event = extracted_events.last.reject { |k| k == :timestamp }
1211+
if compare_keys
1212+
next if last_event.select { |k, _| compare_keys.include?(k) } == current_state.select { |k, _| compare_keys.include?(k) }
1213+
else
1214+
next if last_event == current_state
1215+
end
1216+
end
1217+
1218+
extracted_events << current_state.merge(timestamp: timestamp - offset)
12051219

1206-
screenshare_content_events << {
1207-
timestamp: timestamp - offset,
1208-
screenshareAsContent: screenshare_as_content,
1209-
}
12101220
when %w[PARTICIPANT RecordStatusEvent]
12111221
record = event.at_xpath('status').content == 'true'
12121222
# Don't update timestamps until we're past the segment start time
@@ -1217,12 +1227,17 @@ def self.get_screenshare_as_content_events(events, start_time, end_time)
12171227
offset += timestamp - last_stop_timestamp
12181228

12191229
# Don't emit an event if the previous event has the same state
1220-
next if screenshare_content_events.dig(-1, :screenshareAsContent) == screenshare_as_content
1230+
next if current_state.nil?
1231+
if extracted_events.last
1232+
last_event = extracted_events.last.reject { |k| k == :timestamp }
1233+
if compare_keys
1234+
next if last_event.select { |k, _| compare_keys.include?(k) } == current_state.select { |k, _| compare_keys.include?(k) }
1235+
else
1236+
next if last_event == current_state
1237+
end
1238+
end
12211239

1222-
screenshare_content_events << {
1223-
timestamp: timestamp - offset,
1224-
screenshareAsContent: screenshare_as_content,
1225-
}
1240+
extracted_events << current_state.merge(timestamp: timestamp - offset)
12261241
else
12271242
# Recording paused
12281243
last_stop_timestamp = timestamp
@@ -1232,18 +1247,36 @@ def self.get_screenshare_as_content_events(events, start_time, end_time)
12321247
# whatever the state happened to be when start_time was reached
12331248

12341249
# Don't emit an event during unrecorded sections of the meeting, or if one has already been emitted.
1235-
next unless timestamp >= start_time && record && screenshare_content_events.empty?
1250+
next unless timestamp >= start_time && record && extracted_events.empty?
12361251

1237-
# Don't emit an event if we haven't seen a SetScreenshareAsContentEvent yet
1238-
next if screenshare_as_content.nil?
1252+
# Don't emit an event if we haven't seen the target event yet
1253+
next if current_state.nil?
12391254

1240-
screenshare_content_events << {
1241-
timestamp: 0,
1242-
screenshareAsContent: screenshare_as_content,
1243-
}
1255+
extracted_events << current_state.merge(timestamp: 0)
12441256
end
12451257
end
1246-
screenshare_content_events
1258+
extracted_events
1259+
end
1260+
1261+
def self.get_screenshare_as_content_events(events, start_time, end_time)
1262+
get_events(events, start_time, end_time, 'PARTICIPANT', 'SetScreenshareAsContentEvent', [:screenshareAsContent]) do |event|
1263+
{
1264+
screenshareAsContent: event.at_xpath('screenshareAsContent')&.content == "true"
1265+
}
1266+
end
1267+
end
1268+
1269+
def self.get_layout_broadcasted_events(events, start_time, end_time)
1270+
get_events(events, start_time, end_time, 'PARTICIPANT', 'LayoutBroadcastedEvent', [:presentationIsOpen]) do |event|
1271+
{
1272+
focusedCamera: event.at_xpath('focusedCamera')&.content,
1273+
presentationVideoRate: event.at_xpath('presentationVideoRate')&.content.to_f,
1274+
cameraPosition: event.at_xpath('cameraPosition')&.content,
1275+
layout: event.at_xpath('layout')&.content,
1276+
presentationIsOpen: event.at_xpath('presentationIsOpen')&.content == "true",
1277+
isResizing: event.at_xpath('isResizing')&.content == "true"
1278+
}
1279+
end
12471280
end
12481281
end
12491282
end

record-and-playback/presentation/scripts/publish/presentation.rb

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1316,18 +1316,27 @@ def copy_media_files_helper(media, media_files, package_dir)
13161316
end
13171317
end
13181318

1319-
def process_swap_events(events)
1320-
BigBlueButton.logger.info("Processing screenshare as content events")
1319+
def process_layout_events(events)
1320+
BigBlueButton.logger.info("Processing screenshare as content and layout events")
13211321
swap_events = BigBlueButton::Events.get_screenshare_as_content_events(events, @meeting_start.to_i, @meeting_end.to_i)
1322+
layout_events = BigBlueButton::Events.get_layout_broadcasted_events(events, @meeting_start.to_i, @meeting_end.to_i)
13221323
@layout_swap_xml = Builder::XmlMarkup.new(indent: 2)
13231324
@layout_swap_xml.instruct!
13241325

13251326
@layout_swap_xml.recording('id' => 'layout_swap_events') do
1326-
swap_events.each do |event|
1327-
@layout_swap_xml.event(
1328-
timestamp: (event[:timestamp].to_f / 1000.0).round(1),
1329-
show_screenshare: event[:screenshareAsContent],
1330-
)
1327+
# Merge and sort events chronologically
1328+
all_events = (swap_events + layout_events).sort_by { |e| e[:timestamp] }
1329+
1330+
all_events.each do |event|
1331+
attributes = { timestamp: (event[:timestamp].to_f / 1000.0).round(1) }
1332+
1333+
if event.key?(:screenshareAsContent)
1334+
attributes[:show_screenshare] = event[:screenshareAsContent]
1335+
elsif event.key?(:presentationIsOpen)
1336+
attributes[:show_presentation] = event[:presentationIsOpen]
1337+
end
1338+
1339+
@layout_swap_xml.event(attributes)
13311340
end
13321341
end
13331342
end
@@ -1497,7 +1506,7 @@ def process_swap_events(events)
14971506

14981507
process_deskshare_events(@doc)
14991508

1500-
process_swap_events(@doc)
1509+
process_layout_events(@doc)
15011510

15021511
process_poll_events(@doc, package_dir)
15031512

0 commit comments

Comments
 (0)