Skip to content

Commit bc4e5bb

Browse files
committed
Implement initialize and release, fix volume
1 parent 46b34e2 commit bc4e5bb

File tree

8 files changed

+134
-41
lines changed

8 files changed

+134
-41
lines changed

CHANGELOG.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
## 0.0.1
22

3-
* TODO: Describe initial release.
3+
Initial release:
4+
- Added `load` function to load a sound file from a path
5+
- Added `play` function to play a sound

README.md

+38-8
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,45 @@
11
# sound_effect
22

3-
A new Flutter plugin project.
3+
A Flutter plugin for playing sound effects with a simple API and the lowest
4+
possible latency.
45

56
## Getting Started
67

7-
This project is a starting point for a Flutter
8-
[plug-in package](https://flutter.dev/developing-packages/),
9-
a specialized package that includes platform-specific implementation code for
10-
Android and/or iOS.
8+
Initialize the plugin, before using any of the other methods:
119

12-
For help getting started with Flutter development, view the
13-
[online documentation](https://flutter.dev/docs), which offers tutorials,
14-
samples, guidance on mobile development, and a full API reference.
10+
```dart
11+
import 'package:sound_effect/sound_effect.dart';
1512
13+
void main() async {
14+
final _soundEffect = SoundEffect();
15+
await _soundEffect.initialize();
16+
}
17+
```
18+
19+
Load a sound effect, using a unique identifier and the path to the sound file:
20+
21+
```dart
22+
Future<void> loadSound(String soundId) async {
23+
await _soundEffect.load(soundId, 'assets/sound_effect.mp3');
24+
}
25+
```
26+
27+
Play the sound effect:
28+
29+
```dart
30+
Future<void> playSound(String soundId) async {
31+
await _soundEffect.play(soundId);
32+
}
33+
```
34+
35+
You can also play the sound effect with a custom volume:
36+
37+
```dart
38+
_soundEffect.play('effect', volume: 0.5);
39+
```
40+
41+
Release the loaded sounds when they are no longer needed:
42+
43+
```dart
44+
_soundEffect.release();
45+
```

android/src/main/kotlin/org/lichess/sound_effect/SoundEffectPlugin.kt

+25-12
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,7 @@ class SoundEffectPlugin: FlutterPlugin, MethodCallHandler {
1717
private lateinit var channel : MethodChannel
1818
private lateinit var binding: FlutterPlugin.FlutterPluginBinding
1919

20-
private val soundPool: SoundPool = SoundPool.Builder()
21-
.setMaxStreams(1)
22-
.setAudioAttributes(
23-
AudioAttributes.Builder()
24-
.setUsage(AudioAttributes.USAGE_GAME)
25-
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
26-
.build()
27-
).build()
28-
20+
private var soundPool: SoundPool? = null
2921
private val audioMap = HashMap<String, Int>()
3022

3123
override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
@@ -36,6 +28,21 @@ class SoundEffectPlugin: FlutterPlugin, MethodCallHandler {
3628

3729
override fun onMethodCall(call: MethodCall, result: Result) {
3830
when (call.method) {
31+
"init" -> {
32+
if (soundPool !== null) {
33+
result.error("Already initialized", null, null)
34+
return
35+
}
36+
soundPool = SoundPool.Builder()
37+
.setMaxStreams(1)
38+
.setAudioAttributes(
39+
AudioAttributes.Builder()
40+
.setUsage(AudioAttributes.USAGE_GAME)
41+
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
42+
.build()
43+
).build()
44+
result.success(null)
45+
}
3946
"load" -> {
4047
val audioId = call.argument<String>("soundId")
4148
val path = call.argument<String>("path")
@@ -52,15 +59,15 @@ class SoundEffectPlugin: FlutterPlugin, MethodCallHandler {
5259
try {
5360
val assetPath = binding.flutterAssets.getAssetFilePathBySubpath(path)
5461
val afd = binding.applicationContext.assets.openFd(assetPath)
55-
audioMap[audioId] = soundPool.load(afd, 1)
62+
audioMap[audioId] = soundPool!!.load(afd, 1)
5663
result.success(null)
5764
} catch (e: Exception) {
5865
result.error("Failed to load sound", e.message, null)
5966
}
6067
}
6168
"play" -> {
6269
val audioId = call.argument<String>("soundId")
63-
val volume = call.argument<String>("volume")?.toFloat() ?: 1f
70+
val volume = call.argument<Double>("volume")?.toFloat() ?: 1f
6471

6572
if (audioId === null) {
6673
result.error("Must supply a soundId", null, null)
@@ -74,10 +81,16 @@ class SoundEffectPlugin: FlutterPlugin, MethodCallHandler {
7481
return
7582
}
7683

77-
soundPool.play(audio, volume, volume, 1, 0, 1f)
84+
soundPool?.play(audio, volume, volume, 1, 0, 1f)
7885

7986
result.success(null)
8087
}
88+
"release" -> {
89+
soundPool?.release()
90+
soundPool = null
91+
audioMap.clear()
92+
result.success(null)
93+
}
8194
else -> result.notImplemented()
8295
}
8396
}

example/lib/main.dart

+21-3
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ class _MyAppState extends State<MyApp> {
2828

2929
Future<void> loadSounds() async {
3030
try {
31+
await _soundEffectPlugin.initialize();
3132
await _soundEffectPlugin.load('demo', 'assets/sounds/demo.mp3');
3233
setState(() {
3334
_soundLoaded = true;
@@ -39,6 +40,16 @@ class _MyAppState extends State<MyApp> {
3940
}
4041
}
4142

43+
Future<void> releaseSounds() async {
44+
await _soundEffectPlugin.release();
45+
}
46+
47+
@override
48+
void dispose() {
49+
super.dispose();
50+
releaseSounds();
51+
}
52+
4253
@override
4354
Widget build(BuildContext context) {
4455
return MaterialApp(
@@ -54,14 +65,21 @@ class _MyAppState extends State<MyApp> {
5465
children: <Widget>[
5566
if (_loadError != null)
5667
Text(_loadError!)
57-
else if (_soundLoaded)
68+
else if (_soundLoaded) ...[
5869
ElevatedButton(
5970
onPressed: () {
6071
_soundEffectPlugin.play('demo');
6172
},
6273
child: const Text('Play sound'),
63-
)
64-
else
74+
),
75+
const SizedBox(height: 16),
76+
ElevatedButton(
77+
onPressed: () {
78+
_soundEffectPlugin.play('demo', volume: 0.3);
79+
},
80+
child: const Text('Play sound (30% volume)'),
81+
),
82+
] else
6583
const CircularProgressIndicator(),
6684
],
6785
),

ios/Classes/SoundEffectPlugin.swift

+15-11
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,6 @@ public class SoundEffectPlugin: NSObject, FlutterPlugin {
88
private var registrar: FlutterPluginRegistrar? = nil
99

1010
public static func register(with registrar: FlutterPluginRegistrar) {
11-
let session: AVAudioSession = AVAudioSession.sharedInstance()
12-
do {
13-
try session.setCategory(AVAudioSession.Category.ambient,
14-
mode: AVAudioSession.Mode.default,
15-
options: [])
16-
try session.setPreferredIOBufferDuration(0.005)
17-
try session.setActive(true)
18-
} catch let error as NSError {
19-
print("Failed to set the audio session: \(error.localizedDescription)")
20-
}
21-
2211
let channel = FlutterMethodChannel(name: "org.lichess/sound_effect", binaryMessenger: registrar.messenger())
2312
let instance = SoundEffectPlugin()
2413
registrar.addMethodCallDelegate(instance, channel: channel)
@@ -27,6 +16,18 @@ public class SoundEffectPlugin: NSObject, FlutterPlugin {
2716

2817
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
2918
switch call.method {
19+
case "init":
20+
let session: AVAudioSession = AVAudioSession.sharedInstance()
21+
do {
22+
try session.setCategory(AVAudioSession.Category.ambient,
23+
mode: AVAudioSession.Mode.default,
24+
options: [])
25+
try session.setPreferredIOBufferDuration(0.005)
26+
try session.setActive(true)
27+
} catch let error as NSError {
28+
print("Failed to set the audio session: \(error.localizedDescription)")
29+
}
30+
result(nil)
3031
case "load":
3132
let args = call.arguments as! [String: Any]
3233
guard let audioId = args["soundId"] as? String else {
@@ -81,6 +82,9 @@ public class SoundEffectPlugin: NSObject, FlutterPlugin {
8182

8283
player.play()
8384
result(nil)
85+
case "release":
86+
audioMap.removeAll()
87+
result(nil)
8488
default:
8589
result(FlutterMethodNotImplemented)
8690
}

lib/sound_effect.dart

+10-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,19 @@
11
import 'sound_effect_platform_interface.dart';
22

33
class SoundEffect {
4+
Future<void> initialize() {
5+
return SoundEffectPlatform.instance.initialize();
6+
}
7+
48
Future<void> load(String soundId, String path) {
59
return SoundEffectPlatform.instance.load(soundId, path);
610
}
711

8-
Future<void> play(String soundId, [double volume = 1.0]) {
9-
return SoundEffectPlatform.instance.play(soundId);
12+
Future<void> play(String soundId, {double volume = 1.0}) {
13+
return SoundEffectPlatform.instance.play(soundId, volume: volume);
14+
}
15+
16+
Future<void> release() {
17+
return SoundEffectPlatform.instance.release();
1018
}
1119
}

lib/sound_effect_method_channel.dart

+13-3
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,25 @@ class MethodChannelSoundEffect extends SoundEffectPlatform {
99
@visibleForTesting
1010
final methodChannel = const MethodChannel('org.lichess/sound_effect');
1111

12+
@override
13+
Future<void> initialize() async {
14+
await methodChannel.invokeMethod<String>('init');
15+
}
16+
1217
@override
1318
Future<void> load(String soundId, String path) async {
1419
await methodChannel.invokeMethod<String>(
1520
'load', <String, String>{'soundId': soundId, 'path': path});
1621
}
1722

1823
@override
19-
Future<void> play(String soundId, [double volume = 1.0]) async {
20-
await methodChannel.invokeMethod<String>('play',
21-
<String, String>{'soundId': soundId, 'volume': volume.toString()});
24+
Future<void> play(String soundId, {double volume = 1.0}) async {
25+
await methodChannel.invokeMethod<String>(
26+
'play', <String, Object>{'soundId': soundId, 'volume': volume});
27+
}
28+
29+
@override
30+
Future<void> release() async {
31+
await methodChannel.invokeMethod<String>('release');
2232
}
2333
}

lib/sound_effect_platform_interface.dart

+9-1
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,19 @@ abstract class SoundEffectPlatform extends PlatformInterface {
2323
_instance = instance;
2424
}
2525

26+
Future<void> initialize() {
27+
throw UnimplementedError('init() has not been implemented.');
28+
}
29+
2630
Future<void> load(String soundId, String path) {
2731
throw UnimplementedError('load() has not been implemented.');
2832
}
2933

30-
Future<void> play(String soundId, [double volume = 1.0]) {
34+
Future<void> play(String soundId, {double volume = 1.0}) {
3135
throw UnimplementedError('play() has not been implemented.');
3236
}
37+
38+
Future<void> release() {
39+
throw UnimplementedError('release() has not been implemented.');
40+
}
3341
}

0 commit comments

Comments
 (0)