Skip to content

Commit 8c6b921

Browse files
authored
camera zoom and focus (#924)
1 parent e2f8031 commit 8c6b921

File tree

2 files changed

+64
-0
lines changed

2 files changed

+64
-0
lines changed

packages/stream_video/CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
## Unreleased
2+
3+
✅ Added
4+
* Added camera focus and zoom control features:
5+
* New `Call.setZoom()` method that allows adjusting camera zoom level.
6+
* New `Call.focus()` method that enables setting focus and exposure points on the camera.
7+
18
## 0.9.0
29

310
✅ Added

packages/stream_video/lib/src/call/call.dart

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// ignore_for_file: deprecated_member_use_from_same_package
22

33
import 'dart:async';
4+
import 'dart:math';
45
import 'dart:typed_data';
56

67
import 'package:collection/collection.dart';
@@ -2137,6 +2138,62 @@ class Call {
21372138
return const Result.success(false);
21382139
}
21392140

2141+
Future<Result<None>> setZoom({
2142+
required double zoomLevel,
2143+
}) async {
2144+
_logger.d(() => '[setZoom] zoomLevel: $zoomLevel');
2145+
2146+
final localTrackIdPrefix = state.value.localParticipant?.trackIdPrefix;
2147+
2148+
if (localTrackIdPrefix == null) {
2149+
_logger.w(() => '[setZoom] local participant not found');
2150+
return Result.error('Local participant not found');
2151+
}
2152+
final localTrack =
2153+
_session?.getTrack(localTrackIdPrefix, SfuTrackType.video);
2154+
2155+
if (localTrack == null) {
2156+
_logger.w(() => '[setZoom] local track not found');
2157+
return Result.error('Local track not found');
2158+
}
2159+
2160+
try {
2161+
await rtc.Helper.setZoom(localTrack.mediaTrack, zoomLevel);
2162+
return const Result.success(none);
2163+
} catch (error, stackTrace) {
2164+
_logger.e(() => '[setZoom] Failed to set zoom: $error');
2165+
return Result.error('Failed to set zoom', stackTrace);
2166+
}
2167+
}
2168+
2169+
Future<Result<None>> focus({Point<double>? focusPoint}) async {
2170+
_logger.d(() => '[focus] focusPoint: $focusPoint');
2171+
2172+
final localTrackIdPrefix = state.value.localParticipant?.trackIdPrefix;
2173+
2174+
if (localTrackIdPrefix == null) {
2175+
_logger.w(() => '[focus] local participant not found');
2176+
return Result.error('Local participant not found');
2177+
}
2178+
2179+
final localTrack =
2180+
_session?.getTrack(localTrackIdPrefix, SfuTrackType.video);
2181+
if (localTrack == null) {
2182+
_logger.w(() => '[focus] local track not found');
2183+
return Result.error('Local track not found');
2184+
}
2185+
2186+
try {
2187+
await Helper.setFocusPoint(localTrack.mediaTrack, focusPoint);
2188+
await Helper.setExposurePoint(localTrack.mediaTrack, focusPoint);
2189+
} catch (error, stackTrace) {
2190+
_logger.e(() => '[focus] Failed to set focus: $error');
2191+
return Result.error('Failed to set focus', stackTrace);
2192+
}
2193+
2194+
return const Result.success(none);
2195+
}
2196+
21402197
Future<Result<None>> setVideoInputDevice(RtcMediaDevice device) async {
21412198
final result = await _session?.setVideoInputDevice(device) ??
21422199
Result.error('Session is null');

0 commit comments

Comments
 (0)