I have an iPad application (a tuner) that uses Core Audio Audio Units. It reads the signal from the mic and processes it. It does NOT echo the sound to the speaker.
Unfortunately, at different times, the signal actually feedbacks and comes out of the speaker - loud and sort of phasey. I haven't made any connection from the mic to the speaker - but it creates the illusion that the mic is somehow "on". It isn't a direct signal - it is chopped up and requires you to make somewhat loud noises before it will happen.
I'm concerned this is related to overloading the cpu or something. I don't think the callback is getting behind. If I put debug statements into the callback, they seem to stop when I turn off the Audio Unit ... which brings up another oddity. At certain times, even when the Audio Unit has been stopped, the feedback continues to occur from the mic to the speaker so that the app has to be shutdown and removed from the background processing queue before the incessant noise stops.
Oddly, this doesn't happen every time and to every tester but it does occur often enough to create a stir.
If your RemoteIO callbacks are too slow and/or your app crashes and stops handling the audio callbacks, the RemoteIO audio buffers may get recycled, which may cause some of your old play buffers, or perhaps even record buffers, to end up repeated or repeating in the underflowed audio channel. One way to test this is to comment out all your processing code (and debug prints, which can also be too slow) inside your callbacks and see if this fixes your "feedback" problem.
Try to do only simple buffer copies and/or other low-overhead fast processing in both your RemoteIO record and play callbacks. Do not process data inside the Remote callback, instead handshake, schedule or queue the work to be done later outside the callback.
If your app can somehow detect that it can't keep up, it should stop the RemoteIO audio unit (AudioOutputUnitStop).
Also try zero-ing the data each record buffer after you are done with it before exiting each record callback. There have been reports that this may help fix a bug in some very old versions of iPhoneOS.
Related
I have a AVQueuePlayer based audio streaming player that needs to run in the background. The player needs to continue running until it finishes playing all the list. Of course it is going to have to pause if the network connection becomes bad, but it should automatically resume when the network connection comes back.
For this, I am monitoring
AVPlayerItem.status
AVPlayerItem.playbackLikelyToKeepUp
AVPlayer.currentItem
AVPlayer.status
AVPlayer.error
using KVO. For example, if the network connection recovers from temporary error, I expect currentAVPlayerItem.status becomes AVPlayerStatusItemReadyToPlay, which will be reported to my player and I can issue [AVQueuePlayer play] at that point.
This mechanism (logic) seems to work some cases, but quite frequently in offline environment, AVPlayerItem.status becomes AVPlayerItemStatusFailed, which item AVQueuePlayer seems to skip automatically. As a result, the queue will end up being empty and no callback can be received from AVPlayerItem.
I was hoping that some property in AVPlayer will change when network connection goes bad/recovers, but nothing seems to change (status, error etc).
Obviously I can monitor Reachability, but that doesn't work when the app is running in the background.
How can I know when the network comes back up and AVQueuePlayer is playable again in this situation?
I may be just being a novice around this area. If anybody can give me a general idea how he/she achieves continuous AVQueuePlayer playing experience without being completely stopped by temporary network connection issues, that would be an awesome help as well!
You can monitor AVPlayerItemPlaybackStalledNotification to know when the item finished playing its buffer but not the entire file:
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:#selector(AVPlayerItemPlaybackStalledNotification:)
name:AVPlayerItemPlaybackStalledNotification object:playerItem];
Once there's enough buffer to continue, you should get a notification sent to playbackLikelyToKeepUp which it sounds like you're already monitoring.
If I register an app for background app in did enter background and make a background handler with approximately 10 mins to finish the task, after the time is over the handler will call finishing block and in this block again create the background handler you will get again 10 mins and so on, in this way application will remain in background. I mean is it OK to do that....? or will apple object to this?
From the documentation:
Applications running background tasks have a finite amount of time in
which to run them. (You can find out how much time is available using
the backgroundTimeRemaining property.) If you do not call
endBackgroundTask: for each task before time expires, the system kills
the application.
So, no, you can't indefinitely run in the background.
Yeah thats correct, you cannot run infinitely in this way. But i have found one more trick, when applicatuon enters background, start playing an audio with 0 volume :-) Your app will never get killed.
There is a VoIP app, Media5, which can receive in background incoming calls using UDP sockets.
Developers said they used a "trick" to mantain the app active forever and I'd exclude the silent audio playing option. So the question is: what's that trick?
Also Bria can receive with UDP in background.
From Comment 20 at Issue 515: Background app support for iPhones with multitasking support:
I'm pretty sure that without playing continuously an audio file or
logging GPS position you cannot keep alive UDP listening sockets in
iOS 4.3+ (both in the main thread or in a secondary one). If you play
an audio play with AVAudioPlayer (after initializing an AudioSession
before) in a nsrunloop every 5 seconds, the main thread is kept active
and moreover it's NOT necessary to declare the audio background
support in info.plist.
I think this is the "trick" used by Media5 and Bria. I tried also
creating a infinite TCP stream to the loopback interface declaring it
as VoIP, just to see if also UDP socket is kept alive. The answer is
no, only TCP sockets works while in background (and with screen
locked), UDP is closed in the meanwhile and cannot listen for incoming
calls anymore.
So the key point is that the main thread must be kept active... using
a simple nstimer o infinite runloop alone is useless, since the
watchdog kills the process after few seconds in background (except if
you work in debug mode with GDB interface attached, it runs forever).
I'm looking for some way to let my app play a sound at a specific time while it's in the background (IOS4 multitasking). Currently, I use local notifications for that which works quite well, except for:
the sound will not be played if the phone is muted
the 30 second playback limit
I saw there's setKeepAliveTimeout:handler: but it's only available for voip-apps and since that's not the purpose of my app, I guess Apple would reject it because of this. I also saw a solution where an "empty" sound is being played until it's time has been reached, but - ignoring that this is not a very elegant way, anyways - I read that this, too, might get the app rejected.
Since there are a few alarm clock apps that do just what I'm looking for, I wonder how they implemented this functionality.
Thanks for any hints in advance!
If you seek a solution that will be approved by Apple, you're right you can't use the setKeepAliveTimeout:handler and even if you could - you can't set the timeout to something that's smaller than 600 seconds, so I guess it won't be of a great use anyway (besides that It's not guaranteed to fire the event even remotely close to the timeout you specified. For example, I set it to 600 seconds and some event fired as early as 360 seconds..).
About playing the silent sound, except the waste of battery, if you're app has legitimate use for background audio (if you're implementing an alarm clock, that's pretty obvious), I don't see a reason for your app to be rejected, as long as you don't try to use other background features (GPS signal, VoIP handlers, etc).
Here's one example app that used this "feature" for their benefit:
http://tapbots.com/blog/pastebot/pastebot-music-in-background
About other methods, you can look in this thread:
How do I start playing audio when in silent mode & locked in iOS 6?
On a personal note, it's not very easy to cope with background policies of Apple. Me and my company had (have?) a hard time just to maintain a simple VoIP connection due to all the limitations. My best advice is try to do as less as possible in the background as you can. If the UILocalNotificaion solution suits you, you'll probably should stick to it and live with the limitations.
Is it possible to still play sound / music even if audio has been interrupted, or more precisely: even if MyInterruptionListener got called from the OS with the interruption state kAudioSessionBeginInterruption ?
Yeah I know that's not good idea to do. But want to know anyways.
By the time you get an interrupt message, the audio resources you've been using have been shut down.
For AVAudioPlayer, playback will be stopped until you start it again.
For OpenAL, your context will be invalid. All OpenAL commands will fail with an error until you clear the current context and set it to current again.
For Audio Units, your graph will be in an invalid state. No sound will be played until you set the graph inactive and then active.
I don't know what would happen if you tried to start your audio resources again upon getting an interrupt start message, but at the very least you'd get rejected in the app store if the reviewers ever discovered this behavior.
This question seems to be the essence of several others on this forum. I believe that it is possible for the active iPhone application to continue running, and specifically, to continue receiving timer call-backs, after it has entered the inactive state (either through the idle timer kicking in the screen lock, or through the user pressing the hardware lock button).
The documentation specifically says that while an application is inactive, it is executing, but not dispatching incoming events (I'm not giving a link because I'm jumpy about NDA - should I relax about that? Is this whole post a breach? sigh).
Also, two answers by user "Ambr Str" directly state that it is possible to continue receiving timer call-backs, and he supplies a snip of code to achieve it (I can't link to this because I'm a new user, sorry - search for the question: "What happens to an iPhone app when iPhone goes into stand-by mode?" to find his answer).
I've tried to create my call-backs as he suggests, but once my application becomes inactive, the call-backs cease firing.
I've just noticed that while the iPhone is plugged in, if the application becomes inactive (due to idle time out or me pressing the sleep button), call-backs do continue to occur - perhaps I should get my users to carry a battery pack with them ;-)
There is a good answer to this question on Apple's forums. Search for "Timer" and "Eskimo" (the helpful chap who provides the answers).
In brief, shortly after the application becomes inactive, the phone really does go to sleep. The only way to prevent this is to be playing some audio (or for some audio to be playing in a background application). While audio is playing the phone will not sleep, and your application continues to be run.
It is suggested that playing stay awake audio is a hack, and that you shouldn't do it if at all possible. I think in my application (which performs audio playback interspersed with silent periods), the approach is valid, if not ideal!
I have an app. which includes an embedded webserver. I'm planning to offer an option of disabling auto-sleep IFF the server is turned on, AND the device is on power. So you might consider checking the batteryState property of UIDevice. So if batteryState != UIDeviceBatteryStateUnplugged, go ahead and disable idle timer. (note: the docs say that UIDeviceBatteryStateUnknown will be returned when in simulator.)
You'll also want to listen for UIDeviceBatteryStateUnplugged notifications and set batteryMonitoringEnabled appropriately.