OiO.lk Community platform!

Oio.lk is an excellent forum for developers, providing a wide range of resources, discussions, and support for those in the developer community. Join oio.lk today to connect with like-minded professionals, share insights, and stay updated on the latest trends and technologies in the development field.
  You need to log in or register to access the solved answers to this problem.
  • You have reached the maximum number of guest views allowed
  • Please register below to remove this limitation

How to replay an audio track using Expo AV

  • Thread starter Thread starter George S Mulbah II
  • Start date Start date
G

George S Mulbah II

Guest
I am working on a musical app with React native, aws and Expo. I am using the Expo AV library to play audio files. I am trouble getting the song to automatically replay after it finishes.

Below are my attempts at this.

Failed approaches:


  1. I see a didjustFinish boolean variable. I try to reset it to true after the audio finishes playing, then I can await sound.playAsync(); but it appears that is not working


  2. I try to match the durationMillis with the playableDurationMillis - if they are equal then call await sound.playAsync();. This also doe not work.

Code:
    import React, { useContext, useEffect, useState } from 'react';
    import { Text, Image, View, TouchableOpacity } from 'react-native';
    import { AntDesign, FontAwesome } from "@expo/vector-icons";
    import { API, graphqlOperation } from 'aws-amplify';
    
    import styles from './styles';
    import { Song } from "../../types";
    import { Sound } from "expo-av/build/Audio/Sound";
    
    import { AppContext } from '../../AppContext';
    import { getSong } from "../../src/graphql/queries";
    
    const PlayerWidget = () => {
    
        const [song, setSong] = useState(null);
        const [sound, setSound] = useState<Sound | null>(null);
        const [isPlaying, setIsPlaying] = useState<boolean>(true);
        const [duration, setDuration] = useState<number | null>(null);
        const [position, setPosition] = useState<number | null>(null);
        const [finish, setFinish] = useState<boolean>(true);
    
        const { songId } = useContext(AppContext);
    
    
    
        useEffect(() => {
            const fetchSong = async () => {
                try {
                    const data = await API.graphql(graphqlOperation(getSong, { id: songId }))
                    setSong(data.data.getSong);
                } catch (e) {
                    console.log(e);
                }
            }
    
            fetchSong();
        }, [songId])
    
        const onPlaybackStatusUpdate = (status) => {
            setIsPlaying(status.isPlaying);
            setDuration(status.durationMillis);
            setPosition(status.positionMillis);
            setFinish(status.didJustFinish);
           // console.log(finish);
            console.log(status);
        }
    
        const playCurrentSong = async () => {
    
            if (song.artist.length > 10) {
                song.artist = song.artist.substring(0, 6) + "...";
            }
    
            if (song.title.length > 8) {
                song.title = song.title.substring(0, 5) + "...";
            }
            if (sound) {
                await sound.unloadAsync();
            }
    
            const { sound: newSound } = await Sound.createAsync(
                { uri: song.uri },
                { shouldPlay: isPlaying },
                onPlaybackStatusUpdate
            )
    
            setSound(newSound)
        }
    
        useEffect(() => {
            if (song) {
                playCurrentSong();
            }
        }, [song])
    
        const onPlayPausePress = async () => {
            if (!sound) {
                return;
            }
            if (isPlaying) {
                await sound.pauseAsync();
            }
    
            else {
                await sound.playAsync();
            }
    
            if (finish) {
                await sound.playAsync();
            }
    
    
        }
    
        const getProgress = () => {
            if (sound === null || duration === null || position === null) {
                return 0;
            }
    
            return (position / duration) * 100;
        }
    
        if (!song) {
            return null;
        }
     
    
        return (
            <View style={styles.container}>
                <View style={[styles.progress, { width: `${getProgress()}%` }]} />
                <View style={styles.row}>
                    <Image source={{ uri: song.imageUri }} style={styles.image} />
                    <View style={styles.rightContainer}>
                        <View style={styles.nameContainer}>
                            <Text style={styles.title}>{song.title}</Text>
                            <Text style={styles.artist}>{song.artist}</Text>
                        </View>
    
                        <View style={styles.iconsContainer}>
                            <AntDesign name="hearto" size={20} color={'white'} />
                            <TouchableOpacity onPress={onPlayPausePress}>
                                <AntDesign name={isPlaying ? 'pausecircleo' : 'playcircleo'} size={25} color={'white'} />
                            </TouchableOpacity>
    
                        </View>
    
                    </View>
    
                </View>
    
            </View>
        )
    }
    
    export default PlayerWidget;

