Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -113,9 +113,6 @@ end
function CameraAttributeHandlers.rate_distortion_trade_off_points_handler(driver, device, ib, response)
if not ib.data.elements then return end
local resolutions = {}
local max_encoded_pixel_rate = device:get_field(camera_fields.MAX_ENCODED_PIXEL_RATE)
local max_fps = device:get_field(camera_fields.MAX_FRAMES_PER_SECOND)
local emit_capability = max_encoded_pixel_rate ~= nil and max_fps ~= nil
for _, v in ipairs(ib.data.elements) do
local rate_distortion_trade_off_points = v.elements
local width = rate_distortion_trade_off_points.resolution.elements.width.value
Expand All @@ -124,77 +121,63 @@ function CameraAttributeHandlers.rate_distortion_trade_off_points_handler(driver
width = width,
height = height
})
if emit_capability then
local fps = camera_utils.compute_fps(max_encoded_pixel_rate, width, height, max_fps)
if fps > 0 then
resolutions[#resolutions].fps = fps
end
end
end
if emit_capability then
device:emit_event_for_endpoint(ib, capabilities.videoStreamSettings.supportedResolutions(resolutions))
end
device:set_field(camera_fields.SUPPORTED_RESOLUTIONS, resolutions)
local max_encoded_pixel_rate = device:get_field(camera_fields.MAX_ENCODED_PIXEL_RATE)
local max_fps = device:get_field(camera_fields.MAX_FRAMES_PER_SECOND)
if max_encoded_pixel_rate and max_fps and device:get_field(camera_fields.MAX_RESOLUTION) and device:get_field(camera_fields.MIN_RESOLUTION) then
local supported_resolutions = camera_utils.build_supported_resolutions(device, max_encoded_pixel_rate, max_fps)
device:emit_event_for_endpoint(ib, capabilities.videoStreamSettings.supportedResolutions(supported_resolutions))
end
end

function CameraAttributeHandlers.max_encoded_pixel_rate_handler(driver, device, ib, response)
local resolutions = device:get_field(camera_fields.SUPPORTED_RESOLUTIONS)
device:set_field(camera_fields.MAX_ENCODED_PIXEL_RATE, ib.data.value)
local max_fps = device:get_field(camera_fields.MAX_FRAMES_PER_SECOND)
local emit_capability = resolutions ~= nil and max_fps ~= nil
if emit_capability then
for _, v in pairs(resolutions or {}) do
local fps = camera_utils.compute_fps(ib.data.value, v.width, v.height, max_fps)
if fps > 0 then
v.fps = fps
end
end
device:emit_event_for_endpoint(ib, capabilities.videoStreamSettings.supportedResolutions(resolutions))
if max_fps and device:get_field(camera_fields.SUPPORTED_RESOLUTIONS) and device:get_field(camera_fields.MAX_RESOLUTION) and device:get_field(camera_fields.MIN_RESOLUTION) then
local supported_resolutions = camera_utils.build_supported_resolutions(device, ib.data.value, max_fps)
device:emit_event_for_endpoint(ib, capabilities.videoStreamSettings.supportedResolutions(supported_resolutions))
end
device:set_field(camera_fields.MAX_ENCODED_PIXEL_RATE, ib.data.value)
end

function CameraAttributeHandlers.video_sensor_parameters_handler(driver, device, ib, response)
if not ib.data.elements then return end
local resolutions = device:get_field(camera_fields.SUPPORTED_RESOLUTIONS)
local sensor_width = ib.data.elements.sensor_width.value
local sensor_height = ib.data.elements.sensor_height.value
local max_fps = ib.data.elements.max_fps.value
device:set_field(camera_fields.MAX_RESOLUTION, {
width = sensor_width,
height = sensor_height
})
device:set_field(camera_fields.MAX_FRAMES_PER_SECOND, max_fps)
device:emit_event_for_endpoint(ib, capabilities.cameraViewportSettings.videoSensorParameters({
width = sensor_width,
height = sensor_height,
maxFPS = max_fps
}))
local max_encoded_pixel_rate = device:get_field(camera_fields.MAX_ENCODED_PIXEL_RATE)
local emit_capability = resolutions ~= nil and max_encoded_pixel_rate ~= nil
local sensor_width, sensor_height, max_fps
for _, v in pairs(ib.data.elements) do
if v.field_id == 0 then
sensor_width = v.value
elseif v.field_id == 1 then
sensor_height = v.value
elseif v.field_id == 2 then
max_fps = v.value
end
end

if max_fps then
if sensor_width and sensor_height then
device:emit_event_for_endpoint(ib, capabilities.cameraViewportSettings.videoSensorParameters({
width = sensor_width,
height = sensor_height,
maxFPS = max_fps
}))
end
if emit_capability then
for _, v in pairs(resolutions or {}) do
local fps = camera_utils.compute_fps(max_encoded_pixel_rate, v.width, v.height, max_fps)
if fps > 0 then
v.fps = fps
end
end
device:emit_event_for_endpoint(ib, capabilities.videoStreamSettings.supportedResolutions(resolutions))
end
device:set_field(camera_fields.MAX_FRAMES_PER_SECOND, max_fps)
if max_encoded_pixel_rate and max_fps and device:get_field(camera_fields.SUPPORTED_RESOLUTIONS) and device:get_field(camera_fields.MIN_RESOLUTION) then
local supported_resolutions = camera_utils.build_supported_resolutions(device, max_encoded_pixel_rate, max_fps)
device:emit_event_for_endpoint(ib, capabilities.videoStreamSettings.supportedResolutions(supported_resolutions))
end
end

function CameraAttributeHandlers.min_viewport_handler(driver, device, ib, response)
if not ib.data.elements then return end
device:emit_event_for_endpoint(ib, capabilities.cameraViewportSettings.minViewportResolution({
width = ib.data.elements.width.value,
height = ib.data.elements.height.value
}))
device:set_field(camera_fields.MIN_RESOLUTION, {
width = ib.data.elements.width.value,
height = ib.data.elements.height.value
})
local max_encoded_pixel_rate = device:get_field(camera_fields.MAX_ENCODED_PIXEL_RATE)
local max_fps = device:get_field(camera_fields.MAX_FRAMES_PER_SECOND)
if max_encoded_pixel_rate and max_fps and device:get_field(camera_fields.SUPPORTED_RESOLUTIONS) and device:get_field(camera_fields.MAX_RESOLUTION) then
local supported_resolutions = camera_utils.build_supported_resolutions(device, max_encoded_pixel_rate, max_fps)
device:emit_event_for_endpoint(ib, capabilities.videoStreamSettings.supportedResolutions(supported_resolutions))
end
end

function CameraAttributeHandlers.allocated_video_streams_handler(driver, device, ib, response)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ CameraFields.MAX_FRAMES_PER_SECOND = "__max_frames_per_second"
CameraFields.MAX_VOLUME_LEVEL = "__max_volume_level"
CameraFields.MIN_VOLUME_LEVEL = "__min_volume_level"
CameraFields.SUPPORTED_RESOLUTIONS = "__supported_resolutions"
CameraFields.MAX_RESOLUTION = "__max_resolution"
CameraFields.MIN_RESOLUTION = "__min_resolution"
CameraFields.TRIGGERED_ZONES = "__triggered_zones"
CameraFields.VIEWPORT = "__viewport"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,38 @@ function CameraUtils.compute_fps(max_encoded_pixel_rate, width, height, max_fps)
return math.tointeger(math.floor(fps / fps_step) * fps_step)
end

function CameraUtils.build_supported_resolutions(device, max_encoded_pixel_rate, max_fps)
local resolutions = {}
local added_resolutions = {}

local function add_resolution(width, height)
local key = width .. "x" .. height
if not added_resolutions[key] then
local resolution = { width = width, height = height }
resolution.fps = CameraUtils.compute_fps(max_encoded_pixel_rate, width, height, max_fps)
table.insert(resolutions, resolution)
added_resolutions[key] = true
end
end

local min_resolution = device:get_field(camera_fields.MIN_RESOLUTION)
if min_resolution then
add_resolution(min_resolution.width, min_resolution.height)
end

local trade_off_resolutions = device:get_field(camera_fields.SUPPORTED_RESOLUTIONS)
for _, v in pairs(trade_off_resolutions or {}) do
add_resolution(v.width, v.height)
end

local max_resolution = device:get_field(camera_fields.MAX_RESOLUTION)
if max_resolution then
add_resolution(max_resolution.width, max_resolution.height)
end

return resolutions
end

function CameraUtils.profile_changed(synced_components, prev_components)
if #synced_components ~= #prev_components then
return true
Expand Down
38 changes: 35 additions & 3 deletions drivers/SmartThings/matter-switch/src/test/test_matter_camera.lua
Original file line number Diff line number Diff line change
Expand Up @@ -683,6 +683,18 @@ local function receive_max_encoded_pixel_rate()
})
end

