neoagent 3.1.1-beta.9 → 3.2.1-beta.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 (151) 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 +875 -383
  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 +2 -2
  56. package/server/public/index.html +174 -0
  57. package/server/public/main.dart.js +92036 -91145
  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/formatting_guides.js +1 -0
  80. package/server/services/messaging/whatsapp.js +18 -0
  81. package/server/services/security/tool_categories.js +0 -5
  82. package/server/services/social_video/service.js +2 -20
  83. package/server/services/tasks/adapters/index.js +1 -1
  84. package/server/services/tasks/integration_runtime.js +3 -67
  85. package/server/services/tasks/runtime.js +1 -6
  86. package/server/services/tasks/task_repository.js +6 -13
  87. package/server/services/timeline/service.js +0 -224
  88. package/server/services/voice/message.js +0 -24
  89. package/server/services/voice/providers.js +42 -1
  90. package/server/services/voice/runtimeManager.js +9 -5
  91. package/server/services/voice/turnRunner.js +0 -22
  92. package/server/services/wearable/service.js +0 -5
  93. package/docs/recordings-and-health.md +0 -41
  94. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/recording/RecordingBootReceiver.kt +0 -21
  95. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/recording/RecordingForegroundService.kt +0 -586
  96. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/recording/RecordingStateStore.kt +0 -78
  97. package/flutter_app/android/app/src/main/kotlin/com/neoagent/flutter_app/recording/RecordingUploadClient.kt +0 -104
  98. package/flutter_app/lib/main_recordings.dart +0 -920
  99. package/flutter_app/lib/src/desktop_ocr_bridge.dart +0 -2
  100. package/flutter_app/lib/src/desktop_ocr_bridge_io.dart +0 -125
  101. package/flutter_app/lib/src/desktop_ocr_bridge_stub.dart +0 -30
  102. package/flutter_app/lib/src/desktop_passive_history.dart +0 -332
  103. package/flutter_app/lib/src/recording_bridge.dart +0 -232
  104. package/flutter_app/lib/src/recording_bridge_io.dart +0 -1027
  105. package/flutter_app/lib/src/recording_bridge_stub.dart +0 -120
  106. package/flutter_app/lib/src/recording_bridge_web.dart +0 -702
  107. package/flutter_app/lib/src/recording_chunk_queue.dart +0 -149
  108. package/flutter_app/lib/src/recording_chunk_queue_io.dart +0 -182
  109. package/flutter_app/lib/src/recording_payloads.dart +0 -95
  110. package/flutter_app/third_party/desktop_audio_capture/LICENSE +0 -21
  111. package/flutter_app/third_party/desktop_audio_capture/README.md +0 -262
  112. package/flutter_app/third_party/desktop_audio_capture/lib/audio_capture.dart +0 -65
  113. package/flutter_app/third_party/desktop_audio_capture/lib/config/mic_audio_config.dart +0 -153
  114. package/flutter_app/third_party/desktop_audio_capture/lib/config/system_adudio_config.dart +0 -110
  115. package/flutter_app/third_party/desktop_audio_capture/lib/mic/mic_audio_capture.dart +0 -461
  116. package/flutter_app/third_party/desktop_audio_capture/lib/model/audio_status.dart +0 -91
  117. package/flutter_app/third_party/desktop_audio_capture/lib/model/decibel_data.dart +0 -106
  118. package/flutter_app/third_party/desktop_audio_capture/lib/model/input_device_type.dart +0 -219
  119. package/flutter_app/third_party/desktop_audio_capture/lib/system/system_audio_capture.dart +0 -336
  120. package/flutter_app/third_party/desktop_audio_capture/linux/CMakeLists.txt +0 -101
  121. package/flutter_app/third_party/desktop_audio_capture/linux/audio_capture_plugin.cc +0 -692
  122. package/flutter_app/third_party/desktop_audio_capture/linux/include/audio_capture/audio_capture_plugin.h +0 -35
  123. package/flutter_app/third_party/desktop_audio_capture/linux/include/audio_capture/mic_capture_plugin.h +0 -36
  124. package/flutter_app/third_party/desktop_audio_capture/linux/include/desktop_audio_capture/audio_capture_plugin.h +0 -32
  125. package/flutter_app/third_party/desktop_audio_capture/linux/include/desktop_audio_capture/mic_capture_plugin.h +0 -32
  126. package/flutter_app/third_party/desktop_audio_capture/linux/mic_capture_plugin.cc +0 -878
  127. package/flutter_app/third_party/desktop_audio_capture/macos/Classes/AudioCapturePlugin.swift +0 -27
  128. package/flutter_app/third_party/desktop_audio_capture/macos/Classes/MicCapturePlugin.swift +0 -1172
  129. package/flutter_app/third_party/desktop_audio_capture/macos/Classes/SystemCapturePlugin.swift +0 -655
  130. package/flutter_app/third_party/desktop_audio_capture/macos/Resources/PrivacyInfo.xcprivacy +0 -12
  131. package/flutter_app/third_party/desktop_audio_capture/macos/desktop_audio_capture.podspec +0 -30
  132. package/flutter_app/third_party/desktop_audio_capture/pubspec.yaml +0 -87
  133. package/flutter_app/third_party/desktop_audio_capture/windows/CMakeLists.txt +0 -105
  134. package/flutter_app/third_party/desktop_audio_capture/windows/audio_capture_plugin.cpp +0 -80
  135. package/flutter_app/third_party/desktop_audio_capture/windows/audio_capture_plugin.h +0 -31
  136. package/flutter_app/third_party/desktop_audio_capture/windows/audio_capture_plugin_c_api.cpp +0 -12
  137. package/flutter_app/third_party/desktop_audio_capture/windows/include/audio_capture/audio_capture_plugin_c_api.h +0 -23
  138. package/flutter_app/third_party/desktop_audio_capture/windows/include/desktop_audio_capture/audio_capture_plugin.h +0 -25
  139. package/flutter_app/third_party/desktop_audio_capture/windows/mic_capture_plugin.cpp +0 -1117
  140. package/flutter_app/third_party/desktop_audio_capture/windows/mic_capture_plugin.h +0 -115
  141. package/flutter_app/third_party/desktop_audio_capture/windows/system_audio_capture_plugin.cpp +0 -777
  142. package/flutter_app/third_party/desktop_audio_capture/windows/system_audio_capture_plugin.h +0 -87
  143. package/server/routes/recordings.js +0 -335
  144. package/server/routes/screenHistory.js +0 -190
  145. package/server/services/ai/recordingInsights.js +0 -105
  146. package/server/services/integrations/neomail/provider.js +0 -993
  147. package/server/services/recordings/deepgram.js +0 -58
  148. package/server/services/recordings/manager.js +0 -1273
  149. package/server/services/tasks/adapters/neomail_email_received.js +0 -46
  150. package/server/services/voice/screenshotContext.js +0 -73
  151. 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
- }