Versions Compared

Key

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

Пример Android-приложения для аудиозвонков

Поля ввода, необходимые для установления SIP-соединения

...

В поле 'Callee' вводится SIP имя пользователя вызываемого.
При нажатии на кнопку Connect/Disconnect устанавливается/закрывается SIP-соединение.
При нажатии на кнопку Call/Hangup делается/завершается звонок.
Кнопка Hold/Unhold используется для удержания/снятия с удержания звонка.

Работа с кодом примера

Для разбора кода возьмем класс PhoneMinActivity.java примера phone-min, который доступен для скачивания в соответствующей сборке 1.0.1.38.

...

Flashphoner.init() код

Code Block
languagejsjava
themeRDark
Flashphoner.init(this);

...

Методу передается объект SessionOptions с URL WCS-сервера.

Code Block
languagejsjava
themeRDark
SessionOptions sessionOptions = new SessionOptions(mWcsUrlView.getText().toString());
session = Flashphoner.createSession(sessionOptions);

...

Методу передается объект Connection с параметрами SIP-соединения

Code Block
languagejsjava
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());
session.connect(connection);

...

Session.onConnected() код

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

...

Button.setOnClickListener() код

Code Block
languagejsjava
themeRDark
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);

            SharedPreferences sharedPref = PhoneMinActivity.this.getPreferences(Context.MODE_PRIVATE);
        }    SharedPreferences.Editor editor = sharedPref.edit();else {
            editormCallButton.putString("callee", mCalleeView.getText().toString())setEnabled(false);
            editorcall.applyhangup();
        } 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);
        }
    }
});

...

  • SIP логин вызываемого аккаунта
  • настройки аудио
  • дополнительные параметры сообщения SIP INVITE
