Skip to content

Commit 3b8ab86

Browse files
committed
Use a camera-specific EventChannel
Instead of a global `EventSink` that is re-used for each stream, create a dedicated `EventChannel` for each capture stream. The channel gets an unique name like `plugins.flutter.io/camera_android/imageStream/<cameraId>` for each camera instance. Addresses: flutter#7067 (comment)
1 parent 1f5ab72 commit 3b8ab86

File tree

4 files changed

+44
-56
lines changed

4 files changed

+44
-56
lines changed

packages/camera/camera_windows/lib/camera_windows.dart

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ class CameraWindows extends CameraPlatform {
133133

134134
@override
135135
Future<void> dispose(int cameraId) async {
136+
await _stopPlatformStream(cameraId);
136137
await _hostApi.dispose(cameraId);
137138

138139
// Destroy method channel after camera is disposed to be able to handle last messages.
@@ -266,13 +267,14 @@ class CameraWindows extends CameraPlatform {
266267
}
267268

268269
Future<void> _startPlatformStream(int cameraId) async {
269-
_startStreamListener();
270270
await _hostApi.startImageStream(cameraId);
271+
_startStreamListener(cameraId);
271272
}
272273

273-
void _startStreamListener() {
274-
const EventChannel cameraEventChannel =
275-
EventChannel('plugins.flutter.io/camera_android/imageStream');
274+
void _startStreamListener(int cameraId) {
275+
final eventChannelName =
276+
'plugins.flutter.io/camera_windows/imageStream/$cameraId';
277+
final EventChannel cameraEventChannel = EventChannel(eventChannelName);
276278
_platformImageStreamSubscription =
277279
cameraEventChannel.receiveBroadcastStream().listen((dynamic imageData) {
278280
_frameStreamController!
@@ -281,6 +283,10 @@ class CameraWindows extends CameraPlatform {
281283
}
282284

283285
FutureOr<void> _onFrameStreamCancel(int cameraId) async {
286+
await _stopPlatformStream(cameraId);
287+
}
288+
289+
Future<void> _stopPlatformStream(int cameraId) async {
284290
await _hostApi.stopImageStream(cameraId);
285291
await _platformImageStreamSubscription?.cancel();
286292
_platformImageStreamSubscription = null;

packages/camera/camera_windows/windows/camera_plugin.cpp

Lines changed: 22 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include <cassert>
2020
#include <chrono>
2121
#include <memory>
22+
#include <sstream>
2223

2324
#include "capture_device_info.h"
2425
#include "com_heap_ptr.h"
@@ -35,10 +36,6 @@ namespace {
3536

3637
const std::string kPictureCaptureExtension = "jpeg";
3738
const std::string kVideoCaptureExtension = "mp4";
38-
constexpr char kFrameEventChannelName[] =
39-
"plugins.flutter.io/camera_android/imageStream";
40-
41-
std::unique_ptr<flutter::EventSink<flutter::EncodableValue>> event_sink;
4239

4340
// Builds CaptureDeviceInfo object from given device holding device name and id.
4441
std::unique_ptr<CaptureDeviceInfo> GetDeviceInfo(IMFActivate* device) {
@@ -123,34 +120,12 @@ std::optional<std::string> GetFilePathForVideo() {
123120
}
124121
} // namespace
125122

126-
// a setter for the event sink helpful for testing.
127-
void CameraPlugin::SetEventSink(
128-
std::unique_ptr<flutter::EventSink<flutter::EncodableValue>> events) {
129-
event_sink = std::move(events);
130-
}
131-
132123
// static
133124
void CameraPlugin::RegisterWithRegistrar(
134125
flutter::PluginRegistrarWindows* registrar) {
135126
std::unique_ptr<CameraPlugin> plugin = std::make_unique<CameraPlugin>(
136127
registrar->texture_registrar(), registrar->messenger());
137128

138-
auto frameEventchannel = std::make_unique<flutter::EventChannel<>>(
139-
registrar->messenger(), kFrameEventChannelName,
140-
&flutter::StandardMethodCodec::GetInstance());
141-
142-
auto event_channel_handler =
143-
std::make_unique<flutter::StreamHandlerFunctions<>>(
144-
[plugin = plugin.get()](auto arguments, auto events) {
145-
plugin->SetEventSink(std::move(events));
146-
return nullptr;
147-
},
148-
[](auto arguments) {
149-
event_sink.reset();
150-
return nullptr;
151-
});
152-
frameEventchannel->SetStreamHandler(std::move(event_channel_handler));
153-
154129
CameraApi::SetUp(registrar->messenger(), plugin.get());
155130

156131
registrar->AddPlugin(std::move(plugin));
@@ -377,14 +352,29 @@ std::optional<FlutterError> CameraPlugin::StartImageStream(int64_t camera_id) {
377352
return FlutterError("camera_error", "Camera not created");
378353
}
379354

380-
if (!event_sink) {
381-
return FlutterError("camera_error",
382-
"Unable to make event channel from windows");
383-
}
384-
385355
CaptureController* cc = camera->GetCaptureController();
386356
assert(cc);
387-
cc->StartImageStream(std::move(event_sink));
357+
358+
std::ostringstream event_channel_name;
359+
event_channel_name << "plugins.flutter.io/camera_windows/imageStream/"
360+
<< camera_id;
361+
362+
auto frame_event_channel =
363+
flutter::EventChannel(messenger_, event_channel_name.str(),
364+
&flutter::StandardMethodCodec::GetInstance());
365+
366+
auto event_channel_handler =
367+
std::make_unique<flutter::StreamHandlerFunctions<>>(
368+
[cc](auto arguments, auto events) {
369+
cc->StartImageStream(std::move(events));
370+
return nullptr;
371+
},
372+
[cc](auto arguments) {
373+
cc->StopImageStream();
374+
return nullptr;
375+
});
376+
377+
frame_event_channel.SetStreamHandler(std::move(event_channel_handler));
388378

389379
return std::nullopt;
390380
}

packages/camera/camera_windows/windows/camera_plugin.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,6 @@ class CameraPlugin : public flutter::Plugin,
3232
public CameraApi,
3333
public VideoCaptureDeviceEnumerator {
3434
public:
35-
void SetEventSink(
36-
std::unique_ptr<flutter::EventSink<flutter::EncodableValue>> events);
3735
static void RegisterWithRegistrar(flutter::PluginRegistrarWindows* registrar);
3836

3937
CameraPlugin(flutter::TextureRegistrar* texture_registrar,

packages/camera/camera_windows/windows/test/camera_plugin_test.cpp

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,10 @@ using ::testing::_;
2727
using ::testing::DoAll;
2828
using ::testing::EndsWith;
2929
using ::testing::Eq;
30-
using ::testing::Pointee;
31-
using ::testing::Return;
3230
using ::testing::Optional;
31+
using ::testing::Pointee;
3332
using ::testing::Property;
33+
using ::testing::Return;
3434

3535
void MockInitCamera(MockCamera* camera, bool success) {
3636
EXPECT_CALL(*camera,
@@ -371,12 +371,10 @@ TEST(CameraPlugin, StartImageStreamHandlerCallsStartImageStream) {
371371

372372
EXPECT_CALL(*camera, GetCaptureController)
373373
.Times(1)
374-
.WillOnce([cam = camera.get()]() {
375-
return cam->capture_controller_.get();
376-
});
374+
.WillOnce(
375+
[cam = camera.get()]() { return cam->capture_controller_.get(); });
377376

378-
EXPECT_CALL(*capture_controller, StartImageStream)
379-
.Times(1);
377+
EXPECT_CALL(*capture_controller, StartImageStream).Times(1);
380378

381379
camera->camera_id_ = mock_camera_id;
382380
camera->capture_controller_ = std::move(capture_controller);
@@ -385,10 +383,6 @@ TEST(CameraPlugin, StartImageStreamHandlerCallsStartImageStream) {
385383
std::make_unique<MockBinaryMessenger>().get(),
386384
std::make_unique<MockCameraFactory>());
387385

388-
// Set the event sink to a mocked event sink.
389-
auto mock_event_sink = std::make_unique<MockEventSink>();
390-
plugin.SetEventSink(std::move(mock_event_sink));
391-
392386
// Add mocked camera to plugins camera list.
393387
plugin.AddCamera(std::move(camera));
394388

@@ -425,7 +419,8 @@ TEST(CameraPlugin, StartImageStreamHandlerErrorOnInvalidCameraId) {
425419
// Add mocked camera to plugins camera list.
426420
plugin.AddCamera(std::move(camera));
427421

428-
EXPECT_THAT(plugin.StartImageStream(missing_camera_id), Optional(Property("code", &FlutterError::code, "camera_error")));
422+
EXPECT_THAT(plugin.StartImageStream(missing_camera_id),
423+
Optional(Property("code", &FlutterError::code, "camera_error")));
429424
}
430425

431426
TEST(CameraPlugin, StopImageStreamHandlerCallsStopImageStream) {
@@ -445,12 +440,10 @@ TEST(CameraPlugin, StopImageStreamHandlerCallsStopImageStream) {
445440

446441
EXPECT_CALL(*camera, GetCaptureController)
447442
.Times(1)
448-
.WillOnce([cam = camera.get()]() {
449-
return cam->capture_controller_.get();
450-
});
443+
.WillOnce(
444+
[cam = camera.get()]() { return cam->capture_controller_.get(); });
451445

452-
EXPECT_CALL(*capture_controller, StopImageStream)
453-
.Times(1);
446+
EXPECT_CALL(*capture_controller, StopImageStream).Times(1);
454447

455448
camera->camera_id_ = mock_camera_id;
456449
camera->capture_controller_ = std::move(capture_controller);
@@ -495,7 +488,8 @@ TEST(CameraPlugin, StopImageStreamHandlerErrorOnInvalidCameraId) {
495488
// Add mocked camera to plugins camera list.
496489
plugin.AddCamera(std::move(camera));
497490

498-
EXPECT_THAT(plugin.StopImageStream(missing_camera_id), Optional(Property("code", &FlutterError::code, "camera_error")));
491+
EXPECT_THAT(plugin.StopImageStream(missing_camera_id),
492+
Optional(Property("code", &FlutterError::code, "camera_error")));
499493
}
500494

501495
TEST(CameraPlugin, InitializeHandlerErrorOnInvalidCameraId) {

0 commit comments

Comments
 (0)