-
Notifications
You must be signed in to change notification settings - Fork 234
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
5916395
commit 55b97b7
Showing
10 changed files
with
521 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
|
||
# Events | ||
|
||
All interaction from javascript to pjsip module is asynchromius. | ||
So for each action, promise will be returned. | ||
|
||
# Create account | ||
|
||
``` | ||
let configuration = { | ||
"name": "John", | ||
"username": "sip_username", | ||
"domain": "pbx.carusto.com", | ||
"password": "****", | ||
"proxy": null, | ||
"transport": null, // Default TCP | ||
"regServer": null, // Default wildcard | ||
"regTimeout": null // Default 3600 | ||
"regHeaders": { | ||
"X-Custom-Header": "Value" | ||
}, | ||
"regContactParams": ";unique-device-token-id=XXXXXXXXX", | ||
"regOnAdd": false, // Default true, use false for manual REGISTRATION | ||
}; | ||
let endpoint = new Endpoint(); | ||
let state = await endpoint.start(); | ||
let account = await endpoint.createAccont(configuration); | ||
// Do smth with account. For example wait until registration complete and make a call. | ||
``` | ||
|
||
* There is no change account method. But this functionality is easy to implement by calling delete and create account methods. | ||
|
||
|
||
# Remove account | ||
|
||
TODO: Description | ||
|
||
``` | ||
let account = ...; | ||
await endpoint.deleteAccont(account); | ||
await endpoint.deleteAccont(account); // There should be exception, bcs account already removed. | ||
``` | ||
|
||
|
||
# Events | ||
|
||
|
||
## registration_changed | ||
|
||
TODO: Answer how much times it will be executed during lifetime, with examples. | ||
|
||
``` | ||
``` | ||
|
||
|
||
Example: Forbidden | ||
|
||
Example: Invalid host | ||
|
||
|
||
|
||
.then((account) => { | ||
console.log("Account: ", account); | ||
|
||
setTimeout(() => { | ||
endpoint.registerAccount(account, true); | ||
}, 10000); | ||
|
||
setTimeout(() => { | ||
endpoint.registerAccount(account, false); | ||
}, 20000); | ||
}); | ||
|
||
|
||
|
||
|
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
# Android background service | ||
|
||
In order to accept incoming calls while applicaiton in background you should set `notifications` property to `true` (true by default). | ||
This will make PJSIP service run in the *foreground*, supplying the ongoing notification to be shown to the user while in this state. | ||
Without foreground notification, Android could kill PJSIP service to reclaim more memory. | ||
|
||
![Android Pending Intent PjSip](android_notification_example.png) | ||
|
||
```javascript | ||
let configuration = { | ||
service: { | ||
ua: Platform.select({ios: "Reachify iOS", android: "Reachify Android"}), // Default: React Native PjSip (version) | ||
notifications: true, // Creates peding notification that will allow service work while your app in background | ||
notifications: false, // Disables pending notification | ||
notifications: { | ||
account: true, | ||
call: false // Disables only call notification | ||
}, | ||
notifications: { | ||
account: { | ||
title: "My cool react native app", // Default: account name | ||
text: "Here we go", // Default: account registration status | ||
info: null, | ||
ticker: null, | ||
smallIcon: null, | ||
largeIcon: null | ||
}, | ||
call: { | ||
title: "Active call", // Default: "Call in Progress - %Account Name%" | ||
text: "John Doe", // Default: "%Caller Name% (%Number%)" | ||
info: null, | ||
ticker: null, // Default: "Call in Progress" | ||
smallIcon: "icon_call", // Default: R.drawable.stat_sys_phone_call | ||
largeIcon: null | ||
} | ||
} | ||
}, | ||
network: { | ||
useAnyway: false, // Default: true | ||
useWifi: true, // Default: true | ||
use3g: true, // Default: false | ||
useEdge: false, // Default: false | ||
useGprs: false, // Default: false | ||
useInRoaming: false, // Default: false | ||
useOtherNetworks: true // Default: false | ||
} | ||
}; | ||
let endpoint = new Endpoint(); | ||
let state = await endpoint.start(configuration); | ||
// ... | ||
``` | ||
|
||
### smallIcon & largeIcon | ||
To use own images for nofitications, copy them into `android/app/src/main/res/mipmap-XXXX/` and set thier names into `smallIcon` and `largeIcon` without extension. | ||
For more info: [ui_guidelines/icon_design_status_bar](https://developer.android.com/guide/practices/ui_guidelines/icon_design_status_bar.html) | ||
|
||
### Handle clicks to call notifications | ||
|
||
Typically you should contain code that will change "route" in react-native app depending on result of `endpoint.start` command | ||
```javascript | ||
let state = await endpoint.start(configuration); | ||
let calls = state.calls; // A list of active calls | ||
|
||
if (state.hasOwnProperty("notificationCallId")) { | ||
for (let c of calls) { | ||
if (c.getId() == state['notificationCallId']) { | ||
route = {name:'call', call: c}; | ||
break; | ||
} | ||
} | ||
} | ||
|
||
//... | ||
|
||
// If true you should use slider instead of buttons for incoming call, because device was in sleep when this call comes. | ||
if (state.notificationIsFromForeground) { | ||
//... | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
TODO: Introduction + links to other sections. | ||
|
||
# Events | ||
|
||
All interaction from javascript to pjsip module is asynchronous. | ||
So for each action, promise will be returned. | ||
|
||
## call_received | ||
|
||
TODO: Description | ||
|
||
## call_changed | ||
|
||
TODO: Description | ||
|
||
## call_terminated | ||
|
||
TODO: Description | ||
|
||
|
||
# Actions | ||
|
||
## Initiate a call | ||
To be able to make a call first of all you should createAccount, and pass account instance into Endpoint.makeCall function. | ||
This function will return a promise that will be resolved when PjSIP initializes the call. | ||
|
||
``` | ||
let options = { | ||
headers: { | ||
"P-Assserted-Identity": "Header example", | ||
"X-UA": "React native" | ||
} | ||
} | ||
let call = await endpoint.makeCall(account, destination, options); | ||
call.getId() // Use this id to detect changes and make actions | ||
endpoint.addListener("call_changed", (newCall) => { | ||
if (call.getId() === newCall.getId()) { | ||
// Our call changed, do smth. | ||
} | ||
} | ||
endpoint.addListener("call_terminated", (newCall) => { | ||
if (call.getId() === newCall.getId()) { | ||
// Our call terminated | ||
} | ||
} | ||
``` | ||
|
||
## Answer the call | ||
|
||
After answer there will be event "call_changed" that reflect the changes. | ||
If there is already active call, it will be placed on hold (so expect "call_changed" event) | ||
|
||
``` | ||
let options = {}; | ||
let call = ...; | ||
let promise = endpoint.answerCall(call, options); | ||
promise.then(() => { | ||
// Answer complete, expect that "call_changed" will be fired. | ||
})); | ||
promise.catch(() => { | ||
// Answer failed, show error | ||
}); | ||
``` | ||
|
||
## Hangup | ||
Use this function when you have active call, and Decline for unanswered incoming calls. | ||
After successul hangup, Endpoint should fire "call_terminated" event, use it to how final call duration and status. | ||
|
||
``` | ||
let options = {}; | ||
let call = ...; | ||
await endpoint.hangupCall(call, options); | ||
``` | ||
|
||
## Decline | ||
Use this function when you have unanswered incoming call. | ||
After successul decline, Endpoint should fire "call_terminated" event. | ||
|
||
``` | ||
let options = {}; | ||
let call = ...; | ||
await endpoint.declineCall(call, options); | ||
``` | ||
|
||
## Hold/Unhold | ||
|
||
TODO: Description | ||
After successul hold/unhold, Endpoint should fire "call_changed" event, where `isHeld` should be false or true. | ||
|
||
``` | ||
let options = {}; | ||
let call = ...; | ||
await endpoint.holdCall(call, options); | ||
await endpoint.unholdCall(call, options); | ||
``` | ||
|
||
## Transfer | ||
|
||
TODO: Description | ||
|
||
``` | ||
let options = {}; | ||
let call = ...; | ||
await endpoint.xferCall(call, destination, options); | ||
``` | ||
|
||
## DTMF | ||
|
||
TODO: Description | ||
|
||
``` | ||
let options = {}; | ||
let call = ...; | ||
let key = "3"; | ||
await endpoint.dtmfCall(call, key, options); | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
# Android installation | ||
|
||
## Step 1 | ||
Add permissions & service to `android/app/src/main/AndroidManifest.xml` | ||
|
||
```xml | ||
<uses-feature android:name="android.hardware.camera" /> | ||
<uses-feature android:name="android.hardware.camera.autofocus"/> | ||
|
||
<uses-permission android:name="android.permission.INTERNET" /> | ||
<uses-permission android:name="android.permission.CAMERA" /> | ||
<uses-permission android:name="android.permission.RECORD_AUDIO"/> | ||
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/> | ||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> | ||
<uses-permission android:name="android.permission.WAKE_LOCK"/> | ||
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/> | ||
<uses-permission android:name="android.permission.CALL_PHONE"/> | ||
<uses-permission android:name="android.permission.READ_PHONE_STATE" /> | ||
``` | ||
|
||
```xml | ||
<application> | ||
... | ||
<service | ||
android:name="com.carusto.ReactNativePjSip.PjSipService" | ||
android:enabled="true" | ||
android:exported="true" /> | ||
... | ||
</application> | ||
``` | ||
|
||
## Step 2 | ||
```bash | ||
react-native link | ||
``` | ||
|
||
## Additional step: Ability to answer incoming call without Lock Screen | ||
|
||
In `android/app/src/main/java/com/xxx/MainActivity.java` | ||
|
||
```java | ||
import android.view.Window; | ||
import android.view.WindowManager; | ||
import android.os.Bundle; | ||
... | ||
@Override | ||
public void onCreate(Bundle savedInstanceState) { | ||
super.onCreate(savedInstanceState); | ||
|
||
Window w = getWindow(); | ||
w.setFlags( | ||
WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED, | ||
WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED | ||
); | ||
} | ||
``` | ||
|
||
## If Android targetSdk >= 23 | ||
|
||
If your Android targetSdk is 23 or above you should grant `android.permission.RECORD_AUDIO` at runtime before making/receiving an audio call. | ||
|
||
To check and request Android permissions, please check out [react-native-android-permissions](https://github.com/lucasferreira/react-native-android-permissions). |
Oops, something went wrong.