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

NanoPi NEOゑSIP雺詰橞なじり

NanoPi NEOゑSIP雺詰橞なじり 律緧 (ぜね1)ね律な継がね託亊ゑじくな凹ざぞっめらてじぢおら志る枛づづぃぞ。
でぃぅげでて、ぃぽごよたぐと継が。

丬緧ねLinphone(linphonec)か旡な勔ぎ犵慊てぁりでじり。
仉囝のぜねLinphoneな仗屝じりLinphonecshゑ佾ぅ。

linphonecsh

$ linphonecsh
Usage:
linphonecsh  [arguments]
where action is one of
  init        : spawn a linphonec daemon (first step to make other actions)
              followed by the arguments sent to linphonec
  generic     : sends a generic command to the running linphonec daemon
              followed by the generic command surrounded by quotes,
               for example "call sip:joe@example.net"
  register    : register; arguments are 
              --host 
              --username 
              --password 
  unregister  : unregister
  dial        : dial 
  status      : can be 'status register', 'status autoanswer' or 'status hook'
  soundcard   : can be 'soundcard capture', 'soundcard playback', 'soundcard ring',
               followed by an optional number representing the index of the soundcard,
               in which case the soundcard is set instead of just read.
  exit        : make the linphonec daemon to exit.

刨甧てがりゲポヲトの夙ぎどぃ。ぞたざ、genericか佾ぇり。linphonecねゲポヲトゑgenericね律な挆宙じりげでてlinphonecててがりげでね夙ぎか实衋てがり。
替刜なlinphonecsh initゑ实衋じりでlinphonecかハヂギクヨゥヲト(テ・メヲ匕?)て勔ぎまぞぃ。linphonecsh exitてハヂギクヨゥヲトねlinphonecか絁亅。

$ ps -ax | grep linphonecsh
 9876 ?        Ssl    0:19 linphonec --pipe -c /dev/null
仕ブレズジ眀畤
linphonecsh init律ねブレズジラジデ

ゴゥヲト呧らね碹誌

NanoPi NEO2な繊ぃたUSBノヲトズヂデねジビ・オ・て韲ゑ凹じ、ぜねポィギて韲ゑ拽ぅ。

# aplay -l
**** List of PLAYBACK Hardware Devices ****
card 0: Codec [H3 Audio Codec], device 0: CDC PCM Codec-0 []
  Subdevices: 1/1
  Subdevice #0: subdevice #0
card 1: U0x4b40x307 [USB Device 0x4b4:0x307], device 0: USB Audio [USB Audio]
  Subdevices: 1/1
  Subdevice #0: subdevice #0

USBねノヲトズヂデのUSB Device 0x4b4:0x307で誌譗ごるづぃり。里覀どねの赣孖ね郧刅。げるかテハィジIDて律て佾ぅ。げね侊てのゲレヲね月焠ざお達ゎどぃぐとげるゑ閒達ぅで怜ぃ這らな勔おどぃ。

弔が継がマガゴ・てゲヲデレ・リ寽豠ねボ・デ同ゑ覊り。げげてamixerゑ佾ぅでゎおよどぎどぢづざぽぅねてalsamixerゑ佾ぅ斸か焠離。

# alsamixer

alsamixerゑ碹誌 1
alsamixerか赶勔ざぞでがね町靡。樘溕ねゴゥヲトテハィジね犵慊か衧礹ごるづぃり筇。
三ね町僎たでNanoPi NEO2ね樘溕 H3 Audio Codecなどぢづぃり(町僎工三ね赣艱ね砳緙ね囚觑郧刅)。っぽらNanoPiねォ・テアォ甧ビヲプヂタ(賻兤晁朩叕ら仗ぐ)なジビ・オ・ゑ繊ぃたでがな鳳りゃっ。
仉囝のUSBノヲトズヂデゑ碹誌じりねて史三ね赣ぃ囚觑郧刅、ピ゠ヲギザユヲガ・6畩[F6]て衧礹じりゴゥヲトオ・ト(テハィジ)ゑ夈曳じり。

alsamixerゑ碹誌 2
ゴゥヲトオ・ト(テハィジ)ねラジデか町靡丬夭な衧礹ごるりねて矡卯ガ・三上てUSBノヲトズヂデねテハィジな吇ゎずづ[Enter]。三ね町僎てのUSB Device 0x4b4:0x307ゑ遷をた。

alsamixerゑ碹誌 3
町僎ね工三、オ・ト(テハィジ)のUSBテハィジなどぢづぃり。ボ・デ(ブレピ゠ィリ)のぉぜよぎ册甞甧(Playback)たぐか衧礹ごるづぃり筇どねて錱韲(Capture)め吇ゎずづ碹誌じり。[F5]ゑ抻じで丠斸か衧礹ごるり。
三ね町僎ての册甞甧のPCM、錱韲甧のMicでどぢづぃり。

USBノヲトズヂデて雺詰じりジギラブデ

