Skip to content

Commit

Permalink
Merge pull request #72 from SimformSolutionsPvtLtd/feature/UNT-T28297…
Browse files Browse the repository at this point in the history
…_Implement_playback_speed

feat(UNT-T28297): Implement playback speed
  • Loading branch information
mukesh-simform authored Sep 11, 2024
2 parents 3f31e64 + 2cd5766 commit 162fe4e
Show file tree
Hide file tree
Showing 26 changed files with 216 additions and 32 deletions.
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ A React Native package featuring native modules for generating and rendering aud

## 🎬 Preview

| Audio Playback Waveform | Audio Record Waveform |
| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| <a href="https://github.com/SimformSolutionsPvtLtd/react-native-audio-waveform"><img width="352px;" height="640px;" alt="AudioPlaybackWaveform" src="./assets/audio_playback.gif"> </a> | <a href="https://github.com/SimformSolutionsPvtLtd/react-native-audio-waveform"><img width="352px;" height="640px;" alt="AudioRecordWaveform" src="./assets/audio_record.gif"> </a> |
| Audio Playback Waveform | Audio Record Waveform | Audio Waveform with Speed |
| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| <a href="https://github.com/SimformSolutionsPvtLtd/react-native-audio-waveform"><img width="400px;" height="500px;" alt="AudioPlaybackWaveform" src="./assets/audio_playback.gif"> </a> | <a href="https://github.com/SimformSolutionsPvtLtd/react-native-audio-waveform"><img width="400px;" height="500px;" alt="AudioRecordWaveform" src="./assets/audio_record.gif"> </a> | <a href="https://github.com/SimformSolutionsPvtLtd/react-native-audio-waveform"><img width="400px;" height="500px;" alt="AudioRecordWaveform" src="./assets/audio_playback_with_speed.gif"> </a> |

## Quick Access

Expand Down Expand Up @@ -132,6 +132,7 @@ You can check out the full example at [Example](./example/src/App.tsx).
| mode\* | - ||| 'live' or 'static' | Type of waveform. It can be either `static` for the resource file or `live` if you want to record audio |
| ref\* | - ||| IWaveformRef | Type of ref provided to waveform component. If waveform mode is `static`, some methods from ref will throw error and same for `live`.<br> Check [IWaveformRef](#iwaveformref-methods) for more details about which methods these refs provides. |
| path\* | - ||| string | Used for `static` type. It is the resource path of an audio source file. |
| playbackSpeed | 1.0 ||| 1.0 / 1.5 / 2.0 | The playback speed of the audio player. Note: Currently playback speed only supports, Normal (1x) Faster(1.5x) and Fastest(2.0x), any value passed to playback speed greater than 2.0 will be automatically adjusted to normal playback speed |
| candleSpace | 2 ||| number | Space between two candlesticks of waveform |
| candleWidth | 5 ||| number | Width of single candlestick of waveform |
| candleHeightScale | 3 ||| number | Scaling height of candlestick of waveform |
Expand Down
28 changes: 27 additions & 1 deletion android/src/main/java/com/audiowaveform/AudioPlayer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,18 @@ class AudioPlayer(
}
}

