I am using the StageXL package for Sounds.
The problem that I have is that I am trying to mute the sounds that are currently playing. The only way that I could find to resolve this is to update all the Sounds currently playing SoundTransform volume to 0.
This is fine but this requires all SoundChannels to be stored somewhere. And without a completed event or something similar this collection will be ever increasing.
So is there a way to tell when a Sound finishes playing?
Use the SoundMixer.soundTransform property to change the global volume as simple as this:
SoundMixer.soundTransform = new SoundTransform(0.5);
This will change all sounds to half of the volume. Of course you can set it to 0.0 to mute all sounds.
Related
I am using AVAudioPlayer in my app. I have a use case where user specifies the time in future for the sound to play. I can play the sound in background using background modes but I want to control the volume level and set it to max when the sound plays (this is a requirement of the client). After calling [self.player prepareToPlay];, I am setting the volume to max by calling [self.player setVolume: 1.0]; but it seems to have no effect. The sound plays with the device sound level. Any way I can achieve this?
Thanks in advance.
As per my knowledge it's not possible to change the device volume directly.
Do check Apple's documentation to cater this scenario using MPVolumeView - https://developer.apple.com/documentation/mediaplayer/mpvolumeview
I found myself in a situation where I need to simulate audio playback to trick OS controls and MPNowPlayingInfoCenter into thinking that an audio is being played. This is because I am building a player that plays multiple audio tracks, with pauses in-between creating one, continuous "audio" track. I have already everything setup inside the app itself, and the lock screen controls are working correctly but the only problem I am facing is while the actual audio stops and a pause is being "played", the lock screen info center stops the timer, and it only continues with showing correct time and overall state once another audio track starts playing.
Here is the example of my audio track built from audio files and pause items:
let items: [AudioItem] = [
.audio("part-1.mp3"),
.pause(duration: 5), // value of type: TimeInterval
.audio("part-2.mp3"),
.pause(duration: 3),
... // the list goes on
]
then in my custom player, once AVAudioPlayer finishes its job with current item, I get the next one from the array and play either a .pause with a scheduled Timer or another .audio with AVAudioPlayer.
extension Player: AVAudioPlayerDelegate {
func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
playNextItem()
}
}
And here lies the problem, once the AVAudioPlayer stops, the Now Playing info center automatically stops too, even tho I keep feeding it fresh nowPlayingInfo. Then when it hits another .audio item, it resumes correctly and shows current time, etc.
And here lies the question
how do I trick the MPNowPlayingInfoCenter into thinking that audio is being played while I "play" my .pause item?
I realise that it may still not be clear, what I am trying to achieve but I am happy to share more insight if needed. Thanks!
Some solutions I am currently thinking about:
A. Keeping 1s long empty audio track that would play on loop for as long as the pause is needed to play.
B. Creating programatically empty audio track with appropriate lenght and playing it instead of using Timer for keeping track of pause duration/progress and relying completely on AVAudioPlayer for both .audio and .pause items. Not sure this is possible though.
C. Maybe there is a way to tell the MPNowPlayingInfoCenter that the audio keeps playing without the need of using AVAudioPlayer but some API I am not familiar with?
AVAudioPlayer is probably the wrong tool here. You want AVAudioPlayerNode, which is slightly lower-level. Create an AVAudioEngine, and attach an AVAudioPlayerNode. You can then call scheduleFile(_:at:completionHandler:) to play the audio at the times you want.
Much of the Apple documentation on AVAudioEngine appears broken right this moment, but the links hopefully will be available again shortly in the links for Audio Engine Building Blocks. (If it stays down and you have trouble finding docs, leave a comment and I'll hunt down the WWDC videos and other tutorials on using AVAudioEngine. It's not particularly difficult for simple problems.)
If you know in advance how you want to compose these items (and it looks like you may), see also AVMutableComposition, which lets you glue together assets very efficiently, including adding empty segments of silence. See Media Composition and Editing for the various tools in that space.
I have used AVPlayer to play videos in slow motion. I am using addPeriodicTimeObserverForInterval: message to get time at specific interval, and checking some condition according to current playback time. once condition is fulfilled, I am calculating rate and using setRate: message of AVPlayer. i.e I am setting rate frequently. but once I have done with this, video is not playing smoothly, it's glitchy.
Can anybody please let me know how can I set setRate: frequently.
Thanks
We were having kind of the same issue. We were using setRate:1 (or 1.5/2.0 depending on what the user chose) to play the video instead of calling play. We have changed to call play then setRate: and the video plays smoothly now.
I know that you can easily set the volume property of the music player, but I want to do it smoothly like Google Maps does when they use the voiceover for navigation instructions.
I was wondering what the best way to do this is.
Thanks!
I would try using a repeating NSTimer. Every time the timer fires you lower the volume a bit. When it reaches the target value you invalidate the timer.
Other ways of getting a repeated event (so that you can do something in stages gradually over time) are DISPATCH_SOURCE_TYPE_TIMER and CADisplayLink. But I think a timer is probably the simplest way to get started.
If you have a pre-existing sound that you're playing, a completely different solution is to apply a fadeout to it before you start playing it (and then just play it all at the same volume, because the sound itself fades out, do you see). AVFoundation gives you the tools to do that (e.g. setVolumeRampFromStartVolume:toEndVolume:timeRange:).
Within my application, I am playing downloaded audio using an AVAudioPlayer, while simultaneously playing audio from the user's iPod music library with an MPMusicPlayerController.
I need to be able to adjust the Volume of the AVAudioPlayer instance so that it's louder
than the audio coming from the MPMusicPlayerController.
The problem is, when I adjust the Volume property of the AVAudioPlayer, it also
adjusts the volume of the MPMusicPlayerController.
Is there any solution which would allow me to independently control the volume of
these two players?
If not, is there another technique I should use to do this? Any help is appreciated.
Take a look at the documentation for AVAudioSession. For example, in the AVAudioSession Programming Guide, says the following:
"Finally, you can enhance a category to automatically lower the volume of other audio when your audio is playing. This could be used, for example, in an exercise application. Say the user is exercising along to their iPod when your application wants to overlay a verbal message—for instance, “You’ve been rowing for 10 minutes.” To ensure that the message from your application is intelligible, apply the kAudioSessionProperty_OtherMixableAudioShouldDuck property to your audio session. When ducking takes place, all other audio on the device—apart from phone audio—lowers in volume."
I think it might solve your problem. The documentation on initializing an AVAudioSession and setting its categories and properties is pretty clear and easy to follow; you should have no trouble.