Interaksi dengan server Asterisk dari aplikasi Java

Berinteraksi dengan server Asterisk dari aplikasi java melalui Asterisk Managment Interface (AMI)


Jika Anda baru memulai penelitian di bidang ini, maka interaksi dengan server ini mungkin bagi Anda agak membingungkan, seperti yang pernah saya alami.

Agar tidak mencari bit informasi yang diperlukan di forum dengan gaya jawaban-pertanyaan, saya melampirkan tutorial kecil tentang berinteraksi dengan server Asterisk dari java.

Penting: Saya berasumsi bahwa begitu Anda telah mencapai tahap penulisan kode, maka Anda sudah memiliki server Asterisk yang dapat Anda akses.

1) Apa yang harus dipilih agar nyaman bekerja?

Definitely - Asterisk Managment Interface (AMI): antarmuka ini memiliki berbagai fungsi yang memungkinkan Anda melakukan panggilan, mendengarkan acara secara real time dari server, menerima status panggilan dan menyela jika diperlukan.

2) Pustaka apa yang akan dihubungkan?

Ini:

<dependency> <groupId>org.asteriskjava</groupId> <artifactId>asterisk-java</artifactId> <version>2.0.4</version> </dependency> 

3) Konfigurasi apa yang perlu dilihat di server?

extensions.conf - konfigurasi yang menjelaskan diaplan. Anda akan terus menghubunginya. Jika dalam bahasa yang lebih dimengerti, maka itu berisi skrip dari apa yang akan dilakukan server ketika menerima panggilan ke nomor tertentu. Pertama, konteks spesifik dicari di diaplan - ditulis dalam tanda kurung, setelah itu nomor dicari di bawah tag konteks ini yang Anda hubungi.

manager.conf - konfigurasi dengan pengguna dan kata sandi untuk server Asterisk Anda

Konten konfigurasi ini kira-kira sebagai berikut:

 [user_name] secret = password read = all write = all deny=0.0.0.0/0.0.0.0 permit=0.0.0.0/255.255.255.0 

  • user_name - nama pengguna
  • rahasia - kata sandi untuk itu
  • deny - ip address yang ditolak aksesnya di bawah pengguna ini
  • izin - akses yang diizinkan. Pastikan untuk menentukan ip yang Anda hubungi dengan izin, karena aster dapat menolak permintaan Anda.

sip.conf - semua batang terdaftar di sini. Trunk adalah telepon dari mana kita akan memanggil klien.

4) Di mana mulai menulis kode?

Ada dua opsi: Anda harus melakukan beberapa tindakan di server Asterisk, atau mendengarkan acara di server. Urutan kami mencakup keduanya.

Kami menggambarkan rencana tindakan:

  1. Buka koneksi ke server;
  2. Kami menggambarkan skenario kerja;
  3. Kami mendengarkan acara;
  4. Tutup koneksi.

Oleh karena itu, koneksi diinisialisasi selama pembuatan objek DefaultAsteriskServer:

 import org.asteriskjava.live.AsteriskServer; import org.asteriskjava.live.DefaultAsteriskServer; 

 AsteriskServer asteriskServer = new DefaultAsteriskServer(HOSTNAME, USERNAME, PASSWORD); asteriskServer.initialize(); 

Setelah membuka koneksi, kita perlu memanggil pengguna. Kami akan menyebutnya skenario aksi. Deskripsi skenario akan berada di kelas yang terpisah:

 /** *    */ public class ScenarioCall extends OriginateAction { private final Logger log = LoggerFactory.getLogger(ScenarioCall.class); private String TRUNK; private final String PHONE_FOR_RINGING; private final String EXTEN_FOR_APP; private final String CONTEXT_FOR_APP; public ScenarioCall(String trunk, String phoneForRinging, String extension, String context) { this.TRUNK = trunk; this.PHONE_FOR_RINGING = phoneForRinging; this.EXTEN_FOR_APP = extension; this.CONTEXT_FOR_APP = context; this.init(); } /** *         OriginateAction */ private void init() { //  String callId = ValidValues.getValidCallId(this.PHONE_FOR_RINGING); //    String channelAsterisk = ValidValues.getValidChannel(this.TRUNK, this.PHONE_FOR_RINGING); this.setContext(CONTEXT_FOR_APP); this.setExten(EXTEN_FOR_APP); this.setPriority(1); this.setAsync(true); this.setCallerId(callId); this.setChannel(channelAsterisk); log.info("Create Scenario Call: phone '{}',chanel '{}',context '{}',extension '{}'", callId, channelAsterisk, CONTEXT_FOR_APP, EXTEN_FOR_APP); } } 

Apa yang perlu kita pahami dalam skenario ini? Pertama, koneksi trunk dibuat. Trunk adalah nomor dari mana Anda akan memanggil pelanggan. Setelah itu, koneksi dibuat antara trunk dan pelanggan, setelah itu koneksi antara pelanggan dan siapa lagi yang Anda butuhkan ada di sana.

Dalam urutan itu.

 this.setContext(CONTEXT_FOR_APP) 
Nilai yang dikirimkan: konteks di mana kami akan mencari nomor telepon yang ingin Anda kaitkan dengan pelanggan (dari extensions.conf).

 this.setExten(EXTEN_FOR_APP) 
Nilai yang dikirimkan: skrip yang akan dieksekusi setelah Anda menghubungi pelanggan (dari extensions.conf).

 this.setCallerId(callId) 
Nilai yang ditransmisikan: nomor pelanggan kami

 this.setChannel(channelAsterisk) 
Nilai yang ditransmisikan: saluran komunikasi yang dibuat, biasanya terlihat seperti ini: trunk_name / phone_user.

Di mana mencari trunk_name? Ada konfigurasi sip.conf di server asterisk - semua batang terdaftar di sana.

Buat panggilan:

 if (asteriskServer .getManagerConnection().getState().equals(ManagerConnectionState.CONNECTED) || asteriskServer .getManagerConnection().getState().equals(ManagerConnectionState.CONNECTING) || asteriskServer .getManagerConnection().getState().equals(ManagerConnectionState.INITIAL)) { try { ScenarioCall scenarioCall = new ScenarioCall(trank, phone, extension, context); CallBack callBackForScenarioCall = new CallBack(); asteriskServer.originateAsync(scenarioCall, callBackForScenarioCall); } catch (ManagerCommunicationException e) { //   , StateConnection    RECONNECTING,     } } 

Kami membuat panggilan, tetapi bagaimana cara melacaknya secara dinamis?

Dua hal dilakukan untuk ini: turunan dari kelas CallBack dilewatkan dalam metode origininateAsync
dan pendengar digantung di server, yang akan menggabungkan semua yang terjadi pada kita.

Seorang pendengar diperlukan karena kelas CallBack tidak akan memberi tahu Anda tentang akhir panggilan saat pengguna sudah berbicara, juga tidak akan memberi tahu Anda bahwa pengguna masih dapat mentransfer di tempat lain.

 /** *        asteriskConnection.originateAsync  *  CallBack -     ,     *  originateAsync. CallBack      , *       ,    onNoAnswer ,  *     onBusy,     ,  onFailure,  . *        . ,      *      (      ,    ) */ public class CallBack implements OriginateCallback { /** *     PRERING,       * OriginateCallback -    */ private ChannelState resultCall = ChannelState.PRERING; /** *    ,   .         */ @Override public void onDialing(AsteriskChannel asteriskChannel) { //   ,  resultCall, //   asteriskChannel    null, //    resultCall   //   } /** *   .      *      6 - setStatus */ @Override public void onSuccess(AsteriskChannel asteriskChannel) { //   , asteriskChannel   null, // asteriskChannel.getState()      ChannelState.UP //   } /** *      ,    *      7 - setStatus () */ @Override public void onNoAnswer(AsteriskChannel asteriskChannel) { //   , //   asteriskChannel    null, //    resultCall   //   } /** *   *      7 - setStatus () */ @Override public void onBusy(AsteriskChannel asteriskChannel) { //   , //   asteriskChannel    null, //    resultCall   //   } /** *      */ @Override public void onFailure(LiveException e) { //     , //     , // onFailure      } } 

Bagaimana cara menggantung pendengar di asterisk?

Untuk melakukan ini, buat kelas pelaksana AsteriskServerListener, PropertyChangeListener.
Untuk koneksi yang dibuat, melalui turunan kelas AsteriskConnection, kami menerapkan:

  this.asteriskConnection.addAsteriskServerListener(this.callBackEventListener); 

this.callBackEventListener - turunan dari kelas pendengar kami, lahir dari:

 ** *    Asterisk *  PropertyChangeListener   ,     . *  AsteriskServerListener   ,     AsteriskConnection. */ public class CallBackEventListener implements AsteriskServerListener, PropertyChangeListener { public void onNewAsteriskChannel(AsteriskChannel channel) { channel.addPropertyChangeListener(this); } public void onNewMeetMeUser(MeetMeUser user) { user.addPropertyChangeListener(this); } public void onNewQueueEntry(AsteriskQueueEntry user) { user.addPropertyChangeListener(this); } public void onNewAgent(AsteriskAgent asteriskAgent) { asteriskAgent.addPropertyChangeListener(this); } /** *    .   {@link PropertyChangeEvent} *    , *        , *        CallBack * * @param propertyChangeEvent      */ public void propertyChange(PropertyChangeEvent propertyChangeEvent) { findEventEndCall(propertyChangeEvent); } private void findEventEndCall(PropertyChangeEvent event) { if (event.getSource() instanceof AsteriskChannel) { AsteriskChannel callBackChannel = (AsteriskChannel) event.getSource(); String callId = getStringWithOnlyDigits(callBackChannel.getCallerId().toString()); callId = ValidValues.getValidCallId(callId); if (callBackChannel.getState().toString().equals("HUNGUP") && event.getOldValue().toString().contains("RINGING")) { //      callBackChannel.removePropertyChangeListener(this); //     } else if (callBackChannel.getState().toString().equals("HUNGUP") && event.getOldValue().toString().contains("UP")) { //     callBackChannel.removePropertyChangeListener(this); //     } else if (callBackChannel.getState().toString().equals("HUNGUP")) { //      callBackChannel.removePropertyChangeListener(this); //     } } } private String getStringWithOnlyDigits(String strForParse) { String result = ""; if (strForParse != null && !strForParse.isEmpty()) { CharMatcher ASCII_DIGITS = CharMatcher.anyOf("<>").precomputed(); result = ASCII_DIGITS.removeFrom(strForParse.replaceAll("[^0-9?!]", "")); } return result; } } 

Saya menyarankan Anda di awal hanya untuk berjanji, apa yang datang ke propertyChange dan lihat di PropertyChangeEvent, itu akan menjadi tumpukan dari semua yang terjadi di server. Itu tidak menyaring informasi sama sekali. Oleh karena itu, kesimpulannya: gantung pendengar sesedikit mungkin. Tidak untuk setiap panggilan, karena itu dapat dilakukan bahkan di kelas OriginateCallback, sejauh yang saya temukan. Ini tidak berguna. Lihatlah objek PropertyChangeEvent apa yang datang kepada Anda, lihat jenis bidang di sana dan mana yang Anda butuhkan. Berikutnya - selamat datang di dunia pemrosesan informasi.

Sedikit tentang validasi data.

Dalam OriginateAction.setChannel - trunk_name / phone_user dilewatkan
phone_user - jika ini bahasa Rusia, itu harus dimulai dengan angka delapan, jika nomor internasional dengan nilai plus.

Di OriginateAction.setCallerId - nomor telepon klien ditransmisikan,
kemudian di CallBackEventListener akan muncul di callBackChannel.getCallerId ().

Akan menerimanya seperti ini:

 String callId = getStringWithOnlyDigits(callBackChannel.getCallerId().toString()); 

Pada akhirnya, jangan lupakan:

 asteriskServer.shutdown(); 

Jika Anda perlu menyela panggilan apa pun, maka baik di kelas CallBackEventListener
ke saluran komunikasi yang ada kami lakukan:

 callBackChannel.hangup(); 

Ternyata tutorial yang sederhana. Sekilas, tentu saja, ini sangat sederhana, tapi percayalah, butuh banyak waktu dan keberanian untuk menemukan informasi, menunda semua metode, dan pergi bekerja.

Semoga berhasil dengan server Asterisk Anda!

Bacaan lebih lanjut:

1) tutorial Asterisk-Java

2) Asterisk Managment Interface (AMI)

Source: https://habr.com/ru/post/id469491/


All Articles