Skip to end of metadata
Go to start of metadata

Example of Android application for audio calls

Input fields to establish SIP connection

  • 'WCS URL' - WCS server address
  • 'SIP Login'- SIP user name
  • 'SIP Password' - SIP password
  • 'SIP Domain' - SIP server address
  • 'SIP port' - SIP port

SIP callee user name should be set to 'Callee' input field.
Connect/Disconnect button establishes/closes SIP-connection.
Call/Hangup button makes a SIP call or finishes it.
Hold/Unhold button is used to hold the call.

Work with code of the example

To analyze the code, let's take class PhoneMinActivity.java of the phone-min example, which can be downloaded with corresponding build 1.1.0.55.

1. Initialization of the API.

Flashphoner.init() code

For initialization, object Сontext is passed to the init() method.

Flashphoner.init(this);

2. Session creation.

Flashphoner.createSession() code

Object SessionOptions with URL of WCS server is passed to the method.

SessionOptions sessionOptions = new SessionOptions(mWcsUrlView.getText().toString());
session = Flashphoner.createSession(sessionOptions);

3. Connection to the server.

Session.connect() code

Connection object with parameters required for establishing SIP connection is passed to the method

Connection connection = new Connection();
connection.setSipLogin(mSipLoginView.getText().toString());
connection.setSipPassword(mSipPasswordView.getText().toString());
connection.setSipDomain(mSipDomainView.getText().toString());
connection.setSipOutboundProxy(mSipDomainView.getText().toString());
connection.setSipPort(Integer.parseInt(mSipPortView.getText().toString()));
connection.setSipRegisterRequired(mSipRegisterRequiredView.isChecked());
connection.setKeepAlive(true);
session.connect(connection);

4. Receiving the event confirming successful connection.

Session.onConnected(), Session.getAuthToken() code

A session token should be kept to connect to the session later 

            @Override
            public void onConnected(final Connection connection) {
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        ...
                        String token = connection.getAuthToken();
                        if (token != null && !token.isEmpty()) {
                            mAuthTokenView.setText(token);
                            mConnectTokenButton.setEnabled(true);
                        }
                    }
                });
            }

5. Call/Hangup button click handler

Button.setOnClickListener() code

mCallButton.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View view) {
        if (mCallButton.getTag() == null || Integer.valueOf(R.string.action_call).equals(mCallButton.getTag())) {
            if ("".equals(mCalleeView.getText().toString())) {
                return;
            }
            ActivityCompat.requestPermissions(PhoneMinActivity.this,
                  new String[]{Manifest.permission.RECORD_AUDIO},
                  CALL_REQUEST_CODE);
            ...
        } else {
            mCallButton.setEnabled(false);
            call.hangup();
            call = null;
        }
        View currentFocus = getCurrentFocus();
        if (currentFocus != null) {
            InputMethodManager inputManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
            inputManager.hideSoftInputFromWindow(currentFocus.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
        }
    }
});

6. Outgoing call.

Session.createCall(), Call.call() code
CallOptions object with these parameters is passed to the method:

  • SIP username
  • audio constraints
  • SIP INVITE parameters
case CALL_REQUEST_CODE: {
    if (grantResults.length == 0 ||
          grantResults[0] != PackageManager.PERMISSION_GRANTED) {
        Log.i(TAG, "Permission has been denied by user");
    } else {
        mCallButton.setEnabled(false);
        /**
          * Get call options from the callee text field
          */
        CallOptions callOptions = new CallOptions(mCalleeView.getText().toString());
        AudioConstraints audioConstraints = callOptions.getConstraints().getAudioConstraints();
        MediaConstraints mediaConstraints = audioConstraints.getMediaConstraints();
        ...
        try {
            Map<String, String> inviteParameters = new Gson().fromJson(mInviteParametersView.getText().toString(),
               new TypeToken<Map<String, String>>() {
               }.getType());
            callOptions.setInviteParameters(inviteParameters);
        } catch (Throwable t) {
            Log.e(TAG, "Invite Parameters have wrong format of json object");
        }
        call = session.createCall(callOptions);
        call.on(callStatusEvent);
        /**
          * Make the outgoing call
          */
        call.call();
        Log.i(TAG, "Permission has been granted by user");
        break;
    }
}

