golang modules问题的理解与踩坑记

golang 在1.11版本开始增加modules的功能,解决包管理的问题,之前包管理方案废除了。这个方案感觉都几好,不过最近使用的时候。发觉都点问题,可能是我对它的理解不是很清晰。导致的出问题。

现在讲讲我遇到的问题。如果大家想跟着我的项目试验,请去

github下载并切换到这个commit。这里我列一下我项目的go.mod的主要部分

require (
github.com/deepch/av v0.0.0-20160612005306-c437a98c9300 // indirect
github.com/deepch/rtsp v0.0.0-20180827192050-70ae0abf31bd // indirect
github.com/deepch/sample_rtsp v0.0.0-20180827191708-90250a0f88be // indirect
github.com/gorilla/mux v1.7.1 // indirect
github.com/pion/webrtc/v2 v2.0.9 // indirect
)

目前项目有点问题,我需要升级下github.com/pion/webrtc/这个库的版本。升级这个库的版本有几个方面。

  1. 使用命令go get github.com/pion/webrtc/v2@v2.0.12
  2. 使用命令go get -u github.com/pion/webrtc/v2@v2.0.12
  3. 直接编辑go.mod文件,把版本号修改。

大家是否会觉得用以上三个方法结果都一样。我开始以为这个三个方法都一样的。不过后发觉他们直接还是有点不一样的。

方法1,go get github.com/pion/webrtc/v2@v2.0.12命令之后。go.mod文件只是修改了github.com/pion/webrtc/v2的版本号。go.sum增加了2.0.12依赖的包对应的新的版本库。

require (
	github.com/deepch/av v0.0.0-20160612005306-c437a98c9300 // indirect
	github.com/deepch/rtsp v0.0.0-20180827192050-70ae0abf31bd // indirect
	github.com/deepch/sample_rtsp v0.0.0-20180827191708-90250a0f88be // indirect
	github.com/gorilla/mux v1.7.1 // indirect
	github.com/pion/webrtc/v2 v2.0.12 // indirect
)

方法2. go get -u github.com/pion/webrtc/v2@v2.0.12命令后,go.mod文件多了很多依赖包。go.sum也出现了很多更新包。这些依赖包都是次级依赖的包的升级版本,可能是github.com/pion/webrtc库需要。都列在go.mod哪里了。

require (
	github.com/deepch/av v0.0.0-20160612005306-c437a98c9300 // indirect
	github.com/deepch/rtsp v0.0.0-20180827192050-70ae0abf31bd // indirect
	github.com/deepch/sample_rtsp v0.0.0-20180827191708-90250a0f88be // indirect
	github.com/golang/mock v1.3.0 // indirect
	github.com/gorilla/mux v1.7.1 // indirect
	github.com/lucas-clemente/quic-go v0.11.1 // indirect
	github.com/onsi/ginkgo v1.8.0 // indirect
	github.com/onsi/gomega v1.5.0 // indirect
	github.com/pion/datachannel v1.4.3 // indirect
	github.com/pion/dtls v1.3.4 // indirect
	github.com/pion/webrtc/v2 v2.0.12 // indirect
	github.com/stretchr/objx v0.2.0 // indirect
	golang.org/x/crypto v0.0.0-20190506204251-e1dfcc566284 // indirect
	golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c // indirect
	golang.org/x/sys v0.0.0-20190508220229-2d0786266e9c // indirect
	golang.org/x/text v0.3.2 // indirect
	golang.org/x/tools v0.0.0-20190509014725-d996b19ee77c // indirect
	gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
	gopkg.in/yaml.v2 v2.2.2 // indirect
)

方法3。直接编辑go.mod,然后编译程序和或者运行,得到的结果是和方法1一样的。

现在来一条思考题:,如果命令是go get -u github.com/pion/webrtc/v2@v2.0.9版本号不变化。你会觉得go.mod会有变化么?

结果来了。

