How to guarantee a process starts at an exact time in iOS - ios

We are playing a metronome audio file at time intervals (bpm), while simultaneously recording an audio file. However currently the start time of the two threads are not exactly simultaneously, and there is a slight time difference, which for music, is not allowable.
What strategies can we use to guarantee that the two processes start at the exact same time (or under a few milliseconds)?
Thanks!

I can think of three ways to get this done (but obviously I never tested them).
Each of your threads should do all the initialization they can up front, then wait for an "event". A few timing events I can think of:
use a Notification - both threads an listen for some "start" notification. That should be fairly quick.
have both threads do keyValue listening - so they both are listening for changes to some property on a known object, like appDelegate (or a singleton), or any object they both know (delegate?)
have each call a delegate when there initialization is done. When both are "ready", the delegate can send each a message, one after the other (on the main thread) to "start".
You could also experiment with NSLock and friends - not sure what kind of latency you would get there. Key-Value Observing is pretty fast and lightweight, and works on any thread.

The most accurate and reliable way of achieving this is to implement audio record and metronome playback in CoreAudio audio render/input handlers rather than using higher level APIs and relying on synchronising two threads. None of the mechanisms in #David H's answer provide any guarantees about thread execution by the kernel, although they'll probably all work most of the time on a lightly loaded system.
The callbacks are called on a real-time thread managed to CoreAudio, and synchronously with the hardware audio-clock - which is probably asynchronous with the kernel's timers.
You will need to load the metronome sample into memory and convert to the output format on initialisation - probably using one of the AudioToolbox APIs. The audio render callback simply copies this to the output buffer at the appropriate time.

Related

UIDocument synchronous read - completion handler stalled in dispatch