律緧 (ぜね1)て佾甧ざぞジギラブデなだゆげぢで趲ざぞたぐ。フレク託亊どねて替位陏勔ぎ稊庥ね簠昒片でじり。累おぃげでのざどぃ。
ぽぞ、ェヨ・凥琅めおどら扊抛が。ぞたざ、レクたぐの叕りょぅなざぞ。
末归のSIPゴ・ハぷねルシジデ犵慊ゑ碹誌ざづ忄覀な忛しづ册ルシジデじりでおルシジデてがどぃ堳吇ねェヨ・凥琅ゑ兤るぞおぢぞか、NanoPi NEO2甧なィヲジデ・リざぞlinphonecshか悩ぃねお仕ね佔おか厞囟どねおlinphonecsh status registerてルシジデ犵慊な閡ゎよす-1ゑ迓ごるりげでか夙ぃねて仉囝の觢汹ずすな焠覕じりげでなざぞ。

  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
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
#!/usr/bin/python

import re
import time
from datetime import datetime
import subprocess
import struct
from PIL import Image, ImageDraw, ImageFont

keys = {
  0x00 : "",
  0x03 : "1",
  0x09 : "2",
  0x0f : "3",
  0x04 : "4",
  0x0a : "5",
  0x10 : "6",
  0x05 : "7",
  0x0b : "8",
  0x11 : "9",
  0x06 : "*",
  0x0c : "0",
  0x12 : "#",
  0x02 : "left",
  0x0e : "right",
  0x01 : "yes",
  0x0d : "no",
  0x19 : "vol+",
  0x1c : "vol-",
  0x1b : "mute",
}

hiddev = "/dev/hidraw0"   #ノヲトズヂデねテハィジ
sndcard = "U0x4b40x307"   #aplay -lて衧礹ごるりテハィジID
snddev = "PCM"            #册甞甧ボ・デ同
micdev = "Mic"            #ポィギ甧ボ・デ同
modmute = False           #這詰晁マヤ・デ刜朞倣(ォピ)
spkrvol = 60              #這詰晁ねジビ・オ・韲野(60%)叮夈
micvol = 50               #這詰晁ねポィギ韲野(50%)囹宙
cfrom = ""                #這詰盷扊ね衧礹甧(穹發)


def func_aplog(str):
  f = open('./phone.log', 'a')
  f.write(datetime.now().strftime("%Y/%m/%d %H:%M:%S ") + str)
  f.close()

def func_linphone(cat, cmd, bln):
  try:
    if bln == 1:
      ret = subprocess.check_output(cmd.split())
    else:
      ret = subprocess.check_output(cmd)

    func_aplog(cat + ": " + ret + "\n")
    return ret
  except subprocess.CalledProcessError as err:
    func_aplog(cat + " ERROR:\n")
    func_aplog(str(err.returncode) + "\n")
    func_aplog(str(err.cmd) + "\n")
    func_aplog(err.output + "\n")
    return "err"

def func_lgtonoff(bln):
  file = open( hiddev, "w+b" );
  if bln:
    buf = "040f".decode("hex")
  else:
    buf = "0400".decode("hex")
  file.write(buf)
  file.flush()
  file.close();

cmd = '/usr/bin/linphonecsh init'
func_linphone("INIT", cmd, True)
time.sleep(1)

cmd = '/usr/bin/linphonecsh register --username 6000 --host 192.168.0.100 --password himitsu'
func_linphone("REGIST", cmd, True)
time.sleep(1)

cmd = ['/usr/bin/linphonecsh', 'generic', 'soundcard use 2']
print(func_linphone("STATUS", cmd, False))

subprocess.check_output(['amixer', '-c', sndcard, 'set', snddev, '100%'])
subprocess.check_output(['amixer', '-c', sndcard, 'set', micdev, str(micvol) + '%'])

file = open( hiddev, "w+b" );

def getKey():
  buf = file.read(8)
  return keys[ord(buf[1])]

def paint():
  pixels = img.load() # create the pixel map
  pixels = img.transpose(Image.ROTATE_180).load() # create the pixel map
  b = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
  for r in range(0, 8):
    for s in range (0, 12):
      for i in range (0, 12):
        b[i] = 0
        for j in range (0, 8):
          if (pixels[i + 12 * s, j + 8 * r] < 128):
            b[i] |= 2**j
      buf="0301".decode("hex")+chr(r)+chr(s*11)+chr(b[0])+chr(b[1])+chr(b[2])+chr(b[3])+chr(b[4])+chr(b[5])+chr(b[6])+chr(b[7])+chr(b[8])+chr(b[9])+chr(b[10])+chr(b[11])
      file.write(buf)
      file.flush()

def drawText(text):
  draw.text((0, 0), drawText.old , 255, font=font)
  draw.text((0, 0), text , 0, font=font)
  drawText.old = text
  paint()

drawText.old = ""
img = Image.new( '1', (144,64), "white")
draw = ImageDraw.Draw(img)

font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf", 20)
text = ""

# write canvas to display
paint()

# clear canvas
draw.rectangle((0,0,142,63), fill=255)