require (
	github.com/deepch/av v0.0.0-20160612005306-c437a98c9300 // indirect
	github.com/deepch/rtsp v0.0.0-20180827192050-70ae0abf31bd // indirect
	github.com/deepch/sample_rtsp v0.0.0-20180827191708-90250a0f88be // indirect
	github.com/golang/mock v1.3.0 // indirect
	github.com/gorilla/mux v1.7.1 // indirect
	github.com/lucas-clemente/quic-go v0.11.1 // indirect
	github.com/onsi/ginkgo v1.8.0 // indirect
	github.com/onsi/gomega v1.5.0 // indirect
	github.com/pion/datachannel v1.4.3 // indirect
	github.com/pion/dtls v1.3.4 // indirect
	github.com/pion/ice v0.2.6 // indirect
	github.com/pion/srtp v1.2.4 // indirect
	github.com/pion/webrtc/v2 v2.0.9 // indirect
	github.com/stretchr/objx v0.2.0 // indirect
	golang.org/x/crypto v0.0.0-20190506204251-e1dfcc566284 // indirect
	golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c // indirect
	golang.org/x/sys v0.0.0-20190508220229-2d0786266e9c // indirect
	golang.org/x/text v0.3.2 // indirect
	golang.org/x/tools v0.0.0-20190509014725-d996b19ee77c // indirect
	gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
	gopkg.in/yaml.v2 v2.2.2 // indirect
)

二级依赖包都更新了。所以平时更新项目的依赖包要小心,最好别用go get -u来更新,只要用go get来更新具体某个依赖包就好了,带-u的会把次级的依赖都升价到新版本,不理会你直接引用的库是否有升级。这个问题不是很好的。因为有时候回归问题根源的时候,会把依赖包进行升级和降级处理进行查找一些问题。加了-u的选项,它把次级依赖包都升价了。不能很好地回归问题。
假设,你使用go get -u github.com/pion/webrtc/v2@v2.0.12升价了包,然后用go get  github.com/pion/webrtc/v2@v2.0.9进行降级。其他依赖包也是被升价了。

所以大家以后升价依赖包,要不手动改文件。要不只用go get。千万别用go get -u了。要不然降级的时候就麻烦了。另外这个go的依赖包的升级是根据语义化版本来决定升级的。如果你原来是1.X.X的版本,不会知道升级到2.X.X的版本的。而且go现在的包的import语句引入2.X.X版本的时候需要跟一个v2的尾巴。这个超级不习惯。跟其他语言很大不同。

我目前使用的go的版本号:go version go1.12.4 darwin/amd64

TensorFlow with CUDA安装在Ubuntu的踩坑记录

最近研究TensorFlow,需要开发环境,需要安装一个。我选择了在Ubuntu上使用docker来进行TensorFlow开发环境。因为使用docker是目前最方便搭建开发环境的工具。

安装步骤官方文档说明得比较详细。其实用docker安装环境没有什么可以说的,能会有问题么?如果你使用cpu版本基本不会有问题的。但是如果你使用的是GPU版本。那你还要安装CUDA环境和需要这些支持。我选择了使用CUDA9.1,安装教程在这。在CUDA9.1的下载安装我选择了从网络deb的方式

不过安装后,运行测试程序(nvidia-smi)或在运行nvidia-docker失败。

 
Failed to initialize NVML: GPU access blocked by the operating system

nvidia-docker failed to initialize nvml: driver/library version mismatch

后来发觉这是驱动的安装问题。我使用的是这里的下载的驱动文件,你可以在www.nvidia.com/drivers按照你显卡型号选择驱动,我发觉最后下载的文件都一样的。下载的文件名称NVIDIA-Linux-x86_64-390.48.run。使用

sudo sh NVIDIA-Linux-x86_64-390.48.run

进行安装,途中会有些报错,不理会继续继续。但是安装出来后,cuda不能正常运行。查询google。最后发现原来官方说这个驱动在ubuntu上需要手动安装。不要直接运行run文件。

#这里先卸载之前安装的驱动。
sudo apt-get remove --purge nvidia-390 nvidia-modprobe nvidia-settings
#重新安装驱动,虽然安装过程中有报错,不过后来测试运行暂时没有发现问题。
sudo apt-get install nvidia-390 nvidia-modprobe nvidia-settings

