HTML5 audio is not playing in my React app in localhost
Asked Answered
D

3

7

I'm making an mp3 player with React.js and the HTML5 web audio javascript API. I've just been learning React for two weeks so I'm just getting used to the structure and setup (with components etc) however have several years experience with JavaScript.

I had the mp3 player working when using React within the browser. I.e. I had an index.html file and I included the React scripts as follows:

<script src="js/react.min.js"></script>
<script src="js/react-dom.min.js"></script>
<script src="js/browser.min.js"></script>

Now I would like to get used to building a React app using the command line and localhost so I started to rewrite the code for use within this environment. I started off by creating the skeleton app as follows:

create-react-app my-app
cd my-app/
npm start

Then I added in my own components etc. The application is displaying properly on localhost:3000 however the audio files do not seem to be playing in this environment. I'm unsure if the problem is directly related to the HTML5 audio just not working in localhost or if it's something else. There are no errors being returned.

I've simplified my code and also hard-coded in the directory of the mp3 file to the audio tag (see AudioPlayer component) for the moment in order to see if I can get the audio element working.

Can you see anything I might be missing? Thanks

App Component

    import React, { Component } from 'react';
    import Header from './Header';

    import AudioPlayer from './AudioPlayer';

    import Controls from './Controls';

    import './music-player.css';
    import './css/font-awesome.css';


    class App extends Component {

         //This class is the main component of the application.
         //it contains the header, the audio player and the side panel components.
         constructor(props) {
                super(props);
                this.state = {
                sidePanelIsOpen: false,
                currentSoundIndex: 0,
                isPlaying: false,
                playerDuration: 0,
                currentTime: "0:00",
                currentWidthOfTimerBar: 0,
                backButtonIsDisabled: false,
                forwardButtonIsDisabled: false,
                playButtonIsDisabled: false


            };
            this.toggleSidePanel = this.toggleSidePanel.bind(this);

        }   
        componentDidMount() {
            this.player = document.getElementById('audio_player');
            this.player.load();
            this.player.play(); //this is not doing anything
        }   
        toggleSidePanel(){
            var sidePanelIsOpen = this.state.sidePanelIsOpen;
            this.setState({sidePanelIsOpen: !sidePanelIsOpen})
        }


        render() {


            return(<div>
                <div id="main-container" className={this.state.sidePanelIsOpen === true ? 'swipe-left' : ''}>
                <div className="overlay">

                <AudioPlayer sounds={this.props.sounds} currentSoundIndex={this.state.currentSoundIndex} />
                </div>  
                </div>


                <div id="side-panel-area" className="scrollable">       
                    <div className="side-panel-container">
                    <div className="side-panel-header"><p>Menu</p></div>

                    </div>
                </div>
                </div>
            );  
        }

    }

    export default App;

AudioPlayer Component

    import React, { Component } from 'react';
    import './music-player.css';

    const AudioPlayer = function(props) {
        var mp3Src = props.sounds[props.currentSoundIndex].mp3;
        console.log(mp3Src); //this is returning the correct mp3 value
            return (<audio id="audio_player">
            <source id="src_mp3" type="audio/mp3" src="sounds/0010_beat_egyptian.mp3" />
            <source id="src_ogg" type="audio/ogg" src=""/>
            <object id="audio_object" type="audio/x-mpeg" width="200px" height="45px" data={mp3Src}>
                <param id="param_src" name="src" value={mp3Src} />
                <param id="param_src" name="src" value={mp3Src} />
                <param name="autoplay" value="false" />
                <param name="autostart" value="false" />
            </object>
            </audio>    
            );

    }

    export default AudioPlayer;

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import registerServiceWorker from './registerServiceWorker';
import './music-player.css';

