• <strike id="fdgpu"><input id="fdgpu"></input></strike>
    <label id="fdgpu"></label>
    <s id="fdgpu"><code id="fdgpu"></code></s>

  • <label id="fdgpu"></label>
  • <span id="fdgpu"><u id="fdgpu"></u></span>

    <s id="fdgpu"><sub id="fdgpu"></sub></s>
    您當(dāng)前的位置是:  首頁 > 新聞 > 國內(nèi) >
     首頁 > 新聞 > 國內(nèi) >

    Aterisk接口-ARI對(duì)通道的狀態(tài)管理

    2017-06-26 09:27:58   作者:james.zhu   來源:Aterisk   評(píng)論:0  點(diǎn)擊:


      以前我們討論了ARI接口對(duì)DTMF事件的處理,其實(shí)ARI也支持對(duì)通道方面的處理方式,否則ARI就不能成為一個(gè)未來Asterisk接口通信的主要方式。Asterisk通過ARI接口可以獲得各種通道的狀態(tài)信息,然后通過ARI對(duì)其進(jìn)行管理控制,按照用戶的業(yè)務(wù)需求做進(jìn)一步的處理。首先我們簡單說明一下什么是通道和其狀態(tài)的含義。通道狀態(tài)是反映當(dāng)前介于Asterisk和終端設(shè)備之間的通信介質(zhì)的狀態(tài)。通道的狀態(tài)會(huì)影響所支持的操作,什么樣的通道狀態(tài)支持什么樣的通道操作,同時(shí)也會(huì)最終影響終端設(shè)備的操作執(zhí)行。
      目前通道可以支持多種狀態(tài),基本常見的幾種狀態(tài)是:
    • Down - 通信路徑存在,但是Asterisk和終端之間沒有任何媒體。
    • Ringing - 設(shè)備正在振鈴,在Asterisk和設(shè)備之間可能存在媒體。
    • Up - 設(shè)備之間已經(jīng)互相應(yīng)答。當(dāng)在UP狀態(tài)時(shí),在Asterisk和設(shè)備之間的媒體可以雙向流動(dòng)。
      注意
      某些通道介紹,例如Dahdi通道,可能支持了更多的狀態(tài) (例如,"Pre-ring" 或者 "Dialing Offhook")。當(dāng)處理通道狀態(tài)市,需要訪問Channel data model 的各種變量信息。現(xiàn)在我們主要介紹幾種不同的狀態(tài)處理方式和腳本語言的處理流程。
      指示振鈴
      Asterisk 可以通知設(shè)備對(duì)呼叫方進(jìn)行振鈴,使用的方式是POST /channels/{channel_id}/ring 的操作模式,或者可以使用
      DELETE /channels/{channel_id}/ring 的操作停止振鈴。這里用戶要注意,指示振鈴并不是真正從Asterisk到設(shè)備之間傳輸媒體。Asterisk僅是通知設(shè)備振鈴,但是終端是否振鈴取決于設(shè)備自己本身。
    \
      應(yīng)答通道
      當(dāng)通道沒有應(yīng)答之前,Asterisk仍然沒有通知設(shè)備如何進(jìn)行通信。應(yīng)答通道以后,Asterisk才完成了服務(wù)器端和設(shè)備端之間的通信路徑的創(chuàng)建,可以實(shí)現(xiàn)媒體的雙向流通。使用的方法是
      POST /channels/{channel_id}/answer 操作。
      對(duì)通道掛機(jī)
      用戶可以對(duì)通道掛機(jī),使用的是DELETE /channels/{channel_id} 操作方式。當(dāng)掛機(jī)以后,介于Asterisk和設(shè)備終端之間的通信會(huì)結(jié)束,通道離開Stasis的應(yīng)用程序。用戶的應(yīng)用程序通過一個(gè) StasisEnd 事件被提醒。
      設(shè)備掛機(jī)也是同樣的方式。在這種環(huán)境下,Asterisk和終端之間的通信結(jié)束以后,通道掛機(jī),用戶程序通過一個(gè)StasisEnd 事件被通知通道離開了應(yīng)用程序。
      一般情況下,一旦通道離開了用戶應(yīng)用程序,用戶就不能收到任何關(guān)于通道的事件信息。但是當(dāng)用戶程序訂閱了通道的所有事件時(shí),無論通道是否在應(yīng)用程序中,如果通道確實(shí)掛機(jī),用戶會(huì)收到一個(gè)ChannelDestroyed事件。
      舉例:控制通道的狀態(tài)
      這個(gè)實(shí)例ARI 程序會(huì)執(zhí)行以下步驟:
    • 等待通道進(jìn)入到一個(gè)Stasis 應(yīng)用程序。
    • 當(dāng)通道進(jìn)入到Stasis程序后,它會(huì)對(duì)通道指示振鈴,如果通道沒有準(zhǔn)備好振鈴,那么就讓通道現(xiàn)在開始振鈴。
    • 幾秒鐘以后,通道應(yīng)答呼叫。
    • 一旦通道應(yīng)答了呼叫,我們對(duì)通道啟動(dòng)一個(gè)靜音的時(shí)段。幾秒鐘以后,通道掛機(jī)。
    • 如果在這個(gè)過程中終端掛機(jī),系統(tǒng)會(huì)平滑處理掛機(jī)流程。
    • 撥號(hào)規(guī)則
      以下?lián)芴?hào)實(shí)例僅表示通道進(jìn)入到Stasis程序中:
      extensions.conf
    \
      Python
      這個(gè)例子中我們使用了ari-py 支持包。這個(gè)基本的架構(gòu)類似于channel-dump Python- 用戶可以參考這個(gè)實(shí)例來學(xué)習(xí)如何使用這個(gè)支持包連接ARI。
      這里,我們首先需要?jiǎng)?chuàng)建我們的ARI客戶端,并且注冊(cè)三個(gè)不同的事件-StasisStart,ChannelStateChange,和StasisEnd。
      很多流程的處理是在StasisStart中進(jìn)行,當(dāng)通道進(jìn)入到我們的應(yīng)用程序時(shí),StasisStart就會(huì)被調(diào)用。大部分情況下,這里還要設(shè)置一個(gè)Python定時(shí)器來初始化通道中的一些指令。
      當(dāng)通道應(yīng)答呼叫后,ChannelStateChange 句柄會(huì)打印出通道改變狀態(tài)的輸出信息。
      最后,系統(tǒng)會(huì)把初始化的定時(shí)器權(quán)限,然后發(fā)出StasisEnd 的事件。當(dāng)通道離開應(yīng)用程序后,這個(gè)事件就會(huì)馬上被調(diào)用,通常情況下,可能是呼叫方掛機(jī),或者我們自己掛機(jī)。
      我們可以啟動(dòng)一個(gè)通道的定時(shí)器:
      \
      然后注冊(cè)三個(gè)事件:
    \
      這里的StasisStart 事件需要用戶更多注意一下。
    • 首先,我們通知通道指令,2秒鐘以后,應(yīng)答這個(gè)通道:
     \
      這里,我們?cè)谕ǖ纁hannel_timers 中存儲(chǔ)了一個(gè)定時(shí)器,如果用戶掛機(jī)以后,我們可以發(fā)出StasisEnd 的事件。
    • 一旦程序執(zhí)行進(jìn)入到answer_channel中,系統(tǒng)應(yīng)答這個(gè)通道,在通道中啟動(dòng)一個(gè)靜音播放。注意,我們會(huì)繼續(xù)聲明一個(gè)answer_channel,這是一個(gè)在我們StasisStart 句柄內(nèi)嵌的函數(shù):
    \
    • 我們應(yīng)答了通道以后,系統(tǒng)會(huì)在4秒鐘內(nèi)啟動(dòng)另外一個(gè)定時(shí)器對(duì)通道進(jìn)行掛機(jī)處理。當(dāng)定時(shí)器被觸發(fā)后,它會(huì)調(diào)用hangup_channel。這是通道中最后的掛機(jī)程序。另外,我們會(huì)在StasisStart句柄中再次聲明hangup_channel:
     \
      當(dāng)創(chuàng)建了定時(shí)器以后,我們?cè)谕ǖ乐姓疋彆r(shí),系統(tǒng)會(huì)把定時(shí)器信息存儲(chǔ)到程序中的channel_timers 中。在StasisEnd事件句柄中,我們可以取消掉定時(shí)器。如果通道離開了我們的應(yīng)用程序后,我們可以觸發(fā)這個(gè)定時(shí)器來執(zhí)行某些流程或告警信息,例如HTTP返回消息等。
      \
      最后,我們打印出在ChannelStateChanged 句柄中的通道狀態(tài)信息。這里打印出通道應(yīng)答的消息:
      \
      channel-state.py
      完整的channel-state.py 源代碼:
      channel-state.py
     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62

    #!/usr/bin/env python
     
    import ari
    import logging
    import threading
     
    logging.basicConfig(level=logging.ERROR)
     
    client = ari.connect('http://localhost:8088''asterisk''asterisk')
     
    channel_timers = {}
     
    def stasis_end_cb(channel, ev):
        """Handler for StasisEnd event"""
     
        print "Channel %s just left our application" % channel.json.get('name')
     
        # Cancel any pending timers
        timer = channel_timers.get(channel.id)
        if timer:
            timer.cancel()
            del channel_timers[channel.id]
     
    def stasis_start_cb(channel_obj, ev):
        """Handler for StasisStart event"""
     
        def answer_channel(channel):
            """Callback that will actually answer the channel"""
            print "Answering channel %s" % channel.json.get('name')
            channel.answer()
            channel.startSilence()
     
            # Hang up the channel in 4 seconds
            timer = threading.Timer(4, hangup_channel, [channel])
            channel_timers[channel.id= timer
            timer.start()
     
         def hangup_channel(channel):
            """Callback that will actually hangup the channel"""
     
            print "Hanging up channel %s" % channel.json.get('name')
            channel.hangup()
     
        channel = channel_obj.get('channel')
        print "Channel %s has entered the application" % channel.json.get('name')
     
        channel.ring()
        # Answer the channel after 2 seconds
        timer = threading.Timer(2, answer_channel, [channel])
        channel_timers[channel.id= timer
        timer.start()
     
    def channel_state_change_cb(channel, ev):
        """Handler for changes in a channel's state"""
        print "Channel %s is now: %s" % (channel.json.get('name'),
                                         channel.json.get('state'))
     
    client.on_channel_event('StasisStart', stasis_start_cb)
    client.on_channel_event('ChannelStateChange', channel_state_change_cb)
    client.on_channel_event('StasisEnd', stasis_end_cb)
     
    client.run(apps='channel-state')

      channel-state.py 實(shí)際輸出結(jié)果
      這是我們終端“alice” 使用PJSIP通道進(jìn)入到我們應(yīng)用程序時(shí)的輸出結(jié)果:
    \
      JavaScript (Node.js)
      這個(gè)例子中我們使用了ari-client 支持包。這個(gè)基本的架構(gòu)類似于channel-dump JavaScript- 用戶可以參考這個(gè)實(shí)例來學(xué)習(xí)如何使用這個(gè)支持包連接ARI。
      這里,我們首先需要?jiǎng)?chuàng)建我們的ARI客戶端,并且注冊(cè)三個(gè)不同的事件-StasisStart,ChannelStateChange,和StasisEnd。
      很多流程的處理是在StasisStart中進(jìn)行,當(dāng)通道進(jìn)入到我們的應(yīng)用程序時(shí),StasisStart就會(huì)被調(diào)用。大部分情況下,這里還要設(shè)置一個(gè)Python定時(shí)器來初始化通道中的一些指令。
      當(dāng)通道應(yīng)答呼叫后,ChannelStateChange 句柄會(huì)打印出通道改變狀態(tài)的輸出信息。
      最后,系統(tǒng)會(huì)把初始化的定時(shí)器權(quán)限,然后發(fā)出StasisEnd 的事件。當(dāng)通道離開應(yīng)用程序后,這個(gè)事件就會(huì)馬上被調(diào)用,通常情況下,可能是呼叫方掛機(jī),或者我們自己掛機(jī)。
      我們可以啟動(dòng)一個(gè)通道的定時(shí)器:
      \
      然后注冊(cè)三個(gè)事件:
     \
      這里的StasisStart 事件需要用戶更多關(guān)注。
      首先我們通知通道指令,2秒鐘以后應(yīng)答通道:
      \
      這里,我們?cè)谕ǖ纁hannel_timers 中存儲(chǔ)了一個(gè)定時(shí)器,如果用戶掛機(jī)以后,我們可以發(fā)出StasisEnd 的事件。
      一旦程序執(zhí)行進(jìn)入到answer_channel中,系統(tǒng)應(yīng)答這個(gè)通道,在通道中啟動(dòng)一個(gè)靜音播放。注意,我們會(huì)繼續(xù)聲明一個(gè)answer_channel,這是一個(gè)在我們StasisStart 句柄內(nèi)嵌的函數(shù):
    \
      我們應(yīng)答了通道以后,系統(tǒng)會(huì)在4秒鐘內(nèi)啟動(dòng)另外一個(gè)定時(shí)器對(duì)通道進(jìn)行掛機(jī)處理。當(dāng)定時(shí)器被觸發(fā)后,它會(huì)調(diào)用hangup_channel。這是通道中最后的掛機(jī)程序。另外,我們會(huì)在StasisStart句柄中再次聲明hangup_channel:
      \
      當(dāng)創(chuàng)建了定時(shí)器以后,我們?cè)谕ǖ乐姓疋彆r(shí),系統(tǒng)會(huì)把定時(shí)器信息存儲(chǔ)到程序中的channel_timers 中。在StasisEnd事件句柄中,我們可以取消掉定時(shí)器。如果通道離開了我們的應(yīng)用程序后,我們可以觸發(fā)這個(gè)定時(shí)器來執(zhí)行某些流程或告警信息,例如HTTP返回消息等。
      \
      最后,我們打印出在ChannelStateChanged 句柄中的通道狀態(tài)信息。這里打印出通道應(yīng)答的消息:
     \
      channel-state.js
      完整的channel-state.js 源代碼:
      channel-state.js
      

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81

    /*jshint node: true*/
    'use strict';
     
    var ari = require('ari-client');
    var util = require('util');
     
    var timers = {};
    ari.connect('http://localhost:8088''asterisk''asterisk', clientLoaded);
     
    // handler for client being loaded
    function clientLoaded (err, client) {
      if (err) {
        throw err;
      }
     
      // handler for StasisStart event
      function stasisStart(event, channel) {
        console.log(util.format(
              'Channel %s has entered the application', channel.name));
     
        channel.ring(function(err) {
          if (err) {
            throw err;
          }
        });
        // answer the channel after 2 seconds
        var timer = setTimeout(answer, 2000);
        timers[channel.id] = timer;
     
        // callback that will answer the channel
        function answer() {
          console.log(util.format('Answering channel %s', channel.name));
          channel.answer(function(err) {
            if (err) {
              throw err;
            }
          });
          channel.startSilence(function(err) {
            if (err) {
              throw err;
            }
          });
          // hang up the channel in 4 seconds
          var timer = setTimeout(hangup, 4000);
          timers[channel.id] = timer;
        }
     
        // callback that will hangup the channel
        function hangup() {
          console.log(util.format('Hanging up channel %s', channel.name));
          channel.hangup(function(err) {
            if (err) {
              throw err;
            }
          });
        }
      }
     
      // handler for StasisEnd event
      function stasisEnd(event, channel) {
        console.log(util.format(
              'Channel %s just left our application', channel.name));
        var timer = timers[channel.id];
        if (timer) {
          clearTimeout(timer);
          delete timers[channel.id];
        }
      }
     
      // handler for ChannelStateChange event
      function channelStateChange(event, channel) {
        console.log(util.format(
              'Channel %s is now: %s', channel.name, channel.state));
      }
     
      client.on('StasisStart', stasisStart);
      client.on('StasisEnd', stasisEnd);
      client.on('ChannelStateChange', channelStateChange);
     
      client.start('channel-state');
    }

    channel-state.js in action
      這是我們終端“alice” 使用PJSIP通道進(jìn)入到我們應(yīng)用程序時(shí)的輸出結(jié)果:
    \

    相關(guān)閱讀:

    專題

    亚洲精品网站在线观看不卡无广告,国产a不卡片精品免费观看,欧美亚洲一区二区三区在线,国产一区二区三区日韩 郯城县| 大同市| 珠海市| 门源| 乌鲁木齐县| 茶陵县| 东方市| 彭泽县| 炉霍县| 宜黄县| 湘西| 布拖县| 高平市| 望江县| 兴海县| 邓州市| 彝良县| 隆昌县| 烟台市| 苏尼特左旗| 双柏县| 婺源县| 岫岩| 库伦旗| 扶沟县| 瑞昌市| 重庆市| 江孜县| 炎陵县| 永德县| 成武县| 大邑县| 阿拉善左旗| 洛南县| 陇川县| 娱乐| 卓资县| 双城市| 岱山县| 石城县| 兴隆县| http://444 http://444 http://444 http://444 http://444 http://444