经过这一卸载,再安装就成功了。幸福来得有点突然。哈哈哈。

还有一个地方需要注意的是,nvidia-docker的安装需要指定的docker版本,而且这个版本必须是精确的版本。不能高于或在一个小升级的版本。而且这个版本不是稳定版本来的。我这次需要的是Docker version 18.03.1-ce, build 9ee9f40版本。不过你的版本不对他是不会继续给你安装的。

下边给几个用于检查安装好的环境

cat /proc/driver/nvidia/version
NVRM version: NVIDIA UNIX x86_64 Kernel Module  390.30  Wed Jan 31 22:08:49 PST 2018
GCC version:  gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.9)

ls -l /dev/nvidia*
crw-rw-rw- 1 root root 195, 254 May  3 10:00 /dev/nvidia-modeset
crw-rw-rw- 1 root root 243,   0 May  3 09:03 /dev/nvidia-uvm
crw-rw-rw- 1 root root 243,   1 May  3 10:00 /dev/nvidia-uvm-tools
crw-rw-rw- 1 root root 195,   0 May  3 10:00 /dev/nvidia0
crw-rw-rw- 1 root root 195, 255 May  3 09:03 /dev/nvidiactl
(我安装驱动失败的时候这里只有两个设备,/dev/nvidia-uvm和/dev/nvidiactl)

lspci | grep -i nvidia
01:00.0 VGA compatible controller: NVIDIA Corporation GK208 [GeForce GT 730] (rev a1)
01:00.1 Audio device: NVIDIA Corporation GK208 HDMI/DP Audio Controller (rev a1)

cat /proc/driver/nvidia/gpus/0000:01:00.0/information
Model: 		 GeForce GT 730
IRQ:   		 34
GPU UUID: 	 GPU-????????-????-????-????-????????????
Video BIOS: 	 ??.??.??.??.??
Bus Type: 	 PCIe
DMA Size: 	 40 bits
DMA Mask: 	 0xffffffffff
Bus Location: 	 0000:01:00.0
Device Minor: 	 0

大家别笑我的GPU太差。真实使用的时候需要租用云服务器的GPU。

coturn的用于webrtc的测试

coturn是一个开源的turn/stun的服务器,大家可以使用它进行webrtc的测试搭建。当然也可以用于生产环境。此文只是介绍其用于测试环境如何配置其用户于验证。这里可以配合apprtc-go的测试进行说明。

coturn服务器是包括了turn和stun这两个服务的。如果你只需要stun服务。按照下边的命令启动就可以。(假设turn服务器和apprtc-go服务器都运行在192.168.2.170上,另外,如果需要测试turn服务,需要把连接的两台机器分别放在不同的网段,相互之间不能访问,才能发挥turn的功效)

turnserver --no-auth --stun-only -v
参数说明:
--no-auth  不做用户认证,只有stun可以不用用户认证,
                turn服务,在iceServer中必须给出用户名认证等,
                要不然页面建立peerConnect的时候报错。
--stun-only  服务器制作stun服务,不做turn服务。
-v       打印log信息。请不要用-V,大V的信息量太多了。

apprtc-go的启动需要添加stun参数給,命令如下

./apprtc-go -cert=$GOPATH/src/github.com/daozhao/apprtc-go/mycert.pem \
                      -key=$GOPATH/src/github.com/daozhao/apprtc-go/mycert.key  \
                      -httpport=8080 -httpsport=8888 \
                      -stun=192.168.2.170:3478

iceServer返回json,只有stun服务器列表。

{"iceServers":[
{
   "urls": [
           "stun:192.168.2.170:3478"
           ]
}
]}

这样在浏览器就可以键入https://192.168.2.170:8080,就可以进行测试。建议使用两台机器,并连接到不同的的子路由器下进行测试。

测试turn服务,固定用户名,密码

