Before using Stringee Call API for the first time, you must have a Stringee account If you do not have a Stringee account, sign up for free here: https://developer.stringee.com/account/register
Create a Project on Stringee Dashboard
Buy a Number (optional)
For app-to-phone, phone-to-app calling, buy a Number from Dashboard. If you only need app-to-app calling, skip this step.
Configure answer_url
For more information about answer_url, read Stringee Call API Overview. You can view answer_url sample code here: https://github.com/stringeecom/server-samples/tree/master/answer_url
If you do not have answer_url, you can use the following Project's answer_url to accelerate the process:
Project's answer_url for App-to-App call:
https://developer.stringee.com/scco_helper/simple_project_answer_url?record=false&appToPhone=false
Project's answer_url for App-to-Phone call:
https://developer.stringee.com/scco_helper/simple_project_answer_url?record=false&appToPhone=true
(Source code: https://github.com/stringeecom/server-samples/blob/master/answer_url/php/project_answer_url.php)
When building an application, you should use your own answer_url.
If you do not have answer_url, you can use the following Number's answer_url to accelerate the process:
Number's answer_url for Phone-to-App call (The call is routed to Your App which authenticated by USER_ID):
https://developer.stringee.com/scco_helper/simple_number_answer_url?record=true&phoneToPhone=false&to_number=USER_ID
Number's answer_url for Phone-to-Phone call (The call is routed to TO_NUMBER):
https://developer.stringee.com/scco_helper/simple_number_answer_url?record=true&phoneToPhone=true&stringeeNumber=STRINGEE_NUMBER&to_number=TO_NUMBER
(Source code: https://github.com/stringeecom/server-samples/blob/master/answer_url/php/number_answer_url.php)
When building an application, you should use your own answer_url.
In your terminal (Command Prompt in Windows), change into your React Native project's directory
In your terminal (Command Prompt in Windows), run $ npm install stringee-react-native --save
Note Please make sure to have CocoaPods on your computer.
In you terminal, change into your ios
directory.
Now run, pod install
Open XCode
Open <YourProjectName>.xcworkspace
file in XCode. This file can be found in the ios
folder of your React Native project.
In the "Build Settings" tab -> "Other linker flags" add "$(inherited)" flag.
In the "Build Settings" tab -> "Enable bitcode" select "NO".
Right-click the information property list file (Info.plist) and select Open As -> Source Code.
Insert the following XML snippet into the body of your file just before the final element:
<key>NSCameraUsageDescription</key>
<string>$(PRODUCT_NAME) uses Camera</string>
<key>NSMicrophoneUsageDescription</key>
<string>$(PRODUCT_NAME) uses Microphone</string>
Open up android/app/proguard-rules.pro
and add following lines:
-dontwarn org.webrtc.**
-keep class org.webrtc.** { *; }
-keep class com.stringee.** { *; }
The Stringee Android SDK requires some permissions from your AndroidManifest
android/app/src/main/AndroidManifest.xml
// for internet access
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
// for audio access
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
// for camera access
<uses-permission android:name="android.permission.CAMERA" />
In order to connect to Stringee Server, 3-parties authentication is required as described here: Client authentication
For testing purpose, go to Dashboard -> Tools -> Generate Access token and generates an access_token. In production, the access_token should be generated by your server, here is a sample code to generate an access token: https://github.com/stringeecom/server-samples/tree/master/access_token
import {StringeeClient} from "stringee-react-native";
render () {
return (
<View>
...
<StringeeClient
ref="client"
eventHandlers = {this.clientEventHandlers}
/>
...
</View>
)
}
class App extends Component {
constructor(props) {
super(props);
this.clientEventHandlers = {
onConnect: this._clientDidConnect,
onDisConnect: this._clientDidDisConnect,
onFailWithError: this._clientDidFailWithError,
onRequestAccessToken: this._clientRequestAccessToken,
onIncomingCall: this._callIncomingCall,
onIncomingCall2: this._callIncomingCall2,
onCustomMessage: this._clientReceiveCustomMessage,
};
}
// The client connects to Stringee server
_clientDidConnect = ({userId}) => {
console.log('_clientDidConnect: ' + userId);
}
// The client disconnects from Stringee server
_clientDidDisConnect = () => {
console.log('_clientDidDisConnect');
}
// The client fails to connects to Stringee server
_clientDidFailWithError = () => {
console.log('_clientDidFailWithError');
}
// Access token is expired. A new access token is required to connect to Stringee server
_clientRequestAccessToken = () => {
console.log("_clientRequestAccessToken");
// this.refs.client.connect('NEW_YOUR_ACCESS_TOKEN');
}
// IncomingCall event
_callIncomingCall = ({callId, from, to, fromAlias, toAlias, callType, isVideoCall}) => {
console.log('_callIncomingCall: ' + callId);
}
// IncomingCall2 event
_callIncomingCall2 = ({callId, from, to, fromAlias, toAlias, callType, isVideoCall}) => {
console.log('_callIncomingCall2: ' + callId);
}
// Receive custom message
_clientReceiveCustomMessage = ({data}) => {
console.log('_clientReceiveCustomMessage: ' + data);
};
render() {
return (
<View>
...
<StringeeClient
ref="client"
eventHandlers = {this.clientEventHandlers}
/>
...
</View>
);
}
}
async componentDidMount() {
await this.refs.client.connect('YOUR_ACCESS_TOKEN');
}
After the client connects to Stirngee server, follows these steps to make a call:
import {StringeeCall2} from "stringee-react-native";
class App extends Component {
state = {
clientId: null,
};
...
async componentDidMount() {
await this.refs.stringeeClient.connect(token);
this.setState({clientId: this.refs.stringeeClient.getId()});
}
...
render() {
return (
<View>
...
{this.state.clientId !== null && (
<StringeeCall2
ref="stringeeCall2"
clientId={this.state.clientId} />
)}
...
</View>
);
}
}
class App extends Component {
constructor(props) {
super(props);
this.callEventHandlers = {
onChangeSignalingState: this._callDidChangeSignalingState,
onChangeMediaState: this._callDidChangeMediaState,
onReceiveLocalStream: this._callDidReceiveLocalStream,
onReceiveRemoteStream: this._callDidReceiveRemoteStream,
onReceiveDtmfDigit: this._didReceiveDtmfDigit,
onReceiveCallInfo: this._didReceiveCallInfo,
onHandleOnAnotherDevice: this._didHandleOnAnotherDevice,
onAudioDeviceChange: this._didAudioDeviceChange, ///only available on android
};
}
// Invoked when the call signaling state changes
_callDidChangeSignalingState = ({callId, code, reason, sipCode, sipReason}) => {
console.log('_callDidChangeSignalingState: ' + code);
}
// Invoked when the call media state changes
_callDidChangeMediaState = ({callId, code, description}) => {
console.log('_callDidChangeMediaState: ' + code);
}
// Invoked when the local stream is available
_callDidReceiveLocalStream = ({callId}) => {
console.log('_callDidReceiveLocalStream: ' + callId);
}
// Invoked when the remote stream is available
_callDidReceiveRemoteStream = ({callId}) => {
console.log('_callDidReceiveRemoteStream: ' + callId);
}
// Invoked when receives a DMTF
_didReceiveDtmfDigit = ({callId, dtmf}) => {
console.log('_didReceiveDtmfDigit');
}
// Invoked when receives info from other clients
_didReceiveCallInfo = ({callId, data}) => {
console.log('_didReceiveCallInfo: ' + data);
}
// Invoked when the call is handled on another device
_didHandleOnAnotherDevice = ({callId, code, description}) => {
console.log('_didHandleOnAnotherDevice: ' + code);
}
// Invoked when audio device has change
_didAudioDeviceChange = ({selectedAudioDevice, availableAudioDevices}) => {
console.log(
'_didHandleOnAnotherDevice: selectedAudioDevice - ' +
selectedAudioDevice +
' availableAudioDevices - ' +
availableAudioDevices,
);
};
render() {
return (
...
{this.state.clientId !== null && (
<StringeeCall2
ref="stringeeCall2"
clientId={this.state.clientId}
eventHandlers={this.callEventHandlers}
/>
)}
...
);
}
}
const myObj = {
from: 'caller_userId', // caller
to: 'callee_userId', // callee
isVideoCall: false, // Cuộc gọi là video call hoặc voice call
videoResolution: 'NORMAL' // chất lượng hình ảnh 'NORMAL' hoặc 'HD'. Mặc định là 'NORMAL'.
};
const parameters = JSON.stringify(myObj);
this.refs.stringeeCall2.makeCall(parameters, (status, code, message, callId) => {
console.log('status-' + status + ' code-' + code + ' message-' + message + 'callId-' + callId);
if (status) {
// Sucess
} else {
// Fail
}
})
When the client receives an incoming call with callId
// IncomingCall2 event
_callIncomingCall2 = ({callId, from, to, fromAlias, toAlias, callType, isVideoCall}) => {
console.log('_callIncomingCall2: ' + callId);
}
Initialize a StringeeCall2 as described in 4.1, 4.2, 4.3. Then follow these steps:
this.refs.stringeeCall2.initAnswer(callId, (status, code, message) => {
console.log(message);
if (status) {
// Sucess
} else {
// Fail
}
});
this.refs.stringeeCall2.answer(callId, (status, code, message) => {
console.log(message);
if (status) {
// Sucess
} else {
// Fail
}
});
When the client wants to hang up:
this.refs.stringeeCall2.hangup(callId, (status, code, message) => {
console.log(message);
if (status) {
// Sucess
} else {
// Fail
}
});
When the client wants to reject a call:
this.refs.stringeeCall2.reject(callId, (status, code, message) => {
console.log(message);
if (status) {
// Sucess
} else {
// Fail
}
});
const myObj = {
from: 'caller_userId', // caller
to: 'callee_userId', // callee
isVideoCall: true, // Must be true
videoResolution: 'NORMAL' // Set video resolution: 'NORMAL', 'HD'
};
const parameters = JSON.stringify(myObj);
this.refs.stringeeCall2.makeCall(parameters, (status, code, message, callId) => {
console.log('status-' + status + ' code-' + code + ' message-' + message + 'callId-' + callId);
if (status) {
// Sucess
} else {
// Fail
}
})
_callDidReceiveLocalStream = ({callId}) => {
console.log('_callDidReceiveLocalStream ' + callId);
this.setState({hasReceivedLocalStream:true});
}
render () {
return (
<View>
...
{this.props.isVideoCall &&
this.props.hasLocalStream &&
this.props.stringeeCallId != '' && (
<StringeeVideoView
style={styles.localView}
callId={this.props.stringeeCallId}
local={true}
overlay={true}
/>
)}
...
<StringeeCall2
ref="stringeeCall2"
clientId={this.state.clientId}
eventHandlers={this.callEventHandlers}
/>
...
</View>
);
}
}
_callDidReceiveRemoteStream = ({callId}) => {
console.log('_callDidReceiveRemoteStream ' + callId);
this.setState({hasReceivedRemoteStream:true});
}
render () {
return (
<View>
...
{this.props.isVideoCall &&
this.props.hasRemoteStream &&
this.props.stringeeCallId != '' && (
<StringeeVideoView
style={{flex: 1}}
callId={this.props.stringeeCallId}
local={false}
/>
)}
...
<StringeeCall2
ref="stringeeCall2"
clientId={this.state.clientId}
eventHandlers={this.callEventHandlers}
/>
...
</View>
);
}
}
You can view a full version of this sample app on GitHub: https://github.com/stringeecom/react-native-samples