Is there a way to measure latency in iOS? - ios

The problem I'm trying to solve is I would like to have a way to measure network latency and notify users when high latency situations occur. My app allows users to stream audio or video content from online sources and while playback is possible on 3g and even EDGE speeds in my testing, spikes in latency can cause hangups in usability. When this occurs I'd like to be able to alert the user the cause of these problems.
I've gone back to looking into Apple's Reachability sample code and it still does not help. I'll refer back to an issue filed over a year ago (http://openradar.appspot.com/13982938)
Assuming I start with a strong connection, I can set a custom profile in the network link conditioner that would drop 100% of packets sent, and the reachability code in the sample app does not change the positive result. It still tells me I have a connection even though no packets get through.
Are there any reliable values I can KVO or otherwise listen to, in order to get this information?

The easiest way (and probably the only one that really works) is to store time value when you send a request and evaluate latency when you receive a response. You can check how AFNetworkActivityLogger solves this here
https://github.com/AFNetworking/AFNetworkActivityLogger/blob/master/AFNetworkActivityLogger/AFNetworkActivityLogger.m
The most important lines for you are
objc_setAssociatedObject(notification.object, AFNetworkRequestStartDate, [NSDate date], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
when request is sent and
NSTimeInterval elapsedTime = [[NSDate date] timeIntervalSinceDate:objc_getAssociatedObject(notification.object, AFNetworkRequestStartDate)];
when response is received.
How to integrate this logic to your code depends on what do you use to get streamed video.

My app allows users to stream audio or video content from online sources
Some built-in ways of streaming tell you what's going on. If you're using AVPlayerItem, properties such as playbackLikelyToKeepUp and the accessLog, along with notifications such as AVPlayerItemPlaybackStalledNotification, can be helpful in keeping you abreast of any issues.

Related

Latency with Multipeer Connectivity framework

So I've been dumped with a very broken and outdated code base. I'm being asked however to fix only one bug with the latency that occurs when a message is sent between two devices.
The app is for streaming audio to several devices and playing them all at once. The issue is obviously caused when the host sends a "play" message and starts playing itself. This play message is delayed by up to 3 seconds and therefore the clients all end up out of sync.
I've attempted sending a CFAbsoluteTimeGetCurrent(); value to the clients where they then work out the latency but device clocks are very unreliable and I often get negative differences in time despite obviously being positive.
Any idea on how I can combat this? And before suggestions of changing the method entirely, there's isn't much time
Have you considered sending a SYN message along with a local timestamp and then have the per return the timestamp as a ACK message? You can take the difference between the current time and the return time and half it to get a latency.
Source: I did this.

How can I start a process when this play symbol comes up

In my app I am streaming audio and there is a period of 5-10 sec depending on the connection where the buffer is loading and after this, my app starts to play the audio. When it starts to play the audio this symbol comes up in the screen.
Here is an image of what im talking about.
http://img27.imageshack.us/img27/3667/img0596.png
I want to change a label in my app when this symbol comes up in the screen, but i dont know which function let me detect this.
The symbol is the "Play" button common to music devices. There is most likely an NSNotification center message that can be "listened for". However, depending on how you are buffering your sounds there is probably a delegate that can notify a selector once it has begun playback. Without more details I can not give more detailed advice. If I were in your position I would take a very hard look at the API you are utilizing, most likely several methods exist to either post notification or send delegate messages notifying the state of the stream as well as playback. I have worked with some streaming audio API and I was able to get status of the buffer as well many other messages from the stream object(s). These are just part of good design, so most likely it is there.

Detecting the AirPlay latency

While I realize that AirPlay has inherent lag/latency, I'm wondering if there's a way for a (currently hypothetical) iPhone app to detect what that latency is. If so, how precise can that latency value be? I'm more curious in whether an app can "know" its own AirPlay latency, rather than simply minimize it.
The latency does not come from network jitter, but rather is decided by the source device (your iPhone).
Long story short:
It's always precisely 2s (down to the millisecond) with Apple devices.
There is no way to tweak it with public APIs.
Audio latency needs to be very accurate so that multiple outputs can play in sync.
Some explanations about AirPlay's implementation:
The protocol starts with several RTSP commands. During this handshake, the source transmits rtpTime, the time at which the playback starts, which is also your latency. The typical value is 88200 = 2s x 44100 Hz.
AirPlay devices can sync their clock with the source's with NTP to mitigate the network latency.
During playback, the source periodically sends a SYNC packet to adjust the audio latency and make sure that all devices are still in sync.
It's possible to change the latency if you use a custom implementation, but Apple usually rejects them.
Check this writeup for more information. You can also read the unofficial protocol documentation.
The short answer is: no, Apple does not provide a way to do this. Assuming you need your app to be approved in the App Store, you're sort of out of luck. If you can run your app on a jailbroken device you can search around for undocumented APIs that will let you do more.
If you need your app to be available in Apple's App Store, most things you can do network-wise are outlined in the "Reachability" sample app.
The only way I can think of to get a good guess would be to use Bonjour to identify the host (see sample code here https://developer.apple.com/library/ios/#samplecode/BonjourWeb/Introduction/Intro.html) and then ping the host.
However:
If there is more than 1 Airplay station you will need to guess or ask which the user is connected to, or maybe take an average.
The device may not respond to a ping at all (Apple TV and Airport Express both respond to ping, not sure about 3rd party devices.)
The ping may not reflect the actual latency of the audio
Instead of spending too much time on this, you should follow Apple's guidelines for preparing your audio for AirPlay and enriching your app for AirPlay: http://developer.apple.com/library/ios/#documentation/AudioVideo/Conceptual/AirPlayGuide/PreparingYourMediaforAirPlay/PreparingYourMediaforAirPlay.html#//apple_ref/doc/uid/TP40011045-CH4-SW1
Hope this helps! :)
You can query iOS's current hardware audio latency by -[AVAudioSession outputLatency],
According to the document for outputLatency:
Using an AirPlay enabled device for your audio content can result in a 2-second delay. Check for this delay in game content.
And according to my experience, this value changes when switching output device, eg:
Speaker: ~10ms
Bluetooth: ~100+ms
AirPlay: 2s

Issues with audio playback during network activity

I'm using CocoaLibSpotify and the SPPlaybackManager to stream Spotify music to my app. It works very well overall, but I'm experiencing some issues with the playback during other network activity.
Procedure:
(During audio playback) I'm firing a regular ASIHTTPRequest to a server.
When the request has finished, I'm making a number of Spotify searches using SPSearch.
On many devices (in particular iPhone 3GS), I'm getting massive "stuttering"/"skips"/"pauses" in the playback while the Searches are performed.
Earlier, I used regular ASIHTTPRequests instead of the SPSearch class, so I'm quite sure it's got to do with the overall network activity.
Also, the playback issues may appear while doing some other network activity on the device, i.e. loading a number of emails in the Mail app.
Threading?
I'm guessing this is some kind of threading issue (i.e. the audio is played back on the main thread or something), but I'm not sure exactly how to approach the issue... I've tried invoking SPPlaybackManager#playTrack:: on a background thread, but I guess the setup wasn't 100% correct (since the issues remained).
Does anyone have any pointers as to how I should move forward?
Both the audio delivery and audio playback in the classes supplied with CocoaLibSpotify are run on (different) background threads. However, SPPlaybackManager is only intended to be an easy-to-follow example of dealing with audio playback using Core Audio - it hasn't been tested for, nor is it intended for, use during high CPU load and/or in environments very tight on resources.
All I can do is point you towards the standard debugging tools such as Instruments to trace and profile what's going on.

How to sync counter via sockets on iPad

I have a Application on a PC which displays time-information for a mp3 song that is played. I now need to display this time information within an iPad App. The counting timers for remaining time, player position and song length must be in sync between iPad an PC.
I thought about using a socket connection (AsyncSocket on iPad) to keep the counters in sync.
Is there a better way doing this? I don't want to run in the wrong direction...
Additional, it should be possible to have more than one iPad showing the Information in future. That's a "nice to have" feature...
I don't need ready to use code snippets, it's more a theoretical question. (if someone has a ready to use code snippet, that's also good for me :-) )
MadMaxApp
i now used the AsyncSocket to solve the requirements. It works perfectly. Don't forget the handling of closing the socket connection if the app goes in background. Depending on the server the app is talking with, not closing the socket can lead to a problem in reconnecting.

Resources