I have an application that uses Tone.js, and I use the GrainPlayer object specifically. It works perfectly fine on different browsers across different OS and devices... except for iOS. I personally don't have an iOS device, but clients are showing me that iOS isn't playing the audio. It's also not restricted to safari; other browsers on their device also won't play the audio.
I know it's a Tone.js-specific issue here, because I also use Howler.js for a few of the sounds that don't require the Tone GrainPlayer class, and those work. It's also not an AudioContext issue in general, because I have the following code:
Tone.setContext(Howler.ctx);
Which ensures the AudioContext for Tone is routed through the AudioContext for Howler.
Is there a way to get it to play? I need to keep using GrainPlayer because of its unique properties and functions, so switching out will not work for me as a solution unfortunately. I have no way of diagnosing it from a developer standpoint because again I don't have an iOS device, and even then they don't have a way to pull up a developer console... But it seems to not break code or anything, just seems like it 'ignores' the sound playing, and moves on.
The sounds in question are created as such:
standardChord[0] = new Tone.GrainPlayer('/A.flac').connect(Howler.masterGain);
And then when they need to be played:
standardChord[0].start();
Which like I said works fine on other devices.
Finally, not sure if this matters or not, but it's a Meteor application I'm running, bundled into a Node.js for deployment.
In my project I have a simple line that does the job for me in my initAudio()
method:
// necessary for Safari
synth.context.resume();
synth
is just an polysynth oscillator.
But this solution doesn't work if the iPhone or iOS device is muted.
ps. tested on iOS 16.2
I had the exact same problem, Tone.js doesn't play any sound on the newer iPhones and iPads when the device is muted. My solution was to play a silent mp3 on user interaction, using a native HTML audio element to activate the sound. I do this before playing the sound that I actually want to hear.
<audio>
<source src="/silent.mp3" type="audio/mp3"></source>
</audio>
You can get the audio element to start playing on user interaction. So select the audio element, and call it's play() method right before starting the audio you actually want to hear.
audioElement.play();
I tested on the following devices on LambdaTest (highly recommended if you don't own an iOS device):
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With