"Fossies" - the Fresh Open Source Software Archive

Member "jitsi-meet-4433/ios/sdk/src/callkit/CallKit.m" (25 Sep 2020, 11928 Bytes) of package /linux/misc/jitsi-meet-4433.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Matlab source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file.

    1 //
    2 // Based on RNCallKit
    3 //
    4 // Original license:
    5 //
    6 // Copyright (c) 2016, Ian Yu-Hsun Lin
    7 //
    8 // Permission to use, copy, modify, and/or distribute this software for any
    9 // purpose with or without fee is hereby granted, provided that the above
   10 // copyright notice and this permission notice appear in all copies.
   11 //
   12 // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   13 // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
   14 // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
   15 // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
   16 // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
   17 // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
   18 // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   19 //
   20 
   21 #import <AVFoundation/AVFoundation.h>
   22 #import <CallKit/CallKit.h>
   23 #import <Foundation/Foundation.h>
   24 #import <UIKit/UIKit.h>
   25 
   26 #import <React/RCTBridge.h>
   27 #import <React/RCTEventEmitter.h>
   28 #import <React/RCTUtils.h>
   29 #import <WebRTC/WebRTC.h>
   30 
   31 #import <JitsiMeet/JitsiMeet-Swift.h>
   32 
   33 #import "LogUtils.h"
   34 
   35 
   36 // The events emitted/supported by RNCallKit:
   37 static NSString * const RNCallKitPerformAnswerCallAction
   38     = @"performAnswerCallAction";
   39 static NSString * const RNCallKitPerformEndCallAction
   40     = @"performEndCallAction";
   41 static NSString * const RNCallKitPerformSetMutedCallAction
   42     = @"performSetMutedCallAction";
   43 static NSString * const RNCallKitProviderDidReset
   44     = @"providerDidReset";
   45 
   46 @interface RNCallKit : RCTEventEmitter <JMCallKitListener>
   47 @end
   48 
   49 @implementation RNCallKit
   50 
   51 RCT_EXPORT_MODULE();
   52 
   53 - (NSArray<NSString *> *)supportedEvents {
   54     return @[
   55         RNCallKitPerformAnswerCallAction,
   56         RNCallKitPerformEndCallAction,
   57         RNCallKitPerformSetMutedCallAction,
   58         RNCallKitProviderDidReset
   59     ];
   60 }
   61 
   62 - (void)dealloc {
   63     [JMCallKitProxy removeListener:self];
   64 }
   65 
   66 - (dispatch_queue_t)methodQueue {
   67     // Make sure all our methods run in the main thread.
   68     return dispatch_get_main_queue();
   69 }
   70 
   71 // End call
   72 RCT_EXPORT_METHOD(endCall:(NSString *)callUUID
   73                   resolve:(RCTPromiseResolveBlock)resolve
   74                    reject:(RCTPromiseRejectBlock)reject) {
   75     DDLogInfo(@"[RNCallKit][endCall] callUUID = %@", callUUID);
   76 
   77     NSUUID *callUUID_ = [[NSUUID alloc] initWithUUIDString:callUUID];
   78 
   79     if (!callUUID_) {
   80         reject(nil, [NSString stringWithFormat:@"Invalid UUID: %@", callUUID], nil);
   81         return;
   82     }
   83 
   84     CXEndCallAction *action
   85         = [[CXEndCallAction alloc] initWithCallUUID:callUUID_];
   86     [self requestTransaction:[[CXTransaction alloc] initWithAction:action]
   87                      resolve:resolve
   88                       reject:reject];
   89 }
   90 
   91 // Mute / unmute (audio)
   92 RCT_EXPORT_METHOD(setMuted:(NSString *)callUUID
   93                      muted:(BOOL)muted
   94                    resolve:(RCTPromiseResolveBlock)resolve
   95                     reject:(RCTPromiseRejectBlock)reject) {
   96     DDLogInfo(@"[RNCallKit][setMuted] callUUID = %@", callUUID);
   97 
   98     NSUUID *callUUID_ = [[NSUUID alloc] initWithUUIDString:callUUID];
   99 
  100     if (!callUUID_) {
  101         reject(nil, [NSString stringWithFormat:@"Invalid UUID: %@", callUUID], nil);
  102         return;
  103     }
  104 
  105     CXSetMutedCallAction *action
  106         = [[CXSetMutedCallAction alloc] initWithCallUUID:callUUID_ muted:muted];
  107     [self requestTransaction:[[CXTransaction alloc] initWithAction:action]
  108                      resolve:resolve
  109                       reject:reject];
  110 }
  111 
  112 RCT_EXPORT_METHOD(setProviderConfiguration:(NSDictionary *)dictionary) {
  113     DDLogInfo(@"[RNCallKit][setProviderConfiguration:] dictionary = %@", dictionary);
  114 
  115     if (![JMCallKitProxy isProviderConfigured]) {
  116         [self configureProviderFromDictionary:dictionary];
  117     }
  118 
  119     // register to receive CallKit proxy events
  120     [JMCallKitProxy addListener:self];
  121 }
  122 
  123 // Start outgoing call
  124 RCT_EXPORT_METHOD(startCall:(NSString *)callUUID
  125                      handle:(NSString *)handle
  126                       video:(BOOL)video
  127                     resolve:(RCTPromiseResolveBlock)resolve
  128                      reject:(RCTPromiseRejectBlock)reject) {
  129     DDLogInfo(@"[RNCallKit][startCall] callUUID = %@", callUUID);
  130 
  131     NSUUID *callUUID_ = [[NSUUID alloc] initWithUUIDString:callUUID];
  132 
  133     if (!callUUID_) {
  134         reject(nil, [NSString stringWithFormat:@"Invalid UUID: %@", callUUID], nil);
  135         return;
  136     }
  137 
  138     // Don't start a new call if there's an active call for the specified
  139     // callUUID. JitsiMeetView was configured for an incoming call.
  140     if ([JMCallKitProxy hasActiveCallForUUID:callUUID]) {
  141         resolve(nil);
  142         return;
  143     }
  144 
  145     CXHandle *handle_
  146         = [[CXHandle alloc] initWithType:CXHandleTypeGeneric value:handle];
  147     CXStartCallAction *action
  148         = [[CXStartCallAction alloc] initWithCallUUID:callUUID_
  149                                                handle:handle_];
  150     action.video = video;
  151     CXTransaction *transaction = [[CXTransaction alloc] initWithAction:action];
  152     [self requestTransaction:transaction resolve:resolve reject:reject];
  153 }
  154 
  155 // Indicate call failed
  156 RCT_EXPORT_METHOD(reportCallFailed:(NSString *)callUUID
  157                            resolve:(RCTPromiseResolveBlock)resolve
  158                             reject:(RCTPromiseRejectBlock)reject) {
  159     NSUUID *callUUID_ = [[NSUUID alloc] initWithUUIDString:callUUID];
  160 
  161     if (!callUUID_) {
  162         reject(nil, [NSString stringWithFormat:@"Invalid UUID: %@", callUUID], nil);
  163         return;
  164     }
  165 
  166     [JMCallKitProxy reportCallWith:callUUID_
  167                            endedAt:nil
  168                             reason:CXCallEndedReasonFailed];
  169     resolve(nil);
  170 }
  171 
  172 // Indicate outgoing call connected.
  173 RCT_EXPORT_METHOD(reportConnectedOutgoingCall:(NSString *)callUUID
  174                                       resolve:(RCTPromiseResolveBlock)resolve
  175                                        reject:(RCTPromiseRejectBlock)reject) {
  176     NSUUID *callUUID_ = [[NSUUID alloc] initWithUUIDString:callUUID];
  177 
  178     if (!callUUID_) {
  179         reject(nil, [NSString stringWithFormat:@"Invalid UUID: %@", callUUID], nil);
  180         return;
  181     }
  182 
  183     [JMCallKitProxy reportOutgoingCallWith:callUUID_
  184                                connectedAt:nil];
  185     resolve(nil);
  186 }
  187 
  188 // Update call in case we have a display name or video capability changes.
  189 RCT_EXPORT_METHOD(updateCall:(NSString *)callUUID
  190                      options:(NSDictionary *)options
  191                      resolve:(RCTPromiseResolveBlock)resolve
  192                       reject:(RCTPromiseRejectBlock)reject) {
  193     DDLogInfo(@"[RNCallKit][updateCall] callUUID = %@ options = %@", callUUID, options);
  194 
  195     NSUUID *callUUID_ = [[NSUUID alloc] initWithUUIDString:callUUID];
  196 
  197     if (!callUUID_) {
  198         reject(nil, [NSString stringWithFormat:@"Invalid UUID: %@", callUUID], nil);
  199         return;
  200     }
  201 
  202     NSString *displayName = options[@"displayName"];
  203     BOOL hasVideo = [(NSNumber*)options[@"hasVideo"] boolValue];
  204 
  205     [JMCallKitProxy reportCallUpdateWith:callUUID_
  206                                   handle:nil
  207                              displayName:displayName
  208                                 hasVideo:hasVideo];
  209 
  210     resolve(nil);
  211 }
  212 
  213 #pragma mark - Helper methods
  214 
  215 - (void)configureProviderFromDictionary:(NSDictionary* )dictionary {
  216     DDLogInfo(@"[RNCallKit][providerConfigurationFromDictionary: %@]", dictionary);
  217 
  218     if (!dictionary) {
  219         dictionary = @{};
  220     }
  221 
  222     // localizedName
  223     NSString *localizedName = dictionary[@"localizedName"];
  224     if (!localizedName) {
  225         localizedName
  226             = [[NSBundle mainBundle] infoDictionary][@"CFBundleDisplayName"];
  227     }
  228 
  229     // iconTemplateImageData
  230     NSString *iconTemplateImageName = dictionary[@"iconTemplateImageName"];
  231     NSData *iconTemplateImageData;
  232     UIImage *iconTemplateImage;
  233     if (iconTemplateImageName) {
  234         // First try to load the resource from the main bundle.
  235         iconTemplateImage = [UIImage imageNamed:iconTemplateImageName];
  236 
  237         // If that didn't work, use the one built-in.
  238         if (!iconTemplateImage) {
  239             iconTemplateImage = [UIImage imageNamed:iconTemplateImageName
  240                                            inBundle:[NSBundle bundleForClass:self.class]
  241                       compatibleWithTraitCollection:nil];
  242         }
  243 
  244         if (iconTemplateImage) {
  245             iconTemplateImageData = UIImagePNGRepresentation(iconTemplateImage);
  246         }
  247     }
  248 
  249     NSString *ringtoneSound = dictionary[@"ringtoneSound"];
  250 
  251     [JMCallKitProxy
  252         configureProviderWithLocalizedName:localizedName
  253                              ringtoneSound:ringtoneSound
  254                      iconTemplateImageData:iconTemplateImageData];
  255 }
  256 
  257 - (void)requestTransaction:(CXTransaction *)transaction
  258                    resolve:(RCTPromiseResolveBlock)resolve
  259                     reject:(RCTPromiseRejectBlock)reject {
  260     DDLogInfo(@"[RNCallKit][requestTransaction] transaction = %@", transaction);
  261 
  262     [JMCallKitProxy request:transaction
  263                  completion:^(NSError * _Nullable error) {
  264         if (error) {
  265             DDLogError(@"[RNCallKit][requestTransaction] Error requesting transaction (%@): (%@)", transaction.actions, error);
  266             reject(nil, @"Error processing CallKit transaction", error);
  267         } else {
  268             resolve(nil);
  269         }
  270     }];
  271 }
  272 
  273 #pragma mark - JMCallKitListener
  274 
  275 // Called when the provider has been reset. We should terminate all calls.
  276 - (void)providerDidReset {
  277     DDLogInfo(@"[RNCallKit][CXProviderDelegate][providerDidReset:]");
  278 
  279     [self sendEventWithName:RNCallKitProviderDidReset body:nil];
  280 }
  281 
  282 // Answering incoming call
  283 - (void) performAnswerCallWithUUID:(NSUUID *)UUID {
  284     DDLogInfo(@"[RNCallKit][CXProviderDelegate][provider:performAnswerCallAction:]");
  285 
  286     [self sendEventWithName:RNCallKitPerformAnswerCallAction
  287                        body:@{ @"callUUID": UUID.UUIDString }];
  288 }
  289 
  290 // Call ended, user request
  291 - (void) performEndCallWithUUID:(NSUUID *)UUID {
  292     DDLogInfo(@"[RNCallKit][CXProviderDelegate][provider:performEndCallAction:]");
  293 
  294     [self sendEventWithName:RNCallKitPerformEndCallAction
  295                        body:@{ @"callUUID": UUID.UUIDString }];
  296 }
  297 
  298 // Handle audio mute from CallKit view
  299 - (void) performSetMutedCallWithUUID:(NSUUID *)UUID
  300                              isMuted:(BOOL)isMuted {
  301     DDLogInfo(@"[RNCallKit][CXProviderDelegate][provider:performSetMutedCallAction:]");
  302 
  303     [self sendEventWithName:RNCallKitPerformSetMutedCallAction
  304                        body:@{
  305                            @"callUUID": UUID.UUIDString,
  306                            @"muted": @(isMuted)
  307                        }];
  308 }
  309 
  310 // Starting outgoing call
  311 - (void) performStartCallWithUUID:(NSUUID *)UUID
  312                           isVideo:(BOOL)isVideo {
  313     DDLogInfo(@"[RNCallKit][CXProviderDelegate][provider:performStartCallAction:]");
  314 
  315     [JMCallKitProxy reportOutgoingCallWith:UUID
  316                        startedConnectingAt:nil];
  317 }
  318 
  319 - (void) providerDidActivateAudioSessionWithSession:(AVAudioSession *)session {
  320     DDLogInfo(@"[RNCallKit][CXProviderDelegate][provider:didActivateAudioSession:]");
  321 
  322     [[RTCAudioSession sharedInstance] audioSessionDidActivate:session];
  323 }
  324 
  325 - (void) providerDidDeactivateAudioSessionWithSession:(AVAudioSession *)session {
  326     DDLogInfo(@"[RNCallKit][CXProviderDelegate][provider:didDeactivateAudioSession:]");
  327 
  328     [[RTCAudioSession sharedInstance] audioSessionDidDeactivate:session];
  329 }
  330 
  331 - (void) providerTimedOutPerformingActionWithAction:(CXAction *)action {
  332     DDLogWarn(@"[RNCallKit][CXProviderDelegate][provider:timedOutPerformingAction:]");
  333 }
  334 
  335 
  336 // The bridge might already be invalidated by the time a CallKit event is processed,
  337 // just ignore it and don't emit it.
  338 - (void)sendEventWithName:(NSString *)name body:(id)body {
  339     if (!self.bridge) {
  340         return;
  341     }
  342 
  343     [super sendEventWithName:name body:body];
  344 }
  345 
  346 @end