turnserver -v  --user=daozhao:12345 --realm apprtc  --no-stun
参数说明:
--no-stun 不启动stun服务,所有stun的包都被忽略。
--user  用户名和密码 组合形式username:password
--realm  域标志,其实这个在这里随便写就可以。
             但是不能不写,要不然认证失败401

apprtc-go启动的时候添加turn服务器参数,使用静态用户名密码。

./apprtc-go -cert=$GOPATH/src/github.com/daozhao/apprtc-go/mycert.pem \
            -key=$GOPATH/src/github.com/daozhao/apprtc-go/mycert.key \
            -httpport=8080 -httpsport=8888 \
            -turn=192.168.2.170:3478 -turn-username=daozhao -turn-password=12345

iceServers返回,注意,如果使用turn服务列表,必须有username和credential。这里的用户名密码是静态的。

{"iceServers":[
{
    "urls": [
      "turn:192.168.2.170:3478?transport=udp"
    ],
    "username": "daozhao",
    "credential": "12345"
  }
]}

测试turn服务,动态验证用户名,密码:

turnserver -v  --user=daozhao  --realm apprtc --static-auth-secret=654321  --no-stun
参数说明:
--static-auth-secret  认证加密需要的key
--user   有static-auth-secret设置时候,这里只需要写用户名。
             不要写密码,要不然认证失败401

apprtc-go启动命令行。

./apprtc-go -cert=$GOPATH/src/github.com/daozhao/apprtc-go/mycert.pem \
            -key=$GOPATH/src/github.com/daozhao/apprtc-go/mycert.key \
            -httpport=8080 -httpsport=8888 \
            -turn=192.168.2.170:3478 -turn-username=daozhao -turn-static-auth-secret=654321

iceServers返回,注意这里是一个动态的用户名密码。这个用户名密码的计算方法:
用户名由两段组成 timestamp:username
credential的计算方式 base64(sha1_HMAC(timestamp:username,secret-key))
详细的参考这里

{"iceServers":[
{
    "urls": [
      "turn:192.168.2.170:3478?transport=udp"
    ],
    "username": "1504596938:daozhao",
    "credential": "k/yZNM4Jfofkqqa7ygBP5yCstow="
  }
]}

下边是一个完全事例。

turnserver -v  --user=daozhao  --realm apprtc --static-auth-secret=654321 
./apprtc-go -cert=$GOPATH/src/github.com/daozhao/apprtc-go/mycert.pem \
            -key=$GOPATH/src/github.com/daozhao/apprtc-go/mycert.key \
            -stun=192.168.2.170:3478 \
            -turn=192.168.2.170:3478 -turn-username=daozhao -turn-static-auth-secret=654321 \
            -httpport=8080 -httpsport=8888

iceServer返回:

{"iceServers":[
{
    "urls": [
      "stun:192.168.2.170:3478"
    ]
  }
,
{
    "urls": [
      "turn:192.168.2.170:3478?transport=udp"
    ],
	"username": "1504598153:daozhao",
	"credential": "+pUWOR9wKKgBRXQoLJ7tl2PlFSA="
  }
]}

参考链接:

http://www.cnblogs.com/lingdhox/p/4209659.html

http://www.cnblogs.com/kakawater/p/7112925.html

https://stackoverflow.com/questions/30745153/turn-server-for-webrtc-with-rest-api-authentication?noredirect=1&lq=1

在chrome上调试webrtc踩坑记

