skip to Main Content

I have a json that looks like this

{
    q: 'Sitting crossed legged',
    a: 'Anza',
    url: 'assets/audio/Anza.mp3'
},
{
    q: 'Attention!',
    a: 'Kiotsuke!',
    url: 'assets/audio/Kiotzuke.mp3'
},
{
    q: 'Bow!',
    a: 'Rei!',
    url: 'assets/audio/Rei.mp3'
},

And my component using expo av looks like this

import { StyleSheet, ScrollView, Text, View, TouchableOpacity } from 'react-native'
import React, {useState, useEffect} from 'react'
import ScreenTitle from '../../components/ScreenTitle';
import yellowbelt from '../../components/vocab/yellowbelt';
import {Audio} from 'expo-av';
import * as FileSystem from 'expo-file-system';
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';


const RokkyuRoute = () => {  
  const [sound, setSound] = useState();

  const playSound = async (audioPath) => {
    console.clear();
    console.log('Playing Sound: ', FileSystem.documentDirectory + audioPath);
    const { sound } = await Audio.Sound.createAsync(
      { uri: FileSystem.documentDirectory + audioPath },
      { shouldPlay: true }
    );
    setSound(sound);
  };

  console.log('Playing Sound: ', sound);

  useEffect(() => {
    return sound
      ? () => {
          sound.unloadAsync();
        }
      : undefined;
  }, [sound]);

  return(
    <View style={{flex:1, height:"100%"}}>
      <View style={styles.yellowscreentitle}>
        <ScreenTitle title="Yellow Belt - Rokkyu" style={styles.darkh1}/>
      </View>
      <View style={styles.routecontainer}>
        <ScrollView>
          <View>
            {yellowbelt.map((item, index) => {
              return (
                <View key={index} style={styles.item}>
                  <View style={styles.question}>
                    <Text style={styles.questiontext}>{index+1}. {item.q} </Text>
                  </View>
                  <View style={styles.answer}>
                    <Text style={styles.answertext}>{item.a}</Text>

                    {item.url && 
                      <TouchableOpacity 
                        style={styles.button} 
                        onPress={() => playSound(item.url)}>
                        <Icon name="play" size={25} color={theme.colors.primary}/>
                      </TouchableOpacity>
                    }                 
                  </View>
                </View>
              )
            })}
          </View>
        </ScrollView>
      </View>
    </View>
  )
};

export default RokkyuRoute

const styles = StyleSheet.create({
  yellowscreentitle:{
    backgroundColor: "#ffe100",
    paddingTop: 15,
    paddingHorizontal: 25,
  },
  darkh1:{
    fontSize: 20,
    fontWeight: 'bold',
    color: theme.colors.dark,
  },
  routecontainer:{
    padding:25,
    paddingBottom: 250,
  },
  item:{
    width: "100%",
    marginBottom: 20,
  },
  question:{
    width: "100%",
    marginBottom: 10,
  },
  answer:{
    width: "100%",
    marginBottom: 10,
  },
  questiontext:{
    fontSize: 16,
    fontWeight: 'bold',
    color: theme.colors.dark,
  },
  answertext:{
    fontSize: 16,
    color: theme.colors.dark,
  },
  button:{
    backgroundColor: theme.colors.secondary,
    borderRadius: 50,
    width: 40,
    height: 40,
    justifyContent: 'center',
    alignItems: 'center',
    position: 'absolute',
    right: 0,
    bottom: 0,
  }
})

I have tried everything I can think of including replicating this and with a single file rather than a mapped prop and I can’t get it to play. I also added require in front of every instance of the file uri and nothing

EDIT – Following Ben Smith suggestions in the comments I installed FileSystem from expo-file-system and recreated the playSound() function. Console logging the audioPath that get’s the path clicked on, and appending it to FileSystem I get this, But this is not the only sound. Each item has their own sound in the json so it must come from item.url

audioPath:  file:///Users/lotusms/Library/Developer/CoreSimulator/Devices/79B602DF-85B4-4ABE-8745-4A3276E07C58/data/Containers/Data/Application/D0605A63-2061-4064-9B10-5304381E715F/Documents/ExponentExperienceData/%2540anonymous%252Fjudopedia-app-d3ac072a-351a-46b3-b19f-00fec4e03363/assets/audio/Sensei.mp3

But still no sound

I’m out of ideas. Any helps is appreciated

2