fun start(finishMode: Int?, promise: Promise) {
private fun validateAndSetPlaybackSpeed(player: Player, speed: Float?): Boolean {
// Validate the speed: if null or less than or equal to 0, set to 1f
val validSpeed = if (speed == null || speed <= 0f) 1f else speed

// Set the playback speed on the player
val playbackParameters = player.playbackParameters.withSpeed(validSpeed)
player.playbackParameters = playbackParameters

return true // Indicate success
}

fun start(finishMode: Int?, speed: Float?, promise: Promise) {
try {
if (finishMode != null && finishMode == 0) {
this.finishMode = FinishMode.Loop
Expand All @@ -114,6 +125,9 @@ class AudioPlayer(
} else {
this.finishMode = FinishMode.Stop
}

validateAndSetPlaybackSpeed(player, speed)

player.playWhenReady = true
player.play()
promise.resolve(true)
Expand Down Expand Up @@ -158,6 +172,18 @@ class AudioPlayer(
}
}

fun setPlaybackSpeed(speed: Float?, promise: Promise) {
try {
// Call the custom function to validate and set the playback speed
val success = validateAndSetPlaybackSpeed(player, speed)
promise.resolve(success) // Resolve the promise with success

} catch (e: Exception) {
// Handle any exceptions and reject the promise
promise.reject("setPlaybackSpeed Error", e.toString())
}
}

private fun startListening(promise: Promise) {
try {
audioPlaybackListener = object : CountDownTimer(player.duration, UpdateFrequency.Low.value) {
Expand Down
20 changes: 19 additions & 1 deletion android/src/main/java/com/audiowaveform/AudioWaveformModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -133,8 +133,9 @@ class AudioWaveformModule(context: ReactApplicationContext): ReactContextBaseJav
fun startPlayer(obj: ReadableMap, promise: Promise) {
val finishMode = obj.getInt(Constants.finishMode)
val key = obj.getString(Constants.playerKey)
val speed = obj.getDouble(Constants.speed)
if (key != null) {
audioPlayers[key]?.start(finishMode ?: 2, promise)
audioPlayers[key]?.start(finishMode ?: 2, speed.toFloat(),promise)
} else {
promise.reject("startPlayer Error", "Player key can't be null")
}
Expand Down Expand Up @@ -222,6 +223,23 @@ class AudioWaveformModule(context: ReactApplicationContext): ReactContextBaseJav
}
}

@ReactMethod
fun setPlaybackSpeed(obj: ReadableMap, promise: Promise) {
// If the key doesn't exist or if the value is null or undefined, set default speed to 1.0
val speed = if (!obj.hasKey(Constants.speed) || obj.isNull(Constants.speed)) {
1.0f // Set default speed to 1.0 if null, undefined, or missing
} else {
obj.getDouble(Constants.speed).toFloat()
}

val key = obj.getString(Constants.playerKey)
if (key != null) {
audioPlayers[key]?.setPlaybackSpeed(speed, promise)
} else {
promise.reject("setPlaybackSpeed Error", "Player key can't be null")
}
}

private fun initPlayer(playerKey: String) {
if (audioPlayers[playerKey] == null) {
val newPlayer = AudioPlayer(
Expand Down
1 change: 1 addition & 0 deletions android/src/main/java/com/audiowaveform/Utils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ object Constants {
const val currentDecibel = "currentDecibel"
const val bitRate = "bitRate"
const val sampleRate = "sampleRate"
const val speed = "speed"
}

enum class FinishMode(val value:Int) {
Expand Down
Binary file modified assets/audio_playback.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/audio_playback_with_speed.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified assets/audio_record.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 7 additions & 7 deletions example/ios/AudioWaveformExample.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@
13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
4A3054DD28F34283AA8FEE0D /* file_example_mp3_15s.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = C2A26BD00D7D401B9804E1AA /* file_example_mp3_15s.mp3 */; };
578F19E664D14A79A203A29B /* file_example_mp3_12s.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = D09FCEB6D8A04D349E9422A5 /* file_example_mp3_12s.mp3 */; };
6393E563479648F7B8E27E90 /* file_example_mp3_700kb.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = 2026064602944A9C9A1F84D3 /* file_example_mp3_700kb.mp3 */; };
7699B88040F8A987B510C191 /* libPods-AudioWaveformExample-AudioWaveformExampleTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 19F6CBCC0A4E27FBF8BF4A61 /* libPods-AudioWaveformExample-AudioWaveformExampleTests.a */; };
81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */; };
75825DA638CD44CCB89B4B48 /* index.ts in Resources */ = {isa = PBXBuildFile; fileRef = 4879BE3405234CBFAFAD88DB /* index.ts */; };
DDA8C5D92054463296965254 /* index.ts in Resources */ = {isa = PBXBuildFile; fileRef = DEA7EA5ABBD543DFB81B93A1 /* index.ts */; };
F754817CD5E04214A63ED292 /* file_example_mp3_1mg.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = 3D92446673D84104B7DBB5E8 /* file_example_mp3_1mg.mp3 */; };
6393E563479648F7B8E27E90 /* file_example_mp3_700kb.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = 2026064602944A9C9A1F84D3 /* file_example_mp3_700kb.mp3 */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand All @@ -42,18 +42,18 @@
13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = AudioWaveformExample/Info.plist; sourceTree = "<group>"; };
13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = AudioWaveformExample/main.m; sourceTree = "<group>"; };
19F6CBCC0A4E27FBF8BF4A61 /* libPods-AudioWaveformExample-AudioWaveformExampleTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-AudioWaveformExample-AudioWaveformExampleTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
2026064602944A9C9A1F84D3 /* file_example_mp3_700kb.mp3 */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = undefined; includeInIndex = 0; lastKnownFileType = unknown; name = file_example_mp3_700kb.mp3; path = ../src/assets/audio/file_example_mp3_700kb.mp3; sourceTree = "<group>"; };
3B4392A12AC88292D35C810B /* Pods-AudioWaveformExample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AudioWaveformExample.debug.xcconfig"; path = "Target Support Files/Pods-AudioWaveformExample/Pods-AudioWaveformExample.debug.xcconfig"; sourceTree = "<group>"; };
3D92446673D84104B7DBB5E8 /* file_example_mp3_1mg.mp3 */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = undefined; includeInIndex = 0; lastKnownFileType = unknown; name = file_example_mp3_1mg.mp3; path = ../src/assets/audio/file_example_mp3_1mg.mp3; sourceTree = "<group>"; };
5709B34CF0A7D63546082F79 /* Pods-AudioWaveformExample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AudioWaveformExample.release.xcconfig"; path = "Target Support Files/Pods-AudioWaveformExample/Pods-AudioWaveformExample.release.xcconfig"; sourceTree = "<group>"; };
5B7EB9410499542E8C5724F5 /* Pods-AudioWaveformExample-AudioWaveformExampleTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AudioWaveformExample-AudioWaveformExampleTests.debug.xcconfig"; path = "Target Support Files/Pods-AudioWaveformExample-AudioWaveformExampleTests/Pods-AudioWaveformExample-AudioWaveformExampleTests.debug.xcconfig"; sourceTree = "<group>"; };
5DCACB8F33CDC322A6C60F78 /* libPods-AudioWaveformExample.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-AudioWaveformExample.a"; sourceTree = BUILT_PRODUCTS_DIR; };
81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = LaunchScreen.storyboard; path = AudioWaveformExample/LaunchScreen.storyboard; sourceTree = "<group>"; };
89C6BE57DB24E9ADA2F236DE /* Pods-AudioWaveformExample-AudioWaveformExampleTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AudioWaveformExample-AudioWaveformExampleTests.release.xcconfig"; path = "Target Support Files/Pods-AudioWaveformExample-AudioWaveformExampleTests/Pods-AudioWaveformExample-AudioWaveformExampleTests.release.xcconfig"; sourceTree = "<group>"; };
C2A26BD00D7D401B9804E1AA /* file_example_mp3_15s.mp3 */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = undefined; includeInIndex = 0; lastKnownFileType = unknown; name = file_example_mp3_15s.mp3; path = ../src/assets/audio/file_example_mp3_15s.mp3; sourceTree = "<group>"; };
D09FCEB6D8A04D349E9422A5 /* file_example_mp3_12s.mp3 */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = undefined; includeInIndex = 0; lastKnownFileType = unknown; name = file_example_mp3_12s.mp3; path = ../src/assets/audio/file_example_mp3_12s.mp3; sourceTree = "<group>"; };
DEA7EA5ABBD543DFB81B93A1 /* index.ts */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = undefined; includeInIndex = 0; lastKnownFileType = unknown; name = index.ts; path = ../src/assets/audio/index.ts; sourceTree = "<group>"; };
ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; };
4879BE3405234CBFAFAD88DB /* index.ts */ = {isa = PBXFileReference; name = "index.ts"; path = "../src/assets/audio/index.ts"; sourceTree = "<group>"; fileEncoding = undefined; lastKnownFileType = unknown; explicitFileType = undefined; includeInIndex = 0; };
3D92446673D84104B7DBB5E8 /* file_example_mp3_1mg.mp3 */ = {isa = PBXFileReference; name = "file_example_mp3_1mg.mp3"; path = "../src/assets/audio/file_example_mp3_1mg.mp3"; sourceTree = "<group>"; fileEncoding = undefined; lastKnownFileType = unknown; explicitFileType = undefined; includeInIndex = 0; };
2026064602944A9C9A1F84D3 /* file_example_mp3_700kb.mp3 */ = {isa = PBXFileReference; name = "file_example_mp3_700kb.mp3"; path = "../src/assets/audio/file_example_mp3_700kb.mp3"; sourceTree = "<group>"; fileEncoding = undefined; lastKnownFileType = unknown; explicitFileType = undefined; includeInIndex = 0; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -111,9 +111,9 @@
children = (
D09FCEB6D8A04D349E9422A5 /* file_example_mp3_12s.mp3 */,
C2A26BD00D7D401B9804E1AA /* file_example_mp3_15s.mp3 */,
4879BE3405234CBFAFAD88DB /* index.ts */,
3D92446673D84104B7DBB5E8 /* file_example_mp3_1mg.mp3 */,
2026064602944A9C9A1F84D3 /* file_example_mp3_700kb.mp3 */,
DEA7EA5ABBD543DFB81B93A1 /* index.ts */,
);
name = Resources;
path = "";
Expand Down Expand Up @@ -270,9 +270,9 @@
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */,
578F19E664D14A79A203A29B /* file_example_mp3_12s.mp3 in Resources */,
4A3054DD28F34283AA8FEE0D /* file_example_mp3_15s.mp3 in Resources */,
75825DA638CD44CCB89B4B48 /* index.ts in Resources */,
F754817CD5E04214A63ED292 /* file_example_mp3_1mg.mp3 in Resources */,
6393E563479648F7B8E27E90 /* file_example_mp3_700kb.mp3 in Resources */,
DDA8C5D92054463296965254 /* index.ts in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
Loading

0 comments on commit 162fe4e

Please sign in to comment.