着信通話を録音する

数ヶ月前、私の友人から、着信通話の録音の問題の解決を手伝ってほしいと頼まれました。 必要なものはすべて利用可能であったか、提供することが約束されていました。



画像



興味があれば、私のPython実装の経験とcatの下のコード。



友人がコンピューター機器の技術サポートとメンテナンスを提供します。 従業員の仕事の性質は旅行です。 個別のディスパッチャはありません。すべてのコールは従業員自身が受信して保存します。 従業員が電話に出られない(外出中、クライアントとの対話で)場合、または従業員がクライアントから苦情を受け取る場合(要求されたすべてのことをしなかった、またはしなかった)があります。 このような状況は「解決」する必要があります。 一般に、彼はなんらかの方法で、ディスパッチャを雇わずにコールの受信を集中化する必要がありました。



友人と一緒に、すべてのインシデントと変更が記録され、 ITIL要件に従って管理されます。 easla.comを使用した自動プロセス。 欠けていたのは呼び出しだけでした。



挑戦する



本格的なコールセンターについては話していませんでした。 コール分析は「事後」に実行されます。 したがって、要件は簡単でした。







easla.comが提供するデータベースでは、「Call」オブジェクトとすべての必要な属性がすでに作成されています。 ステータスのみがネゴシエートされます。 彼らは、電話口座でお金がなくなった場合に備えて、「不可能」というステータスを追加しました。



解決策



まず第一に、彼らはあなたがまだ都市番号を取得し、着信通話を処理するためにアスタリスクサーバーをアップグレードすることにお金を費やす必要があることに同意しました。 ローカルIPテレフォニープロバイダーから番号を購入し、アスタリスクサーバーを既存のハードウェアを使用して別の仮想サーバーにアップロードしました。 アスタリスクでは、サーバーはセルラーアシスタントへのすべての着信の転送を構成したため、ディスパッチャーになりました。



TwistedをFastAGIサーバーとして使用することが決定されました。これは、完全な呼び出しに関する情報を受信し、SOAPを介してeasla.comに情報を送信します。 すべての手順はシステム管理者のマニュアルに記載されています



会話はMixMonitorコマンドを使用して記録され、ファイル名として$ {UNIQUEID}変数を使用します。

会話の最後に、会話を停止し、制御をFastAGIサーバーに転送します。

exten => h,1,StopMixMonitor

exten => h,n,AGI(agi://127.0.0.1:4573)







FastAGIはstarpyライブラリを使用してプロトコルを実装しました。 コールの継続時間に関する情報は、CDRレコードを通じて取得されます。 必要な情報をすべて個別のストリームで受信した後、easla.comに書き込みます。



通話情報を取得する
 def fastAgiMain( agi ): sequence = fastagi.InSequence() #     . cdr_vars = { 'CDR(start)':'', 'CDR(disposition)}':'', 'CDR(duration)':'', 'CDR(end)':'', 'DIALSTATUS':'', } #         easla.com    sequence.append(sendCDR, None, agi, cdr_vars, iter(cdr_vars)) #     asterisk sequence.append(agi.finish) def onFailure( reason ): log.error( "Failure: %s", reason.getTraceback()) agi.finish() return sequence().addErrback( onFailure ) #  ,       cdr_vars def sendCDR(result, agi, cdr_vars, keys): def setVar(result, key): cdr_vars[key] = result def notAvailable(reason, key): print "key " + key + " not found" try: key = keys.next() except StopIteration, err: duration = str(timedelta(seconds=int(cdr_vars['CDR(duration)']))) #   getVariable   callerid  uniqueid caller_id = agi.variables['agi_callerid'] wav_file = '/data/wav/' + agi.variables['agi_uniqueid'] + '.wav' status = cdr_vars['DIALSTATUS'] #        thread = Thread(target=sendCallInfo, args=(caller_id, duration, wav_file, status)) thread.start() return None else: return agi.getVariable(key) \ #   key .addCallback(setVar, key) \ #    cdr_vars .addErrback(notAvailable, key) \ #       key .addCallback(sendCDR, agi, cdr_vars, keys) #    
      
      









アスタリスクがコール制御を返した後、wavをmp3に変換し、easla.comに情報を送信し始めることができます。 ここでは、多くのマニュアルで提案されているように、変換にMixMonitorを使用しない理由を説明する必要があります。 MixMonitorはサードパーティのアプリケーションを個別のプロセスとして起動し、アプリケーションが完了したことをFastAGIに通知しません。また、呼び出し情報が送信されるまでにmp3ファイルにアクセスできなくなる可能性があります。 変換には、 pydubライブラリが使用され、SOAPクライアントとして泡立ちます。



送ります
 def sendCallInfo(callid, callduration, wav_file ,status): raw_params = { 'incoming_call_number': callid, 'incoming_call_time': callduration,} if status: if status == 'ANSWER': raw_params['status'] = 'incoming_call_answered' if status == 'BUSY': raw_params['status'] = 'incoming_call_busy' if status == 'NOANSWER': raw_params['status'] = 'incoming_call_unanswered' if status == 'CANCEL': raw_params['status'] = 'incoming_call_unanswered' if status == 'CONGESTION': raw_params['status'] = 'incoming_call_congestion' url = 'http://easla.com/user/soap' client = Client(url) client.service.login('login','password') call_management_proc = client.service.getProcess('call_management') incoming_call_def = client.service.getObjectdef(call_management_proc, 'incoming_call', 0) keyval_array = client.factory.create('KeyValuesPairSoapArray') #   KeyValuesPairSoapArray    easla.com for key, value in raw_params.iteritems(): keyval = client.factory.create('KeyValuesPairSoap') keyval.key = key keyval.values.item.append(value) keyval_array.item.append(keyval) #      easla.com incoming_call_obj = client.service.createObjectref(incoming_call_def, None, keyval_array) if os.path.exists(wav_file): # asterisk      while is_locked(wav_file): time.sleep(1) mp3_file = wav2mp3(wav_file) with open(mp3_file, "rb") as image_file: encoded_string = base64.b64encode(image_file.read()) if encoded_string: #       mp3  file_attr = client.factory.create('KeyValuePairSoapArray') file_name = client.factory.create('KeyValuePairSoap') file_content = client.factory.create('KeyValuePairSoap') file_name.key = 'srcname' file_name.value = os.path.basename(mp3_file) file_content.key = 'content' file_content.value = encoded_string file_attr.item.append(file_name) file_attr.item.append(file_content) #     client.service.addFile(incoming_call_obj, 'incoming_call_file', file_attr) if wav_file: os.remove(wav_file) if mp3_file: os.remove(mp3_file)
      
      









モジュールは、運用の最初の週に実行できました。 最初は、口座に十分な資金がなかったため、ステータスが「Impossible」のコールの登録を確認しました。 その後、アカウントを補充し、他のステータスのコールの登録を確認しました。

着信呼び出しのレジストリは次のようになります。







コール登録の開始後、登録されたコールの加入者を決定し、登録されたコールに基づいてインシデントを作成する機能を追加できました。



そのような解決策が誰かに役立つなら、私はうれしいです。



All Articles