AKMetronomeSampler delay - ios

I'm making a metronome app and use AKSamplerMetronome class. I did synchronization between devices with Ableton link so they could play together. I start playing and after a while sound on the device starts to delay and after couple of minutes I can clearly hear it.
The thing is beat count synchronized correctly but the sound that comes from the phone is not.
This bug is not on all devices, on some of them it's working great, no delay.
for synchronization I call setBeatTime once on start
Any suggestions what it might be?
If I create instance of AKSamplerMetronome, wait for couple minutes and then play, sound immediately would be out of sync.

Related

Periodically play short audio, in the background, on iOS

I need my iOS app to be able to play a very short sound at regular intervals while my app is in the background. I must support almost any duration/interval time. One example would be a one-second sound, played every 3 seconds for 45 minutes.
I've found an app in the App Store which can do exactly this. (On iOS15). Though from what I've read, this is not possible, outside of creating a 45 minute audio file on the fly, and using background audio to play the clip. (Though not sure Apple wouldn't reject even this.)
Any ideas how this app achieves this? Maybe they're creating an audio file?

Flutter Run code and play sound in the background IOS

I've been googling for a long time about how to run code in the background for IOS, and for what I have come up with the short answer is that you can't. And the long answer that you can but is limited. I've seen similar apps to the one I am creating so I feel like there should be a way to make it.
So on to the actual app I want to create. I want to create an application that will continuously play a random sound from a list in between a set interval, let's say for this example 30-60 seconds. So randomly every 30<t<60 seconds a sound should play. You can think of it as a positive affirmations app that should play positive affirmations throughout the day. I've seen such apps exist for IOS, I haven't tried them but I assume they should work like that? And when the app is firing the code to play the sound, Ideally I also want it to send information to a server.
I am using "Flutter Background Service" and "AudioPlayer" packages and have gotten a very very early demo version to work on android where it plays the sound after a random amount of time. And now I want it to work for Iphones also. Since it's not a playlist, I can't use the inbuilt functions for IOS that allows media players to run in the background. For what I can understand is that no code can run for longer then 30 seconds on IOS from when the app goes to the background, or the screen locks. And you can't run background tasks more often then every 15 minutes, or 3 minutes for small work. But that is way to long for the use case I want. I'd want to be able to run the function every 10 seconds to maybe 1 minute at the latest.
So I am wondering, is there a way to get such an application to work for IOS? It feels like it should be possible somehow. I don't really care if you have to "play dirty" to achieve it, and I don't know if it matters or not but I am not planning on publishing the app to the app store. It will only be a private app for me and a few friends.
One way I've been thinking about is maybe use push notifications from a server to trigger it. But I'd rather not have to resort to this if I can help it, if it even is possible to have a push notification to run code/trigger functions in the background?

IOS (Swift) Background speech

I'm writing an exercise app that runs a series of timers back to back that are determined by the users exercises and the times they have entered for them e.g. push UPS for 30 seconds, squats 20 seconds...
When the timer reaches zero, the app speaks the next exercise, and starts the next timer.
The app also allows the user to play music from playlists whilst they exercise, so I have set the Audio background mode in capabilities in swift.
When in the foreground, everything works as expected, and the times, and speech fire when they are meant to, however, when the app is backgrounded, only the music continues and everything else stops.
I understand that Apple have strict rules on background processes and multitasking, but I have downloaded a number of apps that seem to work fine in the background and continue to speak the intervals as they become due (Seconds Pro, Onyx Timer etc.)
I have researched this for days, but cannot come up with an answer, background fetching doesn't seem to be reliable enough for a time based app, as you can't guarantee when it will fire, I've also looked into local notifications, but they don't allow speech when they trigger, just a short sound, they also have a limit of 64 notifications, which limits the amount of intervals the user can set
I have set the app to keep the screen awake whilst the timer screen is running, but this means you have to keep the screen on whilst you train, which in turn will add an unnecessary drain on the battery, which seems to go against everything Apple is trying to accomplish with the limited background activity
Push notifications seemed like one solution, but this would mean I have to setup some sort of external server and surely this would be interrupted if the user didn't have an Internet connection.
I have read multiple threads about people running a silent audio stream in the background to keep their app alive in the background (not approved by Apple), but my app already plays audio in the background and has no effect on the rest of the app being suspended?
How would I go about achieving this?
I have thought of a workaround, but I don't know if it's good practice, or if it will get the app kicked if I try to upload it to the app store
My solution was to queue my speech based on the time set in each timer
for timer in 0...timersArray.count{
let sentence = timer.speech
let speechUtterance = AVSpeechUtterance(string: "\(sentence)")
speechUtterance.postUtteranceDelay = timer.time
synth.speakUtterance(speechUtterance)
}
Then the speech would just trigger at the appropriate times, even though the timer wasn't running in the background
When I ran this code, it worked as expected and the speech triggered when the timer would have finished (just as if it was running)
When running this code though, I noticed that not only did it trigger the speech at the correct time, it also kept my app running in the background, which is exactly what I wanted in the first place.
Is this allowed practice, or will it get booted from the store?
As my app plays music in the background and has the audio capability set, is there a way I can use a similar approach, but with the music in the background, rather than the queued utterance approach.
I tried with MPMediaPlayer, AVPlayer, and AVQueuePlayer, but nothing worked, the music played in the background, but the rest of the app stopped
If I set "Does not run in background" to "Yes" in the Plist.info, the app will now run when the screen is locked, it still won't run in the background though?
There are so many apps in the App Store that seem to run happily in the background, I can't believe it's this hard to get it to work?
A number of the ones I have tried, are not listed under notifications, so I know it's not a local notification, they also work in airplane mode, so it can't be remote push notifications

MPMusicPlayerController Does not prepare/preload correct

I am using MPMusicPlayerController so my app can play music that the user has bought through iTunes. When I select a song and start to play, there is a lag before the sound starts. I am assuming that the song is being buffered from the cloud.
The problem is that I have not found a way to know when the buffering is complete and the audio actually starts.
To play the song I use:
_mediaController = [MPMusicPlayerController applicationMusicPlayer];
[_mediaController setQueueWithItemCollection:collection];
[_mediaController beginGeneratingPlaybackNotifications];
[_mediaController play];
As soon as I call "play", the playback state change notification is called and the playback state is "MPMusicPlaybackStatePlaying" even though the user can't hear any music. I've noticed that even though the mediaController is in the "playing" playback state, the _mediaController.currentPlaybackTime always equals 0 until the music can be heard at which time the currentPlaybackTime properly tracks with the music.
I thought I could use the [_mediaController prepareToPlay] method to preload the audio file, but when I use that, the MPMediaPlaybackIsPreparedToPlayDidChangeNotification notification is never called. So the mediaController is never marked as "prepared".
With all this being said, I have not found a way to prebuffer songs using the MPMusicPlayerController. I know this issue has been around for a while because there is an old question from a few years ago with essentially the same issue, but no answer. Does anyone know how to make this work?
MPMediaPlaybackIsPreparedToPlayDidChangeNotification looks deprecated.
The MPMediaPlayerController getters and notifications are kind of garbage, and aren't "consistent" at all in the way where you set a value and expect the same value to come back when you grab it again.
I solved this by "buffering" the song first, as my app frequently will start in the middle of a song. So my buffering algo is - I'll play the song, then wait for the playback state changed notification, then pause it again and wait for another notifcation. This process will without a doubt trigger the MPMusicPlayerControllerNowPlayingItemDidChangeNotification, then finally the song is ready to play or be mutated (set currentTime or Rate). This seems to work very well.
The prepareToPlay completion handler is also garbage. It seems to fire before the song is actually ready to play, and the method actually seems to start playback :( , which is more than it leads on. This seems to be commonly reported as a "bug" in the apple dev forums.
In the prepareToPlay callback, setting currentPlaybackTime or Rate won't actually mutate the player - you need to wait for the additional MPMusicPlayerControllerNowPlayingItemDidChangeNotification sometime after playback starts for the first time on the song before you'll have any luck mutating any of the player properties.
currentPlaybackRate and Time also aren't very reliable, although they are more reliable once playback actually starts. I'll cache it to what the user sets it to until playback starts to solve the consistency problem. There is a lot more here to get the currentPlaybackRate or time consistently, let me know if you want a code sample, as grabbing those properties for reading will yield different results depending on the executing thread :(
Checking the playback state isn't reliable either unfortunately. Often I've found that the player reports MPMusicPlaybackStatePlaying when its fully paused and not playing - it stays like this indefinitely in certain situations. I recommend abstracting out any determinations if the MPMediaPlayerController is actually playing based on calls to play or pause and a subsequent follow-up of a MPMusicPlayerControllerPlaybackStateDidChangeNotification confirming the player has started that action.
I should mention I'm on iOS 12.1.3, as Apple seems to intermittently fix a small bug or add more API breakages as time goes on. Since its pretty broken now, any improvements may break any abstraction layer you build to fix it - so I'm testing each iOS release to make sure everything still "works".
Hope this helps a bit, its a real struggle.

How to schedule a task at accurate time on Jailbroken iPhone in deep sleep

I'm developing an background (daemon) application that will schedule a task on an exact time. For example, do something at 3 PM, or it can be do something after 3 hours. I've tried NSTimer and scheduling NSThread, but it does not do the task at the time I schedule because iPhone is in deep sleep.
Note that this is an application on a jail-broken device and run as a daemon, so it doesn't have UIApplication instance.
I had the same problem with my daemon. I couldn't find any working method for scheduling device wakes. Instead I prevent it from ever falling in a deep sleep by infinitely playing audio file with silence. That way you don't need IOKit to cancel sleep and your device will stay awake. I can't find the code now but it's very simple - a few calls to AVAudioPlayer. You also need to setup audio session for audio playing and mixing. It's all public and very well known APIs so there shouldn't be any problems implementing that.
There are problems with it. For example, playing audio file will reroute audio to the device receiver. By default audio is playing through the speaker so you need to take care of that. You also need to detect when the screen is turned on/off because device will not sleep when the screen is turned on. When the screen is turned off you start playing silence. When it's turned on you stop it. That will also solve mixing problems with other apps that are trying to play audio.
Unfortunately I don't have any code with me right now to show you some examples. I can add the code later if need it.

Resources