var sounds = [{"title" : "Egyptian Beat", "artist" : "Sarah Monks", "length": 16, "mp3" : "sounds/0010_beat_egyptian.mp3"}, 
        {"title" : "Euphoric Beat", "artist" : "Sarah Monks", "length": 31, "mp3" : "sounds/0011_beat_euphoric.mp3"},
        {"title" : "Latin Beat", "artist" : "Sarah Monks", "length": 59, "mp3" : "sounds/0014_beat_latin.mp3"}, 
        {"title" : "Pop Beat", "artist" : "Sarah Monks", "length": 24, "mp3" : "sounds/0015_beat_pop.mp3"},
        {"title" : "Falling Cute", "artist" : "Sarah Monks", "length": 3, "mp3" : "sounds/0027_falling_cute.mp3"}, 
        {"title" : "Feather", "artist" : "Sarah Monks", "length": 6, "mp3" : "sounds/0028_feather.mp3"},
        {"title" : "Lose Cute", "artist" : "Sarah Monks", "length": 3, "mp3" : "sounds/0036_lose_cute.mp3"}, 
        {"title" : "Pium", "artist" : "Sarah Monks", "length": 3, "mp3" : "sounds/0039_pium.mp3"}];

ReactDOM.render(<App sounds={sounds} />, document.getElementById('root'));

registerServiceWorker();
Devlen answered 22/5, 2017 at 20:18 Comment(8)
Can you attach an error event handler to your audio tag? In raw JavaScript this would be: document.getElementById("audio_player").addEventListener("error", function(e){ console.error(e); }); At the very least you could then debug that to see if any errors are being generated.Holmann
@Holmann Thanks I just tried adding that but it does not return an error. Another thing, when I visit localhost:3000/sounds/0010_beat_egyptian.mp3 I would have expected the mp3 to play on this url but it just displays the main app page. however when I build the app within my browser (i.e with an index.html file) I am able to play the sound files by visiting their url as follows: file:///C:/nodejs/sarah_music_app/sounds/0010_beat_egyptian.mp3 ..could that mean that maybe the files are just not playable on localhost?Devlen
@Holmann ok so I have found something out. I tried importing the mp3 file at the top of the AudioPlayer component e.g. import mp3_file from './sounds/0010_beat_egyptian.mp3'; and then inserted it as the source of the audio tag as follows src={mp3_file} and this is working now.. So I shall experiment with this idea and import the rest of the sounds. Maybe there's a more efficient way but this will do for the moment. Thanks for the help.Devlen
Regarding localhost:3000/sounds/0010_beat_egyptian.mp3, I would have expected the same as you. What kind of server are you using to host localhost:3000? If it's something native to React, then I guess it could make the decision to show the main app instead. That said, I'm glad you found a solution. Please consider adding it as an answer, and accepting it, so others can see your question was resolved.Holmann
@Holmann yes it must be something native to react. I will indeed upload the solution once I tidy it up :) thanks for the helpDevlen
Have you check this: npmjs.com/package/react-sound?Sn
I'm having this same problem (react-h5-audio-player works fine in production but doesn't load/play files on localhost). I am using firebase storage URLs for the MP3s and these links work fine outside the app. Still not sure how to solve this problem.Twannatwattle
@MarcMaxmeister Hello. Well I solved my problem (see the answer below). I store them in the public folder and then use the environment variable: "process.env.PUBLIC_URL" before the path... I'm not familiar with Firebase but are your MP3 URLs public? If so can you send me the link to one of them and i'll try playing it from my react app in localhost? (and experiment with a few things)Devlen
D
11

After some experimenting I discovered that the mp3 file needs to be imported (using import) in order to be able to play it within this environment.

So i've found a solution and edited my AudioPlayer component as follows (which works perfect):

import React, { Component } from 'react';
import './music-player.css';
//Now we import the mp3 file that this JavaScript file uses.
//This will ensure that when the project is built, 
//webpack will correctly move the mp3 file into the build folder, 
//and provide us with the right paths.  
//See docs: https://create-react-app.dev/docs/adding-images-fonts-and-files/
import mp3_file from './sounds/0010_beat_egyptian.mp3'; 

const AudioPlayer = function(props) {
    
        return (<audio id="audio_player">
        <source id="src_mp3" type="audio/mp3" src={mp3_file}/>
        <source id="src_ogg" type="audio/ogg" src=""/>
        <object id="audio_object" type="audio/x-mpeg" width="200px" height="45px" data={mp3_file}>
            <param id="param_src" name="src" value={mp3_file} />
            <param id="param_src" name="src" value={mp3_file} />
            <param name="autoplay" value="false" />
            <param name="autostart" value="false" />
        </object>
        </audio>    
        );
  
}
export default AudioPlayer;

Update 2022

