flutter / flutter

Flutter makes it easy and fast to build beautiful apps for mobile and beyond
https://flutter.dev
BSD 3-Clause "New" or "Revised" License
164.97k stars 27.18k forks source link

[camera_web] Disposing of CameraController while recording is paused or in progress throws Error #135368

Open wreppun opened 12 months ago

wreppun commented 12 months ago

Is there an existing issue for this?

What package does this bug report belong to?

camera

What target platforms are you seeing this bug on?

Web

Have you already upgraded your packages?

Yes

Dependency versions

pubspec.lock ```lock # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: _fe_analyzer_shared: dependency: transitive description: name: _fe_analyzer_shared sha256: eb376e9acf6938204f90eb3b1f00b578640d3188b4c8a8ec054f9f479af8d051 url: "https://pub.dev" source: hosted version: "64.0.0" analyzer: dependency: transitive description: name: analyzer sha256: "69f54f967773f6c26c7dcb13e93d7ccee8b17a641689da39e878d5cf13b06893" url: "https://pub.dev" source: hosted version: "6.2.0" args: dependency: transitive description: name: args sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596 url: "https://pub.dev" source: hosted version: "2.4.2" async: dependency: transitive description: name: async sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" url: "https://pub.dev" source: hosted version: "2.11.0" boolean_selector: dependency: transitive description: name: boolean_selector sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" url: "https://pub.dev" source: hosted version: "2.1.1" build: dependency: transitive description: name: build sha256: "80184af8b6cb3e5c1c4ec6d8544d27711700bc3e6d2efad04238c7b5290889f0" url: "https://pub.dev" source: hosted version: "2.4.1" build_config: dependency: transitive description: name: build_config sha256: bf80fcfb46a29945b423bd9aad884590fb1dc69b330a4d4700cac476af1708d1 url: "https://pub.dev" source: hosted version: "1.1.1" build_daemon: dependency: transitive description: name: build_daemon sha256: "5f02d73eb2ba16483e693f80bee4f088563a820e47d1027d4cdfe62b5bb43e65" url: "https://pub.dev" source: hosted version: "4.0.0" build_resolvers: dependency: transitive description: name: build_resolvers sha256: d912852cce27c9e80a93603db721c267716894462e7033165178b91138587972 url: "https://pub.dev" source: hosted version: "2.3.2" build_runner: dependency: "direct dev" description: name: build_runner sha256: "10c6bcdbf9d049a0b666702cf1cee4ddfdc38f02a19d35ae392863b47519848b" url: "https://pub.dev" source: hosted version: "2.4.6" build_runner_core: dependency: transitive description: name: build_runner_core sha256: "6d6ee4276b1c5f34f21fdf39425202712d2be82019983d52f351c94aafbc2c41" url: "https://pub.dev" source: hosted version: "7.2.10" built_collection: dependency: transitive description: name: built_collection sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100" url: "https://pub.dev" source: hosted version: "5.1.1" built_value: dependency: transitive description: name: built_value sha256: ff627b645b28fb8bdb69e645f910c2458fd6b65f6585c3a53e0626024897dedf url: "https://pub.dev" source: hosted version: "8.6.2" camera: dependency: "direct main" description: path: ".." relative: true source: path version: "0.10.5+4" camera_android: dependency: transitive description: name: camera_android sha256: ed4f645848074166fc3b8e20350f83ca07e09a2becc1e185040ee561f955d4df url: "https://pub.dev" source: hosted version: "0.10.8+8" camera_avfoundation: dependency: transitive description: name: camera_avfoundation sha256: "718b60ed2e22b4067fe6e2c0e9ebe2856c2de5c8b1289ba95d10db85b0b00bc2" url: "https://pub.dev" source: hosted version: "0.9.13+4" camera_platform_interface: dependency: transitive description: name: camera_platform_interface sha256: "8734d1c682f034bdb12d0d6ff379b0535a9b8e44266b530025bf8266d6a62f28" url: "https://pub.dev" source: hosted version: "2.5.2" camera_web: dependency: transitive description: name: camera_web sha256: d4c2c571c7af04f8b10702ca16bb9ed2a26e64534171e8f75c9349b2c004d8f1 url: "https://pub.dev" source: hosted version: "0.3.2+3" characters: dependency: transitive description: name: characters sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" url: "https://pub.dev" source: hosted version: "1.3.0" checked_yaml: dependency: transitive description: name: checked_yaml sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff url: "https://pub.dev" source: hosted version: "2.0.3" clock: dependency: transitive description: name: clock sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf url: "https://pub.dev" source: hosted version: "1.1.1" code_builder: dependency: transitive description: name: code_builder sha256: "315a598c7fbe77f22de1c9da7cfd6fd21816312f16ffa124453b4fc679e540f1" url: "https://pub.dev" source: hosted version: "4.6.0" collection: dependency: transitive description: name: collection sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687 url: "https://pub.dev" source: hosted version: "1.17.2" convert: dependency: transitive description: name: convert sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" url: "https://pub.dev" source: hosted version: "3.1.1" cross_file: dependency: transitive description: name: cross_file sha256: fd832b5384d0d6da4f6df60b854d33accaaeb63aa9e10e736a87381f08dee2cb url: "https://pub.dev" source: hosted version: "0.3.3+5" crypto: dependency: transitive description: name: crypto sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab url: "https://pub.dev" source: hosted version: "3.0.3" dart_style: dependency: transitive description: name: dart_style sha256: abd7625e16f51f554ea244d090292945ec4d4be7bfbaf2ec8cccea568919d334 url: "https://pub.dev" source: hosted version: "2.3.3" fake_async: dependency: transitive description: name: fake_async sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" url: "https://pub.dev" source: hosted version: "1.3.1" ffi: dependency: transitive description: name: ffi sha256: "7bf0adc28a23d395f19f3f1eb21dd7cfd1dd9f8e1c50051c069122e6853bc878" url: "https://pub.dev" source: hosted version: "2.1.0" file: dependency: transitive description: name: file sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d" url: "https://pub.dev" source: hosted version: "6.1.4" fixnum: dependency: transitive description: name: fixnum sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1" url: "https://pub.dev" source: hosted version: "1.1.0" flutter: dependency: "direct main" description: flutter source: sdk version: "0.0.0" flutter_driver: dependency: "direct dev" description: flutter source: sdk version: "0.0.0" flutter_plugin_android_lifecycle: dependency: transitive description: name: flutter_plugin_android_lifecycle sha256: f185ac890306b5779ecbd611f52502d8d4d63d27703ef73161ca0407e815f02c url: "https://pub.dev" source: hosted version: "2.0.16" flutter_test: dependency: "direct dev" description: flutter source: sdk version: "0.0.0" flutter_web_plugins: dependency: transitive description: flutter source: sdk version: "0.0.0" frontend_server_client: dependency: transitive description: name: frontend_server_client sha256: "408e3ca148b31c20282ad6f37ebfa6f4bdc8fede5b74bc2f08d9d92b55db3612" url: "https://pub.dev" source: hosted version: "3.2.0" fuchsia_remote_debug_protocol: dependency: transitive description: flutter source: sdk version: "0.0.0" glob: dependency: transitive description: name: glob sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63" url: "https://pub.dev" source: hosted version: "2.1.2" graphs: dependency: transitive description: name: graphs sha256: aedc5a15e78fc65a6e23bcd927f24c64dd995062bcd1ca6eda65a3cff92a4d19 url: "https://pub.dev" source: hosted version: "2.3.1" http_multi_server: dependency: transitive description: name: http_multi_server sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b" url: "https://pub.dev" source: hosted version: "3.2.1" http_parser: dependency: transitive description: name: http_parser sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" url: "https://pub.dev" source: hosted version: "4.0.2" integration_test: dependency: "direct dev" description: flutter source: sdk version: "0.0.0" io: dependency: transitive description: name: io sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e" url: "https://pub.dev" source: hosted version: "1.0.4" js: dependency: transitive description: name: js sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 url: "https://pub.dev" source: hosted version: "0.6.7" json_annotation: dependency: transitive description: name: json_annotation sha256: b10a7b2ff83d83c777edba3c6a0f97045ddadd56c944e1a23a3fdf43a1bf4467 url: "https://pub.dev" source: hosted version: "4.8.1" logging: dependency: transitive description: name: logging sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340" url: "https://pub.dev" source: hosted version: "1.2.0" matcher: dependency: transitive description: name: matcher sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" url: "https://pub.dev" source: hosted version: "0.12.16" material_color_utilities: dependency: transitive description: name: material_color_utilities sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" url: "https://pub.dev" source: hosted version: "0.5.0" meta: dependency: transitive description: name: meta sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" url: "https://pub.dev" source: hosted version: "1.9.1" mime: dependency: transitive description: name: mime sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e url: "https://pub.dev" source: hosted version: "1.0.4" package_config: dependency: transitive description: name: package_config sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd" url: "https://pub.dev" source: hosted version: "2.1.0" path: dependency: transitive description: name: path sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" url: "https://pub.dev" source: hosted version: "1.8.3" path_provider: dependency: "direct main" description: name: path_provider sha256: a1aa8aaa2542a6bc57e381f132af822420216c80d4781f7aa085ca3229208aaa url: "https://pub.dev" source: hosted version: "2.1.1" path_provider_android: dependency: transitive description: name: path_provider_android sha256: "6b8b19bd80da4f11ce91b2d1fb931f3006911477cec227cce23d3253d80df3f1" url: "https://pub.dev" source: hosted version: "2.2.0" path_provider_foundation: dependency: transitive description: name: path_provider_foundation sha256: "19314d595120f82aca0ba62787d58dde2cc6b5df7d2f0daf72489e38d1b57f2d" url: "https://pub.dev" source: hosted version: "2.3.1" path_provider_linux: dependency: transitive description: name: path_provider_linux sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 url: "https://pub.dev" source: hosted version: "2.2.1" path_provider_platform_interface: dependency: transitive description: name: path_provider_platform_interface sha256: "94b1e0dd80970c1ce43d5d4e050a9918fce4f4a775e6142424c30a29a363265c" url: "https://pub.dev" source: hosted version: "2.1.1" path_provider_windows: dependency: transitive description: name: path_provider_windows sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170" url: "https://pub.dev" source: hosted version: "2.2.1" platform: dependency: transitive description: name: platform sha256: "4a451831508d7d6ca779f7ac6e212b4023dd5a7d08a27a63da33756410e32b76" url: "https://pub.dev" source: hosted version: "3.1.0" plugin_platform_interface: dependency: transitive description: name: plugin_platform_interface sha256: da3fdfeccc4d4ff2da8f8c556704c08f912542c5fb3cf2233ed75372384a034d url: "https://pub.dev" source: hosted version: "2.1.6" pool: dependency: transitive description: name: pool sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a" url: "https://pub.dev" source: hosted version: "1.5.1" process: dependency: transitive description: name: process sha256: "53fd8db9cec1d37b0574e12f07520d582019cb6c44abf5479a01505099a34a09" url: "https://pub.dev" source: hosted version: "4.2.4" pub_semver: dependency: transitive description: name: pub_semver sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c" url: "https://pub.dev" source: hosted version: "2.1.4" pubspec_parse: dependency: transitive description: name: pubspec_parse sha256: c63b2876e58e194e4b0828fcb080ad0e06d051cb607a6be51a9e084f47cb9367 url: "https://pub.dev" source: hosted version: "1.2.3" quiver: dependency: transitive description: name: quiver sha256: b1c1ac5ce6688d77f65f3375a9abb9319b3cb32486bdc7a1e0fdf004d7ba4e47 url: "https://pub.dev" source: hosted version: "3.2.1" shelf: dependency: transitive description: name: shelf sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4 url: "https://pub.dev" source: hosted version: "1.4.1" shelf_web_socket: dependency: transitive description: name: shelf_web_socket sha256: "9ca081be41c60190ebcb4766b2486a7d50261db7bd0f5d9615f2d653637a84c1" url: "https://pub.dev" source: hosted version: "1.0.4" sky_engine: dependency: transitive description: flutter source: sdk version: "0.0.99" source_span: dependency: transitive description: name: source_span sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" url: "https://pub.dev" source: hosted version: "1.10.0" stack_trace: dependency: transitive description: name: stack_trace sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 url: "https://pub.dev" source: hosted version: "1.11.0" stream_channel: dependency: transitive description: name: stream_channel sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" url: "https://pub.dev" source: hosted version: "2.1.1" stream_transform: dependency: transitive description: name: stream_transform sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f" url: "https://pub.dev" source: hosted version: "2.1.0" string_scanner: dependency: transitive description: name: string_scanner sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" url: "https://pub.dev" source: hosted version: "1.2.0" sync_http: dependency: transitive description: name: sync_http sha256: "7f0cd72eca000d2e026bcd6f990b81d0ca06022ef4e32fb257b30d3d1014a961" url: "https://pub.dev" source: hosted version: "0.3.1" term_glyph: dependency: transitive description: name: term_glyph sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 url: "https://pub.dev" source: hosted version: "1.2.1" test_api: dependency: transitive description: name: test_api sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8" url: "https://pub.dev" source: hosted version: "0.6.0" timing: dependency: transitive description: name: timing sha256: "70a3b636575d4163c477e6de42f247a23b315ae20e86442bebe32d3cabf61c32" url: "https://pub.dev" source: hosted version: "1.0.1" typed_data: dependency: transitive description: name: typed_data sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c url: "https://pub.dev" source: hosted version: "1.3.2" vector_math: dependency: transitive description: name: vector_math sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" url: "https://pub.dev" source: hosted version: "2.1.4" vm_service: dependency: transitive description: name: vm_service sha256: c620a6f783fa22436da68e42db7ebbf18b8c44b9a46ab911f666ff09ffd9153f url: "https://pub.dev" source: hosted version: "11.7.1" watcher: dependency: transitive description: name: watcher sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8" url: "https://pub.dev" source: hosted version: "1.1.0" web: dependency: transitive description: name: web sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10 url: "https://pub.dev" source: hosted version: "0.1.4-beta" web_socket_channel: dependency: transitive description: name: web_socket_channel sha256: d88238e5eac9a42bb43ca4e721edba3c08c6354d4a53063afaa568516217621b url: "https://pub.dev" source: hosted version: "2.4.0" webdriver: dependency: transitive description: name: webdriver sha256: "3c923e918918feeb90c4c9fdf1fe39220fa4c0e8e2c0fffaded174498ef86c49" url: "https://pub.dev" source: hosted version: "3.0.2" win32: dependency: transitive description: name: win32 sha256: "9e82a402b7f3d518fb9c02d0e9ae45952df31b9bf34d77baf19da2de03fc2aaa" url: "https://pub.dev" source: hosted version: "5.0.7" xdg_directories: dependency: transitive description: name: xdg_directories sha256: "589ada45ba9e39405c198fe34eb0f607cddb2108527e658136120892beac46d2" url: "https://pub.dev" source: hosted version: "1.0.3" yaml: dependency: transitive description: name: yaml sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" url: "https://pub.dev" source: hosted version: "3.1.2" sdks: dart: ">=3.1.0 <4.0.0" flutter: ">=3.13.0" ```

