opentok / CallKit

A sample app to demonstrate how to integrate Apple CallKit into OpenTok iOS SDK
MIT License
110 stars 24 forks source link

Speaker automatically selected on callkit #14

Open mrazam110 opened 6 years ago

mrazam110 commented 6 years ago

If it is an audio call then it should use iPhone's built-in receiver (output).

How to make it possible?

https://stackoverflow.com/questions/50502518/issue-with-opentok-and-callkit

Lucashuang0802 commented 6 years ago

@mrazam110 thanks for this concise report. We'll work on that change.

alexbaramilis commented 5 years ago

Hi, any updates on this?

thehavre commented 5 years ago

Hello, everyone :)

If you are using this example in your app and experiencing issue with speakerphone instead of headset, you need to do some changes in the custom audio driver - OTDefaultAudioDevice.

  1. Remove from audio session setup - setupAudioSession and setupAudioSession:(AVAudioSession *)audioSession setting of default speaker option:

    audioOptions |= AVAudioSessionCategoryOptionDefaultToSpeaker;
  2. In same session setup methods change audio session mode from Video

    [mySession setMode:AVAudioSessionModeVideoChat error:nil];

    to Voice

    [mySession setMode:AVAudioSessionModeVoiceChat error:nil];
  3. If you need to turn on headset by default (after previous steps it should be chosen by default, but if not...) you can force set it manually by calling

    [self configureAudioSessionWithDesiredAudioRoute:AUDIO_DEVICE_HEADSET];

    You can do this also in the setupAudioSession or before creation and connection to the OpenTok session.

Here is how setupAudioSession looks like after changes:

- (void) setupAudioSession
{
    AVAudioSession *mySession = [AVAudioSession sharedInstance];
    _previousAVAudioSessionCategory = mySession.category;
    avAudioSessionMode = mySession.mode;
    avAudioSessionPreffSampleRate = mySession.preferredSampleRate;
    avAudioSessionChannels = mySession.inputNumberOfChannels;

    [mySession setPreferredSampleRate: kSampleRate error: nil];
    [mySession setPreferredInputNumberOfChannels:1 error:nil];
    [mySession setPreferredIOBufferDuration:kPreferredIOBufferDuration
                                      error:nil];

    NSError *error = nil;
    NSUInteger audioOptions = 0;
#if !(TARGET_OS_TV)
    audioOptions |= AVAudioSessionCategoryOptionAllowBluetooth ;
    [mySession setCategory:AVAudioSessionCategoryPlayAndRecord
               withOptions:audioOptions
                     error:&error];
#else
    [mySession setCategory:AVAudioSessionCategoryPlayback
               withOptions:audioOptions
                     error:&error];
#endif

    [mySession setMode:AVAudioSessionModeVoiceChat error:nil];

    if (error)
        OT_AUDIO_DEBUG(@"Audiosession setCategory %@",error);

    error = nil;

    [self setupListenerBlocks];
    [self configureAudioSessionWithDesiredAudioRoute:AUDIO_DEVICE_HEADSET];
    [mySession setActive:YES error:&error];

    if (error)
        OT_AUDIO_DEBUG(@"Audiosession setActive %@",error);

}
  1. Don't forget to pre-heat audio session before starting CallKit's AudioSession as TokBox provided in example - in CXStartCallAction and CXAnswerCallAction

Minor explanation why it's all happening with us :)

  1. When Audio Session configured with AVAudioSessionCategoryOptionDefaultToSpeaker it's obviously uses speaker by default :)
  2. When you choose AVAudioSessionModeVideoChat mode, session obviously (for Apple :D) uses speaker by default and you can't switch because... it's Apple's logic, I suppose.
  3. And if session is configured with AVAudioSessionModeVoiceChat mode, iOS and CallKit behaves as voice call with ability yo switch between speakers (and also turning screen off when user brings phone to ear).

BTW, from Apples documentation:

/* Only valid with kAudioSessionCategory_PlayAndRecord. Reduces the number of allowable audio
routes to be only those that are appropriate for video chat applications. May engage appropriate
system-supplied signal processing.  **Has the side effect of setting
AVAudioSessionCategoryOptionAllowBluetooth and AVAudioSessionCategoryOptionDefaultToSpeaker.** */
AVF_EXPORT AVAudioSessionMode const AVAudioSessionModeVideoChat API_AVAILABLE(ios(7.0), watchos(2.0), tvos(9.0)) API_UNAVAILABLE(macos);

And also, from documentation, Apple suggests to use AVAudioSessionModeVoiceChat for both audio and video calls.