diff --git a/lib/audio_player.dart b/lib/audio_player.dart new file mode 100644 index 0000000..5b4af7d --- /dev/null +++ b/lib/audio_player.dart @@ -0,0 +1,177 @@ +import 'dart:async'; + +import 'package:audioplayers/audioplayers.dart' as ap; +import 'package:audioplayers/audioplayers.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; + +class AudioPlayer extends StatefulWidget { + /// Path from where to play recorded audio + final String source; + + /// Callback when audio file should be removed + /// Setting this to null hides the delete button + final VoidCallback onDelete; + + const AudioPlayer({ + super.key, + required this.source, + required this.onDelete, + }); + + @override + AudioPlayerState createState() => AudioPlayerState(); +} + +class AudioPlayerState extends State { + static const double _controlSize = 56; + static const double _deleteBtnSize = 24; + + final _audioPlayer = ap.AudioPlayer()..setReleaseMode(ReleaseMode.stop); + late StreamSubscription _playerStateChangedSubscription; + late StreamSubscription _durationChangedSubscription; + late StreamSubscription _positionChangedSubscription; + Duration? _position; + Duration? _duration; + + @override + void initState() { + _playerStateChangedSubscription = + _audioPlayer.onPlayerComplete.listen((state) async { + await stop(); + }); + _positionChangedSubscription = _audioPlayer.onPositionChanged.listen( + (position) => setState(() { + _position = position; + }), + ); + _durationChangedSubscription = _audioPlayer.onDurationChanged.listen( + (duration) => setState(() { + _duration = duration; + }), + ); + + _audioPlayer.setSource(_source); + + super.initState(); + } + + @override + void dispose() { + _playerStateChangedSubscription.cancel(); + _positionChangedSubscription.cancel(); + _durationChangedSubscription.cancel(); + _audioPlayer.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return LayoutBuilder( + builder: (context, constraints) { + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + _buildControl(), + _buildSlider(constraints.maxWidth), + IconButton( + icon: const Icon(Icons.delete, + color: Color(0xFF73748D), size: _deleteBtnSize), + onPressed: () { + if (_audioPlayer.state == ap.PlayerState.playing) { + stop().then((value) => widget.onDelete()); + } else { + widget.onDelete(); + } + }, + ), + ], + ), + Text('${_duration ?? 0.0}'), + ], + ); + }, + ); + } + + Widget _buildControl() { + Icon icon; + Color color; + + if (_audioPlayer.state == ap.PlayerState.playing) { + icon = const Icon(Icons.pause, color: Colors.red, size: 30); + color = Colors.red.withOpacity(0.1); + } else { + final theme = Theme.of(context); + icon = Icon(Icons.play_arrow, color: theme.primaryColor, size: 30); + color = theme.primaryColor.withOpacity(0.1); + } + + return ClipOval( + child: Material( + color: color, + child: InkWell( + child: + SizedBox(width: _controlSize, height: _controlSize, child: icon), + onTap: () { + if (_audioPlayer.state == ap.PlayerState.playing) { + pause(); + } else { + play(); + } + }, + ), + ), + ); + } + + Widget _buildSlider(double widgetWidth) { + bool canSetValue = false; + final duration = _duration; + final position = _position; + + if (duration != null && position != null) { + canSetValue = position.inMilliseconds > 0; + canSetValue &= position.inMilliseconds < duration.inMilliseconds; + } + + double width = widgetWidth - _controlSize - _deleteBtnSize; + width -= _deleteBtnSize; + + return SizedBox( + width: width, + child: Slider( + activeColor: Theme.of(context).primaryColor, + inactiveColor: Theme.of(context).colorScheme.secondary, + onChanged: (v) { + if (duration != null) { + final position = v * duration.inMilliseconds; + _audioPlayer.seek(Duration(milliseconds: position.round())); + } + }, + value: canSetValue && duration != null && position != null + ? position.inMilliseconds / duration.inMilliseconds + : 0.0, + ), + ); + } + + Future play() => _audioPlayer.play(_source); + + Future pause() async { + await _audioPlayer.pause(); + setState(() {}); + } + + Future stop() async { + await _audioPlayer.stop(); + setState(() {}); + } + + Source get _source => + kIsWeb ? ap.UrlSource(widget.source) : ap.DeviceFileSource(widget.source); +} \ No newline at end of file diff --git a/lib/audio_recorder.dart b/lib/audio_recorder.dart new file mode 100644 index 0000000..5dcbe77 --- /dev/null +++ b/lib/audio_recorder.dart @@ -0,0 +1,252 @@ +import 'dart:async'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:record/record.dart'; + +import 'platform/audio_recorder_platform.dart'; + +class Recorder extends StatefulWidget { + final void Function(String path) onStop; + + const Recorder({super.key, required this.onStop}); + + @override + State createState() => _RecorderState(); +} + +class _RecorderState extends State with AudioRecorderMixin { + int _recordDuration = 0; + Timer? _timer; + late final AudioRecorder _audioRecorder; + StreamSubscription? _recordSub; + RecordState _recordState = RecordState.stop; + StreamSubscription? _amplitudeSub; + Amplitude? _amplitude; + + @override + void initState() { + _audioRecorder = AudioRecorder(); + + _recordSub = _audioRecorder.onStateChanged().listen((recordState) { + _updateRecordState(recordState); + }); + + _amplitudeSub = _audioRecorder + .onAmplitudeChanged(const Duration(milliseconds: 300)) + .listen((amp) { + setState(() => _amplitude = amp); + }); + + super.initState(); + } + + Future _start() async { + try { + if (await _audioRecorder.hasPermission()) { + const encoder = AudioEncoder.aacLc; + + if (!await _isEncoderSupported(encoder)) { + return; + } + + final devs = await _audioRecorder.listInputDevices(); + debugPrint(devs.toString()); + + const config = RecordConfig(encoder: encoder, numChannels: 1); + + // Record to file + await recordFile(_audioRecorder, config); + + // Record to stream + // await recordStream(_audioRecorder, config); + + _recordDuration = 0; + + _startTimer(); + } + } catch (e) { + if (kDebugMode) { + print(e); + } + } + } + + Future _stop() async { + final path = await _audioRecorder.stop(); + + if (path != null) { + widget.onStop(path); + + downloadWebData(path); + } + } + + Future _pause() => _audioRecorder.pause(); + + Future _resume() => _audioRecorder.resume(); + + void _updateRecordState(RecordState recordState) { + setState(() => _recordState = recordState); + + switch (recordState) { + case RecordState.pause: + _timer?.cancel(); + break; + case RecordState.record: + _startTimer(); + break; + case RecordState.stop: + _timer?.cancel(); + _recordDuration = 0; + break; + } + } + + Future _isEncoderSupported(AudioEncoder encoder) async { + final isSupported = await _audioRecorder.isEncoderSupported( + encoder, + ); + + if (!isSupported) { + debugPrint('${encoder.name} is not supported on this platform.'); + debugPrint('Supported encoders are:'); + + for (final e in AudioEncoder.values) { + if (await _audioRecorder.isEncoderSupported(e)) { + debugPrint('- ${encoder.name}'); + } + } + } + + return isSupported; + } + + @override + Widget build(BuildContext context) { + return MaterialApp( + home: Scaffold( + body: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + _buildRecordStopControl(), + const SizedBox(width: 20), + _buildPauseResumeControl(), + const SizedBox(width: 20), + _buildText(), + ], + ), + if (_amplitude != null) ...[ + const SizedBox(height: 40), + Text('Current: ${_amplitude?.current ?? 0.0}'), + Text('Max: ${_amplitude?.max ?? 0.0}'), + ], + ], + ), + ), + ); + } + + @override + void dispose() { + _timer?.cancel(); + _recordSub?.cancel(); + _amplitudeSub?.cancel(); + _audioRecorder.dispose(); + super.dispose(); + } + + Widget _buildRecordStopControl() { + late Icon icon; + late Color color; + + if (_recordState != RecordState.stop) { + icon = const Icon(Icons.stop, color: Colors.red, size: 30); + color = Colors.red.withOpacity(0.1); + } else { + final theme = Theme.of(context); + icon = Icon(Icons.mic, color: theme.primaryColor, size: 30); + color = theme.primaryColor.withOpacity(0.1); + } + + return ClipOval( + child: Material( + color: color, + child: InkWell( + child: SizedBox(width: 56, height: 56, child: icon), + onTap: () { + (_recordState != RecordState.stop) ? _stop() : _start(); + }, + ), + ), + ); + } + + Widget _buildPauseResumeControl() { + if (_recordState == RecordState.stop) { + return const SizedBox.shrink(); + } + + late Icon icon; + late Color color; + + if (_recordState == RecordState.record) { + icon = const Icon(Icons.pause, color: Colors.red, size: 30); + color = Colors.red.withOpacity(0.1); + } else { + final theme = Theme.of(context); + icon = const Icon(Icons.play_arrow, color: Colors.red, size: 30); + color = theme.primaryColor.withOpacity(0.1); + } + + return ClipOval( + child: Material( + color: color, + child: InkWell( + child: SizedBox(width: 56, height: 56, child: icon), + onTap: () { + (_recordState == RecordState.pause) ? _resume() : _pause(); + }, + ), + ), + ); + } + + Widget _buildText() { + if (_recordState != RecordState.stop) { + return _buildTimer(); + } + + return const Text("Waiting to record"); + } + + Widget _buildTimer() { + final String minutes = _formatNumber(_recordDuration ~/ 60); + final String seconds = _formatNumber(_recordDuration % 60); + + return Text( + '$minutes : $seconds', + style: const TextStyle(color: Colors.red), + ); + } + + String _formatNumber(int number) { + String numberStr = number.toString(); + if (number < 10) { + numberStr = '0$numberStr'; + } + + return numberStr; + } + + void _startTimer() { + _timer?.cancel(); + + _timer = Timer.periodic(const Duration(seconds: 1), (Timer t) { + setState(() => _recordDuration++); + }); + } +} \ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart index 99d0644..fbef3d1 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,5 +1,8 @@ import 'package:flutter/services.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/foundation.dart'; +import 'audio_player.dart'; +import 'audio_recorder.dart'; void main() { runApp(const MyApp()); @@ -57,10 +60,14 @@ class MyHomePage extends StatefulWidget { class _MyHomePageState extends State { String _key = ' '; + bool showPlayer = false; + bool record = true; + String? audioPath; @override void initState() { super.initState(); + showPlayer = false; ServicesBinding.instance.keyboard.addHandler(_onKey); } @@ -134,36 +141,40 @@ class _MyHomePageState extends State { title: Text(widget.title), ), body: Center( - // Center is a layout widget. It takes a single child and positions it - // in the middle of the parent. - child: Column( - // Column is also a layout widget. It takes a list of children and - // arranges them vertically. By default, it sizes itself to fit its - // children horizontally, and tries to be as tall as its parent. - // - // Column has various properties to control how it sizes itself and - // how it positions its children. Here we use mainAxisAlignment to - // center the children vertically; the main axis here is the vertical - // axis because Columns are vertical (the cross axis would be - // horizontal). - // - // TRY THIS: Invoke "debug painting" (choose the "Toggle Debug Paint" - // action in the IDE, or press "p" in the console), to see the - // wireframe for each widget. + child: record + ? showPlayer + ? Padding( + padding: const EdgeInsets.symmetric(horizontal: 25), + child: AudioPlayer( + source: audioPath!, + onDelete: () { + setState(() => showPlayer = false); + }, + ), + ) + : Recorder( + onStop: (path) { + if (kDebugMode) print('Recorded file path: $path'); + setState(() { + audioPath = path; + showPlayer = true; + }); + }, + ) + : Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + '$_key', + // set text color to white - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - '$_key', - // set text color to white - - style: TextStyle( - color: Colors.lightGreen, - fontSize: 160.0, // Change this to your preferred color + style: TextStyle( + color: Colors.lightGreen, + fontSize: 160.0, // Change this to your preferred color + ), + ), + ], ), - ), - ], - ), ), floatingActionButton: FloatingActionButton( onPressed: _incrementKey, diff --git a/lib/platform/audio_recorder_io.dart b/lib/platform/audio_recorder_io.dart new file mode 100644 index 0000000..bd3c2c4 --- /dev/null +++ b/lib/platform/audio_recorder_io.dart @@ -0,0 +1,47 @@ +import 'dart:io'; +import 'dart:typed_data'; + +import 'package:path/path.dart' as p; +import 'package:path_provider/path_provider.dart'; +import 'package:record/record.dart'; + +mixin AudioRecorderMixin { + Future recordFile(AudioRecorder recorder, RecordConfig config) async { + final path = await _getPath(); + + await recorder.start(config, path: path); + } + + Future recordStream(AudioRecorder recorder, RecordConfig config) async { + final path = await _getPath(); + + final file = File(path); + + final stream = await recorder.startStream(config); + + stream.listen( + (data) { + // ignore: avoid_print + print( + recorder.convertBytesToInt16(Uint8List.fromList(data)), + ); + file.writeAsBytesSync(data, mode: FileMode.append); + }, + // ignore: avoid_print + onDone: () { + // ignore: avoid_print + print('End of stream. File written to $path.'); + }, + ); + } + + void downloadWebData(String path) {} + + Future _getPath() async { + final dir = await getApplicationDocumentsDirectory(); + return p.join( + dir.path, + 'audio_${DateTime.now().millisecondsSinceEpoch}.m4a', + ); + } +} diff --git a/lib/platform/audio_recorder_platform.dart b/lib/platform/audio_recorder_platform.dart new file mode 100644 index 0000000..b60dee1 --- /dev/null +++ b/lib/platform/audio_recorder_platform.dart @@ -0,0 +1 @@ +export 'audio_recorder_web.dart' if (dart.library.io) 'audio_recorder_io.dart'; diff --git a/lib/platform/audio_recorder_web.dart b/lib/platform/audio_recorder_web.dart new file mode 100644 index 0000000..fb66a2d --- /dev/null +++ b/lib/platform/audio_recorder_web.dart @@ -0,0 +1,33 @@ +// ignore_for_file: avoid_web_libraries_in_flutter + +import 'dart:html' as html; +import 'dart:typed_data'; + +import 'package:record/record.dart'; + +mixin AudioRecorderMixin { + Future recordFile(AudioRecorder recorder, RecordConfig config) { + return recorder.start(config, path: ''); + } + + Future recordStream(AudioRecorder recorder, RecordConfig config) async { + final b = []; + final stream = await recorder.startStream(config); + + stream.listen( + (data) => b.add(data), + onDone: () => downloadWebData(html.Url.createObjectUrl(html.Blob(b))), + ); + } + + void downloadWebData(String path) { + // Simple download code for web testing + final anchor = html.document.createElement('a') as html.AnchorElement + ..href = path + ..style.display = 'none' + ..download = 'audio.wav'; + html.document.body!.children.add(anchor); + anchor.click(); + html.document.body!.children.remove(anchor); + } +} diff --git a/linux/flutter/generated_plugin_registrant.cc b/linux/flutter/generated_plugin_registrant.cc index e71a16d..145c9eb 100644 --- a/linux/flutter/generated_plugin_registrant.cc +++ b/linux/flutter/generated_plugin_registrant.cc @@ -6,6 +6,14 @@ #include "generated_plugin_registrant.h" +#include +#include void fl_register_plugins(FlPluginRegistry* registry) { + g_autoptr(FlPluginRegistrar) audioplayers_linux_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "AudioplayersLinuxPlugin"); + audioplayers_linux_plugin_register_with_registrar(audioplayers_linux_registrar); + g_autoptr(FlPluginRegistrar) record_linux_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "RecordLinuxPlugin"); + record_linux_plugin_register_with_registrar(record_linux_registrar); } diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake index 2e1de87..ecad9e4 100644 --- a/linux/flutter/generated_plugins.cmake +++ b/linux/flutter/generated_plugins.cmake @@ -3,6 +3,8 @@ # list(APPEND FLUTTER_PLUGIN_LIST + audioplayers_linux + record_linux ) list(APPEND FLUTTER_FFI_PLUGIN_LIST diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index cccf817..8c35971 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,6 +5,12 @@ import FlutterMacOS import Foundation +import audioplayers_darwin +import path_provider_foundation +import record_darwin func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + AudioplayersDarwinPlugin.register(with: registry.registrar(forPlugin: "AudioplayersDarwinPlugin")) + PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) + RecordPlugin.register(with: registry.registrar(forPlugin: "RecordPlugin")) } diff --git a/pubspec.lock b/pubspec.lock index e4a8596..7b78c8e 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -9,6 +9,62 @@ packages: url: "https://pub.dev" source: hosted version: "2.11.0" + audioplayers: + dependency: "direct main" + description: + name: audioplayers + sha256: c05c6147124cd63e725e861335a8b4d57300b80e6e92cea7c145c739223bbaef + url: "https://pub.dev" + source: hosted + version: "5.2.1" + audioplayers_android: + dependency: transitive + description: + name: audioplayers_android + sha256: b00e1a0e11365d88576320ec2d8c192bc21f1afb6c0e5995d1c57ae63156acb5 + url: "https://pub.dev" + source: hosted + version: "4.0.3" + audioplayers_darwin: + dependency: transitive + description: + name: audioplayers_darwin + sha256: "3034e99a6df8d101da0f5082dcca0a2a99db62ab1d4ddb3277bed3f6f81afe08" + url: "https://pub.dev" + source: hosted + version: "5.0.2" + audioplayers_linux: + dependency: transitive + description: + name: audioplayers_linux + sha256: "60787e73fefc4d2e0b9c02c69885402177e818e4e27ef087074cf27c02246c9e" + url: "https://pub.dev" + source: hosted + version: "3.1.0" + audioplayers_platform_interface: + dependency: transitive + description: + name: audioplayers_platform_interface + sha256: "365c547f1bb9e77d94dd1687903a668d8f7ac3409e48e6e6a3668a1ac2982adb" + url: "https://pub.dev" + source: hosted + version: "6.1.0" + audioplayers_web: + dependency: transitive + description: + name: audioplayers_web + sha256: "22cd0173e54d92bd9b2c80b1204eb1eb159ece87475ab58c9788a70ec43c2a62" + url: "https://pub.dev" + source: hosted + version: "4.1.0" + audioplayers_windows: + dependency: transitive + description: + name: audioplayers_windows + sha256: "9536812c9103563644ada2ef45ae523806b0745f7a78e89d1b5fb1951de90e1a" + url: "https://pub.dev" + source: hosted + version: "3.1.0" boolean_selector: dependency: transitive description: @@ -41,6 +97,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.18.0" + crypto: + dependency: transitive + description: + name: crypto + sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab + url: "https://pub.dev" + source: hosted + version: "3.0.3" cupertino_icons: dependency: "direct main" description: @@ -57,6 +121,30 @@ packages: 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: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" + url: "https://pub.dev" + source: hosted + version: "7.0.0" + fixnum: + dependency: transitive + description: + name: fixnum + sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1" + url: "https://pub.dev" + source: hosted + version: "1.1.0" flutter: dependency: "direct main" description: flutter @@ -75,6 +163,35 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_web_plugins: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + http: + dependency: transitive + description: + name: http + sha256: a2bbf9d017fcced29139daa8ed2bba4ece450ab222871df93ca9eec6f80c34ba + url: "https://pub.dev" + source: hosted + version: "1.2.0" + http_parser: + dependency: transitive + description: + name: http_parser + sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + url: "https://pub.dev" + source: hosted + version: "4.0.2" + js: + dependency: transitive + description: + name: js + sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 + url: "https://pub.dev" + source: hosted + version: "0.6.7" lints: dependency: transitive description: @@ -115,6 +232,126 @@ packages: url: "https://pub.dev" source: hosted version: "1.8.3" + path_provider: + dependency: transitive + description: + name: path_provider + sha256: b27217933eeeba8ff24845c34003b003b2b22151de3c908d0e679e8fe1aa078b + url: "https://pub.dev" + source: hosted + version: "2.1.2" + path_provider_android: + dependency: transitive + description: + name: path_provider_android + sha256: "477184d672607c0a3bf68fbbf601805f92ef79c82b64b4d6eb318cbca4c48668" + url: "https://pub.dev" + source: hosted + version: "2.2.2" + path_provider_foundation: + dependency: transitive + description: + name: path_provider_foundation + sha256: "5a7999be66e000916500be4f15a3633ebceb8302719b47b9cc49ce924125350f" + url: "https://pub.dev" + source: hosted + version: "2.3.2" + 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: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + path_provider_windows: + dependency: transitive + description: + name: path_provider_windows + sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170" + url: "https://pub.dev" + source: hosted + version: "2.2.1" + platform: + dependency: "direct main" + description: + name: platform + sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec" + url: "https://pub.dev" + source: hosted + version: "3.1.4" + plugin_platform_interface: + dependency: transitive + description: + name: plugin_platform_interface + sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" + url: "https://pub.dev" + source: hosted + version: "2.1.8" + record: + dependency: "direct main" + description: + name: record + sha256: "5c8e12c692a4800b33f5f8b6c821ea083b12bfdbd031b36ba9322c40a4eeecc9" + url: "https://pub.dev" + source: hosted + version: "5.0.4" + record_android: + dependency: transitive + description: + name: record_android + sha256: "805ecaa232a671aff2ee9ec4730ef6addb97c548d2db6b1fbd5197f1d4f47a5a" + url: "https://pub.dev" + source: hosted + version: "1.0.4" + record_darwin: + dependency: transitive + description: + name: record_darwin + sha256: ee8cb1bb1712d7ce38140ecabe70e5c286c02f05296d66043bee865ace7eb1b9 + url: "https://pub.dev" + source: hosted + version: "1.0.1" + record_linux: + dependency: transitive + description: + name: record_linux + sha256: "7d0e70cd51635128fe9d37d89bafd6011d7cbba9af8dc323079ae60f23546aef" + url: "https://pub.dev" + source: hosted + version: "0.7.1" + record_platform_interface: + dependency: transitive + description: + name: record_platform_interface + sha256: "3a4b56e94ecd2a0b2b43eb1fa6f94c5b8484334f5d38ef43959c4bf97fb374cf" + url: "https://pub.dev" + source: hosted + version: "1.0.2" + record_web: + dependency: transitive + description: + name: record_web + sha256: "24847cdbcf999f7a5762170792f622ac844858766becd0f2370ec8ae22f7526e" + url: "https://pub.dev" + source: hosted + version: "1.0.5" + record_windows: + dependency: transitive + description: + name: record_windows + sha256: "39998b3ea7d8d28b04159d82220e6e5e32a7c357c6fb2794f5736beea272f6c3" + url: "https://pub.dev" + source: hosted + version: "1.0.2" sky_engine: dependency: transitive description: flutter @@ -128,6 +365,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.10.0" + sprintf: + dependency: transitive + description: + name: sprintf + sha256: "1fc9ffe69d4df602376b52949af107d8f5703b77cda567c4d7d86a0693120f23" + url: "https://pub.dev" + source: hosted + version: "7.0.0" stack_trace: dependency: transitive description: @@ -152,6 +397,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.2.0" + synchronized: + dependency: transitive + description: + name: synchronized + sha256: "539ef412b170d65ecdafd780f924e5be3f60032a1128df156adad6c5b373d558" + url: "https://pub.dev" + source: hosted + version: "3.1.0+1" term_glyph: dependency: transitive description: @@ -168,6 +421,22 @@ packages: url: "https://pub.dev" source: hosted version: "0.6.1" + typed_data: + dependency: transitive + description: + name: typed_data + sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c + url: "https://pub.dev" + source: hosted + version: "1.3.2" + uuid: + dependency: transitive + description: + name: uuid + sha256: cd210a09f7c18cbe5a02511718e0334de6559871052c90a90c0cca46a4aa81c8 + url: "https://pub.dev" + source: hosted + version: "4.3.3" vector_math: dependency: transitive description: @@ -184,5 +453,22 @@ packages: url: "https://pub.dev" source: hosted version: "0.3.0" + win32: + dependency: transitive + description: + name: win32 + sha256: "464f5674532865248444b4c3daca12bd9bf2d7c47f759ce2617986e7229494a8" + url: "https://pub.dev" + source: hosted + version: "5.2.0" + xdg_directories: + dependency: transitive + description: + name: xdg_directories + sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d + url: "https://pub.dev" + source: hosted + version: "1.0.4" sdks: dart: ">=3.2.6 <4.0.0" + flutter: ">=3.10.0" diff --git a/pubspec.yaml b/pubspec.yaml index 0af93ac..103b725 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -35,6 +35,9 @@ dependencies: # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^1.0.2 + record: ^5.0.4 + platform: ^3.1.4 + audioplayers: ^5.2.1 dev_dependencies: flutter_test: diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index 8b6d468..c566a56 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -6,6 +6,12 @@ #include "generated_plugin_registrant.h" +#include +#include void RegisterPlugins(flutter::PluginRegistry* registry) { + AudioplayersWindowsPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("AudioplayersWindowsPlugin")); + RecordWindowsPluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("RecordWindowsPluginCApi")); } diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index b93c4c3..045e16c 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -3,6 +3,8 @@ # list(APPEND FLUTTER_PLUGIN_LIST + audioplayers_windows + record_windows ) list(APPEND FLUTTER_FFI_PLUGIN_LIST