neoagent 3.1.1-beta.9 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (150) hide show
  1. package/.env.example +2 -2
  2. package/README.md +5 -1
  3. package/docs/architecture.md +1 -1
  4. package/docs/benchmarking.md +68 -87
  5. package/docs/capabilities.md +1 -1
  6. package/docs/clients-and-devices.md +3 -4
  7. package/docs/configuration.md +1 -1
  8. package/docs/devices.md +1 -2
  9. package/docs/health.md +24 -0
  10. package/docs/index.md +2 -2
  11. package/docs/integrations-architecture.md +6 -0
  12. package/docs/integrations.md +15 -1
  13. package/docs/models.md +1 -1
  14. package/docs/persistence.md +1 -1
  15. package/docs/why-neoagent.md +1 -1
  16. package/flutter_app/README.md +0 -5
  17. package/flutter_app/android/app/src/main/AndroidManifest.xml +0 -14
  18. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/MainActivity.kt +0 -98
  19. package/flutter_app/lib/main.dart +0 -6
  20. package/flutter_app/lib/main_app_shell.dart +0 -2
  21. package/flutter_app/lib/main_controller.dart +2 -867
  22. package/flutter_app/lib/main_devices.dart +0 -73
  23. package/flutter_app/lib/main_integrations.dart +339 -187
  24. package/flutter_app/lib/main_launcher.dart +2 -212
  25. package/flutter_app/lib/main_models.dart +0 -259
  26. package/flutter_app/lib/main_navigation.dart +2 -14
  27. package/flutter_app/lib/main_operations.dart +322 -364
  28. package/flutter_app/lib/main_runtime.dart +9 -208
  29. package/flutter_app/lib/main_settings.dart +17 -199
  30. package/flutter_app/lib/main_shared.dart +20 -591
  31. package/flutter_app/lib/main_timeline.dart +26 -122
  32. package/flutter_app/lib/main_voice_assistant.dart +0 -5
  33. package/flutter_app/lib/src/backend_client.dart +0 -102
  34. package/flutter_app/lib/src/desktop_companion_io.dart +1 -65
  35. package/flutter_app/lib/src/desktop_companion_stub.dart +0 -12
  36. package/flutter_app/linux/flutter/generated_plugin_registrant.cc +0 -4
  37. package/flutter_app/linux/flutter/generated_plugins.cmake +0 -1
  38. package/flutter_app/macos/Flutter/GeneratedPluginRegistrant.swift +0 -2
  39. package/flutter_app/macos/Podfile.lock +56 -5
  40. package/flutter_app/pubspec.lock +0 -7
  41. package/flutter_app/pubspec.yaml +0 -2
  42. package/flutter_app/web/index.html +174 -0
  43. package/flutter_app/windows/flutter/generated_plugin_registrant.cc +0 -3
  44. package/flutter_app/windows/flutter/generated_plugins.cmake +0 -1
  45. package/landing/index.html +0 -2
  46. package/lib/manager.js +1 -1
  47. package/lib/schema_migrations.js +75 -0
  48. package/package.json +1 -4
  49. package/server/db/database.js +1 -133
  50. package/server/http/middleware.js +2 -16
  51. package/server/http/routes.js +0 -2
  52. package/server/public/.last_build_id +1 -1
  53. package/server/public/assets/NOTICES +0 -25
  54. package/server/public/assets/fonts/MaterialIcons-Regular.otf +0 -0
  55. package/server/public/flutter_bootstrap.js +1 -1
  56. package/server/public/index.html +174 -0
  57. package/server/public/main.dart.js +88081 -90036
  58. package/server/routes/auth.js +11 -2
  59. package/server/routes/settings.js +0 -5
  60. package/server/routes/voice_assistant.js +1 -128
  61. package/server/services/account/erasure.js +0 -3
  62. package/server/services/ai/deliverables/artifact_helpers.js +1 -1
  63. package/server/services/ai/loop/conversation_loop.js +6 -2
  64. package/server/services/ai/loop/tool_dispatch.js +0 -3
  65. package/server/services/ai/messagingFallback.js +1 -1
  66. package/server/services/ai/settings.js +0 -6
  67. package/server/services/ai/toolEvidence.js +1 -4
  68. package/server/services/ai/tools.js +0 -234
  69. package/server/services/desktop/auth.js +0 -3
  70. package/server/services/desktop/registry.js +2 -50
  71. package/server/services/integrations/neoarchive/provider.js +616 -0
  72. package/server/services/integrations/neorecall/client.js +140 -0
  73. package/server/services/integrations/neorecall/constants.js +87 -0
  74. package/server/services/integrations/neorecall/provider.js +163 -0
  75. package/server/services/integrations/registry.js +4 -2
  76. package/server/services/manager.js +0 -22
  77. package/server/services/memory/manager.js +44 -19
  78. package/server/services/memory/retrieval_reasoning.js +36 -14
  79. package/server/services/messaging/whatsapp.js +18 -0
  80. package/server/services/security/tool_categories.js +0 -5
  81. package/server/services/social_video/service.js +2 -20
  82. package/server/services/tasks/adapters/index.js +1 -1
  83. package/server/services/tasks/integration_runtime.js +3 -67
  84. package/server/services/tasks/runtime.js +1 -6
  85. package/server/services/tasks/task_repository.js +6 -13
  86. package/server/services/timeline/service.js +0 -224
  87. package/server/services/voice/message.js +0 -24
  88. package/server/services/voice/providers.js +42 -1
  89. package/server/services/voice/runtimeManager.js +9 -5
  90. package/server/services/voice/turnRunner.js +0 -22
  91. package/server/services/wearable/service.js +0 -5
  92. package/docs/recordings-and-health.md +0 -41
  93. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/recording/RecordingBootReceiver.kt +0 -21
  94. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/recording/RecordingForegroundService.kt +0 -586
  95. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/recording/RecordingStateStore.kt +0 -78
  96. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/recording/RecordingUploadClient.kt +0 -104
  97. package/flutter_app/lib/main_recordings.dart +0 -920
  98. package/flutter_app/lib/src/desktop_ocr_bridge.dart +0 -2
  99. package/flutter_app/lib/src/desktop_ocr_bridge_io.dart +0 -125
  100. package/flutter_app/lib/src/desktop_ocr_bridge_stub.dart +0 -30
  101. package/flutter_app/lib/src/desktop_passive_history.dart +0 -332
  102. package/flutter_app/lib/src/recording_bridge.dart +0 -232
  103. package/flutter_app/lib/src/recording_bridge_io.dart +0 -1027
  104. package/flutter_app/lib/src/recording_bridge_stub.dart +0 -120
  105. package/flutter_app/lib/src/recording_bridge_web.dart +0 -702
  106. package/flutter_app/lib/src/recording_chunk_queue.dart +0 -149
  107. package/flutter_app/lib/src/recording_chunk_queue_io.dart +0 -182
  108. package/flutter_app/lib/src/recording_payloads.dart +0 -95
  109. package/flutter_app/third_party/desktop_audio_capture/LICENSE +0 -21
  110. package/flutter_app/third_party/desktop_audio_capture/README.md +0 -262
  111. package/flutter_app/third_party/desktop_audio_capture/lib/audio_capture.dart +0 -65
  112. package/flutter_app/third_party/desktop_audio_capture/lib/config/mic_audio_config.dart +0 -153
  113. package/flutter_app/third_party/desktop_audio_capture/lib/config/system_adudio_config.dart +0 -110
  114. package/flutter_app/third_party/desktop_audio_capture/lib/mic/mic_audio_capture.dart +0 -461
  115. package/flutter_app/third_party/desktop_audio_capture/lib/model/audio_status.dart +0 -91
  116. package/flutter_app/third_party/desktop_audio_capture/lib/model/decibel_data.dart +0 -106
  117. package/flutter_app/third_party/desktop_audio_capture/lib/model/input_device_type.dart +0 -219
  118. package/flutter_app/third_party/desktop_audio_capture/lib/system/system_audio_capture.dart +0 -336
  119. package/flutter_app/third_party/desktop_audio_capture/linux/CMakeLists.txt +0 -101
  120. package/flutter_app/third_party/desktop_audio_capture/linux/audio_capture_plugin.cc +0 -692
  121. package/flutter_app/third_party/desktop_audio_capture/linux/include/audio_capture/audio_capture_plugin.h +0 -35
  122. package/flutter_app/third_party/desktop_audio_capture/linux/include/audio_capture/mic_capture_plugin.h +0 -36
  123. package/flutter_app/third_party/desktop_audio_capture/linux/include/desktop_audio_capture/audio_capture_plugin.h +0 -32
  124. package/flutter_app/third_party/desktop_audio_capture/linux/include/desktop_audio_capture/mic_capture_plugin.h +0 -32
  125. package/flutter_app/third_party/desktop_audio_capture/linux/mic_capture_plugin.cc +0 -878
  126. package/flutter_app/third_party/desktop_audio_capture/macos/Classes/AudioCapturePlugin.swift +0 -27
  127. package/flutter_app/third_party/desktop_audio_capture/macos/Classes/MicCapturePlugin.swift +0 -1172
  128. package/flutter_app/third_party/desktop_audio_capture/macos/Classes/SystemCapturePlugin.swift +0 -655
  129. package/flutter_app/third_party/desktop_audio_capture/macos/Resources/PrivacyInfo.xcprivacy +0 -12
  130. package/flutter_app/third_party/desktop_audio_capture/macos/desktop_audio_capture.podspec +0 -30
  131. package/flutter_app/third_party/desktop_audio_capture/pubspec.yaml +0 -87
  132. package/flutter_app/third_party/desktop_audio_capture/windows/CMakeLists.txt +0 -105
  133. package/flutter_app/third_party/desktop_audio_capture/windows/audio_capture_plugin.cpp +0 -80
  134. package/flutter_app/third_party/desktop_audio_capture/windows/audio_capture_plugin.h +0 -31
  135. package/flutter_app/third_party/desktop_audio_capture/windows/audio_capture_plugin_c_api.cpp +0 -12
  136. package/flutter_app/third_party/desktop_audio_capture/windows/include/audio_capture/audio_capture_plugin_c_api.h +0 -23
  137. package/flutter_app/third_party/desktop_audio_capture/windows/include/desktop_audio_capture/audio_capture_plugin.h +0 -25
  138. package/flutter_app/third_party/desktop_audio_capture/windows/mic_capture_plugin.cpp +0 -1117
  139. package/flutter_app/third_party/desktop_audio_capture/windows/mic_capture_plugin.h +0 -115
  140. package/flutter_app/third_party/desktop_audio_capture/windows/system_audio_capture_plugin.cpp +0 -777
  141. package/flutter_app/third_party/desktop_audio_capture/windows/system_audio_capture_plugin.h +0 -87
  142. package/server/routes/recordings.js +0 -335
  143. package/server/routes/screenHistory.js +0 -190
  144. package/server/services/ai/recordingInsights.js +0 -105
  145. package/server/services/integrations/neomail/provider.js +0 -993
  146. package/server/services/recordings/deepgram.js +0 -58
  147. package/server/services/recordings/manager.js +0 -1273
  148. package/server/services/tasks/adapters/neomail_email_received.js +0 -46
  149. package/server/services/voice/screenshotContext.js +0 -73
  150. package/server/services/voice/turnCoordinator.js +0 -51