7. Receiving the event on incoming call

Session.onCall() code

@Override
public void onCall(final Call call) {
    call.on(callStatusEvent);
    /**
      * Display UI alert for the new incoming call
      */
    runOnUiThread(new Runnable() {
        @Override
        public void run() {
            AlertDialog.Builder builder = new AlertDialog.Builder(PhoneMinActivity.this);

            builder.setTitle("Incoming call");

            builder.setMessage("Incoming call from '" + call.getCaller() + "'");
            builder.setPositiveButton("Answer", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialogInterface, int i) {
                    PhoneMinActivity.this.call = call;
                    ActivityCompat.requestPermissions(PhoneMinActivity.this,
                          new String[]{Manifest.permission.RECORD_AUDIO},
                          INCOMING_CALL_REQUEST_CODE);
                }
            });
            builder.setNegativeButton("Hangup", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialogInterface, int i) {
                    call.hangup();
                    incomingCallAlert = null;
                }
            });
            incomingCallAlert = builder.show();
        }
    });
}

8. Answering incoming call.

Call.answer() code

case INCOMING_CALL_REQUEST_CODE: {
    if (grantResults.length == 0 ||
           grantResults[0] != PackageManager.PERMISSION_GRANTED) {
        call.hangup();
        incomingCallAlert = null;
        Log.i(TAG, "Permission has been denied by user");
    } else {
        mCallButton.setText(R.string.action_hangup);
        mCallButton.setTag(R.string.action_hangup);
        mCallButton.setEnabled(true);
        mCallStatus.setText(call.getStatus());
        call.answer();
        incomingCallAlert = null;
        Log.i(TAG, "Permission has been granted by user");
    }
}

9. Call hold and retrieve.

Call.hold(), Call.unhold() code

mHoldButton.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View view) {
        if (mHoldButton.getTag() == null || Integer.valueOf(R.string.action_hold).equals(mHoldButton.getTag())) {
            call.hold();
            mHoldButton.setText(R.string.action_unhold);
            mHoldButton.setTag(R.string.action_unhold);
        } else {
            call.unhold();
            mHoldButton.setText(R.string.action_hold);
            mHoldButton.setTag(R.string.action_hold);
        }

    }
});

10. DTMF sending

Call.sendDTMF() code

mDTMF = (EditText) findViewById(R.id.dtmf);
mDTMFButton = (Button) findViewById(R.id.dtmf_button);
mDTMFButton.setOnClickListener(new OnClickListener() {
@Override
    public void onClick(View view) {
        if (call != null) {
            call.sendDTMF(mDTMF.getText().toString(), Call.DTMFType.RFC2833);
        }
    }
});

11. Outgoing call hangup.

Call.hangup() code

mCallButton.setEnabled(false);
call.hangup();
call = null;

12. Incoming call hangup.

Call.hangup() code

builder.setNegativeButton("Hangup", new DialogInterface.OnClickListener() {
    @Override
    public void onClick(DialogInterface dialogInterface, int i) {
        call.hangup();
        incomingCallAlert = null;
    }
});

13. Disconnection.

Session.disconnect() code

mConnectButton.setEnabled(false);
session.disconnect();

14. Connection to an existing session using token

Connection.setAuthToken(), Session.connect code

        mConnectTokenButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mConnectTokenButton.getTag() == null || Integer.valueOf(R.string.action_connect_token).equals(mConnectTokenButton.getTag())) {
                    connectWithToken = true;
                    String authToken = mAuthTokenView.getText().toString();
                    if (authToken.isEmpty()) {
                        return;
                    }
                    mConnectButton.setEnabled(false);
                    mConnectTokenButton.setEnabled(false);
                    createSession();
                    Connection connection = new Connection();
                    connection.setAuthToken(authToken);
                    connection.setKeepAlive(true);
                    session.connect(connection);
                } else {
                    mConnectButton.setEnabled(false);
                    mConnectTokenButton.setEnabled(false);
                    session.disconnect();
                }
            }
        });
  • No labels