Проблема CallKit с динамиком, который автоматически включается после получения звонка

Я использую CallKit с TokBox и кое как работает с одним багом, т.е. после приема звонка динамик становится активным и его нельзя отключить тапом по нему. Вызов начинается с активного динамика, что я считаю ошибкой, но WhatsApp и FBMassenger использовали то же самое со своим пользовательским просмотром экрана вызова, но их динамик становится неактивным после получения звонка, который я искал, и я не нашел соответствующего ответа, поэтому далеко.

В TokBox они предоставили файлы OTDefaultAudioDevice.h и OTDefaultAudioDevice.m, из которых они настроили все, что касается звука, с помощью CallKitSpeakerBox. Где я нашел следующую конфигурацию:

#define AUDIO_DEVICE_HEADSET     @"AudioSessionManagerDevice_Headset"
#define AUDIO_DEVICE_BLUETOOTH   @"AudioSessionManagerDevice_Bluetooth"
#define AUDIO_DEVICE_SPEAKER     @"AudioSessionManagerDevice_Speaker"

Который использовался следующим образом:

- (BOOL)configureAudioSessionWithDesiredAudioRoute:(NSString*)desiredAudioRoute
{
    OT_AUDIO_DEBUG(@"configureAudioSessionWithDesiredAudioRoute %@",desiredAudioRoute);

    AVAudioSession *audioSession = [AVAudioSession sharedInstance];
    NSError *err;

    //ios 8.0 complains about Deactivating an audio session that has running
    // I/O. All I/O should be stopped or paused prior to deactivating the audio
    // session. Looks like we can get away by not using the setActive call
    if (SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO(@"7.0")) {
        // close down our current session...
        [audioSession setActive:NO error:nil];
    }

    if ([AUDIO_DEVICE_BLUETOOTH isEqualToString:desiredAudioRoute]) {
        [self setBluetoothAsPrefferedInputDevice];
    }

    if (SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO(@"7.0")) {
        // Set our session to active...
        if (![audioSession setActive:YES error:&err]) {
            NSLog(@"unable to set audio session active: %@", err);
            return NO;
        }
    }

    if ([AUDIO_DEVICE_SPEAKER isEqualToString:desiredAudioRoute]) {
        // replace AudiosessionSetProperty (deprecated from iOS7) with
        // AVAudioSession overrideOutputAudioPort
#if !(TARGET_OS_TV)
        [audioSession overrideOutputAudioPort:AVAudioSessionPortOverrideSpeaker
                                        error:&err];
#endif
    } else
    {
        [audioSession overrideOutputAudioPort:AVAudioSessionPortOverrideNone
                                        error:&err];
    }

    return YES;
}

Где AVAudioSessionPortOverrideSpeaker используется для всех устройств, что, я считаю, является основной причиной включения динамика, хотя я точно не знаю. то есть

if ([AUDIO_DEVICE_SPEAKER isEqualToString:desiredAudioRoute]) {
            // replace AudiosessionSetProperty (deprecated from iOS7) with
            // AVAudioSession overrideOutputAudioPort
    #if !(TARGET_OS_TV)
            [audioSession overrideOutputAudioPort:AVAudioSessionPortOverrideSpeaker
                                            error:&err];
    #endif
        } else
        {
            [audioSession overrideOutputAudioPort:AVAudioSessionPortOverrideNone
                                            error:&err];
        }
}

Есть ли у кого-нибудь какие-либо предложения или кто-нибудь здесь, кто уже исправил это состояние?

Я также считаю, что многие, как и я, проходят через эту проблему.

Любая помощь будет ощутима.

Спасибо


person Abhishek Mitra    schedule 02.05.2018    source источник
comment
Если я правильно понял ваш вопрос, вы пытаетесь отключить звук при приеме вызова. Если это так, разве это не здравый смысл, что динамик должен быть активирован, как только вы принимаете вызов? Если пользователи не готовы, они не примут это. Что вы думаете? @Абхишек Митра   -  person Lucas Huang    schedule 04.05.2018
comment
@LucasHuang Спасибо за ответ. Я столкнулся с тем, что когда получатель получает вызов, динамик становится активным (в громком режиме), и, нажав на него, он не отключается для ушей. При приеме вызова динамик не должен быть громкоговорителем.   -  person Abhishek Mitra    schedule 07.05.2018
comment
Когда вы говорите о динамике, вы имеете в виду физического динамика? Итак, вы не можете отключить звук, нажав кнопку отключения звука на динамике? Я тоже не понимаю, что вы имеете в виду под громким режимом. Можете ли вы рассказать об этом подробнее?   -  person Lucas Huang    schedule 09.05.2018
comment
@LucasHuang Спасибо за интерес к моей проблеме, я собираюсь опубликовать скриншот, надеюсь, вы получите его сейчас. ссылка на изображение: ibb.co/nnX91J   -  person Abhishek Mitra    schedule 10.05.2018
comment
@AbhishekMitra, вы нашли решение этой проблемы? У меня такая же проблема   -  person stan    schedule 21.05.2018
comment
@stan да, я пытаюсь решить эту проблему .. Я забыл опубликовать ответ. Я сделаю это к завтрашнему дню... и отмечу тебя... сейчас я не перед маком. Спасибо.   -  person Abhishek Mitra    schedule 21.05.2018
comment
@AbhishekMitra спасибо за быстрый ответ, жду вашего решения   -  person stan    schedule 22.05.2018
comment
@stan Привет, я добавил ответ, пройди его. Надеюсь, это поможет вам. Спасибо.   -  person Abhishek Mitra    schedule 22.05.2018


Ответы (2)


Я обратился в службу поддержки opentok, и они серьезно отнеслись к этой проблеме, и, поскольку сервис был создан только для видеочата, по этой причине они включили этот динамик в пользовательском интерфейсе CallKit. Чтобы отключить его или использовать только для аудиовызова, используя их класс Objective C, а именно OTDefaultAudioDevice.h и OTDefaultAudioDevice.m, мы должны прокомментировать следующую строку в файле .m.

audioOptions |= AVAudioSessionCategoryOptionDefaultToSpeaker;

Надеюсь, это спасет день многих.

Спасибо.

person Abhishek Mitra    schedule 22.05.2018
comment
Спасибо большое, через пару часов проверю и отпишусь как получилось - person stan; 22.05.2018
comment
Теперь на одном из устройств все в порядке, а на другом все еще в динамике, может быть, что-то с устройством, я все равно оценю ваш ответ, так как он немного помог :) - person stan; 22.05.2018
comment
У приемника должен быть отключен динамик, а насчет звонящего я не знаю. что ты получаешь для кого? @стан - person Abhishek Mitra; 22.05.2018
comment
Кажется, это происходит на том же устройстве ref: включен громкоговоритель. Независимо от того, звонит или принимает - person stan; 22.05.2018
comment
@stan, предположим, у меня есть два устройства, а именно устройство A и устройство B. Если я звоню с устройства A на устройство B, пользовательский интерфейс CallKit устройства B не будет отображать включенный динамик, если он находится только в аудиочате. Я не знаю об устройстве А., потому что я сделал свое приложение для видеозвонка. но до этого я проверял, и это работало. - person Abhishek Mitra; 22.05.2018
comment
Я буду продолжать пробовать и отпишусь здесь, если какой-либо результат. Большое спасибо - person stan; 22.05.2018

Наконец мне удалось решить проблему. Решение было смесью @AbhishekMitra и того, что я нашел сам

Сначала я заменил класс Objective C OTDefaultAudioDevice на DefaultAudioDevice.swift, найденный здесь: https://github.com/opentok/opentok-ios-sdk-samples-swift/blob/master/Custom-Audio-Driver/Custom-Audio-Driver/DefaultAudioDevice.swift

который эквивалентен objc, закомментируйте строку, предложенную Абхишеком, и добавьте еще одну строку в ту же функцию, а именно:

configureAudioSessionWithDesiredAudioRoute(desiredAudioRoute: DefaultAudioDevice.kAudioDeviceHeadset)

вот и вся функция

fileprivate func setupAudioSession() {
        let session = AVAudioSession.sharedInstance()
        
        previousAVAudioSessionCategory = session.category
        avAudioSessionMode = session.mode
        avAudioSessionPreffSampleRate = session.preferredSampleRate
        avAudioSessionChannels = session.inputNumberOfChannels
        do {
            try session.setPreferredSampleRate(Double(DefaultAudioDevice.kSampleRate))
            try session.setPreferredIOBufferDuration(0.01)
            let audioOptions = AVAudioSessionCategoryOptions.mixWithOthers.rawValue |
                AVAudioSessionCategoryOptions.allowBluetooth.rawValue
                //|
                //AVAudioSessionCategoryOptions.defaultToSpeaker.rawValue
            try session.setCategory(AVAudioSessionCategoryPlayAndRecord, mode: AVAudioSessionModeVideoChat, options: AVAudioSessionCategoryOptions(rawValue: audioOptions))
            setupListenerBlocks()
            //set the audio to headset
            configureAudioSessionWithDesiredAudioRoute(desiredAudioRoute: DefaultAudioDevice.kAudioDeviceHeadset)
            
            try session.setActive(true)
        } catch let err as NSError {
            print("Error setting up audio session \(err)")
        } catch {
            print("Error setting up audio session")
        }
    }

Это, наконец, решило мою проблему, и устройства не включали громкоговоритель, когда вызов активен. Дайте знать, если у вас появятся вопросы.

Версия objc этой строки будет:

[self configureAudioSessionWithDesiredAudioRoute:
                 AUDIO_DEVICE_HEADSET];

person stan    schedule 23.05.2018
comment
Отличная работа, Стэн, я обязательно воспользуюсь вашим кодом, когда он мне понадобится, и ваш ответ заслуживает голосования. - person Abhishek Mitra; 23.05.2018