Expo Audio error. Cant go to next track on playback finish

Please provide the following:

  1. SDK Version: ^36.0.0
  2. 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>
        );
    }
}

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.