NanoPi NEOをSIP電話機にする 後編 (その1)

NanoPi NEO2とUSBハンドセット

前々回でUSBハンドセットをNanoPi NEOに接続すると/dev/hidraw*として認識されることが判っている。
で、ハンドセットのマイクとスピーカーは特になにも手を加えずともサウンドデバイスとして認識されることも判っている(既に使えている)。
今回はハンドセットのボタンを使えるようにするのと液晶に表示できるようにしたい。

ボタン入力

まずはボタンを押したときにどういう信号が来るのかを確認する。

USBハンドセット 1

# hexdump /dev/hidraw0
0000000 0301 0100 0101 0101 0001 0100 0101 0101 ← [1]
0000010 0901 0100 0101 0101 0001 0100 0101 0101 ← [2]
0000020 0f01 0100 0101 0101 0001 0100 0101 0101 ← [3]
0000030 0401 0100 0101 0101 0001 0100 0101 0101 ← [4]
0000040 0a01 0100 0101 0101 0001 0100 0101 0101 ← [5]
0000050 1001 0100 0101 0101 0001 0100 0101 0101 ← [6]
0000060 0501 0100 0101 0101 0001 0100 0101 0101 ← [7]
0000070 0b01 0100 0101 0101 0001 0100 0101 0101 ← [8]
0000080 1101 0100 0101 0101 0001 0100 0101 0101 ← [9]
0000090 0601 0100 0101 0101 0001 0100 0101 0101 ← [*]
00000a0 0c01 0100 0101 0101 0001 0100 0101 0101 ← [0]
00000b0 1201 0100 0101 0101 0001 0100 0101 0101 ← [#]
00000c0 0201 0100 0101 0101 0001 0100 0101 0101 ← ① [Off-hook]
00000d0 1301 0100 0101 0101 0001 0100 0101 0101 ← ② [Up]
00000e0 1601 0100 0101 0101 0001 0100 0101 0101 ← ③ [Down]
00000f0 0e01 0100 0101 0101 0001 0100 0101 0101 ← ④ [On-hook]
0000100 0101 0100 0101 0101 0001 0100 0101 0101 ← ⑤[yes]
0000110 0701 0100 0101 0101 0001 0100 0101 0101 ← ⑥[+]
0000120 0d01 0100 0101 0101 0001 0100 0101 0101 ← ⑦[no]
0000130 1b01 0100 0101 0101 0001 0100 0101 0101 ← [mute]
0000140 1901 0100 0101 0101 0001 0100 0101 0101 ← [Vol +]
0000150 1c01 0100 0101 0101 0001 0100 0101 0101 ← [Vol -]
         ↑ この列                     ↑押したボタン

コマンドを入力後、ハンドセットのボタンを1つ押すごとに送信された信号(データ)が1行で表示される。
どのボタンを押したときに何が送信されてくるかメモしておく。

pythonが使えることを確認。

$ python -V
Python 2.7.9

Cheap USB Skype/VoIP phone protocol discoveryのページのpythonスクリプトの1つめを貰ってくる。そのスクリプトでは対象デバイスが/dev/hidraw1になっているので自分の環境に合わせる。

1
2
- file = open( "/dev/hidraw1", "w+b" );
+ file = open( "/dev/hidraw0", "w+b" );

ボタンを押した時に送信される信号(データ)はハンドセットの機種ごとに違う筈なので先ほど調べた信号に書き換える。
例えば「がとらぼ」の中の人のハンドセットはYesとNoの間のボタンが[+]という表示ものだが、上の方で取得したコードのとおり[+]ボタンは 0x07なのでリンクのページから得たスクリプトの[S](0x08)とは違う。その他のボタンは偶然だろうが同じだった

1
2
- 0x08 : "S",
+ 0x07 : "+",

script 1

スクリプト名をscript1.pyとして

# chmod +x script1.py
# ./script1.py

この状態でUSBハンドセットのボタンを押しまくり、押したボタンのラベルがターミナル(PC側)に正しく表示されることを確認。

これでボタン押しによる入力側は全部利用できることが確認できた。

液晶画面出力

Cheap USB Skype/VoIP phone protocol discoveryのページのpythonスクリプトの2つめを貰ってくる。
スクリプトを見るとimport Image, ImageDraw, ImageFontとあるのでイメージ系ライブラリが要るようだがこの手のはPillowでイケる筈。

# apt install python-pil

スクリプトを3箇所変更

1
2
3
4
5
6
7
8
- import Image, ImageDraw, ImageFont
+ from PIL import Image, ImageDraw, ImageFont

- file = open( "/dev/hidraw1", "w+b" );
+ file = open( "/dev/hidraw0", "w+b" );

- font = ImageFont.truetype("/usr/share/fonts/truetype/msttcorefonts/arial.ttf", 20)
+ font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf", 20)

後はダミーのlogo.pngをカレントディレクトリに用意。
先と同様にボタンを押したときのコードも必要に応じて変更。

1
2
- 0x08 : "S",
+ 0x07 : "+",

script 2

スクリプト名をscript2.pyとして

# chmod +x script2.py
# ./script2.py

今度はUSBハンドセットのボタンを押すとハンドセットの液晶画面に押したボタンのラベルが表示される。表示範囲は1行だけで溢れ制御はないので表示範囲が文字で埋まったらオンフック(通話終了)ボタンを押して液晶の表示をクリアする。

USBハンドセット 2
上の写真はボタンを押した時の表示じゃないけど1行にこんな風に表示される。

出力側のメインの処理は以下の部分なので「16進数で適当に」の部分にいろいろ入れて試してみることになるかと思う。

1
2
3
4
5
6
7
#!/usr/bin/python
import struct
file = open( "/dev/hidraw0", "w+b" );
buf="16進数で適当に".decode("hex")
file.write(buf)
file.flush()
file.close();

たとえば「がとらぼ」の中の人のUSBハンドセットだと 0400 を送信すると液晶バックライトOff、 040f を送信すると液晶バックライトOnというのが判明した。当然だけど、ある程度は目星を付けて試さないと干し草の山の中から針を探すようなことになるかと。

全く目星がつかない場合はランダムにデータを送信してみる。それで数秒内にハンドセット側に何か反応があればその機能は比較的簡単に探せるものだと思われる。そういうのを幾つか見つけたら共通する部分からある程度は目星が付くかと。

# cat /dev/random > /dev/hidraw0

USBハンドセット 3
制御方法が解ってしまえばいろいろできちゃう。
なんか液晶画面が傷だらけで汚いけど、何年も押し入れの屑入れの中で他のゴミと擦れてたから。

今回はUSBハンドセットの制御だけ。このハンドセットをSIP電話機にするのは次の記事で。

関連記事:

NanoPi NEOをSIP電話機にする 中編

NanoPi NEO2とUSBハンドセット

NanoPi NEOはおもちゃ卒業でNTPサーバ専用機になったので新しいおもちゃNanoPi NEO2でSIP電話機を目指す

Linphone起動とヘルプ

前回のPJSIPはちょっと扱いにくい部分があるので今回は比較的容易に使えるLinphoneをインストールした。

# apt install linphone

単にSIP電話機能を使うだけであればこれだけで動いてしまうが、いろいろやりたいなら他にpython-dev, liblinphone-dev くらいはインストールしておいた方が良さそう。

Linphoneを実行する前にNanoPi NEO2にUSBハンドセットを接続する。

$ linphonec

実行は特にオプションなどを付ける必要ないが、linphoneではなく最後にc (CLIのCの意味?)が付く方のlinephonecを実行。

inphonec> help
Commands are:
---------------------------
      help      Print commands help.
      call      Call a SIP uri or number
     calls      Show all the current calls with their id and status.
      chat      Chat with a SIP uri
 terminate      Terminate a call
    answer      Answer a call
     pause      pause a call
    resume      resume a call
  transfer      Transfer a call to a specified destination.
conference      Create and manage an audio conference.
      mute      Mute microphone and suspend voice transmission.
    camera      Send camera output for current call.
    unmute      Unmute microphone and resume voice transmission.
playbackga      Adjust playback gain.
  duration      Print duration in seconds of the last call.
autoanswer      Show/set auto-answer mode
     proxy      Manage proxies
 soundcard      Manage soundcards
    webcam      Manage webcams
      ipv6      Use IPV6
       nat      Set nat address
      stun      Set stun server address
  firewall      Set firewall policy
 call-logs      Calls history
    friend      Manage friends
      play      play a wav file
    record      record to a wav file
      quit      Exit linphonec
---------------------------
Type 'help <command />' for more details or
     'help advanced' to list additional commands.
linphonec> help advanced
Advanced commands are:
---------------------------
     codec      Audio codec configuration
    vcodec      Video codec configuration
        ec      Echo cancellation
        el      Echo limiter
nortp-on-a      Set the rtp_no_xmit_on_audio_mute configuration parameter
   vwindow      Control video display window
   pwindow      Control local camera video display (preview window)
  snapshot      Take a snapshot of currently received video stream
    vfureq      Request the other side to send VFU for the current call
    states      Show internal states of liblinphone, registrations and calls, according to linphonecore.h definitions
  register      Register in one line to a proxy
unregister      Unregister from default proxy
    status      Print various status information
     ports      Network ports configuration
     param      parameter set or read as normally given in .linphonerc
     speak      Speak a sentence using espeak TTS engine
 staticpic      Manage static pictures when nowebcam
  identify      Returns the user-agent string of far end
  ringback      Specifies a ringback tone to be played to remote end during incoming calls
  redirect      Redirect an incoming call
zrtp-set-v      Set ZRTP SAS verified.
zrtp-set-u      Set ZRTP SAS not verified.
---------------------------
Type 'help <command />' for more details.
linphonec>

help [Enter]で主なコマンド一覧、またはhelp advanced [Enter]でその他コマンド一覧が表示される。
また、オプション無しでコマンドを実行するとそのオプションが表示される。

Linphone サウンドデバイス設定

linphonec> soundcard list
0: ALSA: default device
1: ALSA: H3 Audio Codec
2: ALSA: USB Device 0x4b4:0x307
3: PulseAudio: default
linphonec>

接続したハンドセットを受話器(マイク兼スピーカー)にしたい。
soundcard list [Enter]を実行すると認識されているサウンドデバイス一覧が表示される。
上の例ではALSA USB Deviceとして表示されている2番がUSBハンドセットであることがわかる。

linphonec> soundcard use 2
Using sound device ALSA: USB Device 0x4b4:0x307
linphonec>

soundcard use [サウンドデバイス一覧の行頭の番号] [Enter]でそのサウンドデバイスの使用を決定する。

linphonec> soundcard show
Ringer device: ALSA: USB Device 0x4b4:0x307
Playback device: ALSA: USB Device 0x4b4:0x307
Capture device: ALSA: USB Device 0x4b4:0x307
linphonec> 

soundcard show [Enter]で使用中(設定された)音声入出力デバイスが表示される。
上の例では呼び出し音を鳴らすデバイス(Ringer)、通話用スピーカー(Playback)、通話用マイク(Capture)のすべてがALSA USBデバイス(つまりUSBハンドセット)に設定されているという意味。USBサウンドデバイスが複数ある場合はその後のデバイスIDも確認。

SIPサーバへの接続

linphonec> register sip:4321@sip.example.com 192.168.0.1 secretpassword

上はSIPアカウントが4321@sip.example.comでSIPサーバが192.168.0.1でパスワードがsecretpasswordの場合。アカウントの前にsip:を付けてやらないとダメなのはPJSIPと同じ。
で、Linphoneでは指定した設定やSipサーバへのレジスト情報は記憶されるので一度レジストされてしまえば次からはLinphoneを起動するだけで自動的にレジストされた状態・各種設定が反映された状態となる。これが便利。

発信

linphonec> call 5000

内線番号5000に発信するならこんな感じ。

着信

linphonec> answer

コマンド操作では普通にanser [Enter]と入力するだけ。

通話切断

linphonec> terminate

通話相手側から切断した場合は切断を認識するのでterminteを実行する必要はない。

一時保留

linphonec> pause

一時保留から通話に戻す

linphonec> resume

Linphone自体の終了

linphonec> quit

基本的なオペレーションはこんなところ。

Linphoneの設定ファイル

ユーザーのホームディレクトリ直下の .linphonerc がそれ。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
#前省略
[rtp]
download_ptime=0
audio_rtp_port=20000
video_rtp_port=9078
audio_jitt_comp=60
video_jitt_comp=60
nortp_timeout=30
audio_adaptive_jitt_comp_enabled=1
video_adaptive_jitt_comp_enabled=1
#後省略

たとえば何か理由があって音声通話用のRTPポートをLinphone標準の7078から20000に変更する必要があるとする。
~/.linphonercをテキストエディタ開くとrtpセクションに audio_rtp_port という項目があるので値を20000に変更して保存する。

linphonec> ports
sip port = 5060
audio rtp port = 20000
video rtp port = 9078
linphonec> 

Linphoneを起動してports [enter]を実行する。audio rtp portの欄が指定した値になっていれば設定できている。

何も難しいところやトラブりやすいところとか無くサクッと使えたのでこの記事はLinphone(c)の使い方だけになっちゃった。

今回もハンドセットを使っての通話は出来てもハンドセットで操作したりハンドセットの液晶に何かを表示するところには触れてないなぁ。一番上の写真でハンドセットの液晶パネルを光らせちゃってるので期待しちゃってたらゴメンなさい。
次でその辺りができたらいいんだけど。ハンドセットの表示とボタン操作で電話ハンドセットにするのは後編の2(次の次に書きました)

関連記事:
Up