<p>I am working on a musical app with React native, aws and Expo. I am using the Expo AV library to play audio
files. I am trouble getting the song to automatically replay after it finishes.</p>
<p>Below are my attempts at this.</p>
<p>Failed approaches:</p>
<ol>
<li><p>I see a didjustFinish boolean variable. I try to reset it to true after the audio finishes playing, then I can <code>await sound.playAsync();</code> but it appears that is not working</p>
</li>
<li><p>I try to match the durationMillis with the playableDurationMillis - if they are equal then call <code>await sound.playAsync();</code>. This also doe not work.</p>
</li>
</ol>
<pre><code> import React, { useContext, useEffect, useState } from 'react';
import { Text, Image, View, TouchableOpacity } from 'react-native';
import { AntDesign, FontAwesome } from "@expo/vector-icons";
import { API, graphqlOperation } from 'aws-amplify';

import styles from './styles';
import { Song } from "../../types";
import { Sound } from "expo-av/build/Audio/Sound";

import { AppContext } from '../../AppContext';
import { getSong } from "../../src/graphql/queries";

const PlayerWidget = () => {

const [song, setSong] = useState(null);
const [sound, setSound] = useState<Sound | null>(null);
const [isPlaying, setIsPlaying] = useState<boolean>(true);
const [duration, setDuration] = useState<number | null>(null);
const [position, setPosition] = useState<number | null>(null);
const [finish, setFinish] = useState<boolean>(true);

const { songId } = useContext(AppContext);



useEffect(() => {
const fetchSong = async () => {
try {
const data = await API.graphql(graphqlOperation(getSong, { id: songId }))
setSong(data.data.getSong);
} catch (e) {
console.log(e);
}
}

fetchSong();
}, [songId])

const onPlaybackStatusUpdate = (status) => {
setIsPlaying(status.isPlaying);
setDuration(status.durationMillis);
setPosition(status.positionMillis);
setFinish(status.didJustFinish);
// console.log(finish);
console.log(status);
}

const playCurrentSong = async () => {

if (song.artist.length > 10) {
song.artist = song.artist.substring(0, 6) + "...";
}

if (song.title.length > 8) {
song.title = song.title.substring(0, 5) + "...";
}
if (sound) {
await sound.unloadAsync();
}

const { sound: newSound } = await Sound.createAsync(
{ uri: song.uri },
{ shouldPlay: isPlaying },
onPlaybackStatusUpdate
)

setSound(newSound)
}

useEffect(() => {
if (song) {
playCurrentSong();
}
}, [song])

const onPlayPausePress = async () => {
if (!sound) {
return;
}
if (isPlaying) {
await sound.pauseAsync();
}

else {
await sound.playAsync();
}

if (finish) {
await sound.playAsync();
}


}

const getProgress = () => {
if (sound === null || duration === null || position === null) {
return 0;
}

return (position / duration) * 100;
}

if (!song) {
return null;
}


return (
<View style={styles.container}>
<View style={[styles.progress, { width: `${getProgress()}%` }]} />
<View style={styles.row}>
<Image source={{ uri: song.imageUri }} style={styles.image} />
<View style={styles.rightContainer}>
<View style={styles.nameContainer}>
<Text style={styles.title}>{song.title}</Text>
<Text style={styles.artist}>{song.artist}</Text>
</View>

<View style={styles.iconsContainer}>
<AntDesign name="hearto" size={20} color={'white'} />
<TouchableOpacity onPress={onPlayPausePress}>
<AntDesign name={isPlaying ? 'pausecircleo' : 'playcircleo'} size={25} color={'white'} />
</TouchableOpacity>

</View>

</View>

</View>

</View>
)
}

export default PlayerWidget;
</code></pre>
 

Latest posts

Top