最近又再次用chrome测试webrtc的demo(https://appr.tc/)。 为了有更多的控制性,和测试两个客户端不同的网络环境的情况是否可以通讯。此网站是google提供的测试网站并且提供了网站的全部源代码(https://github.com/webrtc/apprtc)。可以自行部署在自己的机器上。部署webrtc的服务器,如果想访问摄像头的功能必须部署https。或者你只能通过localhost来访问。apprtc提供的代码是需要部署 Google App Engine SDK for Python的。或者使用使用这个docker(piasy/webrtc-build),使用说明。不过存在一个问题,就是它们都不支持https的访问,如果用chrome来调试,就只能本机访问。或者你在做一个https和wss的转发代理。

上述的方法我并没有采用,我是用golang重写了一次这个demo的python部分。代码请去https://github.com/daozhao/apprtc-go。为什么重写这个,当然有原因,这里就不说了。

先说说我的发现的bug。我发现在windows的chrome经常建立不了呼叫和应答,出不了视频图像。有时候可以有时候不可以。搞不懂。使用的官方的appr.tc的网站测试和自己搭建的测试环境都一样。但是我在mac OS X上的chrome肯定是可以的。实在搞不懂。

测试了很久,终于发现规律了。就是我如果是通过Mac OS X 上的Microsoft Remote Desktop去登陆windows进行操作,进行测试是没有任何问题的。但是如果我是直接在windows的主机上操作就是老出不到图像。或者,先remote过windows,chrome进行过呼叫,并出过图像,然后再在windows主机操作,这样也是可以的。这个真的令我奇怪不已。

不过找其他同事的windows机器测试并没有此问题。真的傻了,chrome升级了一遍又一遍,卸载重装。问题依旧。后来细心思考了一会儿,估计出问题是截屏问题,因为我的windows是台式机,并没有摄像头。呼叫或者应答的时候是输出桌面的截屏视频的。后来我在主机接上了一个usb摄像头。并在chrome的设置使用该摄像头。发觉问题解决了。这个问题搞了我2天。真的TMD。

在这个bug解决后,我继续思考。chrome的桌面输出是需要在启动的时候添加参数才可以。我由第一次使用chrome测试webrtc就没有打开过这个参数,就可以输出桌面的。我开始并不以为然。以为网上的资料有错,由或者我之前打开了chrome的测试模式。现在看来这个桌面输出并不是chrome自带的。而且我安装了一个第三方的截屏输出的驱动。而chrome把它也当作一个摄像头。我查询了一下这个截屏输出是screen-capture-recorder。原来这个东西和chrome有点不合。不过我在别的同事也安装了这个插件的机器上,并没有我的问题。看来是版本的原因。

交叉编译Android平台glib库和其他一些库

最近有需要把glib库编译上Android上。网上搜索了一下,发觉有人已经写了详细的编译步骤出来了。

编译可在Android上运行的依赖库(一):glib库
交叉编译Android平台glib库

但是按照其方法还是有不少问题。我也不想在这里说明了。因为我估计这些问题可能和你的编译环境等有关系。每个人的机器环境可能都有小小区别。虽然文章也給了具体编译环境的说明,和编译的软件的版本信息。理论上应该没有太多问题。但是我实质上还是遇到问题。 现在提供一个docker来统一编译环境,这样就可以减少问题的存在。而且还提供了编译脚本。其实我已经在建立docker的时候也顺便把编译的工作做了。节省时间。你只要把

docker pull daozhao/glib-android-build-docker

下来,就可以直接使用了。使用的编译方式与文中有点区别,使用standalone的方式编译。我觉得这样的方式比较方便,特别需要对C++的支持。

编译了glib库及依赖包列表:
1) iconv (1.14) https://www.gnu.org/software/libiconv/
2) gettext (0.19.8) https://www.gnu.org/software/gettext/
3) pcre (8.40) http://www.pcre.org/
4) libffi (3.2.1) https://sourceware.org/libffi/
5) glib (2.44.1) https://developer.gnome.org/glib/stable/

其他一下库的包列表
6) jansson (2.10) http://www.digip.org/jansson/
7) gengetopt (2.22.6) https://www.gnu.org/software/gengetopt/gengetopt.html
8) libsrtp (2.0.0) https://github.com/cisco/libsrtp
9) gmp (6.1.2) https://gmplib.org/
10) nettle (3.1) https://www.lysator.liu.se/~nisse/nettle/
11) gnutls (3.5.13) http://www.gnutls.org/
12) libnice (0.1.14) https://nice.freedesktop.org/wiki/
13) libmicrohttpd (0.9.54) https://www.gnu.org/software/libmicrohttpd/

使用方法

docker run -it daozhao/glib-android-build-docker bash

相关信息:

NDK=/home/data/android-ndk-r13b
SYSROOT=/home/data/standalone_toolchain/sysroot
.a & .so 文件在目录 /home/data/standalone_toolchain/sysroot/usr/lib/
.h文件在目录 /home/data/standalone_toolchain/sysroot/usr/include/
arm-linux-androideab* 文件在目录 /home/data/standalone_toolchain/bin/

修复mac OS X的Docker: No Space Left on Device

mac os x的docker现在比较好用,虽然macOS都是POSIX系统。但是多少都和linux系统有点不一样。所以我实验一些新软件系统的时候很多时候还是需要linux系统,以前多数使用虚拟机进行。现在喜欢用docker了。虽然mac上的docker也是运行在虚拟机上的。但是运行效果和在linux上没有什么区别。但有一个问题困扰了我很久。就是经常出现No Space Left on Device。明明我的磁盘还有很多空间。就是老出现这句提示。原来的处理方式,是删除一些不需要的image。最近由于剩下的images都是需要的,删无可删了。

只能上网找解决方法。发现这个问题还是不好处理的。最后虽然成功处理了。大家发觉处理的方式和网上说的有点不一样,所以记录下来。不能说别人的方法错误,只能说明我更加黑仔。

首先,这个不够磁盘空间的问题产生有几种情况的。

1 虚拟机的虚拟磁盘空间不够了。

2 是虚拟机的磁盘分区导致空间不够。(估计大部分人都是这个问题,我就是这个问题导致的。)都不知道为什么docker这么傻逼,生成一个虚拟磁盘是64G的。但是在这个磁盘上在分配一个18G的分区进行使用,超过18G就不能用了。超级傻逼。

现在讲处理方法。

继续阅读“修复mac OS X的Docker: No Space Left on Device”

WebRTC Native code在MacOS编译踩坑记

想编译WebRTC的源代码,想测试下一些东西。其实官方有说明怎样编译的。理论上也是比较简单的。但是非常不幸的是。webrtc的源代码在墙外。这个源代码据称有8G那么大。不过最后发觉压缩后还有10G多。

代码怎样下载?虽然webrtc用的是git管理代码,但是他的下载是用另外一套工具下载的,具体为什么我也不知道。而且我发觉他下载的代码除了webrtc外还包含了chrome的代码,还有一些第三方的工具。下载这个代码最困难的是由于是巨大的容量,而且不支持断点续传。google是怎样想的,这么大的容量还不支持断点。虽然可以挂VPN进行代码下载。但是需要非常稳定的VPN。而且速度也要快。我想不出哪里可以提供这么稳定的vpn,有时候不是vpn不稳定,而是自身网络也不一定稳定。现在想到的办法是在海外创建VPS服务,把代码拉好了。然后打包下载回来。

由于本身在DigitalOcean有VPS。所以就在上边进行拉取。由于用的是最低的配置,没有拉多久,git就报内存不足了。TMD的。谁叫你穷,买的是512M的内存服务器,现在手机的内存都比你多尼?最后找了国内的云主机供应商的香港云主机。搞个4G内存。下载代码就是非常快了。最后把代码拉到Mac上。不过发觉编译有问题。

第一个问题:

>gn gen out/mac –args=’target_os=”mac” target_cpu=”x64″ is_component_build=false’
gn.py: Could not find gn executable at: /Users/daozhao/Documents/sourcecode/WebRTCdemo/webrtc_macos_test/src/buildtools/mac/gn

找不到命令,怎么搞的。居然找不到命令。看了看gn的代码,发觉有一个chromium编译路径可设置在环境变量的。然后我设置了这个,在这个目录下再创建了一个mac的目录。把depot tools工具都放在这个mac目录中。

export CHROMIUM_BUILDTOOLS_PATH=XXXXXXXX

这样重要可以运行gn生成工具了。结果有悲剧了。又显示了一个错误。

gn fork: Resource temporarily unavailable

网上google了这个错误。没有发现编译webrtc的时候有别人出现这个错误,在其他地方会会出现这个错误,原因是mac os系统有限制创建线程数量。大家可以输入。