Code Block
languagejsjava
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();

        mediaConstraints..optional.add(
        try {
     new MediaConstraints.KeyValuePair("googEchoCancellation", Boolean.toString(googEchoCancellation.isChecked())));       Map<String, String> inviteParameters = new Gson().fromJson(mInviteParametersView.getText().toString(),
        mediaConstraints.optional.add(
           new MediaConstraints.KeyValuePair("googAutoGainControl"TypeToken<Map<String, Boolean.toString(googAutoGainControl.isChecked())));String>>() {
        mediaConstraints.optional.add(       }.getType());
           new MediaConstraintscallOptions.KeyValuePair("googNoiseSupression", Boolean.toString(googNoiseSupression.isChecked())))setInviteParameters(inviteParameters);
        mediaConstraints.optional.add(} catch (Throwable t) {
           new MediaConstraintsLog.KeyValuePaire("googHighpassFilter", Boolean.toString(googHighpassFilter.isChecked())))TAG, "Invite Parameters have wrong format of json object");
        mediaConstraints.optional.add(}
        call =  new MediaConstraints.KeyValuePair("googEchoCancellation2", Boolean.toString(googEchoCancellation2.isChecked())))session.createCall(callOptions);
        mediaConstraintscall.optional.add(on(callStatusEvent);
        /**
     new MediaConstraints.KeyValuePair("googAutoGainControl2", Boolean.toString(googAutoGainControl2.isChecked())));
   * Make the   mediaConstraints.optional.add(outgoing call
           new MediaConstraints.KeyValuePair("googNoiseSuppression2", Boolean.toString(googNoiseSuppression2.isChecked())));
*/
        try {call.call();
            Map<String, String> inviteParameters = new Gson().fromJson(mInviteParametersView.getText().toString(),
               new TypeToken<Map<String, String>>() {Log.i(TAG, "Permission has been granted by user");
        break;
       }.getType());
            callOptions.setInviteParameters(inviteParameters}
}


7. Получение от сервера события, сигнализирующего о входящем звонке

Session.onCall() код

Code Block
languagejava
themeRDark
@Override
public void onCall(final Call call) {
    call.on(callStatusEvent);
    /**
    } catch (Throwable* t)Display {
UI alert for the new incoming call
      Log.e(TAG, "Invite Parameters have wrong format of json object");*/
    runOnUiThread(new Runnable() {
        }@Override
        callpublic =void session.createCallrun(callOptions); {
        call.on(callStatusEvent);
    AlertDialog.Builder builder =  /**new AlertDialog.Builder(PhoneMinActivity.this);

          * Make the outgoing builder.setTitle("Incoming call");

          */
  builder.setMessage("Incoming call from '"  + call.call(getCaller() + "'");
        Log.i(TAG, "Permission has been granted by user");
    builder.setPositiveButton("Answer", new DialogInterface.OnClickListener() {
            break;
    }
}

7. Получение от сервера события, сигнализирующего о входящем звонке

Session.onCall() код

Code Block
languagejs
themeRDark
@Override
public void onCall(final Call call) {
    call.on(callStatusEvent);
    /**
   public void onClick(DialogInterface *dialogInterface, Displayint UI alert for the new incoming call
i) {
                */
    runOnUiThread(new Runnable() {
PhoneMinActivity.this.call = call;
          @Override
        public void run() {ActivityCompat.requestPermissions(PhoneMinActivity.this,
            AlertDialog.Builder builder = new AlertDialog.Builder(PhoneMinActivity.this);

            builder.setTitle("Incoming call");

new String[]{Manifest.permission.RECORD_AUDIO},
                   builder.setMessage("Incoming call from '" + call.getCaller() + "'" INCOMING_CALL_REQUEST_CODE);
            builder.setPositiveButton("Answer", new DialogInterface.OnClickListener()   }
            });
            builder.setNegativeButton("Hangup", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialogInterface, int i) {
                    PhoneMinActivity.this.call = callcall.hangup();
                    ActivityCompat.requestPermissions(PhoneMinActivity.this,
        incomingCallAlert = null;
                  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. Ответ на входящий звонок.

Call.answer() код

Code Block
languagejs
themeRDark
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(), Call.unhold() код

Code Block
languagejs
themeRDark
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. Посылка тонального сигнала

Call.sendDTMF() код

Code Block
languagejs
themeRDark
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. Завершение исходящего звонка.

Call.hangup() код

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

12. Завершение входящего звонка.

Call.hangup() код

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

13. Закрытие соединения.

Session.disconnect() код

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

Пример Android-приложения для аудиозвонков

Поля ввода, необходимые для установления SIP-соединения

  • 'WCS URL', где 192.168.2.104 - адрес WCS-сервера
  • 'SIP Login'- SIP имя пользователя
  • 'SIP Password' - пароль
  • 'SIP Domain' - SIP-домен
  • 'SIP port' - порт

В поле 'Callee' вводится SIP имя пользователя вызываемого.
При нажатии на кнопку Connect/Disconnect устанавливается/закрывается SIP-соединение.
При нажатии на кнопку Call/Hangup делается/завершается звонок.
Кнопка Hold/Unhold используется для удержания/снятия с удержания звонка.

Image Removed

Работа с кодом примера

Для разбора кода возьмем класс PhoneMinActivity.java примера phone-min, который доступен для скачивания в соответствующей сборке 1.0.1.38.

1. Инициализация API.

Flashphoner.init() код

Code Block
languagejs
Flashphoner.init(this);

При инициализации методу init() передается объект Сontext.

2. Создание сессии.

Flashphoner.createSession() код

Методу передается объект SessionOptions с URL WCS-сервера.

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

3. Подключение к серверу.

Session.connect(). код

Методу передается объект Connection с параметрами SIP-соединения

Code Block
languagejs
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());
session.connect(connection);

4. Получение от сервера события, подтверждающего успешное соединение.

Session.onConnected() код

Code Block
languagejs
@Override
public void onConnected(final Connection connection) {
runOnUiThread(new Runnable() {
@Override
public void run() {
mConnectButton.setText(R.string.action_disconnect);
mConnectButton.setTag(R.string.action_disconnect);
mConnectButton.setEnabled(true);
if (!mSipRegisterRequiredView.isChecked()) {
mConnectStatus.setText(connection.getStatus());
mCallButton.setEnabled(true);
} else {
mConnectStatus.setText(connection.getStatus() + ". Registering...");
}
}
});
}

5. Обработка нажатия кнопки Call/Hangup

Button.setOnClickListener() код

Code Block
languagejs
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);

SharedPreferences sharedPref = PhoneMinActivity.this.getPreferences(Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPref.edit();
editor.putString("callee", mCalleeView.getText().toString());
editor.apply();
} 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. Исходящий звонок.

Session.createCall(), Call.call() код

При создании в метод session.createCall() передается объект CallOptions с параметрами:

  • SIP логин вызываемого аккаунта
  • настройки аудио
  • дополнительные параметры сообщения SIP INVITE
Code Block
languagejs
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();

mediaConstraints.optional.add(
new MediaConstraints.KeyValuePair("googEchoCancellation", Boolean.toString(googEchoCancellation.isChecked())));
mediaConstraints.optional.add(
new MediaConstraints.KeyValuePair("googAutoGainControl", Boolean.toString(googAutoGainControl.isChecked())));
mediaConstraints.optional.add(
new MediaConstraints.KeyValuePair("googNoiseSupression", Boolean.toString(googNoiseSupression.isChecked())));
mediaConstraints.optional.add(
new MediaConstraints.KeyValuePair("googHighpassFilter", Boolean.toString(googHighpassFilter.isChecked())));
mediaConstraints.optional.add(
new MediaConstraints.KeyValuePair("googEchoCancellation2", Boolean.toString(googEchoCancellation2.isChecked())));
mediaConstraints.optional.add(
new MediaConstraints.KeyValuePair("googAutoGainControl2", Boolean.toString(googAutoGainControl2.isChecked())));
mediaConstraints.optional.add(
new MediaConstraints.KeyValuePair("googNoiseSuppression2", Boolean.toString(googNoiseSuppression2.isChecked())));

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. Получение от сервера события, сигнализирующего о входящем звонке

Session.onCall() код

Code Block
languagejs
@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. Ответ на входящий звонок.

Call.answer() код

Code Block
languagejava
themejsRDark
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(), Call.unhold() код

Code Block
languagejsjava
themeRDark
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. Посылка тонального сигнала

Call.sendDTMF() код

Code Block
languagejsjava
themeRDark
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. Завершение исходящего звонка.

Call.hangup() код

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

...

Call.hangup() код

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


13. Закрытие соединения.

Session.disconnect() код

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