In certain cases it is better to store your files (images, mp3 files etc) in the public folder. Such cases include if you need to load these files dynamically to your app. (see the docs https://create-react-app.dev/docs/using-the-public-folder/)

Due to the fact that (in my project) I have multiple mp3 files that I wanted to load dynamically I discovered that storing my mp3 files in the public folder was more suitable to my app.

Note: When storing your files in the public folder you don't need to "import" them but you must use the public environment variable (process.env.PUBLIC_URL) so that the correct path (to your public folder) will be referenced.

So here is my new solution:

  1. I created a folder in the public folder called sounds.
  2. I then changed my the Audio component (in the original post) to the following:

.

import React from 'react';
    const AudioPlayer = props => {
      
      let mp3_file = process.env.PUBLIC_URL + props.sounds[props.currentSoundIndex].mp3;
      return (<audio id="audio_player">
        <source id="src_mp3" type="audio/mp3" src={mp3_file} />
        <source id="src_ogg" type="audio/ogg" src={mp3_file} />
        Your browser does not support this audio player.
      </audio>  
      );
    }
    
    export default AudioPlayer;

Note: If you decide to store your files in the public folder then they won't be part of the webpack build and so therefore if a file is missing we won't get an error during compilation so we won't know it's missing. (The user will get a 404).

If you choose to store your files in the src folder then you need to use import so that webpack will know to include the files in the build. The upside to this is that you will get an error during compilation if any of the files don't exist.

Devlen answered 24/5, 2017 at 12:22 Comment(6)
What if I need dynamic, in that case, I cannot import and do it right?Hopper
@VivekS Funny I only learnt how to do that recently. If you have sounds that you want to load dynamically then you should store them in the public folder. That way you dont have to import them. Then use the public environment variable (which is process.env.PUBLIC_URL in javascript). So for example If I have a sounds folder in my public folder where I have a a sound called mysong.mp3 then I can reference it in javascript like this: let myMp3FIle = process.env.PUBLIC_URL + "sounds/mySong.mp3"; ...Devlen
@VivekS and in my project (in the original post) I have changed it to: let mp3_file = process.env.PUBLIC_URL + props.sounds[props.currentSoundIndex].mp3;Devlen
@VivekS You can read more about using the public folder here. Check out the bottom of the page where it says when you should use the public folder: create-react-app.dev/docs/using-the-public-folderDevlen
@VivekS I have updated my answer to include the new solution.Devlen
Thank you @Sarah! Definitely, it is helpful! :)Hopper
B
5

Try:

import React, { Component } from 'react';
import mp3_file from './sounds/0010_beat_egyptian.mp3';

const AudioPlayer = function(props) {
  return (
    <audio src={mp3_file} controls autoPlay/>
  );
}
export default AudioPlayer;
Batholith answered 24/5, 2017 at 13:34 Comment(8)
yes. this is what I did as you can hopefully see from the answer I posted today. thanks. any idea how you would import an array of mp3 files (rather than just one) into a variable?. i.e something like: import mp3_files from './sounds'; (where mp3_files is a zero indexed array..) .. I can't figure out the correct syntax thanks.Devlen
hi Sarah, one way is to add an 'index.js' inside the './sounds' folder. Let me update my answer with an example. cheersBatholith
oh great thank you. Maybe you could post it as an answer to this question instead as it is more specific to that?thanks... #44156378Devlen
hmmm... am afraid that would make it the wrong answer to the original question. Perhaps we could make a gist for that :)Batholith
actually could you tell me what exactly is happening in the code? are we storing the JSON data into a variable called mp3_files? As what I wanted to store in mp3_files was the mp3 files themselves and not the JSON data if you get me? thanksDevlen
yes, the json data is imported into 'mp3_files'. meaning the mp3 'cued_mp3.mp3' not 'cued_mp3' as i had updated. other properties like the artist can be accessed as 'cued_mp3.artist'Batholith
see the problem I had was that the audio file wasn't playing when only pointing to the URL (i.e 'cued_mp3.mp3' points to the url of the sound (e.g sounds/0010_beat_egyptian.mp3)). I needed to import the actual files themselves first for them to play at all. Hopefully im explaining properly.Devlen
Let us continue this discussion in chat.Devlen
P
1

Incase this helps anyone else, I had the set up pretty much same as the OP and was using the autoplay attribute, but I'd put autoplay instead of autoPlay.

Pyroelectricity answered 22/5, 2019 at 12:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.