Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: ✨ Add a method to pause all players at once #372

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
- Fixed [#386](https://github.com/SimformSolutionsPvtLtd/audio_waveforms/pull/386) - On permission denied isRecording flag changed
- Fixed [#384](https://github.com/SimformSolutionsPvtLtd/audio_waveforms/issues/384) - Provide a callback of drag,tap,start and end details on user gesture
- Fixed [#309](https://github.com/SimformSolutionsPvtLtd/audio_waveforms/issues/309) - Added support for Liner PCM codec in iOS
- Fixes [#325](https://github.com/SimformSolutionsPvtLtd/audio_waveforms/issues/325) - Added feature to pause all player controller at once.
- Fixes [#379](https://github.com/SimformSolutionsPvtLtd/audio_waveforms/pull/379) - Getting error on dispose(Cannot add new events after calling close)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use issue link.


## 1.2.0

Expand Down
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,13 @@ playerController.release();
playerController.stopAllPlayer();
```
There could be any number of players but you can just call this function from any **one** player and it will stop all the players.

#### Pausing players all at once
```dart
playerController.pauseAllPlayers();
```
There could be any number of players but you can just call this function from any **one** player and it will pause all the players.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just write, this function works similar to stopAllPlayer.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jay-simformsolutions update to this this function works similar to stopAllPlayer but just pauses all players.


#### Disposing the controller
```dart
playerController.dispose();
Expand Down
15 changes: 4 additions & 11 deletions android/src/main/kotlin/com/simform/audio_waveforms/AudioPlayer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -129,26 +129,19 @@ class AudioPlayer(
}
}

fun stop(result: MethodChannel.Result) {
fun stop() {
stopListening()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add try catch

if (playerListener != null) {
player?.removeListener(playerListener!!)
}
isPlayerPrepared = false
player?.stop()
result.success(true)
}


fun pause(result: MethodChannel.Result) {
try {
stopListening()
player?.pause()
result.success(true)
} catch (e: Exception) {
result.error(Constants.LOG_TAG, "Failed to pause the player", e.toString())
}

fun pause() {
stopListening()
player?.pause()
Comment on lines +143 to +144
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add try catch

}

fun release(result: MethodChannel.Result) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import androidx.core.app.ActivityCompat
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.PluginRegistry
import java.io.IOException
import java.lang.IllegalStateException
import kotlin.math.log10

private const val LOG_TAG = "AudioWaveforms"
Expand All @@ -38,13 +37,13 @@ class AudioRecorder : PluginRegistry.RequestPermissionsResultListener {
}

fun initRecorder(
path: String,
result: MethodChannel.Result,
recorder: MediaRecorder?,
encoder: Int,
outputFormat: Int,
sampleRate: Int,
bitRate: Int?
path: String,
result: MethodChannel.Result,
recorder: MediaRecorder?,
encoder: Int,
outputFormat: Int,
sampleRate: Int,
bitRate: Int?
) {
recorder?.apply {
setAudioSource(MediaRecorder.AudioSource.MIC)
Expand All @@ -66,7 +65,7 @@ class AudioRecorder : PluginRegistry.RequestPermissionsResultListener {

fun stopRecording(result: MethodChannel.Result, recorder: MediaRecorder?, path: String) {
try {
val hashMap : HashMap<String,Any?> = HashMap()
val hashMap: HashMap<String, Any?> = HashMap()
try {
recorder?.stop()

Expand Down Expand Up @@ -136,9 +135,9 @@ class AudioRecorder : PluginRegistry.RequestPermissionsResultListener {
}

override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
): Boolean {
return if (requestCode == RECORD_AUDIO_REQUEST_CODE) {
successCallback?.onSuccess(grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED)
Expand All @@ -150,7 +149,7 @@ class AudioRecorder : PluginRegistry.RequestPermissionsResultListener {

private fun isPermissionGranted(activity: Activity?): Boolean {
val result =
ActivityCompat.checkSelfPermission(activity!!, permissions[0])
ActivityCompat.checkSelfPermission(activity!!, permissions[0])
return result == PackageManager.PERMISSION_GRANTED
}

Expand All @@ -159,8 +158,8 @@ class AudioRecorder : PluginRegistry.RequestPermissionsResultListener {
if (!isPermissionGranted(activity)) {
activity?.let {
ActivityCompat.requestPermissions(
it, permissions,
RECORD_AUDIO_REQUEST_CODE
it, permissions,
RECORD_AUDIO_REQUEST_CODE
)
}
} else {
Expand All @@ -183,6 +182,7 @@ class AudioRecorder : PluginRegistry.RequestPermissionsResultListener {
MediaRecorder.AudioEncoder.AAC
}
}

Constants.vorbis -> return MediaRecorder.AudioEncoder.VORBIS

else -> return MediaRecorder.AudioEncoder.AAC
Expand All @@ -206,6 +206,7 @@ class AudioRecorder : PluginRegistry.RequestPermissionsResultListener {
Constants.amr_nb -> return MediaRecorder.OutputFormat.AMR_NB
Constants.webm ->
return MediaRecorder.OutputFormat.WEBM

Constants.mpeg_2_ts -> {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
MediaRecorder.OutputFormat.MPEG_2_TS
Expand All @@ -214,6 +215,7 @@ class AudioRecorder : PluginRegistry.RequestPermissionsResultListener {
MediaRecorder.OutputFormat.MPEG_4
}
}

Constants.aac_adts -> return MediaRecorder.OutputFormat.AAC_ADTS
else -> return MediaRecorder.OutputFormat.MPEG_4
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import android.os.Build
import android.util.Log
import androidx.annotation.NonNull
import androidx.annotation.RequiresApi

import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.embedding.engine.plugins.activity.ActivityAware
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding
Expand All @@ -18,7 +17,8 @@ import io.flutter.plugin.common.MethodChannel.Result
import java.io.File
import java.io.IOException
import java.text.SimpleDateFormat
import java.util.*
import java.util.Date
import java.util.Locale


/** AudioWaveformsPlugin */
Expand Down Expand Up @@ -102,7 +102,8 @@ class AudioWaveformsPlugin : FlutterPlugin, MethodCallHandler, ActivityAware {
Constants.stopPlayer -> {
val key = call.argument(Constants.playerKey) as String?
if (key != null) {
audioPlayers[key]?.stop(result)
audioPlayers[key]?.stop()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add try catch

result.success(true)
} else {
result.error(Constants.LOG_TAG, "Player key can't be null", "")
}
Expand All @@ -111,7 +112,8 @@ class AudioWaveformsPlugin : FlutterPlugin, MethodCallHandler, ActivityAware {
Constants.pausePlayer -> {
val key = call.argument(Constants.playerKey) as String?
if (key != null) {
audioPlayers[key]?.pause(result)
audioPlayers[key]?.pause()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add try catch

result.success(true)
} else {
result.error(Constants.LOG_TAG, "Player key can't be null", "")
}
Expand Down Expand Up @@ -187,11 +189,7 @@ class AudioWaveformsPlugin : FlutterPlugin, MethodCallHandler, ActivityAware {
}

Constants.stopAllPlayers -> {
for ((key, _) in audioPlayers) {
audioPlayers[key]?.stop(result)
audioPlayers[key] = null
}
result.success(true)
stopAllPlayer(result)
}

Constants.finishMode -> {
Expand All @@ -202,6 +200,10 @@ class AudioWaveformsPlugin : FlutterPlugin, MethodCallHandler, ActivityAware {
}
}

Constants.pauseAllPlayers -> {
pauseAllPlayer(result)
}

else -> result.notImplemented()
}
}
Expand Down Expand Up @@ -322,4 +324,27 @@ class AudioWaveformsPlugin : FlutterPlugin, MethodCallHandler, ActivityAware {
pluginBinding!!.removeRequestPermissionsResultListener(this.audioRecorder)
}
}

private fun stopAllPlayer(result: MethodChannel.Result) {
try {
for ((key, _) in audioPlayers) {
audioPlayers[key]?.stop()
audioPlayers[key] = null
}
result.success(true)
} catch (e: Exception) {
result.error(Constants.LOG_TAG, "Failed to stop player", e.message)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
result.error(Constants.LOG_TAG, "Failed to stop player", e.message)
result.error(Constants.LOG_TAG, "Failed to stop players", e.message)

}
}

private fun pauseAllPlayer(result: MethodChannel.Result) {
try {
for ((key, _) in audioPlayers) {
audioPlayers[key]?.pause()
}
result.success(true)
} catch (e: Exception) {
result.error(Constants.LOG_TAG, "Failed to pause player", e.message)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
result.error(Constants.LOG_TAG, "Failed to pause player", e.message)
result.error(Constants.LOG_TAG, "Failed to pause players", e.message)

}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ object Constants {

const val resultFilePath = "resultFilePath"
const val resultDuration = "resultDuration"
const val pauseAllPlayers = "pauseAllPlayers"
}

enum class FinishMode(val value: Int) {
Expand Down
2 changes: 1 addition & 1 deletion example/lib/chat_bubble.dart
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ class _WaveBubbleState extends State<WaveBubble> {
IconButton(
onPressed: () async {
controller.playerState.isPlaying
? await controller.pausePlayer()
? await controller.stopAllPlayers()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove this change

: await controller.startPlayer();
controller.setFinishMode(finishMode: FinishMode.loop);
},
Expand Down
6 changes: 2 additions & 4 deletions ios/Classes/AudioPlayer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -91,17 +91,15 @@ class AudioPlayer: NSObject, AVAudioPlayerDelegate {
}


func pausePlayer(result: @escaping FlutterResult) {
func pausePlayer() {
stopListening()
player?.pause()
result(true)
}

func stopPlayer(result: @escaping FlutterResult) {
func stopPlayer() {
stopListening()
player?.stop()
timer = nil
result(true)
}

func release(result: @escaping FlutterResult) {
Expand Down
16 changes: 12 additions & 4 deletions ios/Classes/SwiftAudioWaveformsPlugin.swift
Original file line number Diff line number Diff line change
Expand Up @@ -79,15 +79,17 @@ public class SwiftAudioWaveformsPlugin: NSObject, FlutterPlugin {
case Constants.pausePlayer:
let key = args?[Constants.playerKey] as? String
if(key != nil){
audioPlayers[key!]?.pausePlayer(result: result)
audioPlayers[key!]?.pausePlayer()
result(true)
} else {
result(FlutterError(code: Constants.audioWaveforms, message: "Can not pause player", details: "Player key is null"))
}
break
case Constants.stopPlayer:
let key = args?[Constants.playerKey] as? String
if(key != nil){
audioPlayers[key!]?.stopPlayer(result: result)
audioPlayers[key!]?.stopPlayer()
result(true)
} else {
result(FlutterError(code: Constants.audioWaveforms, message: "Can not stop player", details: "Player key is null"))
}
Expand Down Expand Up @@ -136,8 +138,8 @@ public class SwiftAudioWaveformsPlugin: NSObject, FlutterPlugin {
result(FlutterError(code: Constants.audioWaveforms, message: "Can not get duration", details: "Player key is null"))
}
case Constants.stopAllPlayers:
for (playerKey,_) in audioPlayers{
audioPlayers[playerKey]?.stopPlayer(result: result)
for (playerKey,_) in audioPlayers {
audioPlayers[playerKey]?.stopPlayer()
audioPlayers[playerKey] = nil
}
result(true)
Expand All @@ -150,6 +152,12 @@ public class SwiftAudioWaveformsPlugin: NSObject, FlutterPlugin {
} else {
result(FlutterError(code: Constants.audioWaveforms, message: "Can not get waveform data", details: "Player key is null"))
}
case Constants.pauseAllPlayers:
for(playerKey,_) in audioPlayers {
audioPlayers[playerKey]?.pausePlayer()
}
result(true)
break
default:
result(FlutterMethodNotImplemented)
break
Expand Down
1 change: 1 addition & 0 deletions ios/Classes/Utils.swift
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ struct Constants {
static let linearPCMBitDepth = "linearPCMBitDepth";
static let linearPCMIsBigEndian = "linearPCMIsBigEndian";
static let linearPCMIsFloat = "linearPCMIsFloat";
static let pauseAllPlayers = "pauseAllPlayers"
}


Expand Down
5 changes: 5 additions & 0 deletions lib/src/base/audio_waveforms_interface.dart
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,11 @@ class AudioWaveformsInterface {
return result ?? false;
}

Future<bool> pauseAllPlayers() async {
var result = await _methodChannel.invokeMethod(Constants.pauseAllPlayers);
return result ?? false;
}

Future<void> setMethodCallHandler() async {
_methodChannel.setMethodCallHandler((call) async {
switch (call.method) {
Expand Down
1 change: 1 addition & 0 deletions lib/src/base/constants.dart
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ class Constants {
static const String current = "current";
static const String onCurrentDuration = "onCurrentDuration";
static const String stopAllPlayers = "stopAllPlayers";
static const String pauseAllPlayers = "pauseAllPlayers";
static const String onDidFinishPlayingAudio = "onDidFinishPlayingAudio";
static const String extractWaveformData = "extractWaveformData";
static const String noOfSamples = "noOfSamples";
Expand Down
28 changes: 25 additions & 3 deletions lib/src/controllers/player_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -318,10 +318,32 @@ class PlayerController extends ChangeNotifier {
///
/// This method will close the stream and free resources taken by all
/// players. This method will not dispose controller.
Future<void> stopAllPlayers() async {
///
/// Returns true if all player stopped otherwise return false.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check grammar

Future<bool> stopAllPlayers() async {
PlatformStreams.instance.dispose();
await AudioWaveformsInterface.instance.stopAllPlayers();
PlatformStreams.instance.playerControllerFactory.clear();
var isAllPlayersStopped =
await AudioWaveformsInterface.instance.stopAllPlayers();
if (isAllPlayersStopped) {
PlatformStreams.instance.playerControllerFactory
.forEach((playKey, controller) {
controller._setPlayerState(PlayerState.stopped);
});
}
return isAllPlayersStopped;
}

/// This function works similar to stopAllPlayer.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// This function works similar to stopAllPlayer.
/// Pauses all the players. Works similar to stopAllPlayer.

Future<bool> pauseAllPlayers() async {
var isAllPlayersPaused =
await AudioWaveformsInterface.instance.pauseAllPlayers();
if (isAllPlayersPaused) {
PlatformStreams.instance.playerControllerFactory
.forEach((playKey, controller) {
controller._setPlayerState(PlayerState.paused);
});
}
return isAllPlayersPaused;
}

/// Sets [_shouldRefresh] flag with provided boolean parameter.
Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: audio_waveforms
description: A Flutter package that allow you to generate waveform while recording audio or from audio file.
version: 1.2.0
version: 1.3.0
homepage: https://github.com/SimformSolutionsPvtLtd/audio_waveforms
issue_tracker: https://github.com/SimformSolutionsPvtLtd/audio_waveforms/issues

Expand Down