androidreactjsreact-nativeexpo-av

Sound plays only once using expo-audio in Expo Go / Android emulator (React Native)


I'm new to React Native and I'm using the expo-audio library (from Expo SDK 50+) to play sounds in my app. The sound playback works perfectly in the web preview, but when I run it on Expo Go or an Android emulator, the sound plays only once — subsequent button presses don't trigger the sound again.

Has anyone else experienced this issue or found a workaround to replay the sound reliably on mobile devices?

import { useAudioPlayer } from 'expo-audio';
import React, { useState } from 'react';
import { Alert, Button, Image, Modal, StyleSheet, Text, TextInput, TouchableOpacity, View } from 'react-native';
import { SafeAreaProvider, SafeAreaView } from 'react-native-safe-area-context';

const home = () => {
  const [userNameModalVisibility, setUserNameModalVisibility] = useState(false);
  const [settingModal, setSettingModal] = useState(false);
  const [music, setMusic] = useState(true);
  const [audio, setAudio] = useState(true); 
  const [userName, setUserName] = useState('NONE');

  const musicSource = require('../assets/sounds/homebackground.wav');
  const musicPlayer = useAudioPlayer(musicSource);

  const settingAudio = require('../assets/sounds/settingbutton.wav');
  const settingAudioPlayer = useAudioPlayer(settingAudio); 

  const ouchAudio = require("../assets/sounds/ouch.wav");
  const ouchAudioPlayer = useAudioPlayer(ouchAudio);

  const dooropenAudio = require("../assets/sounds/dooropening.wav");
  const dooropenPlayer = useAudioPlayer(dooropenAudio);

  const musicSetting = () => {
    setMusic(!music);
    music ? musicPlayer.pause() : musicPlayer.play();
  }

  const audioPlayer = (currentAudio: string) => {
    if (currentAudio !== '' && audio) {
      switch(currentAudio) {
        case 'ouch':
          ouchAudioPlayer.play();
          break;
        case 'dooropen':
          dooropenPlayer.play();
          break;
        case 'settingButton':
          settingAudioPlayer.play();
          break;
      }
    }
  }

  return (
    <SafeAreaProvider>
      <SafeAreaView>
        {/* simplified view content */}
        <TouchableOpacity onPress={() => audioPlayer('ouch')}>
          <Text>Play Ouch Sound</Text>
        </TouchableOpacity>
      </SafeAreaView>
    </SafeAreaProvider>
  );
}

export default home;


Solution

  • You need to return to the beginning of your audio before you can play it again because "expo-audio does not reset the playback position when the audio finishes" like it is in expo-av. There's a note about it on the docs here (check note after Usage -> playing sounds).

    Try this (directly from your code)

    import { useAudioPlayer } from 'expo-audio';
    import React, { useState } from 'react';
    import { Alert, Button, Image, Modal, StyleSheet, Text, TextInput, TouchableOpacity, View } from 'react-native';
    import { SafeAreaProvider, SafeAreaView } from 'react-native-safe-area-context';
    
    const home = () => {
      const [userNameModalVisibility, setUserNameModalVisibility] = useState(false);
      const [settingModal, setSettingModal] = useState(false);
      const [music, setMusic] = useState(true);
      const [audio, setAudio] = useState(true); 
      const [userName, setUserName] = useState('NONE');
    
      const musicSource = require('../assets/sounds/homebackground.wav');
      const musicPlayer = useAudioPlayer(musicSource);
    
      const settingAudio = require('../assets/sounds/settingbutton.wav');
      const settingAudioPlayer = useAudioPlayer(settingAudio); 
    
      const ouchAudio = require("../assets/sounds/ouch.wav");
      const ouchAudioPlayer = useAudioPlayer(ouchAudio);
    
      const dooropenAudio = require("../assets/sounds/dooropening.wav");
      const dooropenPlayer = useAudioPlayer(dooropenAudio);
    
      const musicSetting = () => {
        setMusic(!music);
        music ? musicPlayer.pause() : musicPlayer.play();
      }
    
      const audioPlayer = (currentAudio: string) => {
        if (currentAudio !== '' && audio) {
          switch(currentAudio) {
            case 'ouch':
              ouchAudioPlayer.seekTo(0); // add this line
              ouchAudioPlayer.play();
              break;
            case 'dooropen':
              dooropenPlayer.seekTo(0); // and this line
              dooropenPlayer.play();
              break;
            case 'settingButton':
              settingAudioPlayer.seekTo(0);
              settingAudioPlayer.play();
              break;
          }
        }
      }
    
      return (
        <SafeAreaProvider>
          <SafeAreaView>
            {/* simplified view content */}
            <TouchableOpacity onPress={() => audioPlayer('ouch')}>
              <Text>Play Ouch Sound</Text>
            </TouchableOpacity>
          </SafeAreaView>
        </SafeAreaProvider>
      );
    }
    
    export default home;