Answers


  1. If you have the local audio file path, you can use it directly in the AudioPlayer component. Here’s how you can modify the code:

    Update the AudioPlayer component to accept a local file path:jsx

    import React, { useState, useEffect } from 'react';
    import { Text, TouchableOpacity } from 'react-native';
    import { Audio } from 'expo-av';
    
    const AudioPlayer = ({ audioPath }) => {
      const [sound, setSound] = useState();
    
      const playSound = async () => {
        const { sound } = await Audio.Sound.createAsync(
          { uri: audioPath },
          { shouldPlay: true }
        );
        setSound(sound);
      };
    
      useEffect(() => {
        return sound
          ? () => {
              sound.unloadAsync();
            }
          : undefined;
      }, [sound]);
    
      return (
        <TouchableOpacity onPress={playSound}>
          <Text>Play Audio</Text>
        </TouchableOpacity>
      );
    };
    
    export default AudioPlayer;
    

    Use the AudioPlayer component in your main component or screen with the provided local audio path:jsx

    import React from 'react';
    import { View } from 'react-native';
    import AudioPlayer from './AudioPlayer'; // Import the AudioPlayer 
    component
    
    const App = () => {
      const audioPath = "file:///Users/lotusms/Library/Developer/CoreSimulator/Devices/79B602DF-85B4-4ABE-8745-4A3276E07C58/data/Containers/Data/Application/D0605A63-2061-4064-9B10-5304381E715F/Documents/ExponentExperienceData/%2540anonymous%252Fjudopedia-app-d3ac072a-351a-46b3-b19f-00fec4e03363/assets/audio/Sensei.mp3";
    
      return (
        <View>
          <AudioPlayer audioPath={audioPath} />
        </View>
      );
    };
    

    export default App;
    Make sure that the provided path is correct and points to the actual audio file on your local device. This example assumes that the file path is correct, and the audio file is accessible at that location.

    Login or Signup to reply.
  2. This works for a single audio file if you specify the full file path.

    import { StyleSheet, ScrollView, Text, View, TouchableOpacity } from 'react-native'
    import React, { useState, useEffect } from 'react'
    import ScreenTitle from '../../components/ScreenTitle'
    import yellowbelt from '../../components/vocab/yellowbelt'
    import { Audio } from 'expo-av'
    import * as FileSystem from 'expo-file-system'
    import Icon from 'react-native-vector-icons/MaterialCommunityIcons'
    
    const RokkyuRoute = () => {
      return (
        <View style={{ flex: 1, height: '100%' }}>
          <View style={styles.yellowscreentitle}>
            <ScreenTitle title="Yellow Belt - Rokkyu" style={styles.darkh1} />
          </View>
          <View style={styles.routecontainer}>
            <ScrollView>
              <View>
                {yellowbelt.map((item, index) => {
                  return <Audio key={index} item={item} />
                })}
              </View>
            </ScrollView>
          </View>
        </View>
      )
    }
    export default RokkyuRoute
    

    Load each audio in its component. If you plan to store the files in the cloud you can try the commented code that should work.

    const Audio = ({ item, index }) => {
      const AudioPlayer = useRef(new Audio.Sound())
    
      useEffect(() => {
        const loadAudio = async () => {
          if (item.url) {
            //specify the full file path, dynamic file path not working
            await AudioPlayer.current.loadAsync(require('assets/audio/Anza.mp3'))
            //if you store the audio in the cloud try this
            //await AudioPlayer.current.loadAsync({uri: item.url})
          }
        }
    
        loadAudio()
    
        return () => {
          if (AudioPlayer.current) {
            // Stop and unload audio when the component is unmounted
            AudioPlayer?.current?.stopAsync()
            AudioPlayer?.current?.unloadAsync()
          }
        }
      }, [item])
    
      const playSound = async () => {
          const status = await AudioPlayer.current.getStatusAsync()
    
          if (status.isLoaded) {
            await AudioPlayer.current.playAsync()
          }
      }
      return (
        <View style={styles.item}>
          <View style={styles.question}>
            <Text style={styles.questiontext}>
              {index + 1}. {item.q}{' '}
            </Text>
          </View>
          <View style={styles.answer}>
            <Text style={styles.answertext}>{item.a}</Text>
    
            {item.url && (
              <TouchableOpacity style={styles.button} onPress={playSound}>
                <Icon name="play" size={25} color={theme.colors.primary} />
              </TouchableOpacity>
            )}
          </View>
        </View>
      )
    }
    
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search