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(UNT-T27088): external url support #56

Open
wants to merge 1 commit into
base: develop
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
49 changes: 45 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,13 @@ Here's how to get started with react-native-audio-waveform in your React Native
##### 1. Install the package

```sh
npm install @simform_solutions/react-native-audio-waveform react-native-gesture-handler
npm install @simform_solutions/react-native-audio-waveform react-native-blob-util react-native-gesture-handler
```

###### --- or ---

```sh
yarn add @simform_solutions/react-native-audio-waveform react-native-gesture-handler
yarn add @simform_solutions/react-native-audio-waveform react-native-blob-util react-native-gesture-handler
```

##### 2. Install CocoaPods in the iOS project
Expand All @@ -48,7 +48,7 @@ yarn add @simform_solutions/react-native-audio-waveform react-native-gesture-han
npx pod-install
```

##### Know more about [react-native-gesture-handler](https://www.npmjs.com/package/react-native-gesture-handler)
##### Know more about [react-native-blob-util](https://www.npmjs.com/package/react-native-blob-util) and [react-native-gesture-handler](https://www.npmjs.com/package/react-native-gesture-handler)

##### 3. Add audio recording permissions

Expand Down Expand Up @@ -90,7 +90,35 @@ const ref = useRef<IWaveformRef>(null);
<Waveform
mode="static"
ref={ref}
path={item}
path={path}
candleSpace={2}
candleWidth={4}
scrubColor="white"
onPlayerStateChange={playerState => console.log(playerState)}
onPanStateChange={isMoving => console.log(isMoving)}
/>;
```

When you want to show a waveform for a external audio URL, you need to use `static` mode for the waveform and set isExternalUrl to true.

Check the example below for more information.

```tsx
import {
Waveform,
type IWaveformRef,
} from '@simform_solutions/react-native-audio-waveform';

const url = 'https://www2.cs.uic.edu/~i101/SoundFiles/taunt.wav'; // URL to the audio file for which you want to show waveform
const ref = useRef<IWaveformRef>(null);
<Waveform
mode="static"
ref={ref}
path={url}
isExternalUrl={true}
autoDownloadExternalAudio={true}
onDownloadingStateChange={state => console.log(state)}
onDownloadProgressChange={progress => console.log(progress)}
candleSpace={2}
candleWidth={4}
scrubColor="white"
Expand Down Expand Up @@ -133,6 +161,9 @@ You can check out the full example at [Example](./example/src/App.tsx).
| 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 |
| volume | 3 | ✅ | ❌ | number | Used for `static` type. It is a volume level for the media player, ranging from 1 to 10. |
| isExternalUrl | false | ✅ | ❌ | boolean | Used for `static` type. If the resource path of an audio file is a URL, then pass true; otherwise, pass false. |
| autoDownloadExternalAudio | false | ✅ | ❌ | boolean | Used for `static` type. Indicates whether the external media should be auto downloaded or not. |
| 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 All @@ -145,6 +176,8 @@ You can check out the full example at [Example](./example/src/App.tsx).
| onRecorderStateChange | - | ❌ | ✅ | ( recorderState : RecorderState ) => void | callback function which returns the recorder state whenever the recorder state changes. Check RecorderState for more details |
| onCurrentProgressChange | - | ✅ | ❌ | ( currentProgress : number, songDuration: number ) => void | callback function, which returns current progress of audio and total song duration. |
| onChangeWaveformLoadState | - | ✅ | ❌ | ( state : boolean ) => void | callback function which returns the loading state of waveform candlestick. |
| onDownloadingStateChange | - | ✅ | ❌ | ( state : boolean ) => void | A callback function that returns the loading state of a file download from an external URL. |
| onDownloadProgressChange | - | ✅ | ❌ | ( currentProgress : number ) => void | Used when isExternalUrl is true; a callback function that returns the current progress of a file download from an external URL |
| onError | - | ✅ | ❌ | ( error : Error ) => void | callback function which returns the error for static audio waveform |

##### Know more about [ViewStyle](https://reactnative.dev/docs/view-style-props), [PlayerState](#playerstate), and [RecorderState](#recorderstate)
Expand Down Expand Up @@ -191,6 +224,14 @@ resumePlayer(): Promise<boolean>

It returns a boolean indicating whether playback is resumed again.

#### downloadExternalAudio()

```ts
downloadExternalAudio(): Promise<boolean>
```

It returns a boolean indicating whether download and cache operation was successful

#### For Live mode

#### startRecord()
Expand Down
24 changes: 12 additions & 12 deletions example/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -387,10 +387,12 @@ PODS:
- React-jsinspector (0.72.7)
- React-logger (0.72.7):
- glog
- react-native-audio-waveform (1.0.0):
- react-native-audio-waveform (2.1.2):
- RCT-Folly (= 2021.07.22.00)
- React-Core
- react-native-safe-area-context (4.11.0):
- react-native-blob-util (0.19.11):
- React-Core
- react-native-safe-area-context (4.14.0):
- React-Core
- React-NativeModulesApple (0.72.7):
- hermes-engine
Expand Down Expand Up @@ -502,15 +504,13 @@ PODS:
- React-jsi (= 0.72.7)
- React-logger (= 0.72.7)
- React-perflogger (= 0.72.7)
- rn-fetch-blob (0.12.0):
- React-Core
- RNFastImage (8.6.3):
- React-Core
- SDWebImage (~> 5.11.1)
- SDWebImageWebPCoder (~> 0.8.4)
- RNFS (2.20.0):
- React-Core
- RNGestureHandler (2.19.0):
- RNGestureHandler (2.21.2):
- RCT-Folly (= 2021.07.22.00)
- React-Core
- SDWebImage (5.11.1):
Expand Down Expand Up @@ -571,6 +571,7 @@ DEPENDENCIES:
- React-jsinspector (from `../node_modules/react-native/ReactCommon/jsinspector`)
- React-logger (from `../node_modules/react-native/ReactCommon/logger`)
- react-native-audio-waveform (from `../..`)
- react-native-blob-util (from `../node_modules/react-native-blob-util`)
- react-native-safe-area-context (from `../node_modules/react-native-safe-area-context`)
- React-NativeModulesApple (from `../node_modules/react-native/ReactCommon/react/nativemodule/core/platform/ios`)
- React-perflogger (from `../node_modules/react-native/ReactCommon/reactperflogger`)
Expand All @@ -589,7 +590,6 @@ DEPENDENCIES:
- React-runtimescheduler (from `../node_modules/react-native/ReactCommon/react/renderer/runtimescheduler`)
- React-utils (from `../node_modules/react-native/ReactCommon/react/utils`)
- ReactCommon/turbomodule/core (from `../node_modules/react-native/ReactCommon`)
- rn-fetch-blob (from `../node_modules/rn-fetch-blob`)
- RNFastImage (from `../node_modules/react-native-fast-image`)
- RNFS (from `../node_modules/react-native-fs`)
- RNGestureHandler (from `../node_modules/react-native-gesture-handler`)
Expand Down Expand Up @@ -661,6 +661,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native/ReactCommon/logger"
react-native-audio-waveform:
:path: "../.."
react-native-blob-util:
:path: "../node_modules/react-native-blob-util"
react-native-safe-area-context:
:path: "../node_modules/react-native-safe-area-context"
React-NativeModulesApple:
Expand Down Expand Up @@ -697,8 +699,6 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native/ReactCommon/react/utils"
ReactCommon:
:path: "../node_modules/react-native/ReactCommon"
rn-fetch-blob:
:path: "../node_modules/rn-fetch-blob"
RNFastImage:
:path: "../node_modules/react-native-fast-image"
RNFS:
Expand Down Expand Up @@ -743,8 +743,9 @@ SPEC CHECKSUMS:
React-jsiexecutor: c49502e5d02112247ee4526bc3ccfc891ae3eb9b
React-jsinspector: 8baadae51f01d867c3921213a25ab78ab4fbcd91
React-logger: 8edc785c47c8686c7962199a307015e2ce9a0e4f
react-native-audio-waveform: 7cdb6e4963eeae907240396975b9c79713591758
react-native-safe-area-context: 851c62c48dce80ccaa5637b6aa5991a1bc36eca9
react-native-audio-waveform: 99f401dee91ac357ce40cba147a31a18b539d312
react-native-blob-util: 39a20f2ef11556d958dc4beb0aa07d1ef2690745
react-native-safe-area-context: 4532f1a0c5d34a46b9324ccaaedcb5582a302b7d
React-NativeModulesApple: b6868ee904013a7923128892ee4a032498a1024a
React-perflogger: 31ea61077185eb1428baf60c0db6e2886f141a5a
React-RCTActionSheet: 392090a3abc8992eb269ef0eaa561750588fc39d
Expand All @@ -762,10 +763,9 @@ SPEC CHECKSUMS:
React-runtimescheduler: 7649c3b46c8dee1853691ecf60146a16ae59253c
React-utils: 56838edeaaf651220d1e53cd0b8934fb8ce68415
ReactCommon: 5f704096ccf7733b390f59043b6fa9cc180ee4f6
rn-fetch-blob: f065bb7ab7fb48dd002629f8bdcb0336602d3cba
RNFastImage: 5c9c9fed9c076e521b3f509fe79e790418a544e8
RNFS: 4ac0f0ea233904cb798630b3c077808c06931688
RNGestureHandler: 7ad14a6c7b491add489246611d324f10009083ac
RNGestureHandler: 0972b77a2cab0f1a61ca1a3ce348a424614f65c2
SDWebImage: a7f831e1a65eb5e285e3fb046a23fcfbf08e696d
SDWebImageWebPCoder: 908b83b6adda48effe7667cd2b7f78c897e5111d
SocketRocket: f32cd54efbe0f095c4d7594881e52619cfe80b17
Expand Down
4 changes: 2 additions & 2 deletions example/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@
"dependencies": {
"react": "18.2.0",
"react-native": "0.72.7",
"react-native-blob-util": "^0.19.11",
"react-native-fast-image": "^8.6.3",
"react-native-fs": "^2.20.0",
"react-native-gesture-handler": "^2.13.4",
"react-native-safe-area-context": "^4.9.0",
"rn-fetch-blob": "^0.12.0"
"react-native-safe-area-context": "^4.11.0"
},
"devDependencies": {
"@babel/core": "^7.20.0",
Expand Down
51 changes: 46 additions & 5 deletions example/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {
ScrollView,
StatusBar,
Text,
TouchableOpacity,
View,
} from 'react-native';
import { GestureHandlerRootView } from 'react-native-gesture-handler';
Expand All @@ -51,16 +52,19 @@ const RenderListItem = React.memo(
onPanStateChange,
currentPlaybackSpeed,
changeSpeed,
isExternalUrl = false,
}: {
item: ListItem;
onPanStateChange: (value: boolean) => void;
currentPlaybackSpeed: PlaybackSpeedType;
changeSpeed: () => void;
isExternalUrl?: boolean;
}) => {
const ref = useRef<IWaveformRef>(null);
const [playerState, setPlayerState] = useState(PlayerState.stopped);
const styles = stylesheet({ currentUser: item.fromCurrentUser });
const [isLoading, setIsLoading] = useState(true);
const [isLoading, setIsLoading] = useState(isExternalUrl ? false : true);
const [isAudioDownloaded, setIsAudioDownloaded] = useState(false);

const handlePlayPauseAction = async () => {
// If we are recording do nothing
Expand All @@ -75,9 +79,13 @@ const RenderListItem = React.memo(
if (ref.current?.currentState === PlayerState.paused) {
await ref.current?.resumePlayer();
} else {
await ref.current?.startPlayer({
finishMode: FinishMode.stop,
});
try {
await ref.current?.startPlayer({
finishMode: FinishMode.stop,
});
} catch (error) {
console.log('Error starting player', error);
}
}
};

Expand Down Expand Up @@ -105,9 +113,21 @@ const RenderListItem = React.memo(
const handleStopAction = async () => {
ref.current?.stopPlayer();
};
const handleDownloadPress = (): void => {
setIsLoading(true);
ref.current?.downloadExternalAudio();
};

return (
<View key={item.path} style={[styles.listItemContainer]}>
<View
key={item.path}
style={[
styles.listItemContainer,
item.fromCurrentUser &&
isExternalUrl &&
!isAudioDownloaded &&
styles.listItemReverseContainer,
]}>
<View style={styles.listItemWidth}>
<View style={[styles.buttonContainer]}>
<Pressable
Expand Down Expand Up @@ -160,10 +180,21 @@ const RenderListItem = React.memo(
waveColor={Colors.lightWhite}
candleHeightScale={4}
onPlayerStateChange={setPlayerState}
autoDownloadExternalAudio={false}
isExternalUrl={isExternalUrl}
onPanStateChange={onPanStateChange}
onError={error => {
console.log(error, 'we are in example');
}}
onDownloadingStateChange={state => {
console.log('Download State', state);
}}
onDownloadProgressChange={progress => {
console.log('Download Progress', `${progress}%`);
if (progress === 100) {
setIsAudioDownloaded(true);
}
}}
onCurrentProgressChange={(currentProgress, songDuration) => {
console.log(
`currentProgress ${currentProgress}, songDuration ${songDuration}`
Expand All @@ -184,6 +215,15 @@ const RenderListItem = React.memo(
)}
</View>
</View>
{isExternalUrl && !isAudioDownloaded && !isLoading ? (
<TouchableOpacity onPress={handleDownloadPress}>
<Image
source={Icons.download}
style={styles.downloadIcon}
resizeMode="contain"
/>
</TouchableOpacity>
) : null}
</View>
);
}
Expand Down Expand Up @@ -366,6 +406,7 @@ const AppContainer = () => {
<RenderListItem
key={item.path}
item={item}
isExternalUrl={item.isExternalUrl}
onPanStateChange={value => setShouldScroll(!value)}
{...{ currentPlaybackSpeed, changeSpeed }}
/>
Expand Down
Binary file added example/src/assets/icons/download.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions example/src/assets/icons/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ export const Icons = {
logo: require('./logo.png'),
delete: require('./delete.png'),
pause: require('./pause.png'),
download: require('./download.png'),
};
Loading