local function receive_min_viewport()
test.socket.matter:__queue_receive({
mock_device.id,
clusters.CameraAvStreamManagement.attributes.MinViewportResolution:build_test_report_data(
mock_device, CAMERA_EP, clusters.CameraAvStreamManagement.types.VideoResolutionStruct({
width = 1920,
height = 1080
})
)
})
end

local function receive_video_sensor_params()
test.socket.matter:__queue_receive({
mock_device.id,
Expand All @@ -697,6 +709,15 @@ local function receive_video_sensor_params()
})
end

local function emit_min_viewport()
test.socket.capability:__expect_send(
mock_device:generate_test_message("main", capabilities.cameraViewportSettings.minViewportResolution({
width = 1920,
height = 1080,
}))
)
end

local function emit_video_sensor_parameters()
test.socket.capability:__expect_send(
mock_device:generate_test_message("main", capabilities.cameraViewportSettings.videoSensorParameters({
Expand All @@ -719,6 +740,11 @@ local function emit_supported_resolutions()
width = 3840,
height = 2160,
fps = 15
},
{
width = 7360,
height = 4912,
fps = 0
}
}))
)
Expand All @@ -730,24 +756,28 @@ end
-- videoStreamSettings.supportedResolutions is emitted after all three attributes are received.

test.register_coroutine_test(
"Rate Distortion Trade Off Points, MaxEncodedPixelRate, VideoSensorParams reports should generate appropriate events",
"Rate Distortion Trade Off Points, MaxEncodedPixelRate, MinViewport, VideoSensorParams reports should generate appropriate events",
function()
update_device_profile()
test.wait_for_events()
receive_rate_distortion_trade_off_points()
receive_max_encoded_pixel_rate()
receive_min_viewport()
emit_min_viewport()
receive_video_sensor_params()
emit_video_sensor_parameters()
emit_supported_resolutions()
end
)

test.register_coroutine_test(
"Rate Distortion Trade Off Points, VideoSensorParams, MaxEncodedPixelRate reports should generate appropriate events",
"Rate Distortion Trade Off Points, MinViewport, VideoSensorParams, MaxEncodedPixelRate reports should generate appropriate events",
function()
update_device_profile()
test.wait_for_events()
receive_rate_distortion_trade_off_points()
receive_min_viewport()
emit_min_viewport()
receive_video_sensor_params()
emit_video_sensor_parameters()
receive_max_encoded_pixel_rate()
Expand All @@ -756,11 +786,13 @@ test.register_coroutine_test(
)

test.register_coroutine_test(
"MaxEncodedPixelRate, VideoSensorParams, Rate Distortion Trade Off Points reports should generate appropriate events",
"MaxEncodedPixelRate, MinViewport, VideoSensorParams, Rate Distortion Trade Off Points reports should generate appropriate events",
function()
update_device_profile()
test.wait_for_events()
receive_max_encoded_pixel_rate()
receive_min_viewport()
emit_min_viewport()
receive_video_sensor_params()
emit_video_sensor_parameters()
receive_rate_distortion_trade_off_points()
Expand Down
Loading