您的位置:首页 > 编程语言 > Python开发

树莓派sip视频电话-1:exosip2ctype+python使用硬件编解码

2016-11-23 21:21 639 查看
0.树莓派实现视频电话功能

树莓派python环境下可使用的模块有:pjsip,linphone,exosip2ctypesp,sipsimple

(1)pjsip(pjsua2+python)功能强大,但api较多,视频例子较少。主要是看到使用pjsip传输已经编码的视频,源码在github这篇文章,考虑到可以使用omx硬件编解码,但努力了几天,未成功。

(2)linphone有专门的raspberry的python模块,但没有实现omx硬件编解码,视频编码方式只有vp8,遗憾的放弃。

(3)exosip2ctypesp,是libexosip2的python封装,功能较简单,主要实现的是sip协议,rtp,编解码等未包含。根据exapmle中 代码修改,初步实现了树莓派sip客户端使用omx硬件编解码。依赖库太多了!!!

(4)sipsimple,没有安装成功。

-------------------------------------------------

1.安装python下的sip模块:exosip2ctypes

(1)sudo apt-get install libexosip2

(2)依赖库较多,需使用python虚拟环境。virtualenv

pip install virtualenv 安装虚拟环境

virtualenv venv 创建虚拟环境

source venv/bin/active 进入虚拟环境nm

(3)虚拟环境下,在源码包中pip install -r requirements-dev-lt_3.2.txt 安装依赖库,总之太多了。

(4)安装exosip2ctypes python setup.py install

2.修改exosip2ctypes源代码;

(1)错误1:context.py

def start(self, s=0, ms=50, event_executor=None):

self.logger.info('<0x%x>start: >>> s=%s, ms=%s', id(self), s, ms)
if self._is_running:
raise RuntimeError("Context loop already started.")
self._event_executor = event_executor or ThreadPoolExecutor()   =>   self._event_executor = event_executor or ThreadPoolExecutor(2)


(2)错误2:context.py

class Context(BaseContext, LoggerMixin):
def __init__(self, event_callback=None):     =>def __init__(self, event_callback=None,contact_address=None):


(3)错误3:message.py

class OsipMessage:   =>  class OsipMessage(object):


3.树莓派代码

pc上安装ekiga软件与树莓派python程序建立视频通话:

(1)ekiga呼叫树莓派,先输入180回铃

(2)发送rtp视频编码: 这里使用了Camkit这个工具,github上有,感谢作者。需根据远端的sdp信息进行修改端口和IP地址。如果传过来的pt不为96,需修改rtppack这个文件。

(3)接受rtp视频编码:根据本端的sdp信息,创建sdp文件,使用omxplayer 播放这个sdp文件。

(4)输入200,建立链接。这时pc 上可以看到远端视频。

(5)问题1:omxplayer播放花屏,卡顿,不是带宽的问题,未知。

问题2:暂时没有实现树莓派音频采集/编码/打包/发送,下步再研究。

import sys
import logging
import logging.config

from exosip2ctypes import initialize, Context, call, EventType

logging.basicConfig(
level=logging.DEBUG, stream=sys.stdout,
format='%(asctime)-15s [%(threadName)-10s] [%(levelname)-7s] %(name)s - %(message)s'
)

latest_event = None

def on_exosip_event(context, evt):
global latest_event
latest_event = evt

if evt.type == EventType.call_invite:
print('**********************************************************************************')
logging.debug('[%s] on_call_invite', evt.did)
logging.debug('call-id: %s', evt.request.call_id)
# logging.debug("%s" % evt.request)
logging.debug('[%s] from: %s', evt.did, evt.request.from_)
logging.debug('[%s] allows: %s', evt.did, evt.request.allows)
logging.debug('[%s] contacts: %s', evt.did, evt.request.contacts)
for hname in ('User-Agent',):
logging.debug('[%s] header["%s"]: %s', evt.did, hname, evt.request.get_headers(hname))

print('**********************************************************************************')
logging.debug('body: %s', evt.request.bodies[0])
print('**********************************************************************************')
logging.debug('body: %s', evt.request.bodies)
print('**********************************************************************************')

elif evt.type == EventType.call_cancelled:
logging.debug('[%s] call_cancelled', evt.did)

elif evt.type == EventType.call_closed:
logging.debug('[%s] call_closed', evt.did)

initialize()
ctx = Context(event_callback=on_exosip_event)
# ctx.event_callback = on_exosip_event
#ctx.masquerade_contact('192.168.1.132', 5066)

print('listening...')
ctx.listen_on_address(address='192.168.1.132', port=5066)
print('starting...')

ctx.start()
print('started!')

while True:
s = sys.stdin.readline().strip().lower()
if s in ('q', 'quit'):
ctx.stop()
break
elif s == 'ack':
with ctx.lock:
ctx.call_send_ack(latest_event.did)
elif s in ('t', 'terminate'):
with ctx.lock:
ctx.call_terminate(latest_event.cid, latest_event.did)
elif s.isdigit():
status = int(s)
if status == 200:
with ctx.lock:
msg = call.Answer(ctx, latest_event.tid, 200)
msg.content_type = 'application/sdp'
msg.add_body(
"v=0\r\n"
"o=- 0 0 IN IP4 192.168.1.132\r\n"
"s=No Name\r\n"
"c=IN IP4 192.168.1.132\r\n"
"t=0 0\r\n"
"a=tool:libavformat 57.25.10\r\n"
"m=audio 54000 RTP/AVP 0 8 101\r\n"
"a=rtpmap:0 PCMU/8000\r\n"
"a=rtpmap:8 PCMA/8000\r\n"
"a=rtpmap:101 telephone-event/8000\r\n"
"m=video 4002 RTP/AVP 96\r\n"
"a=rtpmap:96 H264/90000\r\n"

)
#                    "a=fmtp:96 packetization-mode=1; sprop-parameter-sets=Z01AM5p0FCNCAAEEugA9CQEeMGVA,aO48gA==; profile-level-id=4D4033\r\n"
#                    "a=fmtp:96 packetization-mode=1; sprop-parameter-sets=J01AKakYDwBE/LgDUBAQG2wrXvfAQA==,KN4JyA==; profile-level-id=4D4029\r\n"
#./ffmpeg -re -i 1.h264 -vcodec copy -f rtp -payload_type 103 rtp://192.168.1.132:5056
#ffplay -vcodec h264_mmal
ctx.call_send_answer(answer=msg)
else:
with ctx.lock:
ctx.call_send_answer(latest_event.tid, status)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: