Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Example of Android application for audio calls

On the screenshot below the example is displayed when a call is established.

In the input field Input fields to establish SIP connection

  • 'WCS URL'

...

  • - WCS server

...

  • address

...

SIP connection is established/closed when Connect/Disconnect button is clicked.
Call is placed/terminated when Call/Hangup button is clicked, and put on hold/retrieve when Hold/Unhold button is clicked.

...

  • '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.

Image Added

Work with code of the example

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

1. Initialization of the API.

Flashphoner.init()   code

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

...

Flashphoner.createSession()   code

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

...

3. Connection to the server.

Session.connect() code

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

Code Block
languagejava
themeRDark
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() code

...

, Session.getAuthToken() code

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

Code Block
languagejava
themeRDark
            @Override
            public void onConnected(final Connection connection) {
                runOnUiThread(new Runnable() {
         @Override
        public void run() {@Override
            mConnectButton.setText(R.string.action_disconnect);        public void run() {
            mConnectButton.setTag(R.string.action_disconnect);
            mConnectButton.setEnabled(true);...
            if (!mSipRegisterRequiredView.isChecked()) {
          String token     mConnectStatus.setText(connection.getStatus()= connection.getAuthToken();
                mCallButton.setEnabled(true);
        if (token != null } else&& !token.isEmpty()) {
                mConnectStatus.setText(connection.getStatus() + ". Registering...");
            }mAuthTokenView.setText(token);
        }
    });
}

5. Call/Hangup button click handler

Button.setOnClickListener() code

Code Block
languagejava
themeRDark
mCallButton.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View view) {
  mConnectTokenButton.setEnabled(true);
              if (mCallButton.getTag() == null || Integer.valueOf(R.string.action_call).equals(mCallButton.getTag())) {          }
            if ("".equals(mCalleeView.getText().toString())) {        }
                return});
            }
  

5. Call/Hangup button click handler

Button.setOnClickListener() code

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

6. Outgoing call.

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

...

   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 ||
Code Block
languagejava
themeRDark
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

Code Block
languagejava
themeRDark
@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() + "'");
            grantResults[0] != PackageManager.PERMISSION_GRANTEDbuilder.setPositiveButton("Answer", new DialogInterface.OnClickListener() {
        Log.i(TAG, "Permission has been denied by user");
    } else {@Override
        mCallButton.setEnabled(false);
        /**
public void onClick(DialogInterface dialogInterface, int i)   {
  * Get call options from the callee text field
          */
    PhoneMinActivity.this.call = call;
     CallOptions callOptions = new CallOptions(mCalleeView.getText().toString());
        AudioConstraints audioConstraints = callOptionsActivityCompat.getConstraintsrequestPermissions().getAudioConstraints();
 PhoneMinActivity.this,
       MediaConstraints mediaConstraints = audioConstraints.getMediaConstraints();
          ...
        trynew String[]{Manifest.permission.RECORD_AUDIO},
              Map<String,  String> inviteParameters = new Gson().fromJson(mInviteParametersView.getText().toString(),
      INCOMING_CALL_REQUEST_CODE);
         new TypeToken<Map<String, String>>()  {
   }
            }.getType());
            callOptions.setInviteParameters(inviteParameters);
builder.setNegativeButton("Hangup", new DialogInterface.OnClickListener() {
            } catch (Throwable t) {@Override
             Log.e(TAG, "Invite Parameters havepublic wrongvoid format of json object");
onClick(DialogInterface dialogInterface, int i) {
          }
        call = sessioncall.createCallhangup(callOptions);
          call.on(callStatusEvent);
        /**
  incomingCallAlert = null;
      * Make the outgoing call
      }
    */
        call.call(});
        Log.i(TAG, "Permission has been grantedincomingCallAlert by user"= builder.show();
        break;}
    });
}

7. Receiving the event on 8. Answering incoming call.

SessionCall.onCallanswer()   code