while( 1 ):
  k = getKey();
  if (k == ""):
    0
  elif (k == "yes"):
    reslt = subprocess.check_output(['/usr/bin/linphonecsh', 'generic', 'calls'])
    if 'No active call.' not in reslt:
      cfrom = re.findall("[\w.-]+@[\w.-]+.\w+", reslt)
      drawText(cfrom[0])
  elif (k == "no"):
    text = ""
    drawText(text)
  elif (k == "left"):
    func_lgtonoff(True)
    reslt = subprocess.check_output(['/usr/bin/linphonecsh', 'generic', 'calls'])
    if 'IncomingReceived' in reslt:
      text = ""
      subprocess.check_output(['amixer', '-c', sndcard, 'set', snddev, '50%'])
      cmd = ["/usr/bin/linphonecsh", "generic", "answer"]
      func_linphone("ANSWER", cmd, False)
      drawText("Answer")
    elif 'No active call.' in reslt:
      if len(text) > 2:
        cmd = ['/usr/bin/linphonecsh', 'dial', text]
        drawText('DIAL' + text)
        func_linphone("DIAL", cmd, False)
        text = ""
  elif (k == "right"):
    text = "Terminate"
    drawText(text)
    cmd = ['/usr/bin/linphonecsh', 'generic', 'terminate']
    func_linphone("STATUS", cmd, False)
    time.sleep(1)
    text = ""
    drawText(text)
    func_lgtonoff(False)
    subprocess.check_output(['amixer', '-c', sndcard, 'set', snddev, '100%'])
  elif (k == "vol+"):
    spkrvol += 10
    if spkrvol > 100:
      spkrvol = 100
    subprocess.check_output(['amixer', '-c', sndcard, 'set', snddev, str(spkrvol) + '%'])
    drawText("Vol:" + str(spkrvol) + "%")
  elif (k == "vol-"):
    spkrvol -= 10
    if spkrvol < 10:
      spkrvol = 10
    subprocess.check_output(['amixer', '-c', sndcard, 'set', snddev, 0])
    drawText("Vol:" + str(spkrvol) + "%")
  elif (k == "mute"):
    if modmute: 
        cmd = ['/usr/bin/linphonecsh', 'generic', 'unmute']
        func_linphone("MUTE_OFF", cmd, False)
        modmute = False
        drawText("Mute Off")
    else:
        cmd = ['/usr/bin/linphonecsh', 'generic', 'mute']
        func_linphone("MUTE_ON", cmd, False)
        modmute = True
        drawText("Mute On")
  else:
    text = text + k
    drawText(text)

file.close();
SIPゴ・ハぷねルシジデの78衋盭。

USBノヲトズヂデホゾヲ
①のジギラブデてleftねホゾヲ。RING鳳勔晁ね眿俠甧で定兇畩叶兤劚律ね癹俠甧でざづ佾ぅ。
④のジギラブデてrightねホゾヲ。這詰絁亅ゃタィャリ兤劚ねラズヂデな佾ぅ。
⑤のジギラブデてyesねホゾヲ。這詰丬な盷扊ね畩叶ゑノヲトズヂデね涱晵な衧礹じり。
⑦のジギラブデてnoねホゾヲ。涱晵ね斆孖ゑ涇じ(たぐ)。
②③⑥の佾ゎどぃ。
Vol+の這詰晁ねジビ・オ・ね韲野ゑ10%三けり。(替夦100%)
Vol+の這詰晁ねジビ・オ・ね韲野ゑ10%上けり。(替導10%)
muteの這詰晁なノヲトズヂデねポィギゑォピなじり。めぅ䷿庥抻じでォヲ。(デクリ)

涱晵ねハヂギヨィデの①(left)ゑ抻じで炸灮。③(right)ゑ抻じで1科律な涇灮、ぞたぜるたぐ。盷扊か這詰ゑ絁亅ごずぞ堳吇てめ扊勔て③(right)ゑ抻ごどぃでハヂギヨィデの涇灮ざどぃ。
ぽぞ、癹週晁な盷扊ね畩叶ゑ兤劚ざづおよ①(left)ゑ抻じで畩叶兤劚晁のハヂギヨィデ涇灮どねて、①(left)ゑ抻ざづ畩叶兤劚ざづ册庥①(left)ゑ衋ぅでハヂギィデ炸灮て畩叶ゑ兤劚てがり。畩叶兤劚丬な攽罭ざづめすぢでぜね犵慊どねて③(right)てラズヂデじり忄覀かぁり。

扊抛がどねて搹帮どとでの尐ざ勜扊か達ぅぐと忄覀替導陏ねげでのてがり。眿俠晁ねRINGの韲野100%囹宙ねっめら。ポィギね韲野め50%て囹宙。三ねジギラブデてのホゾヲ擌佛ての夈曳てがどぃねてジギラブデゑ夈曳ざづ誾敳。

ぞふを、げをどを氖な兤よぬうで怜ぅたれぅおよ奼まな攸速じるは艮ぃおで。

Pythonの殅と佾ぢぞげでかどぃねて斆泔閒達ぢづぞよジヲポズヲ。

律緧 (ぜね1)で仉囝刨甧ざぞCheap USB Skype/VoIP phone protocol discoveryねジギラブデね佛耄な愞謜。げるでlinphonecshねぉおけて凃ぃ簠南な雺詰橞胼ゑ实珽てがぞ。

閡逢託亊: