/*
* TeleStax, Open Source Cloud Communications
* Copyright 2011-2015, Telestax Inc and individual contributors
* by the @authors tag.
*
* This program is free software: you can redistribute it and/or modify
* under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation; either version 3 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
* For questions related to commercial use licensing, please contact sales@telestax.com.
*
*/
package org.restcomm.android.sdk;
/**
* Facility class to publish library's Error Codes and mapping with Error Text
*
* @see RCDevice
* @see RCConnection
*/
public final class RCClient {
private static RCClient instance = null;
private static boolean initialized = false;
/**
* Error codes for the SDK. They can be broken into three categories: 1. RCDevice related, starting with ERROR_DEVICE_*,
* 2. RCConnection related, starting with ERROR_CONNECTION_*, and 4. Text message related, starting with ERROR_MESSAGE_*,
*/
public enum ErrorCodes {
SUCCESS,
ERROR_DEVICE_MISSING_INTENTS,
ERROR_DEVICE_MISSING_USERNAME,
ERROR_DEVICE_MISSING_ICE_URL,
ERROR_DEVICE_MISSING_ICE_USERNAME,
ERROR_DEVICE_MISSING_ICE_PASSWORD,
ERROR_DEVICE_MISSING_ICE_DOMAIN,
ERROR_DEVICE_NO_CONNECTIVITY,
ERROR_DEVICE_ALREADY_OPEN,
ERROR_DEVICE_REGISTER_AUTHENTICATION_FORBIDDEN,
ERROR_DEVICE_REGISTER_TIMEOUT,
ERROR_DEVICE_REGISTER_COULD_NOT_CONNECT,
ERROR_DEVICE_REGISTER_URI_INVALID,
ERROR_DEVICE_REGISTER_SERVICE_UNAVAILABLE,
ERROR_DEVICE_REGISTER_UNTRUSTED_SERVER,
ERROR_CONNECTION_AUTHENTICATION_FORBIDDEN,
ERROR_CONNECTION_URI_INVALID,
ERROR_CONNECTION_PEER_UNAVAILABLE,
ERROR_CONNECTION_SIGNALING_TIMEOUT,
ERROR_CONNECTION_MEDIA_TIMEOUT,
ERROR_CONNECTION_COULD_NOT_CONNECT,
ERROR_CONNECTION_PEER_NOT_FOUND,
ERROR_CONNECTION_SERVICE_UNAVAILABLE,
ERROR_CONNECTION_SERVICE_INTERNAL_ERROR,
ERROR_CONNECTION_PARSE_CUSTOM_SIP_HEADERS,
ERROR_CONNECTION_ACCEPT_FAILED,
ERROR_CONNECTION_ACCEPT_WRONG_STATE,
ERROR_CONNECTION_IGNORE_WRONG_STATE,
ERROR_CONNECTION_REJECT_WRONG_STATE,
ERROR_CONNECTION_DISCONNECT_WRONG_STATE,
ERROR_CONNECTION_DISCONNECT_FAILED,
ERROR_CONNECTION_DECLINE_FAILED,
ERROR_CONNECTION_DTMF_DIGITS_FAILED,
ERROR_CONNECTION_DTMF_DIGITS_WRONG_STATE,
ERROR_CONNECTION_REGISTRARLESS_FULL_URI_REQUIRED,
ERROR_CONNECTION_WEBRTC_PEERCONNECTION_ERROR,
ERROR_CONNECTION_WEBRTC_TURN_ERROR,
ERROR_CONNECTION_PERMISSION_DENIED,
ERROR_CONNECTION_UNTRUSTED_SERVER,
ERROR_MESSAGE_AUTHENTICATION_FORBIDDEN,
ERROR_MESSAGE_URI_INVALID,
ERROR_MESSAGE_PEER_UNAVAILABLE,
ERROR_MESSAGE_TIMEOUT,
ERROR_MESSAGE_COULD_NOT_CONNECT,
ERROR_MESSAGE_PEER_NOT_FOUND,
ERROR_MESSAGE_SERVICE_UNAVAILABLE,
ERROR_MESSAGE_UNTRUSTED_SERVER,
ERROR_MESSAGE_SEND_FAILED_DEVICE_OFFLINE,
}
/**
* Maps the error codes above with an error description, to get more detailed information on what happened
* @param errorCode: The error code
* @return The error text corresponding to the passed errorCode
*/
public static String errorText(ErrorCodes errorCode)
{
if (errorCode == ErrorCodes.SUCCESS) {
return "Success";
}
else if (errorCode == ErrorCodes.ERROR_DEVICE_MISSING_INTENTS) {
return "Device parameter validation error; Call and/or Message intents are missing";
}
else if (errorCode == ErrorCodes.ERROR_DEVICE_MISSING_USERNAME) {
return "Device parameter validation error; username is mandatory";
}
else if (errorCode == ErrorCodes.ERROR_DEVICE_MISSING_ICE_URL) {
return "Device parameter validation error; ICE URL is mandatory";
}
else if (errorCode == ErrorCodes.ERROR_DEVICE_MISSING_ICE_USERNAME) {
return "Device parameter validation error; ICE username is mandatory";
}
else if (errorCode == ErrorCodes.ERROR_DEVICE_MISSING_ICE_PASSWORD) {
return "Device parameter validation error; ICE password is mandatory";
}
else if (errorCode == ErrorCodes.ERROR_DEVICE_MISSING_ICE_DOMAIN) {
return "Device parameter validation error; ICE domain is mandatory";
}
else if (errorCode == ErrorCodes.ERROR_DEVICE_NO_CONNECTIVITY) {
return "Device has no connectivity";
}
else if (errorCode == ErrorCodes.ERROR_DEVICE_ALREADY_OPEN) {
return "Device initialization failed; device is already open";
}
else if (errorCode == ErrorCodes.ERROR_DEVICE_REGISTER_TIMEOUT) {
return "Device registration with Restcomm timed out";
}
else if (errorCode == ErrorCodes.ERROR_DEVICE_REGISTER_AUTHENTICATION_FORBIDDEN) {
return "Device failed to authenticate with Service";
}
else if (errorCode == ErrorCodes.ERROR_DEVICE_REGISTER_COULD_NOT_CONNECT) {
// returned when there is an issue connecting to the domain URI, like no process listening to the server port,
// wrong server domain/ip is used, or domain is not resolvable
return "Device could not connect to Service";
}
else if (errorCode == ErrorCodes.ERROR_DEVICE_REGISTER_URI_INVALID) {
return "Register Domain URI is invalid";
}
else if (errorCode == ErrorCodes.ERROR_DEVICE_REGISTER_SERVICE_UNAVAILABLE) {
return "Device failed to register; service unavailable";
}
else if (errorCode == ErrorCodes.ERROR_DEVICE_REGISTER_UNTRUSTED_SERVER) {
return "Device failed to register; server is not trusted";
}
else if (errorCode == ErrorCodes.ERROR_CONNECTION_AUTHENTICATION_FORBIDDEN) {
return "Connection failed to authenticate with Service";
}
else if (errorCode == ErrorCodes.ERROR_CONNECTION_URI_INVALID) {
return "Connection URI is invalid";
}
else if (errorCode == ErrorCodes.ERROR_CONNECTION_PEER_UNAVAILABLE) {
return "Failed to initiate connection; peer is unavailable";
}
else if (errorCode == ErrorCodes.ERROR_CONNECTION_SIGNALING_TIMEOUT) {
return "Connection timed out (signaling)";
}
else if (errorCode == ErrorCodes.ERROR_CONNECTION_MEDIA_TIMEOUT) {
return "Connection timed out (media)";
}
else if (errorCode == ErrorCodes.ERROR_CONNECTION_COULD_NOT_CONNECT) {
// returned when there is an issue connecting to the destination URI, like no process listening to the server port,
// wrong server domain/ip is used, or domain is not resolvable
return "Failed to initiate connection; could not connect to service";
}
else if (errorCode == ErrorCodes.ERROR_CONNECTION_PEER_NOT_FOUND) {
return "Failed to initiate connection; peer not found";
}
else if (errorCode == ErrorCodes.ERROR_CONNECTION_SERVICE_UNAVAILABLE) {
return "Failed to initiate connection; service is unavailable";
}
else if (errorCode == ErrorCodes.ERROR_CONNECTION_SERVICE_INTERNAL_ERROR) {
return "Failed to initiate connection; service internal error";
}
else if (errorCode == ErrorCodes.ERROR_CONNECTION_PARSE_CUSTOM_SIP_HEADERS) {
return "Failed to initiate connection; error parsing custom SIP headers";
}
else if (errorCode == ErrorCodes.ERROR_CONNECTION_DISCONNECT_FAILED) {
return "Failed to disconnect connection";
}
else if (errorCode == ErrorCodes.ERROR_CONNECTION_ACCEPT_FAILED) {
return "Failed to accept connection";
}
else if (errorCode == ErrorCodes.ERROR_CONNECTION_ACCEPT_WRONG_STATE) {
return "Failed to accept connection; connection state should be CONNECTING";
}
else if (errorCode == ErrorCodes.ERROR_CONNECTION_IGNORE_WRONG_STATE) {
return "Failed to ignore connection; connection state should be CONNECTING";
}
else if (errorCode == ErrorCodes.ERROR_CONNECTION_REJECT_WRONG_STATE) {
return "Failed to reject connection; connection state should be CONNECTING";
}
else if (errorCode == ErrorCodes.ERROR_CONNECTION_DISCONNECT_WRONG_STATE) {
return "Failed to disconnect connection; connection state is already DISCONNECTED";
}
else if (errorCode == ErrorCodes.ERROR_CONNECTION_DECLINE_FAILED) {
return "Failed to decline connection";
}
else if (errorCode == ErrorCodes.ERROR_CONNECTION_DTMF_DIGITS_FAILED) {
return "Failed to send DTMF digits over connection";
}
else if (errorCode == ErrorCodes.ERROR_CONNECTION_DTMF_DIGITS_WRONG_STATE) {
return "Failed to send DTMF digits; connection state should be CONNECTED";
}
else if (errorCode == ErrorCodes.ERROR_CONNECTION_REGISTRARLESS_FULL_URI_REQUIRED) {
return "Failed to initiate connection: when RCDevice is configured with no domain you need to provide full SIP URI in connection peer";
}
else if (errorCode == ErrorCodes.ERROR_CONNECTION_WEBRTC_PEERCONNECTION_ERROR) {
return "Webrtc Peer Connection error";
}
else if (errorCode == ErrorCodes.ERROR_CONNECTION_WEBRTC_TURN_ERROR) {
return "Error retrieving TURN servers";
}
else if (errorCode == ErrorCodes.ERROR_CONNECTION_PERMISSION_DENIED) {
return "Failed to initiate connection; missing Android permissions";
}
else if (errorCode == ErrorCodes.ERROR_MESSAGE_AUTHENTICATION_FORBIDDEN) {
return "Message failed to authenticate with Service";
}
else if (errorCode == ErrorCodes.ERROR_MESSAGE_URI_INVALID) {
return "Message URI is invalid";
}
else if (errorCode == ErrorCodes.ERROR_MESSAGE_PEER_UNAVAILABLE) {
return "Failed to send message; peer is unavailable";
}
else if (errorCode == ErrorCodes.ERROR_MESSAGE_TIMEOUT) {
return "Message timed out";
}
else if (errorCode == ErrorCodes.ERROR_MESSAGE_COULD_NOT_CONNECT) {
// returned when there is an issue connecting to the destination URI, like no process listening to the server port,
// wrong server domain/ip is used, or domain is not resolvable
return "Failed to send message; could not connect to service";
}
else if (errorCode == ErrorCodes.ERROR_MESSAGE_PEER_NOT_FOUND) {
return "Failed to send message; peer not found";
}
else if (errorCode == ErrorCodes.ERROR_MESSAGE_SERVICE_UNAVAILABLE) {
return "Failed to send message; service is unavailable";
}
else if (errorCode == ErrorCodes.ERROR_MESSAGE_SEND_FAILED_DEVICE_OFFLINE) {
return "Failed to send message; RCDevice is offline";
}
return "Unmapped Restcomm Client error";
}
protected RCClient()
{
// Exists to defeat instantiation.
}
/*
static ArrayList<RCDevice> list;
static Context context;
// SDK users need to use initialize()
private static RCClient getInstance()
{
if (instance == null) {
instance = new RCClient();
}
return instance;
}
public static Context getContext()
{
return context;
}
public static void initialize(Context context, final RCInitListener listener)
{
if (context == null) {
throw new IllegalArgumentException("Error: Context cannot be null");
}
else if (listener == null) {
throw new IllegalArgumentException("Error: Listener cannot be null");
}
else {
RCClient.getInstance();
RCClient.context = context;
list = new ArrayList<RCDevice>();
initialized = true;
listener.onInitialized();
}
}
public static void shutdown()
{
if (!initialized) {
return;
}
if (list.size() > 0) {
RCDevice device = list.get(0);
// remove the reference so that RCDevice instance is removed
list.clear();
list = null;
// Need to make sure that shutdown() will finish its job synchronously.
// Keep in mind that once this block is left device can be claimed by GC
device.release();
}
else {
RCLogger.e(TAG, "shutdown(): Warning Restcomm Client already shut down, skipping");
}
// allow the singleton to be GC'd
instance = null;
initialized = false;
}
public static boolean isInitialized()
{
return initialized;
}
public static RCDevice createDevice(HashMap<String, Object> parameters, RCDeviceListener deviceListener)
{
if (!initialized) {
RCLogger.i(TAG, "Attempting to create RCDevice without first initializing RCClient");
return null;
}
if (list.size() == 0) {
// check if RCDevice parameters are ok
ErrorStruct errorStruct = RCUtils.validateParms(parameters);
if (errorStruct.statusCode != RCClient.ErrorCodes.SUCCESS) {
throw new RuntimeException(errorStruct.statusText);
}
RCDevice device = new RCDevice(parameters, deviceListener);
list.add(device);
}
else {
RCLogger.e(TAG, "Device already exists, so we 're returning this one");
}
return list.get(0);
}
public static ArrayList<RCDevice> listDevices()
{
if (!initialized) {
RCLogger.w(TAG, "RCClient uninitialized");
return null;
}
if (list.size() == 0) {
RCLogger.e(TAG, "Warning: RCDevice list size is 0");
}
return list;
}
public static void setLogLevel(int level)
{
RCLogger.setLogLevel(level);
}
public interface RCInitListener {
void onInitialized();
void onError(Exception exception);
}
*/
}