>launchctl limit
cpu         unlimited unlimited
file size  unlimited unlimited
data        unlimited unlimited
stack      8388608 67104768
core       0 unlimited
rss         unlimited unlimited
memlock unlimited unlimited
maxproc 709 1064
maxfiles 256 unlimited

最后把参数调大。但是还是报同样的错误。现在我怀疑mac有专用的gn工具的。在同步代码的时候应该是根据系统下载相关的工具。由于我是使用linux系统下载的代码,下载了linux的编译工具,没有下载mac的工具。需要再次运行gclient sync,当然运行这个命令是需要vpn的。但是由于有之前的下载,不用所有东西都重新下载,只是下载很少一部分工具而已。

rm src/links #需要先删除这个文件,要不然会报错。
gclient sync
rm -rf src/third_party/llvm-build
gclient sync

这时候可以从新运行gn生成工具了。

>gn gen out/mac –args=’target_os=”mac” target_cpu=”x64″ is_component_build=false’
Done. Made 347 targets from 107 files in 5461ms

到了这里就可以编译了,编译时间比较久,

WebRTC入门指导

这篇文章是记录之前研究的webRTC的记录,最近准备再次走进WebRTC,所有写下一些资料,以免忘记的时候可以看看。

入门看什么文章比较好,当然是WebRTC的官方网站的Getting Started。不过资料比较多,而且上边列表的资源重复也不少。

Getting started的推荐的2013的google IO关于WebRTC的视频就别睇了,没有什么营养。大家看这三篇对webRTC入门的文章比较好,Getting Started with WebRTCWebRTC in the real world: STUN, TURN and singlingWebRTC data channels,基本上把WebRTC的结构说得个明白。可以对WebRTC有一个很好的整体了解。

对于入门的代码例子就看这个codelab,进阶少少的例子就看WebRTC samplesWebRTC-Experiment,还有一个完全可以用的Demo的线上例子,别忘记了这个Demo的有很多参数可以调整的,请查看参数设置

看完上边的资料,你已经对WebRTC有了基本的了解了。如果你做WebRTC的前端或者关于Signaling的后端开发,这些知识基本够用了。不够如果要深入研究WebRTC,需要做二次开发或者做MCU的话就需要进入步研究了。

由于WebRTC是P2P的,首先需要研究的了解UDP打洞。关于打洞的问题请看Peer-to-Peer Communication Across Network Address Translators这个是关于P2P的网络神作。如果觉得文章复杂,不如先看看这些入门级的文章:穿越防火牆技術P2P通信原理与实现。再找些开源的STUN服务器研究下。

其实需要研究的东西还是比较多的,不过站在巨人的肩膀好办事。这里列几个比较出名的WebRTC开源项目吧,

1. http://www.kurento.org/

2.Licode

https://doubango.org/ 这个是项目有SIP的部分,有webrtc2sip的转换。兼容SIP系统较好选择。

4. https://mediasoup.org/ 这个是nodejs + c的项目,属于SFU,不是mcu。

5. https://janus.conf.meetecho.com/ Janus一个比较出名的项目,纯C写的项目。

WebRTC有一个比较烦人的问题,Web服务必须使用https来部署,要不然浏览器不给使用相关的api,这样做开发测试的时候比较麻烦。

golang 与cgo的跨平台编译

golang语音本身是支持跨平台编译的,只要在编译的时候添加相应的选项就可以了。不过有一个问题是不支持带有cgo的程序。如果需要支持cgo还需要配置编译cgo的环境,如果一个带cgo的程序需要编译成多个平台的支持,那是一件痛苦的事情,或者需要编译成非开发机本机运行版本,也是一件麻烦事。特别是开发嵌入式arm程序的时候就编译环境的配置就特别麻烦。不过现在有万能的docker对配置进行了简化。

