Please provide the following:
- SDK Version: ^36.0.0
- Platforms(Android/iOS/web/all): Android/iOS
I’m creating a audio player and it’s going pretty so far. I can play the audio on render, go to next track, go to previous track etc. The only thing I can’t manage to do is jump to the next track when the current track is finished.
Here is some code.
class PlayAudioScreen extends React.Component {
constructor(props) {
super(props);
this.state = {
playedMillis: 0,
totalDuration: 0,
activeIndex: 0,
isPlaying: false,
};
this.playbackInstance = null;
this.lastUpdate = new Date();
}
componentDidMount() {
Audio.setAudioModeAsync({
allowsRecordingIOS: false,
interruptionModeIOS: Audio.INTERRUPTION_MODE_IOS_DO_NOT_MIX,
playsInSilentModeIOS: true,
shouldDuckAndroid: true,
interruptionModeAndroid: Audio.INTERRUPTION_MODE_ANDROID_DO_NOT_MIX,
playThroughEarpieceAndroid: false,
});
// This function will be called
this._loadNewPlaybackInstance(true);
}
componentWillUnmount() {
this.playbackInstance.unloadAsync();
}
onPlaying = status => {
if (!status.isLoaded || status.isBuffering) {
if (status.error) {
console.log(status.error);
}
} else {
const { activeIndex } = this.state;
if (status.didJustFinish) {
if (
activeIndex + 1 ===
this.props.navigation.state.params.items.length
) {
console.log('THE END');
} else {
this.playbackInstance.stopAsync();
this._goForwardPlayback();
}
} else {
status.positionMillis
? this.setState({
playedMillis: status.positionMillis,
totalDuration: status.durationMillis,
isPlaying: status.isPlaying,
})
: null;
}
}
};
componentDidUpdate(prevProps, prevState, snapshot) {
if (prevState.activeIndex !== this.state.activeIndex) {
let now = new Date();
let seconds = (now.getTime() - this.lastUpdate.getTime()) / 1000;
if (seconds >= 0.4) {
this._loadNewPlaybackInstance(true);
this.lastUpdate = new Date();
}
}
}
async _loadNewPlaybackInstance(playing) {
const { items } = this.props.navigation.state.params;
const { activeIndex, isPlaying } = this.state;
if (this.playbackInstance !== null) {
await this.playbackInstance.unloadAsync();
this.playbackInstance.setOnPlaybackStatusUpdate(null);
this.playbackInstance = null;
}
try {
this.playbackInstance = new Audio.Sound();
const source = {
uri: items[activeIndex].media,
};
const status = {
shouldPlay: playing,
volume: 1,
};
this.playbackInstance.setOnPlaybackStatusUpdate(this.onPlaying);
await this.playbackInstance.loadAsync(source, status, false);
} catch (err) {
console.log('error loading audio:', err);
}
}
_pausePlayback() {
this.playbackInstance.pauseAsync();
}
_playPlayback() {
this.playbackInstance.playAsync();
}
_goForwardPlayback() {
const { items } = this.props.navigation.state.params;
const { activeIndex } = this.state;
if (activeIndex !== items.length - 1) {
const newIndex = activeIndex + 1;
this.setState({ activeIndex: newIndex });
}
}
_goBackPlayback() {
const { items } = this.props.navigation.state.params;
const { activeIndex } = this.state;
if (activeIndex !== 0) {
const newIndex = activeIndex - 1;
this.setState({ activeIndex: newIndex });
}
}
componentWillUnmount() {
this.playbackInstance.unloadAsync();
}
_renderSliderItem = ({ item, index }) => {
return (
<Container key={item.identifier}>
<SliderItemWrapper>
<ShadowImage
height={wp(74)}
width={wp(78)}
imageUrl={this.props.navigation.state.params.image}
/>
</SliderItemWrapper>
</Container>
);
};
render() {
const { activeIndex } = this.state;
const {
identifier,
title,
image,
items,
} = this.props.navigation.state.params;
return (
<ScreenWrapper style={{ flex: 1, paddingBottom: 0 }}>
<StatusBar
backgroundColor={colors.light}
barStyle="dark-content"
/>
<MyHeader
title={title}
showLeftContent
onLeftClick={() => this.props.navigation.goBack()}
backgroundColor={colors.light}
/>
<TopSection>
<Container style={{ width: '100%', flex: 1 }}>
<ContentWrapper>
<TopSectionContainer>
<Slider
renderItem={this._renderSliderItem}
data={items}
totalLength={items.length}
initialScrollIndex={0}
activeIndex={this.state.activeIndex}
keyExtractor={(item, index) =>
item.identifier
}
/>
</TopSectionContainer>
<BottomSection>
<PlayActiveHeadingContainer>
<Heading1>
{`${activeIndex + 1}. ${
this.props.navigation.state.params
.items[activeIndex].title
}`}
</Heading1>
<Paragraph>{`${this.props.navigation.state.params.items[activeIndex].subtitle}`}</Paragraph>
</PlayActiveHeadingContainer>
<PlayerTrack
playedMillis={this.state.playedMillis}
durationMillis={this.state.totalDuration}
/>
<PlayerControls
onBackFunc={() => this._goBackPlayback()}
onForwardFunc={() =>
this._goForwardPlayback()
}
isPlaying={this.state.isPlaying}
onPress={() =>
this.state.isPlaying
? this._pausePlayback()
: this._playPlayback()
}
/>
</BottomSection>
</ContentWrapper>
</Container>
</TopSection>
</ScreenWrapper>
);
}
}