@Override public void onCall(final Call call) {
Code Block
languagejava
themeRDark
RDark
case INCOMING_CALL_REQUEST_CODE: {
    if (grantResults.length == 0 ||
           grantResults[0] != PackageManager.PERMISSION_GRANTED) {
        call.onhangup(callStatusEvent);
    /**
    incomingCallAlert = *null;
 Display UI alert for the new incoming call
      */ Log.i(TAG, "Permission has been denied by user");
    runOnUiThread(new Runnable()} else {
        @OverridemCallButton.setText(R.string.action_hangup);
        public void run() {
mCallButton.setTag(R.string.action_hangup);
        mCallButton.setEnabled(true);
     AlertDialog.Builder builder = new AlertDialogmCallStatus.BuildersetText(PhoneMinActivitycall.thisgetStatus());

            builder.setTitle("Incoming call"call.answer();

        incomingCallAlert = null;
  builder.setMessage("Incoming call from '" + call.getCaller() + "'");
   Log.i(TAG, "Permission has been granted by user");
    builder.setPositiveButton("Answer", new DialogInterface.}
}

9. Call hold and retrieve.

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

Code Block
languagejava
themeRDark
mHoldButton.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View      @Overrideview) {
        if (mHoldButton.getTag() == null     public void onClick(DialogInterface dialogInterface, int i|| Integer.valueOf(R.string.action_hold).equals(mHoldButton.getTag())) {
            call.hold();
           PhoneMinActivity.this.call = call mHoldButton.setText(R.string.action_unhold);
                    ActivityCompat.requestPermissions(PhoneMinActivity.this,
     mHoldButton.setTag(R.string.action_unhold);
        } else {
           new String[]{Manifest.permission.RECORD_AUDIO},call.unhold();
            mHoldButton.setText(R.string.action_hold);
              INCOMING_CALL_REQUEST_CODEmHoldButton.setTag(R.string.action_hold);
                }

    }
});

10. DTMF sending

Call.sendDTMF() code

Code Block
languagejava
themeRDark
mDTMF =       }(EditText) findViewById(R.id.dtmf);
mDTMFButton =           builder.setNegativeButton("Hangup", new DialogInterface.(Button) findViewById(R.id.dtmf_button);
mDTMFButton.setOnClickListener(new OnClickListener() {
@Override
    public void onClick(View          @Overrideview) {
        if (call != null) {
    public void onClick(DialogInterface dialogInterface, int i) {
    call.sendDTMF(mDTMF.getText().toString(), Call.DTMFType.RFC2833);
        }
       }
});

11. Outgoing call hangup.

Call.hangup() code

Code Block
languagejava
themeRDark
mCallButton.setEnabled(false);
call.hangup();
                    incomingCallAlert call = null;
  

12. Incoming call hangup.

Call.hangup() code

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

813. Answering incoming callDisconnection.

CallSession.answerdisconnect()   code

Code Block
languagejava
themeRDark
case INCOMING_CALL_REQUEST_CODE: {
    if (grantResults.length == 0 ||
mConnectButton.setEnabled(false);
session.disconnect();

14. Connection to an existing session using token

Connection.setAuthToken(), Session.connect code

Code Block
languagejava
themeRDark
        mConnectTokenButton.setOnClickListener(new OnClickListener() {
 grantResults[0] != PackageManager.PERMISSION_GRANTED) {
        call.hangup();@Override
        incomingCallAlert = null;
  public void onClick(View v)   Log.i(TAG, "Permission has been denied by user");
{
           } else {
   if (mConnectTokenButton.getTag() == null || mCallButtonInteger.setTextvalueOf(R.string.action_hangup);
_connect_token).equals(mConnectTokenButton.getTag())) {
                    connectWithToken  mCallButton.setTag(R.string.action_hangup);
= true;
              mCallButton.setEnabled(true);
      String authToken = mCallStatusmAuthTokenView.setTextgetText(call).getStatustoString());
          call.answer();
           incomingCallAlert = null;if (authToken.isEmpty()) {
        Log.i(TAG, "Permission has been granted by user");
    }
}

9. Call hold and retrieve.

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

Code Block
languagejava
themeRDark
mHoldButton.setOnClickListener(new OnClickListener() {
      return;
     @Override
     public void onClick(View view) {
      }
  if (mHoldButton.getTag() == null || Integer.valueOf(R.string.action_hold).equals(mHoldButton.getTag())) {
            callmConnectButton.holdsetEnabled(false);
            mHoldButton.setText(R.string.action_unhold);
            mHoldButton.setTag(R.string.action_unholdmConnectTokenButton.setEnabled(false);
        } else {
            call.unholdcreateSession();
            mHoldButton.setText(R.string.action_hold);
         Connection connection = new mHoldButton.setTag(R.string.action_holdConnection();
        }

    }
});

10. DTMF sending

Call.sendDTMF() code

Code Block
languagejava
themeRDark
mDTMF = (EditText) findViewById(R.id.dtmf);
mDTMFButton = (Button) findViewById(R.id.dtmf_button);
mDTMFButton.setOnClickListener(new OnClickListener() {
@Override
      connection.setAuthToken(authToken);
       public void onClick(View view) {
        if (call != null) {
connection.setKeepAlive(true);
                    callsession.sendDTMF(mDTMF.getText().toString(), Call.DTMFType.RFC2833);
connect(connection);
                } else {
           }
});

11. Outgoing call hangup.

Call.hangup() code

Code Block
languagejava
themeRDark
mCallButton         mConnectButton.setEnabled(false);
call.hangup();
call = null;

12. Incoming call hangup.

Call.hangup() code

Code Block
languagejava
themeRDark
builder.setNegativeButton("Hangup", new DialogInterface.OnClickListener() {
    @Override
    public void onClick(DialogInterface dialogInterface, int i) {
                    mConnectTokenButton.setEnabled(false);
                    session.disconnect();
                call.hangup();
}
          incomingCallAlert = null;}
     }
});

13. Disconnection.

Session.disconnect() code

Code Block
languagejava
themeRDark
mConnectButton.setEnabled(false);
session.disconnect();

...

   });