From 0cba24edc969241dceee2ac2ea2817ceefe6d927 Mon Sep 17 00:00:00 2001 From: mathias5r Date: Tue, 6 Jul 2021 11:57:19 -0300 Subject: [PATCH] change to promise and add audio device change support to android --- .../io/wazo/callkeep/RNCallKeepModule.java | 72 +++++++++++++++++++ index.d.ts | 11 +-- index.js | 4 +- ios/RNCallKeep/RNCallKeep.m | 43 +++++++++-- 4 files changed, 112 insertions(+), 18 deletions(-) diff --git a/android/src/main/java/io/wazo/callkeep/RNCallKeepModule.java b/android/src/main/java/io/wazo/callkeep/RNCallKeepModule.java index a23f62d7..1226d71c 100644 --- a/android/src/main/java/io/wazo/callkeep/RNCallKeepModule.java +++ b/android/src/main/java/io/wazo/callkeep/RNCallKeepModule.java @@ -29,6 +29,8 @@ import android.content.res.Resources; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Icon; +import android.media.AudioDeviceInfo; +import android.media.AudioManager; import android.net.Uri; import android.os.Build; import android.os.Bundle; @@ -491,6 +493,76 @@ public void toggleAudioRouteSpeaker(String uuid, boolean routeSpeaker) { } } + @ReactMethod + public void setAudioRoute(String uuid, String audioRoute, Promise promise){ + try { + VoiceConnection conn = (VoiceConnection) VoiceConnectionService.getConnection(uuid); + if (conn == null) { + return; + } + if(audioRoute.equals("Bluetooth")) { + conn.setAudioRoute(CallAudioState.ROUTE_BLUETOOTH); + promise.resolve("Successfully set bluetooth route"); + return; + } + if(audioRoute.equals("Headset")) { + conn.setAudioRoute(CallAudioState.ROUTE_WIRED_HEADSET); + promise.resolve("Successfully set headset route"); + return; + } + if(audioRoute.equals("Speaker")) { + conn.setAudioRoute(CallAudioState.ROUTE_SPEAKER); + promise.resolve("Successfully set speaker route"); + return; + } + conn.setAudioRoute(CallAudioState.ROUTE_WIRED_OR_EARPIECE); + promise.resolve("Successfully set phone route"); + } catch (Exception e) { + promise.reject("SetAudioRoute", e.getMessage()); + } + } + + @ReactMethod + public void getAudioRoutes(Promise promise){ + try { + Context context = this.getAppContext(); + AudioManager audioManager = (AudioManager) context.getSystemService(context.AUDIO_SERVICE); + WritableArray devices = Arguments.createArray(); + ArrayList typeChecker = new ArrayList<>(); + AudioDeviceInfo[] audioDeviceInfo = audioManager.getDevices(AudioManager.GET_DEVICES_INPUTS + AudioManager.GET_DEVICES_OUTPUTS); + for (AudioDeviceInfo device : audioDeviceInfo){ + String type = getAudioRouteType(device.getType()); + if(type != null && !typeChecker.contains(type)) { + WritableMap deviceInfo = Arguments.createMap(); + deviceInfo.putString("name", type); + deviceInfo.putString("type", type); + typeChecker.add(type); + devices.pushMap(deviceInfo); + } + } + promise.resolve(devices); + } catch(Exception e) { + promise.reject("GetAudioRoutes Error", e.getMessage()); + } + } + + private String getAudioRouteType(int type){ + switch (type){ + case(AudioDeviceInfo.TYPE_BLUETOOTH_A2DP): + case(AudioDeviceInfo.TYPE_BLUETOOTH_SCO): + return "Bluetooth"; + case(AudioDeviceInfo.TYPE_WIRED_HEADPHONES): + case(AudioDeviceInfo.TYPE_WIRED_HEADSET): + return "Headset"; + case(AudioDeviceInfo.TYPE_BUILTIN_MIC): + return "Phone"; + case(AudioDeviceInfo.TYPE_BUILTIN_SPEAKER): + return "Speaker"; + default: + return null; + } + } + @ReactMethod public void sendDTMF(String uuid, String key) { Log.d(TAG, "[VoiceConnection] sendDTMF, uuid: " + uuid + ", key: " + key); diff --git a/index.d.ts b/index.d.ts index 03f3e813..736ee0b9 100644 --- a/index.d.ts +++ b/index.d.ts @@ -138,16 +138,9 @@ declare module 'react-native-callkeep' { static getCalls(): Promise - static getAudioRoutes( - errorCallback: (error: any) => void, - successCallback: (data: any) => void - ): void + static getAudioRoutes(): Promise - static setAudioRoute: ( - inputName: string, - errorCallback: (error: any) => void, - successCallback: (data: any) => void - ) => void + static setAudioRoute: (uuid:string, inputName: string) => Promise /** * @description supportConnectionService method is available only on Android. diff --git a/index.js b/index.js index bb581890..0ba70c1c 100644 --- a/index.js +++ b/index.js @@ -190,9 +190,9 @@ class RNCallKeep { */ toggleAudioRouteSpeaker = (uuid, routeSpeaker) => isIOS ? null : RNCallKeepModule.toggleAudioRouteSpeaker(uuid, routeSpeaker); - getAudioRoutes = (errorCallback, successCallback) => isIOS ? RNCallKeepModule.getAudioRoutes(errorCallback, successCallback) : null; + getAudioRoutes = () => RNCallKeepModule.getAudioRoutes(); - setAudioRoute = (inputName, errorCallback, successCallback) => isIOS ? RNCallKeepModule.setAudioRoute(inputName, errorCallback, successCallback) : null; + setAudioRoute = (uuid, inputName) => RNCallKeepModule.setAudioRoute(uuid, inputName); checkIfBusy = () => isIOS ? RNCallKeepModule.checkIfBusy() : Promise.reject('RNCallKeep.checkIfBusy was called from unsupported OS'); diff --git a/ios/RNCallKeep/RNCallKeep.m b/ios/RNCallKeep/RNCallKeep.m index bd35faa6..810381ff 100644 --- a/ios/RNCallKeep/RNCallKeep.m +++ b/ios/RNCallKeep/RNCallKeep.m @@ -398,7 +398,10 @@ + (void)setup:(NSDictionary *)options { resolve([RNCallKeep getCalls]); } -RCT_EXPORT_METHOD(setAudioRoute: (NSString *)inputName errorCallback:(RCTResponseSenderBlock)errorCallback successCallback:(RCTResponseSenderBlock)successCallback) +RCT_EXPORT_METHOD(setAudioRoute: (NSString *)uuid + inputName:(NSString *)inputName + resolver:(RCTPromiseResolveBlock)resolve + rejecter:(RCTPromiseRejectBlock)reject) { #ifdef DEBUG NSLog(@"[setAudioRoute] - inputName: %@", inputName); @@ -411,7 +414,7 @@ + (void)setup:(NSDictionary *)options { if(!isOverrided){ [NSException raise:@"overrideOutputAudioPort failed" format:@"error: %@", err]; } - successCallback(@"Speaker"); + resolve(@"Speaker"); return; } @@ -422,17 +425,18 @@ + (void)setup:(NSDictionary *)options { if(!isSetted){ [NSException raise:@"setPreferredInput failed" format:@"error: %@", err]; } - successCallback(inputName); + resolve(inputName); } } } @catch ( NSException *e ){ NSLog(@"%@",e); - errorCallback(@[e]); + reject(@"Failure to set audio route", e, nil); } } -RCT_EXPORT_METHOD(getAudioRoutes: (RCTResponseSenderBlock)errorCallback successCallback:(RCTResponseSenderBlock)successCallback) +RCT_EXPORT_METHOD(getAudioRoutes: (RCTPromiseResolveBlock)resolve + rejecter:(RCTPromiseRejectBlock)reject) { #ifdef DEBUG NSLog(@"[getAudioRoutes]"); @@ -440,11 +444,11 @@ + (void)setup:(NSDictionary *)options { @try { NSArray *inputs = [RNCallKeep getAudioInputs]; NSMutableArray *formatedInputs = [RNCallKeep formatAudioInputs: inputs]; - successCallback(@[formatedInputs]); + resolve(formatedInputs); } @catch ( NSException *e ) { NSLog(@"%@",e); - errorCallback(@[e]); + reject(@"Failure to get audio routes", e, nil); } } @@ -520,6 +524,31 @@ + (NSString *) getAudioInputType: (NSString *) type } } ++ (NSString *) getAudioInputType: (NSString *) type +{ + if ([type isEqualToString:AVAudioSessionPortBuiltInMic]){ + return @"Phone"; + } + else if ([type isEqualToString:AVAudioSessionPortHeadsetMic]){ + return @"Headset"; + } + else if ([type isEqualToString:AVAudioSessionPortHeadphones]){ + return @"Headset"; + } + else if ([type isEqualToString:AVAudioSessionPortBluetoothHFP]){ + return @"Bluetooth"; + } + else if ([type isEqualToString:AVAudioSessionPortBluetoothA2DP]){ + return @"Bluetooth"; + } + else if ([type isEqualToString:AVAudioSessionPortBuiltInSpeaker]){ + return @"Speaker"; + } + else{ + return @"Unrecognized"; + } +} + - (void)requestTransaction:(CXTransaction *)transaction { #ifdef DEBUG