CocoaPods is a dependency manager for Objective-C and Swift, which automates and simplifies the process of using 3rd-party frameworks or libraries like ConnectyCubeCalls in your projects.
You can follow their getting started guide if you don’t have CocoaPods installed.
Copy and paste the following lines into your podfile:
Now you can install the dependencies in your project:
From now on, be sure to always open the generated Xcode workspace (.xcworkspace) instead of the project file when building your project.
Importing framework
At this point, everything is ready for you to start using ConnectyCube and ConnectyCubeCalls frameworks. Just import the frameworks wherever you need to use them:
Add a “Run Script Phase” to build phases of your project. Paste the following snippet into the script:
This fixes the known Apple bug, that does not allow to publish archives to the App store with dynamic frameworks that contain simulator platforms. Script is designed to work only for archiving.
Swift namespacing
ConnectyCubeCalls framework supports simple swift names, which means that instead of, for example, CYBCallSession you can just type CallSession. Sometimes it might get you an error: __someclass__ is ambiguous for type lookup in this context, which means that there is another class with the same swift name, and they are conflicting (swift does not understand what class do you want in the current context to be):
In this case you must specify a namespace of that specific class with ., which has the same name as framework and will be:
ConnectyCube Chat API is used as a signaling transport for Video Calling API, so in order to start using Video Calling API you need to connect to Chat.
Initialization
Before any interaction with ConnectyCubeCalls you need to initialize it once using the method below:
Logging is a powerful tool to see the exact flow of the ConnectyCubeCalls framework and analyze its decisions. By enabling logs you will be able to debug most issues, or perhaps help us analyze your problems.
Basic logs are enabled by default. To enable verbose logs use the method below:
CYBCallLogLevelVerbose: basic logs from our framework (enabled by default)
CYBCallLogLevelVerboseWithWebRTC: verbose logs from our framework including all internal webrtc logging (might be helpful to debug some complicated problems with calls)
You can use our SDK in the background mode as well, however this requires you to add a specific app permissions.
Under the app build settings, open the Capabilities tab. In this tab, turn on Background Modes and set the Audio, AirPlay and Picture in Picture checkbox to set the audio background mode.
If everything is correctly configured, iOS provides an indicator that your app is running in the background with an active audio session. This is seen as a red background of the status bar, as well as an additional bar indicating the name of the app holding the active audio session — in this case, your app.
Client delegate
In order to operate and receive calls you need to setup client delegate. Your class must conform to RTCCallSessionCallback (CYBCallClientDelegate v1 deprecated) protocol. Use the method below to subscribe:
In order to perform a call, use CYBCallClient and CYBCallSession methods below:
After this your opponents will receive one call request per 5 second for a duration of 45 seconds (you can configure these settings with WebRTCConfig (CYBCallConfig v1 deprecated):
self.session refers to the current session. Each particular audio - video call has a unique sessionID. This allows you to have more than one independent audio-video conferences.
If you want to increase the call timeout, e.g. set to 60 seconds:
The first thing you will get is startedConnectingToUser callback:
After that webrtc will perform all operations that needed to connect both users internally, and you will either get onConnectedToUser or onDisconnectedFromUser if connection failed to connect for some reason:
After that webrtc will perform all operations that needed to connect both users internally, and you will either get connectedToUser or connectionFailedForUser (you will also receive this callback before connectionClosedForUser if connection failed during active call) if connection failed to connect for some reason:
When you or your opponent close the call, you will receive onDisconnectedFromUser callback first, and then onConnectionClosedForUser when connection is fully closed:
When you or your opponent close the call, you will receive disconnectedFromUser callback first, and then connectionClosedForUser when connection is fully closed:
Use session state to know connection state. You can always access current state by simply calling the P2PSession property:
Each user connection has its own state. By default you can access that state by calling this method from CYBCallSession:
There is also a callback about connection state being changed in the live time:
Here are all possible connection states that can occur:
CYBCallConnectionUnknown: connection state is unknown; this can occur when none of the other states are fit for the current situation
CYBCallConnectionNew: connection was created and ready for the next step
CYBCallConnectionPending: connection is in pending state for other actions to occur
CYBCallConnectionConnecting: one or more of the ICE transports are currently in the process of establishing a connection
CYBCallConnectionChecking: the ICE agent has been given one or more remote candidates and is checking pairs of local and remote candidates against one another to try to find a compatible match, but has not yet found a pair which will allow the peer connection to be made; it’s possible that gathering of candidates is also still underway
CYBCallConnectionConnected: connection was performed successfully
CYBCallConnectionDisconnected: disconnected, but not closed; can still be reconnected
CYBCallConnectionClosed: connection was closed
CYBCallConnectionCount: ICE connection reached max numbers
CYBCallConnectionStateDisconnectTimeout: connection was disconnected by timeout
CYBCallConnectionStateNoAnswer: connection did not receive answer from the opponent user
CYBCallConnectionStateRejected: connection was rejected by the opponent user
CYBCallConnectionStateHangUp: connection was hanged up by the opponent user
CYBCallConnectionStateFailed: one or more of the ICE transports on the connection is in the failed state; this can occur on the different circumstances, e.g. bad network etc.
Show local video
In order to show your local video track from camera you should create UIView on storyboard and then use the following code:
In order to show video views with streams which you have received from your opponents you should create CYBCallRemoteVideoView views on storyboard and then use the following code:
CYBCallAudioTrack class (that represents remote audio track for a specific user) supports audio data sink through CYBCallAudioTrackSinkInterface protocol.
In order to access audio data in real time, simply subscribe to sink interface using methods:
Now handle protocol method to access audio data:
Note
This interface provides AudioBufferList with audio data, AudioStreamBasicDescription description of audio data, a number of frames in current packet, and current media time that conforms to each packet.
ConnectyCubeCalls has its own audio session management which you need to use. It’s located in CYBCallAudioSession class. This class represented as singleton and you can always access shared session by calling instance method:
See CYBCallAudioSession class header for more information.
You can output audio either from receiver (unless you set mode AVAudioSessionModeVideoChat) or speaker:
Screen sharing
Screen sharing allows you to share information from your application to all of your opponents.
It gives you an ability to promote your product, share a screen with formulas to students, distribute podcasts, share video/audio/photo moments of your life in real-time all over the world.
Note
Due to Apple iOS restrictions screen sharing feature works only within an app you are using it in.
With iOS 11 Apple has introduced a new way to capture your in-app screen using ReplayKit’s RPScreenRecorder class. This is the most optimal way to share screen and requires minimum resources as this is handled by iOS itself.
To enable stats report you should first set stats reporting frequency using CYBCallConfig method below:
Now you will be able to receive a client delegate callback and perform operations with CYBCallStatsReport instance for the current period of time:
By calling statsString you will receive a generic report string, which will contain the most useful data to debug a call, example:
Note
CN - connection info, VS - video sent, VR - video received, AvgQP - average quantization parameter (only valid for video; it is calculated as a fraction of the current delta sum over the current delta of encoded frames; low value corresponds with good quality; the range of the value per frame is defined by the codec being used), AS - audio sent, AR - audio received.
You can also use stats reporting to see who is currently talking in a group call. You must use audioReceivedOutputLevel for that.
Take a look to the CYBCallStatsReport header file to see all of the other stats properties that might be useful for you.
Receive a call in background (CallKit)
For mobile apps, it can be a situation when an opponent’s user app is either in closed (killed) or background (inactive) state.
In this case, to be able to still receive a call request, you can use Push Notifications. The flow should be as follows:
a call initiator should send a push notification along with a call request;
when an opponent’s app is killed or in background state - an opponent will receive a push notification about an incoming call, and will be able to accept/reject the call. If accepted or pressed on a push notification - an app will be opened, a user should auto login and connect to chat and then will be able to join an incoming call;
ConnectyCubeCalls fully supports Apple CallKit. In this block, we will guide you through the most important things you need to know when integrating CallKit into your application (besides those Apple has already provided in the link above).
Project preparations
In your Xcode project, make sure that your app supports Voice over IP services. For that open your Info.plist and make sure you have a specific line in Required background modes array:
Now you are ready to integrate CallKit methods using Apple’s guide here.
CallKit requires you to manage Audio session by yourself. Use CYBCallAudioSession for that task. See Audio session management.
Initializing audio session
You must initialize audio session every time before you call -[CXProvider reportNewIncomingCallWithUUID:update:completion:] method, which shows incoming call screen.
Before initializing audio session, set useManualAudio property value to YES. This will not activate webrtc audio before iOS allows us to. We will be activating audio manually later. See Audio session initialization for more information.
Managing audio session activations and deinitializing it
CXProviderDelegate has 2 delegate methods that you must conform to. These are -[CXProviderDelegate provider:didActivateAudioSession:] and -[CXProviderDelegate provider:didDeactivateAudioSession:]. Using CYBCallAudioSessionActivationDelegateprotocol of CYBCallAudioSession class, you need to notify that session was activated outside of it.
-[CXProviderDelegate provider:didActivateAudioSession:] is also a delegate where we need to activate our audio manually. Set audioEnabledproperty of CYBCallAudioSession class in here, to enable webrtc audio as iOS have pushed audio session priority of our app to the top.
Deinitialize audio session every time CXProvider deactivates it in -[CXProviderDelegate provider:didDeactivateAudioSession:] delegate. Deinitializing audio session earlier would lead to issues with the audio session.
If you also have deinitialization code of CYBCallAudioSession somewhere else in your app, you can check and ignore it with -[CYBCallAudioSessionActivationDelegate audioSessionIsActivatedOutside:] method. By this, you will know for sure that CallKit is in charge of your audio session.
Don’t forget to restore CYBCallAudioSession properties to default values in -[CXProviderDelegate provider:performEndCallAction:]:
Group video calls
Because of Mesh architecture we use for multipoint where every participant sends and receives its media to all other participants, current solution supports group calls with up to 4 people.
CYBCallRecorder class handles calls recording. You cannot allocate it by yourself, but it is stored in each instance of CYBCallSession by the property named recorder if the requirements conform. Otherwise, recorder property value will be nil.
Recorder requirements
Device must not be in a low-performance category. To check whether your device is in low performance category use UIDevice+CYBCallPerformance category property CYBCall_lowPerformance.
Only 1 to 1 audio and video calls are supported for now.
Usage
Once you have created new rtc session, you can start recorder by accessing recorder property in session instance. Call start method and input desired file url:
You can configure output file video settings and video orientation using these methods of CYBCallRecorder class:
Once the call is finished or whenever you want before that you need to simply call stop method:
Note
Stop method is asynchronous and will take some time to finalize record file. Once the completion block is called, recording file should be ready by expected url unless some error happens.
In order to handle any recorder errors, simply subscribe to delegate of CYBCallRecorder and handle this method:
Settings and configuration
You can change different settings for your calls using WebRTCConfig (CYBCallConfig v1) class. All of them are listed below:
If an opponent did not answer you within dialing time interval, then onUserNotAnswer: and then onConnectionClosedForUser: delegate methods will be called.
Default value: 60 seconds
Minimum value: 10 seconds
If an opponent did not answer you within dialing time interval, then userDidNotRespond: and then connectionClosedForUser: delegate methods will be called.
Default value: 45 seconds
Minimum value: 10 seconds
Dialing time interval
Indicates how often we send notifications to your opponents about your call.
Datagram Transport Layer Security (DTLS) is used to provide communications privacy for datagram protocols. This fosters a secure signaling channel that cannot be tampered with. In other words, no eavesdropping or message forgery can occur on a DTLS encrypted connection.
You can customize a list of ICE servers. By default ConnectyCubeCalls will use internal ICE servers which is usually enough, but you can always set your own.
Q: How does WebRTC select which TURN server to use if multiple options are given?
A: During the connectivity checking phase, WebRTC will choose the TURN relay with the lowest round-trip time. Thus, setting multiple TURN servers allows your application to scale-up in terms of bandwidth and number of users.
WebRTCMediaConfig.VideoCodec.vp8: VP8 video codec -
WebRTCMediaConfig.VideoCodec.vp9: VP9 video codec -
WebRTCMediaConfig.VideoCodec.h264: h264 high video codec
CYBCallVideoCodecVP8: VP8 video codec - CYBCallVideoCodecH264Baseline:
h264 baseline video codec - CYBCallVideoCodecH264High: h264 high video
codec
VP8 is software supported video codec on Apple devices, which means it is the most demanding among all available ones.
VP9 is an improved version of VP8. It has better compression performance, improved rate control, and more efficient coding tools, which allow for higher-quality video at lower bitrates.
H264 is hardware supported video codec, which means that it is the most optimal one for use when performing video codec, using hardware acceleration you can always gurantee the best performance when encoding and decoding video frames. There are two options available:
baseline: the most suited one for video calls as it has low cost (default value)
high: mainly suited for broadcast to ensure you have the best picture possible. Takes more resources to encode/decode for the same resolution you set
This will set your preferred codec, as webrtc will always choose the most suitable one for both sides in call through negotiations.
Video quality
Video quality depends on hardware you use. iPhone 4s will not handle FullHD rendering, but iPhone 6+ will. It also depends on network you use and how many connections you have.
For multi-calls set lower video quality. For 1 to 1 calls you can set higher quality.
You can use our CYBCallCameraCaptureformatsWithPosition method in order to get all supported formats for current device:
WebRTC has auto scaling of video resolution and quality to keep network connection active.
To get best quality and performance you should use h264-baseline codec as your preferred one.
If some opponent user in call does not support h264, then automatically VP8 will be used.
If both caller and callee have h264 support, then h264 will be used.
Audio codecs
You can choose audio codecs from available values:
In the latest versions of Firefox and Chrome this codec is used by default for encoding audio streams. This codec is relatively new (released in 2012). It implements lossy audio compression. Opus can be used for both low and high bitrates.
Supported bitrate: constant and variable, from 6 kbit/s to 510 kbit/s Supported sampling rates: from 8 kHz to 48 kHz.
If you develop a Calls application that is supposed to work with high-quality audio, the only choice on audio codecs is OPUS.
OPUS has the best quality, but it also requires a good internet connection.
iSAC
This codec was developed specially for VoIP applications and streaming audio.
Supported bitrates: adaptive and variable. From 10 kbit/s to 52 kbit/s. Supported sampling rates: 32 kHz.
Good choice for the voice data, but not nearly as good as OPUS.
iLBC
This audio codec is well-known, it was released in 2004, and became part of the WebRTC project in 2011 when Google acquired Global IP Solutions (the company that developed iLIBC).
When you have very bad channels and low bandwidth, you definitely should try iLBC — it should be strong on such cases.
When you have a strong reliable and good internet connection, then use OPUS. If you use Calls on 3g networks, use iSAC. If you still have problems, try iLBC.
Bandwidth cap
In a case of low bandwidth network, you can try to limit the call bandwidth cap to get better quality vs stability results: