diff --git a/.github/workflows/analyze.yaml b/.github/workflows/analyze.yaml
new file mode 100644
index 0000000..cd30b77
--- /dev/null
+++ b/.github/workflows/analyze.yaml
@@ -0,0 +1,47 @@
+name: Flutter Analyze
+
+on:
+ pull_request:
+ branches:
+ - main
+ push:
+ branches:
+ - main
+
+jobs:
+ build:
+ name: Analyze code and requirements
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+
+ - name: Setup Flutter
+ uses: subosito/flutter-action@v2
+ with:
+ channel: 'stable'
+
+ - name: Verify Flutter installation
+ run: flutter doctor
+
+ - name: Check pub dependencies
+ run: flutter pub get
+
+ - name: "Run Dart Analyze"
+ uses: invertase/github-action-dart-analyzer@v3
+ with:
+ fatal-infos: true
+ fatal-warnings: true
+ annotate: true
+ working-directory: lib/
+
+ - name: Check Code formatting
+ run: dart format -o none --set-exit-if-changed .
+
+ - name: Check pub.dev requirements
+ run: flutter pub publish --dry-run
+
+ - name: Block merge if checks fail
+ if: ${{ failure() }}
+ run: echo "Checks failed, cannot merge." && exit 1
diff --git a/.vscode/launch.json b/.vscode/launch.json
index b6fb754..42a77cf 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -8,7 +8,7 @@
"name": "example debug",
"request": "launch",
"type": "dart",
- "program": "lib/main.dart",
+ "program": "lib/loopback.dart",
"cwd": "${workspaceFolder}/example"
},
{
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 52362ce..11cbee0 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -93,6 +93,8 @@
"xtr1common": "cpp",
"xtree": "cpp",
"xutility": "cpp",
- "bitset": "cpp"
+ "bitset": "cpp",
+ "cfenv": "cpp",
+ "unordered_set": "cpp"
}
}
\ No newline at end of file
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
index a5808d5..61698e2 100755
--- a/.vscode/tasks.json
+++ b/.vscode/tasks.json
@@ -9,7 +9,7 @@
},
{
"label": "compile linux debug",
- "command": "cd ${workspaceFolder}/example; flutter build linux -t lib/main.dart --debug",
+ "command": "cd ${workspaceFolder}/example; flutter build linux -t lib/loopback.dart --debug",
"type": "shell"
},
{
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7cb77d0..1faca61 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,9 +1,20 @@
+## 0.9.3
+- added `autoGain` filter
+- breaking changes:
+ - the `init` method is now async
+ - `FilterType` renamed to `RecorderFilterType`
+ - an [additional script](https://github.com/alnitak/flutter_recorder#web) must be added for the web platform. Now it looks like:
+ ```
+
+
+ ```
+
## 0.9.2
-* fix: the stop was instead einit the device
-* fix: removed dialog when stopping stream in the example
+- fix: the stop was instead einit the device
+- fix: removed dialog when stopping stream in the example
## 0.9.1
-* breaking change:
+- breaking changes:
- renamed `startListen` to `start`
- renamed `stopListen` to `stop`
- renamed `isDeviceStartedListen` to `isDeviceStarted`
diff --git a/README.md b/README.md
index 72f236a..bf7e628 100644
--- a/README.md
+++ b/README.md
@@ -19,11 +19,13 @@ A low-level audio recorder plugin that uses miniaudio as the backend and support
- π **Customizable Silence Threshold**: Define whatβs considered βsilenceβ for your recordings.
- β±οΈ **Adjustable Pause Timing**: Set how long silence lasts before pausing, and how soon to resume recording.
- π **Real-time Audio Metrics**: Access volume, audio wave, and FFT data in real-time.
+- ποΈ **Auto Gain**: Experimental Auto Gain filter.
+- π **Cross Platform**: Supports all platforms with WASM support for the web.
[A web example compiled in WASM.](https://marcobavagnoli.com/flutter_recorder/)
-## π Setup Permissions
-After setting up permission for you Android, MacOS or iOS, in your app, you will need to ask for permission to use the microphonem maybe using [permission_handler](https://pub.dev/packages/permission_handler) plugin.
+## π Setup
+After setting up permission for you Android, MacOS or iOS, in your app, you will need to ask for permission to use the microphone maybe using [permission_handler](https://pub.dev/packages/permission_handler) plugin.
https://pub.dev/packages/permission_handler
#### Android
@@ -43,7 +45,16 @@ Add the permission in `Runner/Info.plist`.
Add this in `web/index.html` under the `
` tag.
```
+
```
+The plugin is **WASM** compatible and your app can be compiled and run locally with something like:
+```
+flutter run -d chrome --web-renderer canvaskit --web-browser-flag '--disable-web-security' -t lib/main.dart --release
+```
+
+#### Linux
+- [`GStreamer`](https://gstreamer.freedesktop.org/documentation/installing/index.html?gi-language=c) is installed by default on most distributions, but if not, please [install it](https://gstreamer.freedesktop.org/documentation/installing/on-linux.html?gi-language=c) through your distribution's package manager.
+- Installing Flutter using `snap` could cause compilation problems with native plugins. The only solution is to uninstall it with `sudo snap remove flutter` and install it the [official way](https://flutter-ko.dev/get-started/install/linux).
## π οΈ Usage Example
```dart
@@ -136,4 +147,28 @@ Recorder.instance.uint8ListStream.listen((data) {
Recorder.instance.startStreamingData();
/// Stop streaming:
Recorder.instance.stopStreamingData();
-```
\ No newline at end of file
+```
+> [!CAUTION]
+> Audio data must be processed as it is received. To optimize performance, the same memory is used to store data for all incoming streams, meaning the data will be overwritten. Therefore, you must copy the data if you need to populate a buffer while it arrives.
+> For example, when using **RxDart.bufferTime**, it will fill a **List** of `AudioDataContainer` objects, but when you attempt to read them, you will find that all the items contain the same data.
+
+### ποΈ Auto Gain Filter
+
+> [!WARNING]
+> This is an experimental feature, may change in the future.
+
+```
+final Recorder recorder = Recorder.instance;
+// Please look at the [Recorder.instance.autoGainFilter] doc to have a parameters overview.
+final AutoGain autoGain = recorder.filters.autoGainFilter;
+
+// You can now query or set parameters:
+// For example with [autoGain.queryTargetRms] you can query the "human" name, `min`, `max` and `def` values.
+
+// Set a new parameter value:
+autoGain.targetRms.value = newValue;
+
+// Get a new parameter value:
+final value = autoGain.targetRms.value;
+```
+Available parameters: `targetRMS`, `attackTime`, `releaseTime`, `gainSmoothing`, `maxGain`, `minGain`.
\ No newline at end of file
diff --git a/example/ios/Podfile b/example/ios/Podfile
index d97f17e..3e44f9c 100644
--- a/example/ios/Podfile
+++ b/example/ios/Podfile
@@ -1,5 +1,5 @@
# Uncomment this line to define a global platform for your project
-# platform :ios, '12.0'
+platform :ios, '13.0'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock
new file mode 100644
index 0000000..524c948
--- /dev/null
+++ b/example/ios/Podfile.lock
@@ -0,0 +1,47 @@
+PODS:
+ - Flutter (1.0.0)
+ - flutter_recorder (0.0.1):
+ - Flutter
+ - flutter_soloud (0.0.1):
+ - Flutter
+ - open_filex (0.0.2):
+ - Flutter
+ - path_provider_foundation (0.0.1):
+ - Flutter
+ - FlutterMacOS
+ - permission_handler_apple (9.3.0):
+ - Flutter
+
+DEPENDENCIES:
+ - Flutter (from `Flutter`)
+ - flutter_recorder (from `.symlinks/plugins/flutter_recorder/ios`)
+ - flutter_soloud (from `.symlinks/plugins/flutter_soloud/ios`)
+ - open_filex (from `.symlinks/plugins/open_filex/ios`)
+ - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
+ - permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`)
+
+EXTERNAL SOURCES:
+ Flutter:
+ :path: Flutter
+ flutter_recorder:
+ :path: ".symlinks/plugins/flutter_recorder/ios"
+ flutter_soloud:
+ :path: ".symlinks/plugins/flutter_soloud/ios"
+ open_filex:
+ :path: ".symlinks/plugins/open_filex/ios"
+ path_provider_foundation:
+ :path: ".symlinks/plugins/path_provider_foundation/darwin"
+ permission_handler_apple:
+ :path: ".symlinks/plugins/permission_handler_apple/ios"
+
+SPEC CHECKSUMS:
+ Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
+ flutter_recorder: 35999d791bb08147db8b8b8167f8a5e561f68237
+ flutter_soloud: 12a37f5fb426c94671d762cbb059bbeb1b46ad97
+ open_filex: 6e26e659846ec990262224a12ef1c528bb4edbe4
+ path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
+ permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2
+
+PODFILE CHECKSUM: a57f30d18f102dd3ce366b1d62a55ecbef2158e5
+
+COCOAPODS: 1.15.2
diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj
index 88fbc77..781af60 100644
--- a/example/ios/Runner.xcodeproj/project.pbxproj
+++ b/example/ios/Runner.xcodeproj/project.pbxproj
@@ -8,12 +8,14 @@
/* Begin PBXBuildFile section */
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
+ 1D9A259E0A65BDED58FC0E1F /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 386A598177C879C697502420 /* Pods_Runner.framework */; };
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
+ AF107EE89F8D5B266B88F910 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 48AB80419F76EED8831B97A1 /* Pods_RunnerTests.framework */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@@ -40,28 +42,45 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
+ 1037086DD8093E5D23D52CAC /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; };
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; };
+ 17C4B834173960B42203FCB0 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; };
331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; };
331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
+ 386A598177C879C697502420 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; };
+ 48AB80419F76EED8831B97A1 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; };
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; };
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; };
+ 97747679D6BD3814C0AA87F2 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; };
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+ C2AA768158B1BFD9B1338F04 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; };
+ DACD54B8B76D7B3084F7E8C0 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; };
+ F700F8D25769228B66ED2553 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
+ 47E16123D84EC497B2A5DA52 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ AF107EE89F8D5B266B88F910 /* Pods_RunnerTests.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
97C146EB1CF9000F007C117D /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
+ 1D9A259E0A65BDED58FC0E1F /* Pods_Runner.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -94,6 +113,8 @@
97C146F01CF9000F007C117D /* Runner */,
97C146EF1CF9000F007C117D /* Products */,
331C8082294A63A400263BE5 /* RunnerTests */,
+ F82E1D2DC785D9CB3A8AD804 /* Pods */,
+ A45EDF3789BB2E7140660151 /* Frameworks */,
);
sourceTree = "";
};
@@ -121,6 +142,28 @@
path = Runner;
sourceTree = "";
};
+ A45EDF3789BB2E7140660151 /* Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ 386A598177C879C697502420 /* Pods_Runner.framework */,
+ 48AB80419F76EED8831B97A1 /* Pods_RunnerTests.framework */,
+ );
+ name = Frameworks;
+ sourceTree = "";
+ };
+ F82E1D2DC785D9CB3A8AD804 /* Pods */ = {
+ isa = PBXGroup;
+ children = (
+ DACD54B8B76D7B3084F7E8C0 /* Pods-Runner.debug.xcconfig */,
+ C2AA768158B1BFD9B1338F04 /* Pods-Runner.release.xcconfig */,
+ 17C4B834173960B42203FCB0 /* Pods-Runner.profile.xcconfig */,
+ F700F8D25769228B66ED2553 /* Pods-RunnerTests.debug.xcconfig */,
+ 97747679D6BD3814C0AA87F2 /* Pods-RunnerTests.release.xcconfig */,
+ 1037086DD8093E5D23D52CAC /* Pods-RunnerTests.profile.xcconfig */,
+ );
+ path = Pods;
+ sourceTree = "";
+ };
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
@@ -128,8 +171,10 @@
isa = PBXNativeTarget;
buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */;
buildPhases = (
+ B2599692132BCEBD1783036A /* [CP] Check Pods Manifest.lock */,
331C807D294A63A400263BE5 /* Sources */,
331C807F294A63A400263BE5 /* Resources */,
+ 47E16123D84EC497B2A5DA52 /* Frameworks */,
);
buildRules = (
);
@@ -145,12 +190,15 @@
isa = PBXNativeTarget;
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
+ 440CCA47AA7F2FA70FBC0828 /* [CP] Check Pods Manifest.lock */,
9740EEB61CF901F6004384FC /* Run Script */,
97C146EA1CF9000F007C117D /* Sources */,
97C146EB1CF9000F007C117D /* Frameworks */,
97C146EC1CF9000F007C117D /* Resources */,
9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
+ DD3FAE5D7FDD9B0A42D6A8B7 /* [CP] Embed Pods Frameworks */,
+ 9A151FA45FF56BE9607BC7C7 /* [CP] Copy Pods Resources */,
);
buildRules = (
);
@@ -238,6 +286,28 @@
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
};
+ 440CCA47AA7F2FA70FBC0828 /* [CP] Check Pods Manifest.lock */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputFileListPaths = (
+ );
+ inputPaths = (
+ "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+ "${PODS_ROOT}/Manifest.lock",
+ );
+ name = "[CP] Check Pods Manifest.lock";
+ outputFileListPaths = (
+ );
+ outputPaths = (
+ "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
+ showEnvVarsInLog = 0;
+ };
9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
@@ -253,6 +323,62 @@
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
};
+ 9A151FA45FF56BE9607BC7C7 /* [CP] Copy Pods Resources */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputFileListPaths = (
+ "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist",
+ );
+ name = "[CP] Copy Pods Resources";
+ outputFileListPaths = (
+ "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
+ showEnvVarsInLog = 0;
+ };
+ B2599692132BCEBD1783036A /* [CP] Check Pods Manifest.lock */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputFileListPaths = (
+ );
+ inputPaths = (
+ "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+ "${PODS_ROOT}/Manifest.lock",
+ );
+ name = "[CP] Check Pods Manifest.lock";
+ outputFileListPaths = (
+ );
+ outputPaths = (
+ "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
+ showEnvVarsInLog = 0;
+ };
+ DD3FAE5D7FDD9B0A42D6A8B7 /* [CP] Embed Pods Frameworks */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputFileListPaths = (
+ "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
+ );
+ name = "[CP] Embed Pods Frameworks";
+ outputFileListPaths = (
+ "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
+ showEnvVarsInLog = 0;
+ };
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
@@ -370,6 +496,7 @@
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.flutterRecorderExample;
PRODUCT_NAME = "$(TARGET_NAME)";
+ STRIP_STYLE = "non-global";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
@@ -378,6 +505,7 @@
};
331C8088294A63A400263BE5 /* Debug */ = {
isa = XCBuildConfiguration;
+ baseConfigurationReference = F700F8D25769228B66ED2553 /* Pods-RunnerTests.debug.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
@@ -395,6 +523,7 @@
};
331C8089294A63A400263BE5 /* Release */ = {
isa = XCBuildConfiguration;
+ baseConfigurationReference = 97747679D6BD3814C0AA87F2 /* Pods-RunnerTests.release.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
@@ -410,6 +539,7 @@
};
331C808A294A63A400263BE5 /* Profile */ = {
isa = XCBuildConfiguration;
+ baseConfigurationReference = 1037086DD8093E5D23D52CAC /* Pods-RunnerTests.profile.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
@@ -549,6 +679,7 @@
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.flutterRecorderExample;
PRODUCT_NAME = "$(TARGET_NAME)";
+ STRIP_STYLE = "non-global";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
@@ -571,6 +702,7 @@
);
PRODUCT_BUNDLE_IDENTIFIER = com.example.flutterRecorderExample;
PRODUCT_NAME = "$(TARGET_NAME)";
+ STRIP_STYLE = "non-global";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
diff --git a/example/ios/Runner.xcworkspace/contents.xcworkspacedata b/example/ios/Runner.xcworkspace/contents.xcworkspacedata
index 1d526a1..21a3cc1 100644
--- a/example/ios/Runner.xcworkspace/contents.xcworkspacedata
+++ b/example/ios/Runner.xcworkspace/contents.xcworkspacedata
@@ -4,4 +4,7 @@
+
+
diff --git a/example/lib/loopback.dart b/example/lib/loopback.dart
new file mode 100644
index 0000000..745e8e6
--- /dev/null
+++ b/example/lib/loopback.dart
@@ -0,0 +1,456 @@
+import 'dart:developer' as dev;
+
+import 'package:flutter/foundation.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_recorder/flutter_recorder.dart';
+import 'package:flutter_recorder_example/ui/bars.dart';
+import 'package:flutter_soloud/flutter_soloud.dart';
+import 'package:logging/logging.dart';
+import 'package:permission_handler/permission_handler.dart';
+
+/// Loopback example which uses `flutter_soloud` to play audio back to the
+/// device from the microphone data stream. Please try it with headset to
+/// prevent audio feedback.
+///
+/// If you want to try other formats than `f32le`, you must comment out
+/// the `Bars()` widget.
+///
+/// The `Echo Cancellation` code is not yet ready and don't know if it will be!
+void main() async {
+ // The `flutter_recorder` package logs everything
+ // (from severe warnings to fine debug messages)
+ // using the standard `package:logging`.
+ // You can listen to the logs as shown below.
+ Logger.root.level = kDebugMode ? Level.FINE : Level.INFO;
+ Logger.root.onRecord.listen((record) {
+ dev.log(
+ record.message,
+ time: record.time,
+ level: record.level.value,
+ name: record.loggerName,
+ zone: record.zone,
+ error: record.error,
+ stackTrace: record.stackTrace,
+ );
+ });
+
+ runApp(
+ MaterialApp(
+ home: Scaffold(
+ appBar: AppBar(
+ title: Text('loopback and filter example'),
+ ),
+ body: Padding(
+ padding: const EdgeInsets.all(16.0),
+ child: LoopBack(),
+ ),
+ ),
+ ),
+ );
+}
+
+class LoopBack extends StatefulWidget {
+ const LoopBack({super.key});
+
+ @override
+ State createState() => _LoopBackState();
+}
+
+class _LoopBackState extends State {
+ final audioStreamChannels = Channels.mono;
+ final audioStreamFormat = BufferPcmType.f32le;
+
+ final recorderChannels = RecorderChannels.mono;
+ final recorderFormat = PCMFormat.f32le;
+
+ final sampleRate = 22050;
+
+ final soloud = SoLoud.instance;
+ final recorder = Recorder.instance;
+ AudioSource? audioSource;
+
+ bool autoGain = false;
+ // bool echoCancellation = false;
+
+ @override
+ void initState() {
+ super.initState();
+ if (defaultTargetPlatform == TargetPlatform.android ||
+ defaultTargetPlatform == TargetPlatform.iOS) {
+ Permission.microphone.request().isGranted.then((value) async {
+ if (!value) {
+ await [Permission.microphone].request();
+ }
+ });
+ }
+
+ /// Listen for microphne data.
+ recorder.uint8ListStream.listen((chunks) {
+ if (audioSource != null) {
+ soloud.addAudioDataStream(
+ audioSource!,
+ chunks.toF32List(from: PCMFormat.f32le).buffer.asUint8List(),
+ );
+ } else {
+ initAudioSource();
+ soloud
+ ..addAudioDataStream(
+ audioSource!,
+ chunks.toF32List(from: PCMFormat.f32le).buffer.asUint8List(),
+ )
+ ..play(audioSource!, volume: 4);
+ }
+ });
+ }
+
+ /// Initialize the audio source
+ void initAudioSource() {
+ if (audioSource != null) disposeAudioSource();
+
+ audioSource = soloud.setBufferStream(
+ channels: audioStreamChannels,
+ pcmFormat: audioStreamFormat,
+ sampleRate: sampleRate,
+ bufferingTimeNeeds: 0.2,
+ );
+
+ audioSource!.allInstancesFinished.listen((data) async {
+ await soloud.disposeSource(audioSource!);
+ audioSource = null;
+ });
+ }
+
+ /// Dispose the audio source if it exists
+ Future disposeAudioSource() async {
+ if (audioSource == null) return;
+
+ await soloud.disposeSource(audioSource!);
+ audioSource = null;
+ }
+
+ @override
+ void dispose() {
+ soloud.deinit();
+ recorder.deinit();
+ super.dispose();
+ }
+
+ Future init() async {
+ /// Initialize the player and the recorder.
+ await disposeAudioSource();
+ await soloud.init(channels: Channels.mono, sampleRate: sampleRate);
+ // soloud.filters.echoFilter.activate();
+ // soloud.filters.echoFilter.delay.value = 0.1;
+ // soloud.filters.echoFilter.decay.value = 0.2;
+
+ await recorder.init(
+ format: recorderFormat,
+ sampleRate: sampleRate,
+ channels: recorderChannels,
+ );
+
+ recorder
+ ..start()
+ ..startStreamingData();
+
+ if (context.mounted) {
+ setState(() {});
+ }
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Column(
+ mainAxisSize: MainAxisSize.min,
+ spacing: 10,
+ children: [
+ // Start / Stop
+ Row(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ OutlinedButton(
+ onPressed: () {
+ init();
+ },
+ child: const Text('Init loopback'),
+ ),
+ OutlinedButton(
+ onPressed: () {
+ soloud.deinit();
+ recorder
+ ..stopStreamingData()
+ ..deinit();
+ audioSource = null;
+ },
+ child: const Text('Stop'),
+ ),
+ ],
+ ),
+
+ Row(
+ mainAxisSize: MainAxisSize.min,
+ spacing: 10,
+ children: [
+ Text('Auto gain'),
+ Checkbox(
+ value: autoGain,
+ onChanged: (v) {
+ if (v!) {
+ recorder.filters.autoGainFilter.activate();
+ } else {
+ recorder.filters.autoGainFilter.deactivate();
+ }
+ setState(() {
+ autoGain = v;
+ });
+ },
+ ),
+ // Text('Echo Cancellation'),
+ // Checkbox(
+ // value: echoCancellation,
+ // onChanged: (v) {
+ // if (v!) {
+ // recorder.filters.echoCancellationFilter.activate();
+ // } else {
+ // recorder.filters.echoCancellationFilter.deactivate();
+ // }
+ // setState(() {
+ // echoCancellation = v;
+ // });
+ // },
+ // ),
+ ],
+ ),
+
+ if (autoGain) AutoGainSliders(),
+
+ // if (echoCancellation) EchoCancellationSliders(),
+
+ const Bars(),
+ ],
+ );
+ }
+}
+
+// class EchoCancellationSliders extends StatefulWidget {
+// const EchoCancellationSliders({super.key});
+
+// @override
+// State createState() =>
+// _EchoCancellationSlidersState();
+// }
+
+// class _EchoCancellationSlidersState extends State {
+// late final Recorder recorder;
+// late final EchoCancellation echoCancellation;
+
+// @override
+// void initState() {
+// super.initState();
+// recorder = Recorder.instance;
+// echoCancellation = recorder.filters.echoCancellationFilter;
+// }
+
+// @override
+// Widget build(BuildContext context) {
+// return Column(
+// children: [
+// Row(
+// mainAxisSize: MainAxisSize.min,
+// children: [
+// Text(
+// '${echoCancellation.queryEchoDelayMs}: '
+// '${echoCancellation.echoDelayMs.value.toStringAsFixed(2)}',
+// ),
+// Expanded(
+// child: Slider(
+// value: echoCancellation.echoDelayMs.value,
+// min: echoCancellation.queryEchoDelayMs.min,
+// max: echoCancellation.queryEchoDelayMs.max,
+// onChanged: (v) {
+// setState(() {
+// echoCancellation.echoDelayMs.value = v;
+// });
+// },
+// ),
+// ),
+// ],
+// ),
+// Row(
+// mainAxisSize: MainAxisSize.min,
+// children: [
+// Text(
+// '${echoCancellation.queryEchoAttenuation}: '
+// '${echoCancellation.echoAttenuation.value.toStringAsFixed(2)}',
+// ),
+// Expanded(
+// child: Slider(
+// value: echoCancellation.echoAttenuation.value,
+// min: echoCancellation.queryEchoAttenuation.min,
+// max: echoCancellation.queryEchoAttenuation.max,
+// onChanged: (v) {
+// setState(() {
+// echoCancellation.echoAttenuation.value = v;
+// });
+// },
+// ),
+// ),
+// ],
+// ),
+// ],
+// );
+// }
+// }
+
+class AutoGainSliders extends StatefulWidget {
+ const AutoGainSliders({super.key});
+
+ @override
+ State createState() => _AutoGainSlidersState();
+}
+
+class _AutoGainSlidersState extends State {
+ late final Recorder recorder;
+ late final AutoGain autoGain;
+
+ @override
+ void initState() {
+ super.initState();
+ recorder = Recorder.instance;
+ autoGain = recorder.filters.autoGainFilter;
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Column(
+ children: [
+ Row(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Text(
+ '${autoGain.queryTargetRms}: '
+ '${autoGain.targetRms.value.toStringAsFixed(2)}',
+ ),
+ Expanded(
+ child: Slider(
+ value: autoGain.targetRms.value,
+ min: autoGain.queryTargetRms.min,
+ max: autoGain.queryTargetRms.max,
+ onChanged: (v) {
+ setState(() {
+ autoGain.targetRms.value = v;
+ });
+ },
+ ),
+ ),
+ ],
+ ),
+ Row(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Text(
+ '${autoGain.queryAttackTime}: '
+ '${autoGain.attackTime.value.toStringAsFixed(2)}',
+ ),
+ Expanded(
+ child: Slider(
+ value: autoGain.attackTime.value,
+ min: autoGain.queryAttackTime.min,
+ max: autoGain.queryAttackTime.max,
+ onChanged: (v) {
+ setState(() {
+ autoGain.attackTime.value = v;
+ });
+ },
+ ),
+ ),
+ ],
+ ),
+ Row(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Text(
+ '${autoGain.queryReleaseTime}: '
+ '${autoGain.releaseTime.value.toStringAsFixed(2)}',
+ ),
+ Expanded(
+ child: Slider(
+ value: autoGain.releaseTime.value,
+ min: autoGain.queryReleaseTime.min,
+ max: autoGain.queryReleaseTime.max,
+ onChanged: (v) {
+ setState(() {
+ autoGain.releaseTime.value = v;
+ });
+ },
+ ),
+ ),
+ ],
+ ),
+ Row(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Text(
+ '${autoGain.queryGainSmoothing}: '
+ '${autoGain.gainSmoothing.value.toStringAsFixed(2)}',
+ ),
+ Expanded(
+ child: Slider(
+ value: autoGain.gainSmoothing.value,
+ min: autoGain.queryGainSmoothing.min,
+ max: autoGain.queryGainSmoothing.max,
+ onChanged: (v) {
+ setState(() {
+ autoGain.gainSmoothing.value = v;
+ });
+ },
+ ),
+ ),
+ ],
+ ),
+ Row(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Text(
+ '${autoGain.queryMaxGain}: '
+ '${autoGain.maxGain.value.toStringAsFixed(2)}',
+ ),
+ Expanded(
+ child: Slider(
+ value: autoGain.maxGain.value,
+ min: autoGain.queryMaxGain.min,
+ max: autoGain.queryMaxGain.max,
+ onChanged: (v) {
+ setState(() {
+ autoGain.maxGain.value = v;
+ });
+ },
+ ),
+ ),
+ ],
+ ),
+ Row(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Text(
+ '${autoGain.queryMinGain}: '
+ '${autoGain.minGain.value.toStringAsFixed(2)}',
+ ),
+ Expanded(
+ child: Slider(
+ value: autoGain.minGain.value,
+ min: autoGain.queryMinGain.min,
+ max: autoGain.queryMinGain.max,
+ onChanged: (v) {
+ setState(() {
+ autoGain.minGain.value = v;
+ });
+ },
+ ),
+ ),
+ ],
+ ),
+ ],
+ );
+ }
+}
diff --git a/example/lib/main.dart b/example/lib/main.dart
index a4669e0..ecd66a8 100644
--- a/example/lib/main.dart
+++ b/example/lib/main.dart
@@ -1,10 +1,11 @@
import 'dart:io';
+import 'dart:developer' as dev;
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
-
import 'package:flutter_recorder/flutter_recorder.dart';
import 'package:flutter_recorder_example/ui/bars.dart';
+import 'package:logging/logging.dart';
import 'package:open_filex/open_filex.dart';
import 'package:path_provider/path_provider.dart';
import 'package:permission_handler/permission_handler.dart';
@@ -14,6 +15,23 @@ import 'package:permission_handler/permission_handler.dart';
/// The silence detection and the visualizer works when using [PCMFormat.f32].
/// Writing audio stream to file is not implemented on Web.
void main() async {
+ // The `flutter_recorder` package logs everything
+ // (from severe warnings to fine debug messages)
+ // using the standard `package:logging`.
+ // You can listen to the logs as shown below.
+ Logger.root.level = kDebugMode ? Level.FINE : Level.INFO;
+ Logger.root.onRecord.listen((record) {
+ dev.log(
+ record.message,
+ time: record.time,
+ level: record.level.value,
+ name: record.loggerName,
+ zone: record.zone,
+ error: record.error,
+ stackTrace: record.stackTrace,
+ );
+ });
+
runApp(
MaterialApp(
home: Scaffold(
@@ -38,7 +56,7 @@ class _MyAppState extends State {
final format = PCMFormat.f32le;
final sampleRate = 22050;
final channels = RecorderChannels.mono;
- final _recorder = Recorder.instance;
+ final recorder = Recorder.instance;
String? filePath;
var thresholdDb = -20.0;
var silenceDuration = 2.0;
@@ -59,7 +77,7 @@ class _MyAppState extends State {
}
/// Listen to audio data stream. The data is received in Uint8List.
- _recorder.uint8ListStream.listen((data) {
+ recorder.uint8ListStream.listen((data) {
/// Write the PCM data to file. It can then be imported with the correct
/// parameters with for example Audacity.
/// Not testing on Web platform.
@@ -94,9 +112,9 @@ class _MyAppState extends State {
child: const Text('listCaptureDevices'),
),
OutlinedButton(
- onPressed: () {
+ onPressed: () async {
try {
- _recorder.init(
+ await recorder.init(
format: format,
sampleRate: sampleRate,
channels: channels,
@@ -110,7 +128,7 @@ class _MyAppState extends State {
OutlinedButton(
onPressed: () {
try {
- _recorder.start();
+ recorder.start();
} on Exception catch (e) {
debugPrint('-------------- start() error: $e\n');
}
@@ -119,7 +137,7 @@ class _MyAppState extends State {
),
OutlinedButton(
onPressed: () {
- _recorder.deinit();
+ recorder.deinit();
},
child: const Text('deinit'),
),
@@ -141,9 +159,9 @@ class _MyAppState extends State {
if (!kIsWeb) {
final downloadsDir = await getDownloadsDirectory();
filePath = '${downloadsDir!.path}/flutter_recorder.wav';
- _recorder.startRecording(completeFilePath: filePath!);
+ recorder.startRecording(completeFilePath: filePath!);
} else {
- _recorder.startRecording();
+ recorder.startRecording();
}
} on Exception catch (e) {
debugPrint('-------------- startRecording() $e\n');
@@ -153,19 +171,19 @@ class _MyAppState extends State {
),
ElevatedButton(
onPressed: () {
- _recorder.setPauseRecording(pause: true);
+ recorder.setPauseRecording(pause: true);
},
child: const Text('Pause recording'),
),
ElevatedButton(
onPressed: () {
- _recorder.setPauseRecording(pause: false);
+ recorder.setPauseRecording(pause: false);
},
child: const Text('UN-Pause recording'),
),
ElevatedButton(
onPressed: () {
- _recorder.stopRecording();
+ recorder.stopRecording();
if (!kIsWeb) {
debugPrint('Audio recorded to "$filePath"');
showFileRecordedDialog(filePath!);
@@ -185,7 +203,7 @@ class _MyAppState extends State {
CircularProgressIndicator(),
OutlinedButton(
onPressed: () async {
- _recorder.startStreamingData();
+ recorder.startStreamingData();
if (!kIsWeb) {
savingDir = await getDownloadsDirectory();
@@ -211,7 +229,7 @@ class _MyAppState extends State {
),
OutlinedButton(
onPressed: () {
- _recorder.stopStreamingData();
+ recorder.stopStreamingData();
},
child: const Text('stop stream'),
),
@@ -227,7 +245,7 @@ class _MyAppState extends State {
Column(
children: [
StreamBuilder(
- stream: _recorder.silenceChangedEvents,
+ stream: recorder.silenceChangedEvents,
builder: (context, snapshot) {
return ColoredBox(
color: snapshot.hasData && snapshot.data!.isSilent
@@ -238,7 +256,7 @@ class _MyAppState extends State {
height: 50,
child: Center(
child: Text(
- _recorder.getVolumeDb().toStringAsFixed(1)),
+ recorder.getVolumeDb().toStringAsFixed(1)),
),
),
);
@@ -251,7 +269,7 @@ class _MyAppState extends State {
children: [
OutlinedButton(
onPressed: () {
- _recorder.setSilenceDetection(
+ recorder.setSilenceDetection(
enable: true,
onSilenceChanged: (isSilent, decibel) {
/// Here you can check if silence is changed.
@@ -260,9 +278,9 @@ class _MyAppState extends State {
// debugPrint('SILENCE CHANGED: $isSilent, $decibel');
},
);
- _recorder.setSilenceThresholdDb(-27);
- _recorder.setSilenceDuration(0.5);
- _recorder.setSecondsOfAudioToWriteBefore(0.0);
+ recorder.setSilenceThresholdDb(-27);
+ recorder.setSilenceDuration(0.5);
+ recorder.setSecondsOfAudioToWriteBefore(0.0);
setState(() {
thresholdDb = -27;
silenceDuration = 0.5;
@@ -274,12 +292,13 @@ class _MyAppState extends State {
),
OutlinedButton(
onPressed: () {
- _recorder.setSilenceDetection(enable: false);
+ recorder.setSilenceDetection(enable: false);
},
child: const Text('setSilenceDetection OFF'),
),
],
),
+
// Threshold dB slider
Row(
mainAxisSize: MainAxisSize.max,
@@ -293,7 +312,7 @@ class _MyAppState extends State {
max: 0,
label: thresholdDb.toStringAsFixed(1),
onChanged: (value) {
- _recorder.setSilenceThresholdDb(value);
+ recorder.setSilenceThresholdDb(value);
setState(() {
thresholdDb = value;
});
@@ -316,7 +335,7 @@ class _MyAppState extends State {
max: 10,
label: silenceDuration.toStringAsFixed(1),
onChanged: (value) {
- _recorder.setSilenceDuration(value);
+ recorder.setSilenceDuration(value);
setState(() {
silenceDuration = value;
});
@@ -339,7 +358,7 @@ class _MyAppState extends State {
max: 5,
label: silenceDuration.toStringAsFixed(1),
onChanged: (value) {
- _recorder.setSecondsOfAudioToWriteBefore(value);
+ recorder.setSecondsOfAudioToWriteBefore(value);
setState(() {
secondsOfAudioToWriteBefore = value;
});
@@ -390,7 +409,7 @@ class _MyAppState extends State {
}
Future showDeviceListDialog() async {
- final devices = _recorder.listCaptureDevices();
+ final devices = recorder.listCaptureDevices();
String devicesString = devices.asMap().entries.map((entry) {
return '${entry.value.id} ${entry.value.isDefault ? 'DEFAULT' : ''} - '
' ${entry.value.name}';
diff --git a/example/linux/flutter/generated_plugins.cmake b/example/linux/flutter/generated_plugins.cmake
index ed75c38..c7af760 100644
--- a/example/linux/flutter/generated_plugins.cmake
+++ b/example/linux/flutter/generated_plugins.cmake
@@ -7,6 +7,7 @@ list(APPEND FLUTTER_PLUGIN_LIST
list(APPEND FLUTTER_FFI_PLUGIN_LIST
flutter_recorder
+ flutter_soloud
)
set(PLUGIN_BUNDLED_LIBRARIES)
diff --git a/example/macos/Podfile b/example/macos/Podfile
index c795730..b52666a 100644
--- a/example/macos/Podfile
+++ b/example/macos/Podfile
@@ -1,4 +1,4 @@
-platform :osx, '10.14'
+platform :osx, '10.15'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
diff --git a/example/macos/Podfile.lock b/example/macos/Podfile.lock
index 449033c..7ad0add 100644
--- a/example/macos/Podfile.lock
+++ b/example/macos/Podfile.lock
@@ -1,22 +1,35 @@
PODS:
- flutter_recorder (0.0.1):
- FlutterMacOS
+ - flutter_soloud (0.0.1):
+ - FlutterMacOS
- FlutterMacOS (1.0.0)
+ - path_provider_foundation (0.0.1):
+ - Flutter
+ - FlutterMacOS
DEPENDENCIES:
- flutter_recorder (from `Flutter/ephemeral/.symlinks/plugins/flutter_recorder/macos`)
+ - flutter_soloud (from `Flutter/ephemeral/.symlinks/plugins/flutter_soloud/macos`)
- FlutterMacOS (from `Flutter/ephemeral`)
+ - path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`)
EXTERNAL SOURCES:
flutter_recorder:
:path: Flutter/ephemeral/.symlinks/plugins/flutter_recorder/macos
+ flutter_soloud:
+ :path: Flutter/ephemeral/.symlinks/plugins/flutter_soloud/macos
FlutterMacOS:
:path: Flutter/ephemeral
+ path_provider_foundation:
+ :path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin
SPEC CHECKSUMS:
- flutter_recorder: 895009aae0b73e643ee1e9f0efa1ae2c69a9c111
+ flutter_recorder: 22eb5e16dae4d05a71c6d119be8d68128b78f3aa
+ flutter_soloud: 401bea07fc43636ab5c6777f7adf691403d0ea48
FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24
+ path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
-PODFILE CHECKSUM: 236401fc2c932af29a9fcf0e97baeeb2d750d367
+PODFILE CHECKSUM: 9ebaf0ce3d369aaa26a9ea0e159195ed94724cf3
COCOAPODS: 1.15.2
diff --git a/example/pubspec.lock b/example/pubspec.lock
index d86cb4c..8ff513b 100644
--- a/example/pubspec.lock
+++ b/example/pubspec.lock
@@ -37,10 +37,10 @@ packages:
dependency: transitive
description:
name: collection
- sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
+ sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf
url: "https://pub.dev"
source: hosted
- version: "1.18.0"
+ version: "1.19.0"
cupertino_icons:
dependency: "direct main"
description:
@@ -84,7 +84,16 @@ packages:
path: ".."
relative: true
source: path
- version: "0.9.1"
+ version: "0.9.3"
+ flutter_soloud:
+ dependency: "direct main"
+ description:
+ path: "."
+ ref: main
+ resolved-ref: "5303435ce7ce5a3fdba6b564e62a81c953bd9e49"
+ url: "https://github.com/alnitak/flutter_soloud.git"
+ source: git
+ version: "2.1.8"
flutter_test:
dependency: "direct dev"
description: flutter
@@ -95,22 +104,38 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
+ http:
+ dependency: transitive
+ description:
+ name: http
+ sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.2.2"
+ http_parser:
+ dependency: transitive
+ description:
+ name: http_parser
+ sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b"
+ url: "https://pub.dev"
+ source: hosted
+ version: "4.0.2"
leak_tracker:
dependency: transitive
description:
name: leak_tracker
- sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05"
+ sha256: "7bb2830ebd849694d1ec25bf1f44582d6ac531a57a365a803a6034ff751d2d06"
url: "https://pub.dev"
source: hosted
- version: "10.0.5"
+ version: "10.0.7"
leak_tracker_flutter_testing:
dependency: transitive
description:
name: leak_tracker_flutter_testing
- sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806"
+ sha256: "9491a714cca3667b60b5c420da8217e6de0d1ba7a5ec322fab01758f6998f379"
url: "https://pub.dev"
source: hosted
- version: "3.0.5"
+ version: "3.0.8"
leak_tracker_testing:
dependency: transitive
description:
@@ -127,6 +152,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "5.0.0"
+ logging:
+ dependency: "direct main"
+ description:
+ name: logging
+ sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61
+ url: "https://pub.dev"
+ source: hosted
+ version: "1.3.0"
matcher:
dependency: transitive
description:
@@ -283,7 +316,7 @@ packages:
dependency: transitive
description: flutter
source: sdk
- version: "0.0.99"
+ version: "0.0.0"
source_span:
dependency: transitive
description:
@@ -296,10 +329,10 @@ packages:
dependency: transitive
description:
name: stack_trace
- sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
+ sha256: "9f47fd3630d76be3ab26f0ee06d213679aa425996925ff3feffdec504931c377"
url: "https://pub.dev"
source: hosted
- version: "1.11.1"
+ version: "1.12.0"
stream_channel:
dependency: transitive
description:
@@ -312,10 +345,10 @@ packages:
dependency: transitive
description:
name: string_scanner
- sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
+ sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3"
url: "https://pub.dev"
source: hosted
- version: "1.2.0"
+ version: "1.3.0"
term_glyph:
dependency: transitive
description:
@@ -328,10 +361,18 @@ packages:
dependency: transitive
description:
name: test_api
- sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb"
+ sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c"
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.7.3"
+ typed_data:
+ dependency: transitive
+ description:
+ name: typed_data
+ sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006
url: "https://pub.dev"
source: hosted
- version: "0.7.2"
+ version: "1.4.0"
vector_math:
dependency: transitive
description:
@@ -352,10 +393,10 @@ packages:
dependency: transitive
description:
name: vm_service
- sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d"
+ sha256: f6be3ed8bd01289b34d679c2b62226f63c0e69f9fd2e50a6b3c1c729a961041b
url: "https://pub.dev"
source: hosted
- version: "14.2.5"
+ version: "14.3.0"
web:
dependency: transitive
description:
diff --git a/example/pubspec.yaml b/example/pubspec.yaml
index d8426b9..1224e5b 100644
--- a/example/pubspec.yaml
+++ b/example/pubspec.yaml
@@ -13,7 +13,14 @@ dependencies:
flutter_recorder:
path: ../
+ flutter_soloud:
+ # path: ../../flutter_soloud # for development
+ git:
+ url: https://github.com/alnitak/flutter_soloud.git
+ ref: main
+
cupertino_icons: ^1.0.8
+ logging: ^1.3.0
open_filex: ^4.5.0
path_provider: ^2.1.5
permission_handler: ^11.3.1
diff --git a/example/web/index.html b/example/web/index.html
index 1945db1..e348a65 100644
--- a/example/web/index.html
+++ b/example/web/index.html
@@ -34,6 +34,8 @@
+
+