Steps to reproduce

  1. Tap on the Open Camera button
  2. Start recording
  3. [Optional] Pause the recording
  4. Hit cancel (which pops the navigator)

Expected results

CameraController disposes safely

Actual results

CameraController throws an error

Code sample

Code sample Note: to reproduct you can also just wrap the official example in a navigated-to scaffold to (and make sure to call `_cameraController.dispose` in the `dispose` method. But the official example is complex, and was throwing other errors in my logs. ```dart // ignore_for_file: public_member_api_docs, use_key_in_widget_constructors import 'dart:async'; import 'package:camera/camera.dart'; import 'package:flutter/material.dart'; Future main() async { try { WidgetsFlutterBinding.ensureInitialized(); } on CameraException catch (e) { print('${e.code}, ${e.description}'); } runApp(const CameraApp()); } class CameraApp extends StatelessWidget { const CameraApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( body: Center( child: Builder(builder: (innerContext) { return TextButton( onPressed: () async { final XFile? file = await Navigator.of(innerContext).push( MaterialPageRoute( builder: (_) => CameraRecorderWeb(), ), ); print('$file'); }, child: const Text('Open Camera'), ); }), ), ), ); } } enum RecordingMedium { audio, image, video } class CameraRecorderWeb extends StatefulWidget { const CameraRecorderWeb(); @override State createState() => _CameraRecorderWebState(); } enum RecorderState { loading, ready } class _CameraRecorderWebState extends State { late CameraController _controller; late final List _cameras; bool _initializedAtLeastOnce = false; RecorderState _cameraSelectorState = RecorderState.loading; RecorderState _previewState = RecorderState.loading; @override void initState() { super.initState(); _init(); } Future _init() async { _cameras = await availableCameras(); await _initController(_cameras.first); setState(() { _cameraSelectorState = RecorderState.ready; }); } Future _initController(CameraDescription cd) async { if (_initializedAtLeastOnce) { await _controller.dispose(); } setState(() { _previewState = RecorderState.loading; }); _controller = CameraController(cd, ResolutionPreset.max); try { await _controller.initialize(); _initializedAtLeastOnce = true; if (!mounted) { return; } _controller.addListener(() => setState(() {})); setState(() { _previewState = RecorderState.ready; }); } catch (e) { if (e is CameraException) { print(e); // Handle access errors here. } } } @override void dispose() { debugPrint('disposing of camera controller'); _controller.dispose(); super.dispose(); } Future setCamera(CameraDescription cd) async { if (cd == _controller.description) { return; } await _initController(cd); } List> buildMenuItems() { return _cameras .map((cd) => DropdownMenuEntry(value: cd, label: cd.name)) .toList(); } void _start() { _controller.startVideoRecording(); } void _pause() { _controller.pauseVideoRecording(); } void _resume() { _controller.resumeVideoRecording(); } void _cancel() { Navigator.of(context).pop(); } Future _save() async { final XFile file = await _controller.stopVideoRecording(); if (mounted) { Navigator.of(context).pop(file); } } @override Widget build(BuildContext context) { if (_cameraSelectorState == RecorderState.loading) { return const Scaffold(body: Center(child: CircularProgressIndicator())); } return Scaffold( body: Row( children: [ Flexible( child: Center( child: Container( constraints: const BoxConstraints(maxWidth: 600), child: Column( children: [ const SizedBox(height: 24), Row( children: [ DropdownMenu( initialSelection: _controller.description, dropdownMenuEntries: [ ...buildMenuItems(), ], onSelected: (cd) => setCamera(cd ?? _cameras.first), ), ], ), const SizedBox(height: 24), Expanded( child: Stack( children: [ Center( child: _previewState == RecorderState.loading ? const CircularProgressIndicator() : CameraPreview(_controller), ), ], ), ), const SizedBox(height: 24), RecordingControls( recording: _controller.value.isRecordingVideo, paused: _controller.value.isRecordingPaused, onSave: _save, onCancel: _cancel, onStart: _start, onPause: _pause, onResume: _resume, ), const SizedBox(height: 24), ], ), ), ), ), ], ), ); } } class RecordingControls extends StatelessWidget { const RecordingControls({ super.key, required this.recording, required this.paused, required this.onSave, required this.onCancel, required this.onStart, required this.onPause, required this.onResume, }); final bool recording; final bool paused; final void Function() onSave; final void Function() onCancel; final void Function() onStart; final void Function() onPause; final void Function() onResume; Widget _padTextButton(Widget text) { return Padding(padding: const EdgeInsets.all(16), child: text); } @override Widget build(BuildContext context) { final TextStyle? cancelSaveStyle = Theme.of(context).textTheme.bodyLarge; return Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ Expanded( child: Center( child: TextButton( onPressed: onCancel, child: _padTextButton(Text('Cancel', style: cancelSaveStyle)), ), ), ), if (recording) paused ? TextButton( onPressed: onResume, child: const Text('Resume'), ) : IconButton( color: Colors.red.shade400, onPressed: () {}, icon: const Icon(Icons.pause), ), if (!recording) IconButton( icon: const Icon(Icons.videocam), onPressed: onStart, ), Expanded( child: Center( child: recording ? TextButton( onPressed: onSave, child: _padTextButton(Text('Save', style: cancelSaveStyle)), ) : const SizedBox(), ), ), ], ); } } ```

Screenshots or Videos

No response

Logs

Logs ```console Uncaught (in promise) Error: Bad state: Cannot add new events after calling close at Object.throw_ [as throw] (errors.dart:294:49) at _AsyncBroadcastStreamController.new.add (broadcast_stream_controller.dart:243:46) at camera.Camera.new._onVideoRecordingStopped (camera.dart:520:31) at _onVideoRecordingStopped.next () at runBody (async_patch.dart:84:54) at Object._async [as async] (async_patch.dart:127:5) at [_onVideoRecordingStopped] (camera.dart:503:40) at MediaRecorder. (camera.dart:459:31) ```

Flutter Doctor output

Doctor output ```console [✓] Flutter (Channel stable, 3.13.4, on macOS 12.6.6 21G646 darwin-arm64, locale en-US) [✓] Android toolchain - develop for Android devices (Android SDK version 32.0.0-rc1) [✓] Xcode - develop for iOS and macOS (Xcode 14.2) [✓] Chrome - develop for the web [✓] Android Studio (version 2021.3) [✓] VS Code (version 1.82.0) [✓] Connected device (2 available) [✓] Network resources ```
wreppun commented 12 months ago

I traced this out:

 Future<void> dispose() async {
    // Stop the camera stream.
    stop();

    await videoRecorderController.close();

Possible fixes

  1. Require users of the library to call, and await, stopVideoRecording before disposing.

    Simple work around for now. But should be documented, and isn't particularly intuitive.

  2. Clear the _videoData in the dispose method.

    _videoData is only ever cleared after writing to a file.

  3. In dispose, remove the listeners to mediaRecorder that catch the 'stop' event.

    This would prevent the 'stop' event from triggering the error (by adding to the closed stream), but would also prevent the cleanup of the _videoData from happening.

Note: there is a second, un-related (to this particular error) cleanup bug in the camera_web/camera class: _videoRecordingStoppedListener, which creates the XFile and does the cleanup, is never actually removed as a listener from MediaRecorder:

    _videoDataAvailableListener =
        (html.Event event) => _onVideoDataAvailable(event, maxVideoDuration);

    _videoRecordingStoppedListener =
        (html.Event event) => _onVideoRecordingStopped(event, maxVideoDuration);

    mediaRecorder!.addEventListener(
      'dataavailable',
      _videoDataAvailableListener,
    );

    mediaRecorder!.addEventListener(
      'stop',
      _videoRecordingStoppedListener,
    );

...
...
...

    // Clean up the media recorder with its event listeners and video data.
    mediaRecorder!.removeEventListener(
      'dataavailable',
      _videoDataAvailableListener,
    );

    mediaRecorder!.removeEventListener(
      'stop',
      /// NOT THE RIGHT LISTENER
      _videoDataAvailableListener,
    );

(note the final removeEventListener removes a listener that was never connected to that event)

Anyway, I'm not sure which direction you want to go in for this fix. My best guess would be to extract the cleanup happening in _onVideoRecordingStopped into a separate method, and then call that method both at:

danagbemava-nc commented 11 months ago

Reproducible using the code sample & steps provided above.

flutter doctor -v ``` [✓] Flutter (Channel stable, 3.13.5, on macOS 13.5.2 22G91 darwin-arm64, locale en-GB) • Flutter version 3.13.5 on channel stable at /Users/nexus/dev/sdks/flutter • Upstream repository https://github.com/flutter/flutter.git • Framework revision 12fccda598 (6 days ago), 2023-09-19 13:56:11 -0700 • Engine revision bd986c5ed2 • Dart version 3.1.2 • DevTools version 2.25.0 [✓] Android toolchain - develop for Android devices (Android SDK version 33.0.1) • Android SDK at /Users/nexus/Library/Android/sdk • Platform android-33, build-tools 33.0.1 • Java binary at: /Users/nexus/Applications/Android Studio.app/Contents/jbr/Contents/Home/bin/java • Java version OpenJDK Runtime Environment (build 17.0.6+0-17.0.6b829.9-10027231) • All Android licenses accepted. [✓] Xcode - develop for iOS and macOS (Xcode 15.0) • Xcode at /Applications/Xcode-15.0.0-Release.Candidate.app/Contents/Developer • Build 15A240d • CocoaPods version 1.12.1 [✓] Chrome - develop for the web • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome [✓] Android Studio (version 2022.3) • Android Studio at /Users/nexus/Applications/Android Studio.app/Contents • Flutter plugin can be installed from: 🔨 https://plugins.jetbrains.com/plugin/9212-flutter • Dart plugin can be installed from: 🔨 https://plugins.jetbrains.com/plugin/6351-dart • Java version OpenJDK Runtime Environment (build 17.0.6+0-17.0.6b829.9-10027231) [✓] IntelliJ IDEA Ultimate Edition (version 2023.2.2) • IntelliJ at /Users/nexus/Applications/IntelliJ IDEA Ultimate.app • Flutter plugin version 75.1.4 • Dart plugin version 232.9559.10 [✓] VS Code (version 1.82.2) • VS Code at /Applications/Visual Studio Code.app/Contents • Flutter extension version 3.72.0 [✓] Connected device (5 available) • TA 1021 (mobile) • PLEGAR1790423460 • android-arm64 • Android 9 (API 28) • Nexus (mobile) • 00008020-001875E83A38002E • ios • iOS 17.0.1 21A340 • Dean’s iPad (mobile) • 00008103-000825C811E3401E • ios • iOS 17.0 21A329 • macOS (desktop) • macos • darwin-arm64 • macOS 13.5.2 22G91 darwin-arm64 • Chrome (web) • chrome • web-javascript • Google Chrome 117.0.5938.92 [✓] Network resources • All expected network resources are available. • No issues found! ``` ``` [!] Flutter (Channel master, 3.15.0-7.0.pre.5, on macOS 13.5.2 22G91 darwin-arm64, locale en-GB) • Flutter version 3.15.0-7.0.pre.5 on channel master at /Users/nexus/dev/sdks/flutters ! Warning: `flutter` on your path resolves to /Users/nexus/dev/sdks/flutter/bin/flutter, which is not inside your current Flutter SDK checkout at /Users/nexus/dev/sdks/flutters. Consider adding /Users/nexus/dev/sdks/flutters/bin to the front of your path. ! Warning: `dart` on your path resolves to /Users/nexus/dev/sdks/flutter/bin/dart, which is not inside your current Flutter SDK checkout at /Users/nexus/dev/sdks/flutters. Consider adding /Users/nexus/dev/sdks/flutters/bin to the front of your path. • Upstream repository https://github.com/flutter/flutter.git • Framework revision be085a9229 (5 hours ago), 2023-09-25 00:37:04 -0400 • Engine revision 3ea1174ecf • Dart version 3.2.0 (build 3.2.0-191.0.dev) • DevTools version 2.28.0-dev.12 • If those were intentional, you can disregard the above warnings; however it is recommended to use "git" directly to perform update checks and upgrades. [✓] Android toolchain - develop for Android devices (Android SDK version 33.0.1) • Android SDK at /Users/nexus/Library/Android/sdk • Platform android-33, build-tools 33.0.1 • Java binary at: /Users/nexus/Applications/Android Studio.app/Contents/jbr/Contents/Home/bin/java • Java version OpenJDK Runtime Environment (build 17.0.6+0-17.0.6b829.9-10027231) • All Android licenses accepted. [✓] Xcode - develop for iOS and macOS (Xcode 15.0) • Xcode at /Applications/Xcode-15.0.0-Release.Candidate.app/Contents/Developer • Build 15A240d • CocoaPods version 1.12.1 [✓] Chrome - develop for the web • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome [✓] Android Studio (version 2022.3) • Android Studio at /Users/nexus/Applications/Android Studio.app/Contents • Flutter plugin can be installed from: 🔨 https://plugins.jetbrains.com/plugin/9212-flutter • Dart plugin can be installed from: 🔨 https://plugins.jetbrains.com/plugin/6351-dart • Java version OpenJDK Runtime Environment (build 17.0.6+0-17.0.6b829.9-10027231) [✓] IntelliJ IDEA Ultimate Edition (version 2023.2.2) • IntelliJ at /Users/nexus/Applications/IntelliJ IDEA Ultimate.app • Flutter plugin version 75.1.4 • Dart plugin version 232.9559.10 [✓] VS Code (version 1.82.2) • VS Code at /Applications/Visual Studio Code.app/Contents • Flutter extension version 3.72.0 [✓] Connected device (5 available) • TA 1021 (mobile) • PLEGAR1790423460 • android-arm64 • Android 9 (API 28) • Nexus (mobile) • 00008020-001875E83A38002E • ios • iOS 17.0.1 21A340 • Dean’s iPad (mobile) • 00008103-000825C811E3401E • ios • iOS 17.0 21A329 • macOS (desktop) • macos • darwin-arm64 • macOS 13.5.2 22G91 darwin-arm64 • Chrome (web) • chrome • web-javascript • Google Chrome 117.0.5938.92 [✓] Network resources • All expected network resources are available. ! Doctor found issues in 1 category. ```