由于工作需要,之前自己做了一个docker编译go 和cgo在android上运行的images,不过当时是手工制作images,并没有记录制作步骤和写下dockerfile。由于目前go和android的版本升级比较快。所以原来的docker images已经不合时宜了。不想再自己去做这个images了。在网上搜索了一个Go CGO cross compiler这个docker images比自己做的强大很多,支持很多平台的编译。使用起来比较方便。大家可以看看说明就可以了。非常方便。

由于这个docker的操作非常自动,可以说太自动了。例如,编译的项目必须在git上,自动下载项目和项目相关的库。对于一些不在git上的公司内部项目不是很友好。而且好像每次都重新下载项目和关联的代码库。导致编译速度非常慢,本来就是比较慢了。所以我没有使用它提供的的xgo工具。只使用它的docker images。

这个docker images的使用方法官方并没有说明。不过通过其dockerfile可以窥探其秘密。

进入这个docker的命令是:

docker run -it –entrypoint /bin/bash  karalabe/xgo-latest

因为这个docker设置了entrypoint是根目录的build.sh,需要把它替换成bash。这个docker的go path位于/go目录中,代码需要放在/go/src目录中。然后可以运行/build.sh XXXX 进行项目编译。当然可以归宿主机的代码映射到docker目录中并自动运行编译那时最方便的。

docker run –rm -it \
-v “$PWD”:/build \
-v “$PWD”/vendor:/go/src \
-v “$PWD”:/go/src/XXXXX \
karalabe/xgo-latest XXXXX

#XXXX代表你的项目目录名称。这里把项目需要包含的依赖包也一并映射到docker的/go/src中。

这样就可以很方便编译出各个平台运行的版本可执行文件,包括windows,macOS,iOS,android,linux,arm等。不过大多数我们并不需要编译这么多平台的版本,很多时候我们只需一个版本就够了。这样可以节省很多的编译时间。

docker run –rm -it \
-v “$PWD”:/build \
-v “$PWD”/vendor:/go/src \
-v “$PWD”:/go/src/XXXXX \
-e TARGETS=android/arm \
karalabe/xgo-latest XXXXX

这样写就可以只编译android的arm的版本。具体TARGETS支持什么参数,请参考官方说明。

RTMP转换成TS流的注意事项

RTMP转换成TS流的注意事项,

一  需要注意PCR的标记,虽然有人说PCR不是必须的,但是如果你标记PCR的话,必须写对PCR,开始做的时候,因为看见网上的评论说,ipad和苹果的系统并不检查PCR的。所以我就乱打,结果在windows上播放出问题,windows上的媒体播放器会播放得特别快,他是根据PCR的时间播放的。

另外PCR的字段生成,不是简单的=DTS就可以了。PCR的组成是33(PCR_Base)+6(PCR_const)+9(PCR_Ext) ,计算方法参考下边,此方法是参照SRS的计算方式,另外stackoverflow有另外一个方式计算。我觉得SRS的计算方式更加好理解。

PCR_Ext = 0;
PCR_Const = 0x3F;
int64_t pcrv = PCR_Ext & 0x1ff;
pcrv |= (PCR_Const << 9) & 0x7E00;
pcrv |= (PCR_Base << 15) & 0xFFFFFFFF8000LL;

pp = (char*)&pcrv;
data[ 6] = pp[5];
data[ 7] = pp[4];
data[ 8] = pp[3];
data[ 9] = pp[2];
data[10] = pp[1];
data[11] = pp[0];

另外PCR转换成播放时间的秒的方法,具体方法可以参考stackoverflow的帖子:

pcrv = 0
pcrv |= uint64(pcr[0]) << 40
pcrv |= uint64(pcr[1]) << 32
pcrv |= uint64(pcr[2]) << 24
pcrv |= uint64(pcr[3]) << 16
pcrv |= uint64(pcr[4]) << 8
pcrv |= uint64(pcr[5])

programClockReferenceBase := (pcrv & 0xFFFFFFFF8000) >> 15
programClockReferenceExtension := pcrv & 0x1FF
constValue := (pcrv & 0x7E00) >> 9
s =float64(programClockReferenceBase * 300 + programClockReferenceExtension) / 27000000

继续阅读“RTMP转换成TS流的注意事项”