I tried multiple ways of wrapping a file read within a synchronous method call (including using multiple queues, specifying target queues, setting up an NSThread and signalling with NSCondition's, even moving the allocation of the UIDocument to the background thread in the end, and also trying dispatch_sync on the background queue as well).
What ended up consistently happening is the completion handler for UIDocument.openWithCompletionHandler wasn't executing, although the documentation indicates that shall happen on the same queue that initiated the openWithCompletionHandler call.
I figured this has ultimately something to do with the control not being returned by the outer/top-level method call to the run loop. It would seem that regardless of what other queues or threads are being set up, the dispatch system expects me to return from the outermost method call, or things get blocked. This would however defeat the whole synchronous design approach.
My use case requires synchronous file reads (with very small data sizes), and I'd prefer the convenience of UIDocument over moving to lower level methods, or looking at ways to introduce async patterns. I reckon UIDocument was designed for more conventional cases, I understand well enough the ubiquity - and in most cases user friendliness and efficiency of async patterns, but in this case it would present a cumbersome situation for both development and user experience.
I wonder if there is something else that could be tried with dispatch queues that could still be explored (like manually consuming events from a queue, creating a custom run loop) that could avoid this seemingly global synchronization effect.
EDIT: this is for an Audio Unit app extension. Instantiation is controlled by the platform, and a "half-initialized" state could become a problematic situation. It is pretty much standard in the industry to fully load the plugin before even allowing the host app to start playing any audio for example, not to mention starting to stream MIDI/automation events. (That's not to say there aren't extensions with crazy load times that could take another look at their design, but in most cases these are well justified in this domain).

How many sounds can be played at a time on iOS - AVAudioPlayer vs. AVAudioEngine & AVAudioPlayerNode

I have an application in which there is a set of about 50 sounds, which range in length from about 300 ms to about 4 seconds. Various combinations of sounds need to be played at precise times (up to 10 of them can be triggered at once). Some sounds need to be repeated at intervals as short as 100 ms.
I've implemented this is as a two dimensional array of AVAudioPlayers, all of which are loaded with sounds at application launch. There are several players for each sound, to accommodate rapidly repeating sounds. The players for a particular sound are reused in strict rotation. When a new sound is scheduled, the oldest player for that sound is stopped and its current time is set to 0, so the sound will repeat from the start, the next time it's scheduled using player.play(atTime:). There's a thread that schedules new sets of sounds about 300 ms before they are to be played.
It all works quite nicely, up to a point that varies with the device. Eventually, as sounds are played more rapidly, and/or more simultaneous sounds are scheduled, some sounds will refuse to play.
I'm contemplating switching to AVAudioEngine and AVAudioPlayerNodes, using a mixer node. Does anyone know if that approach is likely to handle more simultaneous sounds? My guess is that both approaches translate into a rather similar set of CoreAudio functions, but I haven't actually written the code to test that hypothesis - before I do that, I'm hoping that someone else may have explored this issue before me. I've been deep into CoreAudio before, and I'm hoping to be able to use these handy high-level functions instead!
Also, does anyone know of a way to trigger a closure when a sound initiates? The documented functionality allows for a callback closure, but the only way I've been able to trigger events when the sounds start, is to create a high quality of service queue for DispatchQueue. Unfortunately, depending on the system load, queued events may be executed at times that vary from the scheduled times by up to about 50 ms, which is not quite as precise as I'd prefer to be.
Using AVAudioEngine with AVAudioPlayersNodes provides much better performance, albeit at the cost of a bit of code complexity. I was able to easily increase the playback rate by a factor of five, with better buffer control.
The main drawback in switching to this approach was that Apple's documentation is less than stellar. A few additions to Apple's documentation would have made this task a LOT easier:
Mixer nodes are documented as being able to convert sample rates and channel counts, so I attempted to configure audioEngine.mainMixerNode to convert mono buffers to the output node's settings. Setting the main mixer node's output to the output node's format appeared to be accepted, but threw opaque errors at run time that complained about channel count mismatches.
It appears that the main mixer node is not actually a fully functional mixer node. To get this to work, I had to insert another mixer node that performed the channel conversion, and connect it to the main mixer node. If Apple's documentation had actually mentioned this, it would have saved me a lot of experimentation.
Also, just scheduling a buffer does not cause anything to play. You need to call play() on the player node before anything will happen. Apple's documentation is confusing here - it says that calling play() with no arguments will cause playback to occur immediately, which wasn't what I wanted. It took some experimentation to determine that play() just tells the player node to wake up, and that scheduled buffers will actually be played at the scheduled time, rather than immediately.
It would have been enormously helpful if Apple had provided more than the auto-generated class documentation. A bit of human-generated documentation would have saved me an awful lot of frustrating experimentation.
Chris Adamson's well-written "Learning Core Audio" was very helpful when I was working with Core Audio - it's a shame that the newer AVAudioEngine functionality isn't documented nearly as well.

IOS 8: Real Time Sound Processing and Sound Pitching - OpenAL or another framework

I'm trying to realize an app which plays a sequence of tones in a loop.
Actually, I use OpenAL and my experiences with such framework are positive, as I can perform a sound pitch also.
Here's the scenario:
load a short sound (3 seconds) from a CAF file
play that sound in a loop and perform a sound shift also.
This works well, provided that the tact rate isn't too high - I mean a time of more than 10 milliseconds per tone.
Anyhow, my NSTimer (which embeds my sound sequence to play) should be configurable - and as soon as my tact rate increases (I mean less than 10 ms per tone), the sound is no more echoed correctly - even some tones are dropped in an obvious random way.
It seems that real time sound processing becomes an issue.
I'm still a novice in IOS programming, but I believe that Apple sets a limit concerning time consumption and/or semaphore.
Now my questions:
OpenAL is written in C - until now, I didn't understand the whole code and philosophy behind that framework. Is there a possibility to resolve my above mentioned problem making some modifications - I mean setting flags/values or overwriting certain methods?
If not, do you know another IOS sound framework more appropriate for such kind of real time sound processing?
Many thanks in advance!
I know that it deals with a quite extraordinary and difficult problem - maybe s.o. of you has resolved a similar one? Just to emphasize: sound pitch must be guaranteed!
It is not immediately clear from the explanation precisely what you're trying to achieve. Some code is expected.
However, your use of NSTimer to sequence audio playback is clearly problematic. It is neither intended as a reliable nor a high resolution timer.
NSTimer delivers events through a run-loop queue - probably your application's main queue - where they content with user interface events.
As the main thread is not a real-time thread, it may not even be scheduled to run for some time.
There may be quantisation effects on with the delay you requested, meaning your events effectively round to zero clock ticks and get scheduled immediately.
Perioidic timers have deleterious effects on battery life. iOS and MacOSX both take steps to reduce their impact by timer coalescing
The clock you should be using for sequencing events is the playback sample clock - which is available in the render handler of whatever framework you use. As well as being reliable this is efficient as well, as the render handler will be running periodically anyway, and in a real-time thread.

Playing back a WAV file streamed gradually over a network connection in iOS

I'm working with a third party API that behaves as follows:
I have to connect to its URL and make my request, which involves POSTing request data;
the remote server then sends back, "chunk" at a time, the corresponding WAV data (which I receive in my NSURLConnectionDataDelegate's didReceiveData callback).
By "chunk" for argument's sake, we mean some arbitrary "next portion" of the data, with no guarantee that it corresponds to any meaningful division of the audio (e.g. it may not be aligned to a specific multiple of audio frames, the number of bytes in each chunk is just some arbitrary number that can be different for each chunk, etc).
Now-- correct me if I'm wrong, I can't simply use an AVAudioPlayer because I need to POST to my URL, so I need to pull back the data "manually" via an NSURLConnection.
So... given the above, what is then the most painless way for me to play back that audio as it comes down the wire? (I appreciate that I could concatenate all the arrays of bytes and then pass the whole thing to an AVAudioPlayer at the end-- only that this will delay the start of playback as I have to wait for all the data.)
I will give a bird's eye view to the solution. I think that this will help you a great deal in the direction to find a concrete, coded solution.
iOS provides a zoo of audio APIs and several of them can be used to play audio. Which one of them you choose depends on your particular requirements. As you wrote already, the AVAudioPlayer class is not suitable for your case, because with this one, you need to know all the audio data in the moment you start playing audio. Obviously, this is not the case for streaming, so we have to look for an alternative.
A good tradeoff between ease of use and versatility are the Audio Queue Services, which I recommend for you. Another alternative would be Audio Units, but they are a low level C API and therefor less intuitive to use and they have many pitfalls. So stick to Audio Queues.
Audio Queues allow you to define callback functions which are called from the API when it needs more audio data for playback - similarly to the callback of your network code, which gets called when there is data available.
Now the difficulty is how to connect two callbacks, one which supplies data and one which requests data. For this, you have to use a buffer. More specifically, a queue (don't confuse this queue with the Audio Queue stuff. Audio Queue Services is the name of an API. On the other hand, the queue I'm talking about next is a container object). For clarity, I will call this one buffer-queue.
To fill data into the buffer-queue you will use the network callback function, which supplies data to you from the network. And data will be taken out of the buffer-queue by the audio callback function, which is called by the Audio Queue Services when it needs more data.
You have to find a buffer-queue implementation which supports concurrent access (aka it is thread safe), because it will be accessed from two different threads, the audio thread and the network thread.
Alternatively to finding an already thread safe buffer-queue implementation, you can take care of the thread safety on your own, e.g. by executing all code dealing with the buffer-queue on a certain dispatch queue (3rd kind of queue here; yes, Apple and IT love them).
Now, what happens if either
The audio callback is called and your buffer-queue is empty, or
The network callback is called and your buffer-queue is already full?
In both cases, the respective callback function can't proceed normally. The audio callback function can't supply audio data if there is none available and the network callback function can't store incoming data if the buffer-queue is full.
In these cases, I would first try out blocking further execution until more data is available or respectively space is available to store data. On the network side, this will most likely work. On the audio side, this might cause problems. If it causes problems on the audio side, you have an easy solution: if you have no data, simply supply silence as data. That means that you need to supply zero-frames to the Audio Queue Services, which it will play as silence to fill the gap until more data is available from the network.
This is the concept that all streaming players use when suddenly the audio stops and it tells you "buffering" next to some kind of spinning icon indicating that you have to wait and nobody knows for how long.

Precisely scheduling sound in iOS 7

I'm working on an iOS7-only app that needs to display a clock complete with ticking sound. I've used a NSTimer of 1s and I use AVAudioPlayer to play the tick sound every second.
Unfortunately, there's something slightly off with the timing. I've measured that timer is off by between 2 and 22 thousands of a second, which you wouldn't think would matter a great deal, but the lag creates a nail biting tension.. kind of like a heart flutter :-)
I've looked around a bit but it sounds like using audio queue services is the only way to go.. and I really don't fancy delving into the depths of that particular framework again.
My question: Is there some other way of getting precisely scheduled sound events in iOS 7 and failing that is there a decent wrapper framework for audio queue services available somewhere? Or better still is there a way of more precisely scheduling NSTimers?
Using any of NSTimer, libdispatch, or spawning a thread that sleeps for the tick duration rely on the underlying thread getting scheduled in time. The kernel provides no guarantee of this, and it is not surprising that the you observe timing jitter; the latency you observe looks reasonable.
NSTimer running on the main thread is likely to perform worst of these as you are also contending against other events delivered through it.
I think your options here are either to use audio queue services, a real-time thread to schedule the events with AVAudioPlayer, or render the audio yourself to a remoteIO unit.
I don't think AVPlayer provides any particular guarantees about timing either.

Resources