@@ -1,461 +0,0 @@
1
- import 'dart:async';
2
-
3
- import 'package:desktop_audio_capture/audio_capture.dart';
4
- import 'package:flutter/services.dart';
5
- export 'package:desktop_audio_capture/config/mic_audio_config.dart';
6
-
7
- enum _MicAudioMethod {
8
- startCapture,
9
- stopCapture,
10
- requestPermissions,
11
- hasInputDevice,
12
- getAvailableInputDevices,
13
- }
14
-
15
- /// Class for capturing audio from microphone input devices.
16
- ///
17
- /// This class allows you to capture audio from connected microphones,
18
- /// including built-in microphones, external USB microphones, and Bluetooth
19
- /// microphones. It requires microphone permissions.
20
- ///
21
- /// Example:
22
- /// ```dart
23
- /// final micCapture = MicAudioCapture(
24
- /// config: MicAudioConfig(
25
- /// sampleRate: 44100,
26
- /// channels: 1,
27
- /// gainBoost: 2.5,
28
- /// ),
29
- /// );
30
- ///
31
- /// // Check for available devices
32
- /// final devices = await micCapture.getAvailableInputDevices();
33
- /// print('Available microphones: ${devices.length}');
34
- ///
35
- /// await micCapture.startCapture();
36
- ///
37
- /// // Listen to audio stream
38
- /// micCapture.audioStream?.listen((audioData) {
39
- /// // Process audio bytes
40
- /// print('Received ${audioData.length} bytes');
41
- /// });
42
- ///
43
- /// // Listen to status updates
44
- /// micCapture.statusStream?.listen((status) {
45
- /// print('Mic active: ${status.isActive}, Device: ${status.deviceName}');
46
- /// });
47
- ///
48
- /// // Listen to decibel readings
49
- /// micCapture.decibelStream?.listen((data) {
50
- /// print('Mic level: ${data.decibel} dB');
51
- /// });
52
- ///
53
- /// // Stop when done
54
- /// await micCapture.stopCapture();
55
- /// ```
56
- class MicAudioCapture extends AudioCapture {
57
- static const MethodChannel _channel = MethodChannel(
58
- 'com.mic_audio_transcriber/mic_capture',
59
- );
60
- static const EventChannel _audioStreamChannel = EventChannel(
61
- 'com.mic_audio_transcriber/mic_stream',
62
- );
63
- static const EventChannel _statusStreamChannel = EventChannel(
64
- 'com.mic_audio_transcriber/mic_status',
65
- );
66
- static const EventChannel _decibelStreamChannel = EventChannel(
67
- 'com.mic_audio_transcriber/mic_decibel',
68
- );
69
-
70
- Stream<Uint8List>? _audioStream;
71
- Stream<MicAudioStatus>? _statusStream;
72
- Stream<DecibelData>? _decibelStream;
73
- bool _isRecording = false;
74
-
75
- /// Stream of raw audio data bytes from microphone capture.
76
- ///
77
- /// Returns a [Stream<Uint8List>] containing the captured audio data.
78
- /// The stream is only available after [startCapture] has been called.
79
- ///
80
- /// Example:
81
- /// ```dart
82
- /// await micCapture.startCapture();
83
- ///
84
- /// micCapture.audioStream?.listen((audioData) {
85
- /// // Process audio bytes
86
- /// final audioBuffer = audioData.buffer.asUint8List();
87
- /// // Use audio buffer for processing, saving, streaming, etc.
88
- /// });
89
- /// ```
90
- Stream<Uint8List>? get audioStream {
91
- // Return existing stream if available
92
- if (_audioStream != null) {
93
- return _audioStream;
94
- }
95
- // If not recording, return null
96
- if (!_isRecording) {
97
- return null;
98
- }
99
- // Create stream lazily if recording but stream not created yet
100
- _audioStream = _audioStreamChannel.receiveBroadcastStream().map((
101
- dynamic event,
102
- ) {
103
- if (event is Uint8List) {
104
- return event;
105
- } else if (event is List<int>) {
106
- return Uint8List.fromList(event);
107
- }
108
- throw Exception('Unexpected audio data type: ${event.runtimeType}');
109
- });
110
- return _audioStream;
111
- }
112
-
113
- /// Stream of microphone status updates.
114
- ///
115
- /// Returns a [Stream<MicStatus>] containing:
116
- /// - `isActive`: bool - whether mic is currently active
117
- /// - `deviceName`: String? - name of the microphone device (if available)
118
- ///
119
- /// Example:
120
- /// ```dart
121
- /// micCapture.statusStream?.listen((status) {
122
- /// if (status.isActive) {
123
- /// print('Microphone is active');
124
- /// if (status.deviceName != null) {
125
- /// print('Using device: ${status.deviceName}');
126
- /// }
127
- /// } else {
128
- /// print('Microphone is inactive');
129
- /// }
130
- /// });
131
- /// ```
132
- Stream<MicAudioStatus>? get statusStream {
133
- // Create status stream if not already created
134
- _statusStream ??= _statusStreamChannel.receiveBroadcastStream().map((
135
- dynamic event,
136
- ) {
137
- if (event is Map) {
138
- return MicAudioStatus.fromJson(Map<String, dynamic>.from(event));
139
- }
140
- return const MicAudioStatus(isActive: false);
141
- });
142
- return _statusStream;
143
- }
144
-
145
- /// Stream of microphone decibel (dB) readings.
146
- ///
147
- /// Returns a [Stream<DecibelData>] containing:
148
- /// - `decibel`: double - decibel value (-120 to 0 dB)
149
- /// - `timestamp`: double - Unix timestamp
150
- ///
151
- /// The stream is only available while recording is active.
152
- ///
153
- /// Example:
154
- /// ```dart
155
- /// await micCapture.startCapture();
156
- ///
157
- /// micCapture.decibelStream?.listen((data) {
158
- /// print('Microphone level: ${data.decibel.toStringAsFixed(1)} dB');
159
- /// print('Timestamp: ${DateTime.fromMillisecondsSinceEpoch((data.timestamp * 1000).toInt())}');
160
- ///
161
- /// // Use for visual feedback, volume meters, etc.
162
- /// if (data.decibel > -40) {
163
- /// print('Loud input detected!');
164
- /// }
165
- /// });
166
- /// ```
167
- Stream<DecibelData>? get decibelStream => _decibelStream;
168
-
169
- MicAudioConfig _config = MicAudioConfig();
170
-
171
- /// Creates a new [MicAudioCapture] instance.
172
- ///
173
- /// [config] is optional. If not provided, default configuration will be used
174
- /// (sampleRate: 16000, channels: 1, bitDepth: 16, gainBoost: 2.5, inputVolume: 1.0).
175
- ///
176
- /// Example:
177
- /// ```dart
178
- /// final capture = MicAudioCapture(
179
- /// config: MicAudioConfig(
180
- /// sampleRate: 44100,
181
- /// channels: 1,
182
- /// gainBoost: 3.0,
183
- /// inputVolume: 0.8,
184
- /// ),
185
- /// );
186
- /// ```
187
- MicAudioCapture({MicAudioConfig? config}) {
188
- _config = config ?? MicAudioConfig();
189
- }
190
-
191
- /// Updates the audio capture configuration.
192
- ///
193
- /// This method allows you to change the configuration after the instance
194
- /// has been created. The new configuration will be applied on the next
195
- /// [startCapture] call.
196
- ///
197
- /// Example:
198
- /// ```dart
199
- /// final capture = MicAudioCapture();
200
- ///
201
- /// // Update config before starting
202
- /// capture.updateConfig(MicAudioConfig(
203
- /// sampleRate: 48000,
204
- /// channels: 2,
205
- /// gainBoost: 2.0,
206
- /// ));
207
- ///
208
- /// await capture.startCapture();
209
- /// ```
210
- void updateConfig(MicAudioConfig config) {
211
- _config = config;
212
- }
213
-
214
- /// Starts capturing audio from the microphone.
215
- ///
216
- /// This method will request necessary permissions (microphone permission)
217
- /// and begin capturing audio from the default or configured microphone.
218
- ///
219
- /// [config] is optional. If provided, it will update the current configuration
220
- /// before starting capture.
221
- ///
222
- /// Throws an [Exception] if:
223
- /// - Permissions are not granted
224
- /// - No microphone is available
225
- /// - Capture fails to start
226
- ///
227
- /// Example:
228
- /// ```dart
229
- /// final capture = MicAudioCapture();
230
- ///
231
- /// try {
232
- /// await capture.startCapture(
233
- /// config: MicAudioConfig(
234
- /// sampleRate: 44100,
235
- /// channels: 1,
236
- /// gainBoost: 2.5,
237
- /// ),
238
- /// );
239
- /// print('Microphone capture started');
240
- /// } catch (e) {
241
- /// print('Failed to start: $e');
242
- /// }
243
- /// ```
244
- Future<void> startCapture({MicAudioConfig? config}) async {
245
- if (_isRecording) {
246
- return;
247
- }
248
-
249
- if (config != null) {
250
- updateConfig(config);
251
- }
252
-
253
- try {
254
- await requestPermissions();
255
-
256
- try {
257
- final result = await _channel.invokeMethod<dynamic>(
258
- _MicAudioMethod.startCapture.name,
259
- _config.toMap(),
260
- );
261
-
262
- if (result is! bool || result != true) {
263
- final errorMsg = result is String
264
- ? result
265
- : 'Failed to start microphone capture. Returned: $result';
266
- throw Exception(errorMsg);
267
- }
268
- } on PlatformException catch (e) {
269
- throw Exception(
270
- 'Failed to start microphone capture: ${e.message ?? e.code}');
271
- }
272
-
273
- // Create audio stream
274
- // Note: Stream will be subscribed by listeners, which triggers onListen on native side
275
- _audioStream = _audioStreamChannel.receiveBroadcastStream().map((
276
- dynamic event,
277
- ) {
278
- if (event is Uint8List) {
279
- return event;
280
- } else if (event is List<int>) {
281
- return Uint8List.fromList(event);
282
- }
283
- throw Exception('Unexpected audio data type: ${event.runtimeType}');
284
- });
285
-
286
- // Create decibel stream
287
- _decibelStream = _decibelStreamChannel.receiveBroadcastStream().map((
288
- dynamic event,
289
- ) {
290
- if (event is Map) {
291
- return DecibelData.fromMap(Map<String, dynamic>.from(event));
292
- }
293
- return DecibelData(
294
- decibel: -120.0,
295
- timestamp: DateTime.now().millisecondsSinceEpoch / 1000.0);
296
- });
297
-
298
- // Status stream is created lazily via getter, no need to recreate here
299
-
300
- _isRecording = true;
301
- } catch (e) {
302
- rethrow;
303
- }
304
- }
305
-
306
- /// Stops capturing microphone audio.
307
- ///
308
- /// This method will stop the active capture and close all associated streams.
309
- /// If capture is not active, this method does nothing.
310
- ///
311
- /// Throws an [Exception] if stopping fails.
312
- ///
313
- /// Example:
314
- /// ```dart
315
- /// await micCapture.startCapture();
316
- ///
317
- /// // ... use audio stream ...
318
- ///
319
- /// await micCapture.stopCapture();
320
- /// print('Microphone capture stopped');
321
- /// ```
322
- Future<void> stopCapture() async {
323
- if (!_isRecording) return;
324
-
325
- try {
326
- final stoped = await _channel.invokeMethod<bool>(
327
- _MicAudioMethod.stopCapture.name,
328
- );
329
-
330
- if (stoped != true) {
331
- throw Exception("Failed to stop microphone capture");
332
- }
333
-
334
- _isRecording = false;
335
- _audioStream = null;
336
- _statusStream = null;
337
- _decibelStream = null;
338
- } catch (e) {
339
- rethrow;
340
- }
341
- }
342
-
343
- /// Whether microphone capture is currently recording.
344
- ///
345
- /// Returns `true` if capture is active, `false` otherwise.
346
- ///
347
- /// Example:
348
- /// ```dart
349
- /// if (micCapture.isRecording) {
350
- /// print('Microphone is being captured');
351
- /// } else {
352
- /// print('Microphone capture is not active');
353
- /// }
354
- /// ```
355
- @override
356
- bool get isRecording => _isRecording;
357
-
358
- /// Requests necessary permissions for microphone capture.
359
- ///
360
- /// This requests microphone permission which is required to capture audio
361
- /// from input devices.
362
- ///
363
- /// Returns `true` if permissions are granted.
364
- ///
365
- /// Throws an [Exception] if permissions are not granted.
366
- ///
367
- /// Example:
368
- /// ```dart
369
- /// try {
370
- /// final hasPermission = await micCapture.requestPermissions();
371
- /// if (hasPermission) {
372
- /// await micCapture.startCapture();
373
- /// }
374
- /// } catch (e) {
375
- /// print('Permission denied: $e');
376
- /// }
377
- /// ```
378
- Future<bool> requestPermissions() async {
379
- final hasPermission = await _channel.invokeMethod<bool>(
380
- _MicAudioMethod.requestPermissions.name,
381
- );
382
- if (hasPermission != true) {
383
- throw Exception('Microphone permission not granted');
384
- }
385
- return true;
386
- }
387
-
388
- /// Checks if there is any available input device (microphone).
389
- ///
390
- /// Returns `true` if there is at least one available input device,
391
- /// `false` if there is no available input device.
392
- ///
393
- /// Example:
394
- /// ```dart
395
- /// final hasDevice = await micCapture.hasInputDevice();
396
- /// if (hasDevice) {
397
- /// print('Microphone available');
398
- /// await micCapture.startCapture();
399
- /// } else {
400
- /// print('No microphone found');
401
- /// }
402
- /// ```
403
- Future<bool> hasInputDevice() async {
404
- try {
405
- final hasDevice = await _channel.invokeMethod<bool>(
406
- _MicAudioMethod.hasInputDevice.name,
407
- );
408
- return hasDevice ?? false;
409
- } catch (e) {
410
- rethrow;
411
- }
412
- }
413
-
414
- /// Gets a list of all available input devices (microphones).
415
- ///
416
- /// Returns a list of [InputDevice] containing device information:
417
- /// - `id`: String - unique device ID
418
- /// - `name`: String - device name
419
- /// - `type`: [InputDeviceType] - device type (builtIn, bluetooth, external)
420
- /// - `channelCount`: int - number of audio channels
421
- /// - `isDefault`: bool - whether the device is the default device
422
- ///
423
- /// Example:
424
- /// ```dart
425
- /// final devices = await micCapture.getAvailableInputDevices();
426
- ///
427
- /// for (final device in devices) {
428
- /// print('Device: ${device.name}');
429
- /// print(' Type: ${device.type}');
430
- /// print(' Channels: ${device.channelCount}');
431
- /// print(' Default: ${device.isDefault}');
432
- /// }
433
- ///
434
- /// // Find default device
435
- /// final defaultDevice = devices.firstWhere(
436
- /// (device) => device.isDefault,
437
- /// orElse: () => devices.first,
438
- /// );
439
- /// print('Using device: ${defaultDevice.name}');
440
- /// ```
441
- Future<List<InputDevice>> getAvailableInputDevices() async {
442
- try {
443
- final devices = await _channel.invokeMethod<List<dynamic>>(
444
- _MicAudioMethod.getAvailableInputDevices.name,
445
- );
446
-
447
- if (devices == null) {
448
- return [];
449
- }
450
-
451
- return devices
452
- .whereType<Map>()
453
- .map((device) => InputDevice.fromMap(
454
- Map<String, dynamic>.from(device),
455
- ))
456
- .toList();
457
- } catch (e) {
458
- rethrow;
459
- }
460
- }
461
- }
@@ -1,91 +0,0 @@
1
- abstract class AudioStatus {
2
- final bool isActive;
3
-
4
- const AudioStatus({
5
- required this.isActive,
6
- });
7
-
8
- Map<String, dynamic> toJson();
9
-
10
- @override
11
- bool operator ==(Object other) {
12
- if (identical(this, other)) return true;
13
-
14
- return other is AudioStatus && other.isActive == isActive;
15
- }
16
-
17
- @override
18
- int get hashCode => isActive.hashCode;
19
- }
20
-
21
- class MicAudioStatus extends AudioStatus {
22
- final String? deviceName;
23
-
24
- const MicAudioStatus({
25
- required super.isActive,
26
- this.deviceName,
27
- });
28
-
29
- MicAudioStatus copyWith({
30
- bool? isActive,
31
- String? deviceName,
32
- }) {
33
- return MicAudioStatus(
34
- isActive: isActive ?? this.isActive,
35
- deviceName: deviceName ?? this.deviceName,
36
- );
37
- }
38
-
39
- factory MicAudioStatus.fromJson(Map<String, dynamic> json) {
40
- return MicAudioStatus(
41
- isActive: json['isActive'],
42
- deviceName: json['deviceName'],
43
- );
44
- }
45
-
46
- @override
47
- Map<String, dynamic> toJson() {
48
- return {
49
- 'isActive': isActive,
50
- 'deviceName': deviceName,
51
- };
52
- }
53
-
54
- @override
55
- String toString() =>
56
- '''MicAudioStatus(isActive: $isActive, deviceName: $deviceName)''';
57
-
58
- @override
59
- bool operator ==(Object other) {
60
- if (identical(this, other)) return true;
61
-
62
- return other is MicAudioStatus && other.deviceName == deviceName;
63
- }
64
-
65
- @override
66
- int get hashCode => deviceName.hashCode;
67
- }
68
-
69
- class SystemAudioStatus extends AudioStatus {
70
- SystemAudioStatus({required super.isActive});
71
-
72
- SystemAudioStatus copyWith({
73
- bool? isActive,
74
- }) {
75
- return SystemAudioStatus(isActive: isActive ?? this.isActive);
76
- }
77
-
78
- factory SystemAudioStatus.fromJson(Map<String, dynamic> json) {
79
- return SystemAudioStatus(isActive: json['isActive']);
80
- }
81
-
82
- @override
83
- Map<String, dynamic> toJson() {
84
- return {
85
- 'isActive': isActive,
86
- };
87
- }
88
-
89
- @override
90
- String toString() => '''SystemAudioStatus(isActive: $isActive)''';
91
- }
@@ -1,106 +0,0 @@
1
- /// Decibel data from audio capture.
2
- ///
3
- /// This class represents a single decibel reading with its timestamp.
4
- /// Used by both microphone and system audio capture to provide volume level
5
- /// information.
6
- ///
7
- /// Example:
8
- /// ```dart
9
- /// // From stream
10
- /// capture.decibelStream?.listen((data) {
11
- /// print('Decibel: ${data.decibel} dB');
12
- /// print('Time: ${DateTime.fromMillisecondsSinceEpoch((data.timestamp * 1000).toInt())}');
13
- /// });
14
- ///
15
- /// // Create manually
16
- /// final data = DecibelData(
17
- /// decibel: -45.5,
18
- /// timestamp: DateTime.now().millisecondsSinceEpoch / 1000.0,
19
- /// );
20
- ///
21
- /// // Convert to/from map
22
- /// final map = data.toMap();
23
- /// final restored = DecibelData.fromMap(map);
24
- /// ```
25
- class DecibelData {
26
- /// Decibel value in dB, typically ranging from -120 to 0 dB.
27
- ///
28
- /// - -120 dB: silence or very quiet
29
- /// - -60 dB: quiet background noise
30
- /// - -40 dB: normal speech
31
- /// - -20 dB: loud speech
32
- /// - 0 dB: maximum level
33
- final double decibel;
34
-
35
- /// Unix timestamp in seconds (not milliseconds).
36
- ///
37
- /// This represents when the decibel reading was taken.
38
- final double timestamp;
39
-
40
- /// Creates a new [DecibelData] instance.
41
- ///
42
- /// [decibel] should be in the range -120 to 0 dB.
43
- /// [timestamp] should be a Unix timestamp in seconds.
44
- ///
45
- /// Example:
46
- /// ```dart
47
- /// final data = DecibelData(
48
- /// decibel: -45.0,
49
- /// timestamp: DateTime.now().millisecondsSinceEpoch / 1000.0,
50
- /// );
51
- /// ```
52
- const DecibelData({
53
- required this.decibel,
54
- required this.timestamp,
55
- });
56
-
57
- /// Creates a [DecibelData] instance from a map.
58
- ///
59
- /// The map should contain:
60
- /// - `decibel`: num (will be converted to double)
61
- /// - `timestamp`: num (will be converted to double)
62
- ///
63
- /// If values are missing, defaults to -120.0 dB and current timestamp.
64
- ///
65
- /// Example:
66
- /// ```dart
67
- /// final map = {
68
- /// 'decibel': -45.5,
69
- /// 'timestamp': 1234567890.0,
70
- /// };
71
- /// final data = DecibelData.fromMap(map);
72
- /// ```
73
- factory DecibelData.fromMap(Map<String, dynamic> map) {
74
- return DecibelData(
75
- decibel: (map['decibel'] as num?)?.toDouble() ?? -120.0,
76
- timestamp: (map['timestamp'] as num?)?.toDouble() ??
77
- DateTime.now().millisecondsSinceEpoch / 1000.0,
78
- );
79
- }
80
-
81
- /// Converts this [DecibelData] instance to a map.
82
- ///
83
- /// Returns a map containing:
84
- /// - `decibel`: double
85
- /// - `timestamp`: double
86
- ///
87
- /// Example:
88
- /// ```dart
89
- /// final data = DecibelData(
90
- /// decibel: -45.0,
91
- /// timestamp: 1234567890.0,
92
- /// );
93
- /// final map = data.toMap();
94
- /// // map = {'decibel': -45.0, 'timestamp': 1234567890.0}
95
- /// ```
96
- Map<String, dynamic> toMap() {
97
- return {
98
- 'decibel': decibel,
99
- 'timestamp': timestamp,
100
- };
101
- }
102
-
103
- @override
104
- String toString() =>
105
- 'DecibelData(decibel: ${decibel.toStringAsFixed(1)} dB, timestamp: $timestamp)';
106
- }