iOS SDK Reference

    The Plivo iOS SDK allows developers to create applications capable of making and receiving voice calls in iOS apps. This page gives an overview of classes and methods available in the Plivo iOS SDK.

    The current version of the iOS SDK is written in Swift and built over the WebRTC framework. It provides high call quality with native WebRTC improvements such as AEC, AGC, and STUN binding requests.

    The SDK supports iOS 10 and above, and is available across three distribution platforms — Swift Package Manager (SPM), and CocoaPods.

    Notes

    New changes for the iOS SDK

    • To use the new SDK, developers must add Plivo’s custom-built WebRTC framework, which also supports bitcode and is available on SPM, Carthage, and CocoaPods.
    • The SDK is backward compatible.
    • (Note: In Objective-C applications login-related methods will report an error regarding method signature placeholder. Previously methods were exposed for Obj-C as login(_ username: String, AndPassword password: String) and for Swift as login(_ username: String, andPassword password: String). Now in both Swift and Obj-C we use the same login(_ username: String, andPassword password: String)).

    Terminology

    • username: username of an endpoint
    • password: password of an endpoint
    • token: device token for VoIP push notifications. You can obtain a device token from APNS by registering for push notifications.
    • certificateId: certificate ID created in the Plivo console under Voice > Push Credentials — see push credentials documentation

    Register an endpoint

    With options

    This code demonstrates registering an endpoint using a Plivo SIP URI and password with options.

    let username = _"Tatooine"_
    let password = _"Jabba"_
    var endpoint: PlivoEndpoint = PlivoEndpoint(
        [
            _"debug"_:true,
            _"enableTracking"_:true,
            _"maxAverageBitrate"_:"48000"
        ])
    func login(withUserName userName: String, andPassword password: String)
    {
        endpoint.login(userName, andPassword: password)
    }
    

    Without options

    This code demonstrates registering an endpoint using a Plivo SIP URI and password without options.

    let username = _"Tatooine"_ 
    let password = _"Jabba"_ 
    var endpoint: PlivoEndpoint = PlivoEndpoint()
    func login(withUserName userName: String, andPassword password: String) {
        endpoint.login(userName, andPassword: password)
    }
    

    Access the microphone

    We have to provide microphone access before making an outbound or receiving an incoming call using the AVFoundation multimedia framework.

    import AVFoundation //Request Record permission
    let session = AVAudioSession.sharedInstance() if (session.responds(to:#selector(AVAudioSession.requestRecordPermission(_:)))) {
        AVAudioSession.sharedInstance().requestRecordPermission({
            (granted: Bool)-> Void in if granted {
                print(_"granted AVAudioSession permission"_)
                do {
                    try session.setCategory(AVAudioSession.Category.playAndRecord, mode: .default, options: []) try session.setActive(true)
                }
                catch {
                    print(_"Couldn't set Audio session category"_)
                }
            }
            else{
                print(_"not granted AVAudioSession permission"_)
            }
        })
    }
    

    Examples for basic call actions

    Here are a couple of basic code examples for making and receiving a call.

    Make a call

    This code makes an outbound call to an endpoint using the SDK.

    let toURI = _"sip:Coruscant@phone.plivo.com"_
    var outgoing: PlivoOutgoing = endpoint.createOutgoingCall();
    outgoing.call(toURI);
    

    Receive a call

    This code receives an incoming call using the SDK.

    (void)onIncomingCall:(PlivoIncoming*)incoming {
        *// Answer the call* [incoming answer];
    }
    
    Note: For more information on implementing incoming calls in your iOS application, see our documentation on Setting Up Push credentials.

    Classes and methods

    Class: PlivoEndpoint (PlivoEndpoint.h)

    The PlivoEndpoint (PlivoEndpoint.h) class lets you register a Plivo SIP endpoint, after which you can make and receive calls using it. Methods available in the PlivoEndpoint class let you register and unregister an endpoint, create an object for outbound calls, submit call quality feedback, and get a call UUID.

    Method 1: Register an endpoint

    With UserName and Password

    You can register an endpoint using:

    • Username, password, device token, and certificate ID
    • Username, password, and device token
    • Username and password

    For each usage, when the endpoint is successfully registered, the SDK notifies the registerSuccess delegate. In case of a failure, it notifies the registerFailure delegate.

    Registering an endpoint using username, password, device token, and certificate ID

    (void)login:(NSString *)username AndPassword:(NSString *)password DeviceToken:(NSData*)token CertificateId:(NSString*)certificateId;
    
    Note: This is the recommended login method to enable incoming calls using push notifications
    usage
    func login(withUserName userName: String, andPassword password: String, deviceToken token: Data, certificateId certificateId: String) {
        endpoint.login(userName, andPassword: password, deviceToken: token, certificateId: certificateId)
    }
    

    Registering an endpoint using username, password, and device token

    (void)login:(NSString *)username AndPassword:(NSString *)password DeviceToken:(NSData*)token;
    
    usage
    func login(withUserName userName: String, andPassword password: String, deviceToken token: Data) {
        endpoint.login(userName, andPassword: password, deviceToken: token)
    }
    

    Registering an endpoint using username, password, and timeout

    Note: This method has been deprecated. We do not recommend to use this method. Use the setRegisterTimeout() function instead. The endpoint will not be able to accept incoming calls if it's logged in using this method.
    (void)login:(NSString *)username AndPassword:(NSString *)password RegTimeout:(int)regTimeout;
    
    usage
    func login(withUserName userName: String, andPassword password: String, withRegTimeout timeout: int) {
        endpoint.login(userName, andPassword: password, regTimeout: timeout)
    }
    

    Registering an endpoint using username and password

    (void)login:(NSString*) username AndPassword:(NSString*) password;
    
    usage
    func login(withUserName userName: String, andPassword password: String) {
            endpoint.login(userName, andPassword: password)
    }
    

    Method 2: Unregister an endpoint

    This method unregisters an endpoint.

    (void)logout;

    func logout() {
        endpoint.logout()
    }
    

    Method 3: Create an object for initiating outbound calls

    Calling this method returns a PlivoOutgoing object, linked to the registered endpoint. Calling this method on an unregistered PlivoEndpoint object returns an empty object.

    (PlivoOutgoing*)createOutgoingCall;

    endpoint.createOutgoingCall()
    

    Method 4: Submit call quality feedback

    You can pass these parameters.

    • callUUID — Mandatory string parameter used to identify the call the feedback belongs to. You can get the callUUID for the last call using getLastCallUUID().
    • starRating — Mandatory integer parameter with a value from 1 to 5. For a score from 1 to 4, the &issues& parameter is mandatory; for a score of 5 it’s optional.
    • issues — IssueList is an array and must have at least one of these reasons for &starRating& values from 1 to 4 — &AUDIO_LAG&, &BROKEN_AUDIO&, &CALL_DROPPPED&, &CALLERID_ISSUES&, &DIGITS_NOT_CAPTURED&, &ECHO&, &HIGH_CONNECT_TIME&, &LOW_AUDIO_LEVEL&, &ONE_WAY_AUDIO&, &ROBOTIC_AUDIO&, &OTHERS&
    • comments — Optional string attribute for users’ remarks; maximum length 280 characters
    • sendConsoleLog — Optional boolean parameter with default value &false&. Set to &true& to enable Plivo’s team to collect and analyze the iOS SDK’s logs for a better understanding of the issue.

    If feedback is successfully submitted, the SDK notifies the onFeedbackSuccess delegate. In the event of an input validation error, it notifies the onFeedbackValidationError delegate. If feedback submission fails, the SDK notifies the onFeedbackFailure delegate.

    (void)submitCallQualityFeedback : (NSString *) callUUID : (NSInteger) startRating : (NSArray *) issues : (NSString *) notes : (BOOL) sendConsoleLog;
    

    usage

    func submitFeedback(starRating: Int , issueList: [AnyObject], comments: String, addConsoleLog: Bool) {
        let callUUID:String? = endpoint.getLastCallUUID();
        endpoint.submitCallQualityFeedback(callUUID, starRating, issueList, notes, sendConsoleLog)
    }
    

    Method 5: Get a call UUID

    Returns a string call UUID if a call is active, else returns null.

    (NSString *)getCallUUID
    

    usage

    let callUUID:String? = endpoint.getCallUUID();
    

    Method 6: Get last call UUID

    Returns the call UUID of the latest answered call. Useful if you want to send feedback for the last call.

    (NSString *)getLastCallUUID
    

    usage

    let callUUID:String? = endpoint.getLastCallUUID();
    

    Method 7: Set Register Timeout

    Set the registration timeout in seconds. Useful if you want the registratino to be valid for upto certain time

    (Int)setRegTimeout
    

    usage

    let registerTimeout:Int? = endpoint.setRegTimeout(10000);
    

    Class: PlivoOutgoing (PlivoOutgoing.h)

    The PlivoOutgoing class contains methods to make and control outbound calls.

    Method 1: Initiate outbound calls

    Calling this method on the PlivoOutgoing object with the SIP URI initiates an outbound call.

    (void)call:(NSString *)sipURI  error:(NSError **)error;
    

    Method 2: Initiate outbound calls with custom SIP headers

    Calling this method on the PlivoOutgoing object with the SIP URI initiates an outbound call with custom SIP headers.

    (void)call:(NSString *)sipURI headers:(NSDictionary *)headers error:(NSError **)error;
    

    usage

    func call(withDest dest: String, andHeaders headers: [AnyHashable: Any], error: inout NSError?) -> PlivoOutgoing {
        /* construct SIP URI , where kENDPOINTURL is a contant contaning domain name details*/ let sipUri: String = _"sip:\(dest)\(kENDPOINTURL)"_ /* create PlivoOutgoing object */ outCall = (endpoint.createOutgoingCall())! /* do the call */ outCall?.call(sipUri, headers: headers, error: &error) return outCall!
    }
    //To Configure Audio func configureAudioSession() {
    endpoint.configureAudioDevice()
    }
    

    Method 3: Mute a call

    Calling this method on the PlivoOutgoing object mutes the call.

    (void)mute;
    

    usage

    func onIncomingCall(_ incoming: PlivoIncoming) {
        .. // assign incCall var incCall = incoming
    }
    // to mute incoming call if (incCall != nil) {
    incCall?.mute()
    }
    

    Method 4: Unmute a call

    Calling this method on the PlivoOutgoing object unmutes the call.

    (void)unmute;
    

    usage

    if (incCall != nil) { incCall?.unmute() }
    

    Method 5: Send digits

    Calling this method on the PlivoOutgoing object with digits sends DTMF (0-9 , *, and #) on the call.

    (void)sendDigits:(NSString*)digits;

    usage

    func getDtmfText(_ dtmfText: String) {
        if (incCall != nil) {
            incCall?.sendDigits(dtmfText) ..
        }
    }
    

    Method 6: Hang up a call

    Calling this method on the PlivoOutgoing object disconnects the call.

    (void)hangup;
    

    usage

    if (self.incCall != nil) {
        print(_"Incoming call - Hangup"_);
        self.incCall?.hangup() self.incCall = nil
    }
    

    Method 7: Hold a call

    Calling this method on the PlivoOutgoing object disconnects the audio devices.

    (void)hold;
    

    usage

    if (incCall != nil) {
        incCall?.hold()
    }
    if (outCall != nil) {
        outCall?.hold()
    }
    Phone.sharedInstance.stopAudioDevice()
    

    Method 8: Unhold a call

    Calling this method on the PlivoOutgoing object reconnects the audio devices after an audio interruption.

    (void)unhold;
    

    Description:

    usage

    if (incCall != nil) {
        incCall?.unhold()
    }
    if (outCall != nil) {
        outCall?.unhold()
    }
    Phone.sharedInstance.startAudioDevice()
    

    Class: PlivoIncoming (PlivoIncoming.h)

    The PlivoIncoming class contains methods to handle an incoming call. A reference of this class is received in the parameter of this delegate. You can use this class reference to answer and reject the call.

    (void)incomingCall:(PlivoIncoming*) incoming;

    Method 1: Answer an Incoming call

    Calling this method on the PlivoIncoming object answers the call.

    (void)answer;
    

    usage

    func provider(_ provider: CXProvider, perform action: CXAnswerCallAction) {
        //Answer the call incCall?.answer() outCall = nil action.fulfill()
    }
    

    Method 2: Reject an incoming call

    Calling this method on the PlivoIncoming object rejects the call.

    (void)reject;
    

    usage

    if (self.incCall != nil) {
        print(_"Incoming call - Reject"_);
        self.incCall?.reject() self.incCall = nil
    }
    

    Method 3: Mute a call

    Calling this method on the PlivoOutgoing object mutes the call.

    (void)mute;
    

    usage

    func onIncomingCall(_ incoming: PlivoIncoming) {
        .. // assign incCall var incCall = incoming
    }
    // to mute incoming call if (incCall != nil) {
    incCall?.mute()
    }
    

    Method 4: Unmute a call

    Calling this method on the PlivoOutgoing object unmutes the call.

    (void)unmute;
    

    usage

    if (incCall != nil) {
        incCall?.unmute()
    }
    

    Method 5: Send digits

    Calling this method on the PlivoOutgoing object with digits sends DTMF (0-9 , *, and #) on the call.

    (void)sendDigits:(NSString*)digits;
    

    usage

    func getDtmfText(_ dtmfText: String) {
        if (incCall != nil) {
            incCall?.sendDigits(dtmfText) ..
        }
    
    }
    

    Method 6: Hang up a call

    Calling this method on the PlivoOutgoing object disconnects the call.

    (void)hangup;
    

    usage

    if (self.incCall != nil) {
        print(_"Incoming call - Hangup"_);
        self.incCall?.hangup() self.incCall = nil
    }
    

    Method 7: Hold a call

    Calling this method on the PlivoOutgoing object disconnects the audio devices.

    (void)hold;
    

    usage

    if (incCall != nil) {
        incCall?.hold()
    }
    if (outCall != nil) {
        outCall?.hold()
    }
    Phone.sharedInstance.stopAudioDevice()
    

    Method 8: Unhold a call

    Calling this method on the PlivoOutgoing object reconnects the audio devices after an audio interruption.

    (void)unhold;
    

    Description:

    usage

    if (incCall != nil) {
        incCall?.unhold()
    }
    if (outCall != nil) {
        outCall?.unhold()
    }
    Phone.sharedInstance.startAudioDevice()
    

    Configuration parameters

    These are the configuration parameters.

    AttributeDescriptionAllowed ValuesDefault Value
    debugEnable log messages.true/falsefalse
    enableTrackingSet to true if you want to get MediaMetrics events and enable call quality tracking.true/falsetrue
    maxAverageBitrateControls your application's bandwidth consumption for calls.

    A high maxAverageBitrate value yields better audio quality but may result in more bandwidth consumption.

    Lowering maxAverageBitrate impacts call quality as the audio is compressed to reduce bandwidth consumption.

    This parameter applies only to calls using the Opus codec. Check out RFC-7587 section 7.1 for more info.

    8000 – 4800048000
    enableQualityTrackingThis parameter can be used to enable/disable below two functionalities:

    mediaMetrics events: enables the Client device to display local call issues like broken audio, etc. to the user.

    Call quality tracking: enables Plivo to capture and display call quality data in Call Insights.

    When set to 'all'

    Both mediaMetrics events & call quality tracking will be enabled.

    When set to 'remoteonly'

    only call quality tracking will be enabled.

    When set to 'localonly'

    only mediaMetrics events will be enabled.

    When set to 'none'

    Both mediaMetrics events & call quality tracking will be disabled.

    CallAndMediaMetrics.ALL

    CallAndMediaMetrics.NONE

    CallAndMediaMetrics.REMOTE_ONLY

    CallAndMediaMetrics.LOCAL_ONLY

    CallAndMediaMetrics.ALL

    PlivoEndpoint delegates

    Delegate 1: On login

    (void)onLogin;
    

    Description: This delegate is called when registration to an endpoint is successful.

    Parameters: Error details

    Return Value: None

    Delegate 2: Handling login failure

    (void)onLoginFailure;
    

    Description: This delegate is called when registration to an endpoint fails.

    Parameters: None

    Return Value: None

    Delegate 3: Handling login failure with errors

    (void)onLoginFailedWithError:(NSError *)error;
    

    Description: This delegate is called when registration to an endpoint fails. Plivo responds with an error.

    Parameters: Error details

    Return Value: None

    Possible error events: INVALID_ACCESS_TOKEN INVALID_ACCESS_TOKEN_HEADER INVALID_ACCESS_TOKEN_ISSUER INVALID_ACCESS_TOKEN_SUBJECT ACCESS_TOKEN_NOT_VALID_YET ACCESS_TOKEN_EXPIRED INVALID_ACCESS_TOKEN_SIGNATURE INVALID_ACCESS_TOKEN_GRANTS EXPIRATION_EXCEEDS_MAX_ALLOWED_TIME MAX_ALLOWED_LOGIN_REACHED

    Delegate 4: On incoming call

    (void)onIncomingCall:(PlivoIncoming*)incoming;
    

    Description: This delegate is called when a call comes in to a registered endpoint.

    Parameters: Incoming object

    Return Value: None

    Delegate 5: On incoming call rejected

    (void)onIncomingCallRejected:(PlivoIncoming*)incoming;
    

    Description: This delegate is triggered when an incoming call is disconnected by the caller.

    Parameters: Incoming object

    Return Value: None

    Delegate 6: On incoming call hangup

    (void)onIncomingCallHangup:(PlivoIncoming*)incoming;
    

    Description: This delegate is triggered when an incoming call is disconnected by the caller after being answered.

    Parameters: Incoming object

    Return Value: None

    Delegate 7: On incoming digit

    (void)onIncomingDigit:(NSString*)digit;
    

    Description: This delegate is called when a digit is received on a call on an active endpoint.

    Parameters: String for DTMF digit

    Return Value: None

    Delegate 8: On incoming call answered

    (void)onIncomingCallAnswered:(PlivoIncoming*)incoming;
    

    Description: This delegate is called when an incoming call is answered and audio is ready to flow.

    Parameters: Incoming object

    Return Value: None

    Delegate 9: On incoming call invalid

    (void)onIncomingCallInvalid:(PlivoIncoming*)incoming;
    

    Description: This delegate is called when the recipient of an incoming call does not accept or reject the call in 40 seconds or the SDK is unable to establish a connection with Plivo.

    Parameters: Incoming object

    Return Value: None

    Delegate 10: On calling

    (void)onCalling:(PlivoOutgoing*)call;
    

    Description: This delegate is called when an outgoing call is initiated.

    Parameters: Outgoing object

    Return Value None

    Delegate 11: On outgoing call ringing

    (void)onOutgoingCallRinging:(PlivoOutgoing*)call;
    

    Description: This delegate is called when an outgoing call is ringing.

    Parameters: Outgoing object

    Return Value: None

    Delegate 12: On outgoing call answer

    (void)onOutgoingCallAnswered:(PlivoOutgoing*)call;
    

    Description: This delegate is called when an outgoing call is answered.

    Parameters: Outgoing object

    Return Value: None

    Delegate 13: On outgoing call rejected

    (void)onOutgoingCallRejected:(PlivoOutgoing*)call;
    

    Description: This delegate is called when an outgoing call is rejected by the called number.

    Parameters: Outgoing object

    Return Value: None

    Delegate 14: On outgoing call hangup

    (void)onOutgoingCallHangup:(PlivoOutgoing*)call;
    

    Description: This delegate is called when an outgoing call is disconnected by the called number after the call was answered.

    Parameters: Outgoing object

    Return Value: None

    Delegate 15: On outgoing call invalid

    (void)onOutgoingCallInvalid:(PlivoOutgoing*)call;
    

    Description: This delegate is called when an outgoing call is made to an incorrect number/Endpoint.

    Parameters: Outgoing object

    Return Value: None

    Delegate 16: On logout

    (void)onLogout:;
    

    Description: This delegate is called when the user logs out.

    Parameters: None

    Return Value: None

    Delegate 17: MediaMetrics

    Description: This delegate is called if any of the below events are triggered on an ongoing call.

    Parameters: MediaMetrics object

    Return Value: None

    EventsDescriptionExample
    high_jitterWhen jitter is higher than 30 milliseconds for two out of the last three samples.

    This event is generated individually for the local stream and remote stream.

    { group: 'network', level: 'warning', type: 'high_jitter', active: true/false, // false when the value goes to normal level (last 2 out of 3 samples have jitter less than 30 ms) value: '<average jitter value>', desc: 'high jitter detected due to network congestion, can result in audio quality problems', stream: 'local || remote' }
    high_rttWhen round-trip time (RTT) is higher than 400 milliseconds for two out of the last three samples.{ group: 'network', level: 'warning', type: 'high_rtt', active: true/false, // false when value goes to normal level (last 2 out of 3 samples have RTT less than 400 ms) value: '<average rtt value>', desc: 'high latency detected, can result in delay in audio', stream: 'None' }
    high_packetlossWhen packet loss is > 10%.

    This event is generated individually for the local stream and remote stream.

    { group: 'network', level: 'warning', type: 'high_packetloss', active: true/false, // false when value goes to normal level value: '<average packet loss value>', desc: 'high packet loss is detected on media stream, can result in choppy audio or dropped call', stream: 'local || remote' }
    low_mosWhen sampled mean opinion score (MOS) is < 3.5 for two out of the last three samples.{ group: 'network', level: 'warning', type: 'low_mos', active: true/false, // false when value goes to normal level. value: '<current_mos_value>', desc: 'low mean opinion score (MOS)', stream: 'None' }
    no_audio_receivedWhen remote or local audio is silent.

    This event is generated individually for the local stream and remote stream.

    { group: 'audio', level: 'warning', type: 'no_audio_received', active: true/false, // false when value goes to normal level value: '<current_value_in_dB>', desc: 'no audio packets received' stream: 'local || remote' }

    Receiving incoming SIP headers

    You can receive custom SIP headers on an incoming call as a part of the PlivoIncoming object on the onIncomingCall delegate. For example:

    (void)onIncomingCall:(PlivoIncoming*)incoming {
        if ([incoming.extraHeaders count] > 0) {
            NSLog(@_"-- Incoming call extra headers --"_);
            for (NSString *key in incoming.extraHeaders) {
                NSString *value = [incoming.extraHeaders objectForKey:key];
                NSLog(@_"%@ => %@"_, key, value);
            }
        }
    
        *// Answer the call here.*
    }
    

    Resetting an endpoint

    To manually reset endpoints and disable their WebSocket transport, use the resetEndpoint method.

    [PlivoEndpoint resetEndpoint]; self.endpoint = [[PlivoEndpoint alloc] init];

    Be sure to initialize the endpoint after reset, as shown above, or WebSocket transport will not be reinitialized and your application will not be able to communicate with Plivo servers.

    Methods supporting PushKit and CallKit in PlivoEndpoint

    APIs for PushKit integration

    Method 1: Register token

    Use this method to register the device token for VoIP push notifications.

    (void)registerToken:(NSData*)token;
    

    Method 2: Relay VoIP push notification

    pushInfo is the NSDictionary object forwarded by the Apple push notification.

    (void)relayVoipPushNotification:(NSDictionary *)pushInfo;
    
    usage
    func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, forType type: PKPushType) {
        Phone.sharedInstance.relayVoipPushNotification(payload.dictionaryPayload) payload.dictionaryPayload contains below info: {
            alert = _"plivo"_;
            callid = _"ABC-456-DEF-789-GHI"_;
            sound = default;
        }
    
        Pass the payload.dictionaryPayload to relayVoipPushNotification API and then you will receive incoming calls the same way.
    }
    

    APIs for CallKit integration

    These three APIs are required for Apple CallKit integration.

    Method 1: Configure audio session

    This method configures an audio session before a call.

    (void)configureAudioSession
    

    Method 2: Start audio device

    Depending on the call status (Hold or Active) you can start or stop processing the call’s audio. Use this method to signal the SDK to start audio I/O units when you receive an audio activation callback from CallKit.

    (void)startAudioDevice
    

    Method 3: Stop audio device

    Depending on the call status (Hold) you can start or stop processing the call’s audio. Use this method to signal the SDK to stop audio I/O units when you receive deactivation or reset callbacks from CallKit.

    (void)stopAudioDevice
    
    usage
    To configure audio
    func configureAudioSession() {
        endpoint.configureAudioDevice()
    }
    

    Start the Audio service to handle audio interruptions. Use AVAudioSessionInterruptionTypeBegan and AVAudioSessionInterruptionTypeEnded.

    func startAudioDevice() {
        endpoint.startAudioDevice()
    }
    func stopAudioDevice() {
        endpoint.stopAudioDevice()
    }
    
    To turn on speakers
    do {
        try audioSession.overrideOutputAudioPort(AVAudioSessionPortOverride.speaker)
    }
    catch let error as NSError {
        print(_"audioSession error: \(error.localizedDescription)"_)
    }
    
    To turn off speakers

    set AVAudioSessionPortOverride:none