diff --git a/coreapi/help/doc/sphinx/CMakeLists.txt b/coreapi/help/doc/sphinx/CMakeLists.txt
index 78727b5d5..830bcd284 100644
--- a/coreapi/help/doc/sphinx/CMakeLists.txt
+++ b/coreapi/help/doc/sphinx/CMakeLists.txt
@@ -49,6 +49,7 @@ if (ENABLE_SPHINX_DOC)
event_api.rst
index.rst
initializing.rst
+ ios_portability.rst
linphone_address.rst
logo.png
media_parameters.rst
diff --git a/coreapi/help/doc/sphinx/index.rst b/coreapi/help/doc/sphinx/index.rst
index 2ae1a83e8..24fa3502f 100644
--- a/coreapi/help/doc/sphinx/index.rst
+++ b/coreapi/help/doc/sphinx/index.rst
@@ -46,6 +46,7 @@ Beginners' guides
conferencing
event_api
misc
+ ios_portability
Code samples
diff --git a/coreapi/help/doc/sphinx/ios_portability.rst b/coreapi/help/doc/sphinx/ios_portability.rst
new file mode 100644
index 000000000..84d8160d9
--- /dev/null
+++ b/coreapi/help/doc/sphinx/ios_portability.rst
@@ -0,0 +1,285 @@
+iOS portability
+===============
+Multitasking
+------------
+
+Liblinphone for IOS natively supports multitasking assuming application follows multitasking guides provided by Apple.
+
+First step is to declare application as multitasked. It means adding background mode for both audio and voip to Info.plist file.
+
+.. code-block:: xml
+
+ UIBackgroundModes
+
+ voip
+ audio
+
+
+
+SIP socket
+^^^^^^^^^^
+
+Recommended mode is SIP over TCP, because UDP usually requires frequent keep alives for maintaining NAT association at the IP router level. This can
+be as frequent as one UDP packet every 15 seconds to maintain the NAT association accross NAT routers. Doing such drains the battery very fast, and
+furthermore the iOS keep-alive designed by Apple to handle this task can only be called with a minimum of 10 minutes interval.
+
+For TCP, liblinphone automatically configures SIP socket for voip (I.E kCFStreamNetworkServiceType set to kCFStreamNetworkServiceTypeVoIP).
+
+.. note::
+
+ Since IOS > 4.1 Apple disabled voip mode for UDP sockets.
+
+
+Entering background mode
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+Before entering in background mode (through ``- (void)applicationDidEnterBackground:(UIApplication *)application``), the application must first refresh
+sip registration using function :cpp:func:`linphone_core_refresh_registers` and register a keep-alive handler for periodically refreshing the registration.
+The speudo code below shows how to register a keep alive handler:
+
+.. code-block:: objective-c
+
+ //First refresh registration
+ linphone_core_refresh_registers(theLinphoneCore);
+ //wait for registration answer
+ int i=0;
+ while (!linphone_proxy_config_is_registered(proxyCfg) && i++<40 ) {
+ linphone_core_iterate(theLinphoneCore);
+ usleep(100000);
+ }
+ //register keepalive handler
+ [[UIApplication sharedApplication] setKeepAliveTimeout:600/*minimal interval is 600 s*/
+ handler:^{
+ //refresh sip registration
+ linphone_core_refresh_registers(theLinphoneCore);
+ //make sure sip REGISTER is sent
+ linphone_core_iterate(theLinphoneCore);
+ }];
+
+
+Incoming call notification while in background mode
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Assuming application using liblinphone is well configured for multitasking, incoming calls arriving while liblinphone is in background mode will simply wakeup
+liblinphone thread but not resume GUI. To wakeup GUI, it is recommended to send a Local Notification to the user from the #LinphoneCoreCallStateChangedCb. Here
+under a speudo code for this operation:
+
+.. code-block:: objective-c
+
+ if ([UIApplication sharedApplication].applicationState != UIApplicationStateActive) {
+ // Create a new notification
+ UILocalNotification* notif = [[[UILocalNotification alloc] init] autorelease];
+ if (notif) {
+ notif.repeatInterval = 0;
+ notif.alertBody =@"New incoming call";
+ notif.alertAction = @"Answer";
+ notif.soundName = @"oldphone-mono-30s.caf";
+
+ [[UIApplication sharedApplication] presentLocalNotificationNow:notif];
+ }
+
+
+Networking
+----------
+WWAN connection
+^^^^^^^^^^^^^^^
+
+Liblinphone relies on iOS's standard BSD socket layer for sip/rtp networking. On IOS, WWAN connection is supposed to automatically bring up on any networking
+resquest issued by an application. At least on iPhone OS 3.x, BSD sockets do not implement this behavior. So it is recomended to add a special code to make sure
+the WWAN connection is properly setup. Pseudo code below describes a way to force WWAN connection by setting up a dummy TCP connection.
+
+.. code-block:: objective-c
+
+ /*start a new thread to avoid blocking the main ui in case of peer host failure*/
+ [NSThread detachNewThreadSelector:@selector(runNetworkConnection) toTarget:self withObject:nil];
+ -(void) runNetworkConnection {
+ CFWriteStreamRef writeStream;
+ //create a dummy socket
+ CFStreamCreatePairWithSocketToHost(NULL, (CFStringRef)@"192.168.0.200", 15000, nil, &writeStream);
+ CFWriteStreamOpen (writeStream);
+ const char* buff="hello";
+ //try to write on this socket
+ CFWriteStreamWrite (writeStream,(const UInt8*)buff,strlen(buff));
+ CFWriteStreamClose (writeStream);
+ }
+
+It is recommanded to perform this task each time the application is woken up, including keep alive handler.
+
+
+Managing IP connection state
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Liblinphone for IOS relies on the application to be informed of network connectivity changes. Network state changes when the IP connection moves from DOWN to UP,
+or from WIFI to WWAN. Applications using liblinphone must inform libliblinphone of this changes using function :cpp:func:`linphone_core_set_network_reachable`.
+Usually this method is called from the IOS NetworkReachability callback. Here under a sample code:
+
+.. code-block:: c
+
+ //typical reachability callback
+ void networkReachabilityCallBack(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void * info) {
+ if ((flags == 0) | (flags & (kSCNetworkReachabilityFlagsConnectionRequired |kSCNetworkReachabilityFlagsConnectionOnTraffic))) {
+ //network state is off
+ linphone_core_set_network_reachable(lc,false);
+ ((LinphoneManager*)info).connectivity = none;
+ } else {
+ Connectivity newConnectivity = flags & kSCNetworkReachabilityFlagsIsWWAN ? wwan:wifi;
+ if (lLinphoneMgr.connectivity == none) {
+ //notify new network state
+ linphone_core_set_network_reachable(lc,true);
+ } else if (lLinphoneMgr.connectivity != newConnectivity) {
+ // connectivity has changed
+ linphone_core_set_network_reachable(lc,false);
+ linphone_core_set_network_reachable(lc,true);
+ }
+ //store new connectivity status
+ lLinphoneMgr.connectivity=newConnectivity;
+ }
+ }
+
+
+Sound cards
+-----------
+
+Since IOS 5.0, liblinphone supports 2 sound cards. *AU: Audio Unit Receiver* based on IO units for voice calls plus *AQ: Audio Queue Device* dedicated to rings.
+Here under the recommended settings (I.E default one)
+
+.. code-block:: c
+
+ linphone_core_set_playback_device(lc, "AU: Audio Unit Receiver");
+ linphone_core_set_ringer_device(lc, "AQ: Audio Queue Device");
+ linphone_core_set_capture_device(lc, "AU: Audio Unit Receiver");
+
+
+GSM call interaction
+--------------------
+
+To ensure gentle interaction with GSM calls, it is recommended to register an AudioSession delegate. This allows the application to be notified when its audio
+session is interrupted/resumed (presumably by a GSM call).
+
+.. code-block:: objective-c
+
+ // declare a class handling the AVAudioSessionDelegate protocol
+ @interface MyClass : NSObject { [...] }
+ // implement 2 methods : here's an example implementation
+ -(void) beginInterruption {
+ LinphoneCall* c = linphone_core_get_current_call(theLinphoneCore);
+ ms_message("Sound interruption detected!");
+ if (c) {
+ linphone_core_pause_call(theLinphoneCore, c);
+ }
+ }
+
+ -(void) endInterruption {
+ ms_message("Sound interruption ended!");
+ const MSList* c = linphone_core_get_calls(theLinphoneCore);
+
+ if (c) {
+ ms_message("Auto resuming call");
+ linphone_core_resume_call(theLinphoneCore, (LinphoneCall*) c->data);
+ }
+ }
+
+.. seealso:: http://developer.apple.com/library/ios/#documentation/AVFoundation/Reference/AVAudioSessionDelegate_ProtocolReference/Reference/Reference.html
+
+Declare an instance of your class as AudioSession's delegate :
+
+.. code-block:: objective-c
+
+ [audioSession setDelegate:myClassInstance];
+
+.. seealso:: http://developer.apple.com/library/ios/#documentation/AVFoundation/Reference/AVAudioSession_ClassReference/Reference/Reference.html
+
+
+Video
+-----
+
+Since 3.5 video support has been added to liblinphone for IOS. It requires the application to provide liblinphone with pointers to IOS's views hosting video
+display and video previous. These two UIView objects must be passed to the core using functions :cpp:func:`linphone_core_set_native_video_window_id` and
+:cpp:func:`linphone_core_set_native_preview_window_id`. Here under pseudo code:
+
+.. code-block:: objective-c
+
+ UIView* display = [[UIView alloc] init];
+ UIView* preview = [[UIView alloc] init];
+ linphone_core_set_native_video_window_id(lc,(unsigned long)display);
+ linphone_core_set_native_preview_window_id(lc,(unsigned long)preview);
+
+Screen rotations are also handled by liblinphone. Two positions are currently supported, namely *UIInterfaceOrientationPortrait* and *UIInterfaceOrientationLandscapeRight*.
+Applications may invoke :cpp:func:`linphone_core_set_device_rotation` followed by :cpp:func:`linphone_core_update_call` to notify liblinphone of an orientation
+change. Here under a speudo code to handle orientation changes
+
+.. code-block:: c
+
+ -(void) configureOrientation:(UIInterfaceOrientation) oritentation {
+ int oldLinphoneOrientation = linphone_core_get_device_rotation(lc);
+ if (oritentation == UIInterfaceOrientationPortrait ) {
+ linphone_core_set_native_video_window_id(lc,(unsigned long)display-portrait);
+ linphone_core_set_native_preview_window_id(lc,(unsigned long)preview-portrait);
+ linphone_core_set_device_rotation(lc, 0);
+
+ } else if (oritentation == UIInterfaceOrientationLandscapeRight ) {
+ linphone_core_set_native_video_window_id(lc,(unsigned long)display-landscape);
+ linphone_core_set_native_preview_window_id(lc,(unsigned long)preview-landscape);
+ linphone_core_set_device_rotation(lc, 270);
+ }
+
+ if ((oldLinphoneOrientation != linphone_core_get_device_rotation(lc))
+ && linphone_core_get_current_call(lc)) {
+ //Orientation has changed, must call update call
+ linphone_core_update_call(lc, linphone_core_get_current_call(lc), NULL);
+ }
+ }
+
+
+DTMF feedbacks
+--------------
+
+Liblinphone provides functions :cpp:func:`to play dtmf ` to the local user. Usually this is used to play a sound when the user
+presses a digit, inside or outside of any call. On IOS, libLinphone relies on AudioUnits for interfacing with the audio system. Unfortunately the Audio Unit
+initialization is a quite long operation that may trigger a bad user experience if performed each time a DTMF is played, the sound being delayed half a
+second after the press. To solve this issue and thus insure real-time precision, liblinphone introduces two functions for :cpp:func:`preloading `
+and :cpp:func:`unloading ` the underlying audio graph responsible for playing DTMFs.
+
+For an application using function :cpp:func:`linphone_core_play_dtmf`, it is recommanded to call :cpp:func:`linphone_core_start_dtmf_stream` when entering
+in foreground and #linphone_core_stop_dtmf_stream() upon entering background mode.
+
+
+Plugins
+-------
+
+On iOS, plugins are built as static libraries so Liblinphone will not be able to load them at runtime dynamically. Instead, you should declare their prototypes:
+
+.. code-block:: c
+
+ extern void libmsamr_init(MSFactory *factory);
+ extern void libmsx264_init(MSFactory *factory);
+ extern void libmsopenh264_init(MSFactory *factory);
+ extern void libmssilk_init(MSFactory *factory);
+ extern void libmsbcg729_init(MSFactory *factory);
+ extern void libmswebrtc_init(MSFactory *factory);
+
+
+Then you should register them after the instantiation of :cpp:type:`LinphoneCore`:
+
+.. code-block:: c
+
+ theLinphoneCore = linphone_core_new_with_config(/* options ... */);
+
+ // Load plugins if available in the linphone SDK - otherwise these calls will do nothing
+ MSFactory *f = linphone_core_get_ms_factory(theLinphoneCore);
+ libmssilk_init(f);
+ libmsamr_init(f);
+ libmsx264_init(f);
+ libmsopenh264_init(f);
+ libmsbcg729_init(f);
+ libmswebrtc_init(f);
+ linphone_core_reload_ms_plugins(theLinphoneCore, NULL);
+
+
+If the plugin has not been enabled at compilation time, a stubbed library will be generated with only libplugin_init method declared, doing nothing. You should
+see these trace in logs, if plugin is stubbed:
+
+.. code-block:: none
+
+ I/lib/Could not find encoder for SILK
+ I/lib/Could not find decoder for SILK