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流的注意事项”

2015年8月菲律宾宿务薄荷潜水日记

这次的潜水日记不分开每一潜来写,因为我的潜水日记是为了记录我潜水的时候一些操作不佳或者有些做的不好的东西,有待下次改进,主要记录技术问题为主。

这次潜水的是15年8月份在菲律宾宿命薄荷的alone beach和附近著名的Balicasag。潜店选择了无限蓝,选择它的原因是因为有朋友在这里学ow。那我就顺便在这里fun dive。

这次一共潜了7个潜,有4潜是Balicasag。3潜是Alone beach附近。

dive point如下:

1、swiss bamboo

15年08月02日 09:43AM
Dive time 41分钟。
最大深度:19.8米
平均深度:10.5米
水温:29度。


2、tawala marine sanctuary

15年08月02日 02:21pm
Dive time 41分钟。
最大深度:19.6米
平均深度:13.3米
水温:31度。
3、black forest

15年08月03日 10:02AM
Dive time 48分钟。
最大深度:11.5米
平均深度:7.7米
水温:29度。
4、cathedral

15年08月03日 12:08pm
Dive time 44分钟。
最大深度:19.6米
平均深度:13.2米
水温:29度。
5、alona house reef

15年08月03日 06:17pm
Dive time 49分钟。
最大深度:18.3米
平均深度:10.1米
水温:29度。
6、dive’s heaven

15年08月04日 10:00AM
Dive time 40分钟。
最大深度:18.6米
平均深度:10.8米
水温:28度。

7、marine sanctuary

15年08月04日 12:00pm
Dive time 49分钟。
最大深度:19米
平均深度:11.2米
水温:29度。

 

点评一下潜店,这个潜店在国人中都算比较出名,其中有好多国人在这里学习DM,甚至考教练牌。给我的感觉是不过不失啦。没有太多特别。选择中文潜店的好处就是可以大家多交流。这里的教学还是比较认真的,朋友在这里上了4天的ow课程,内容排得满满的。4整天没有闲过。

继续阅读“2015年8月菲律宾宿务薄荷潜水日记”

编译nginx到Android上踩坑了

上个月老细又话把产品移植到android上,哭吧。。。又一堆东西要搞了。收到任务,第一个移植的就是nginx,因为我们的软件使用了nginx作为http服务器,并且针对服务写了些插件绑定在nginx上。心想这个android也是linux内核的,应该左个跨平台编译就差不多了。谁知道折腾了一个多星期。

如果大家只是想最快编译一个nginx上android就不用看我的文章。直接在这里andoid-nginx下载这个针对android修改好的编译配置就可以了。想了解我采坑的就继续看下去。

编译nginx for android主要参考了 这个帖子和另外一个帖子。但是结合自己的遇到的情况做了一些调整。虽然编译不是很顺利,一路遇到不少问题。不过通过万能的google解决了。历尽千辛万苦终于编译完成了。

其中一个主要的修改是对 auto/types/sizeof文件进行修改,由于configure会对编译出来的测试程序并运行,测试出int,long等数值的长度。由于修改了编译器,编译出来的文件只能在arm的系统上跑,那么在编译的主机上是不能跑的。帖子的方法是教你写一个固定的值,我觉得不是太好,事实上也的确不太好。于是我把这个测试程序的编译器改成我编译主机(用的是mac osx系统)的gcc(其实是clang)。还有一个问题就是我的系统是64位的。而我的目标的android是32位的。不过好彩gcc(其实是clang编译器)有一个参数可以编译32位的程序,“-m32″

#ngx_test=”$CC $CC_TEST_FLAGS $CC_AUX_FLAGS \
ngx_test=”gcc -m32 $CC_TEST_FLAGS $CC_AUX_FLAGS \

继续阅读“编译nginx到Android上踩坑了”

使用docker重建Gitlab服务

新年假期回到公司,就发现一个噩耗,就是代码服务器意外关机,重启不成功。虽然我知道linux的机器意外关机会造成不可以预知的损坏,但是在10多年的linux使用生涯中还是真的未遇过。这次终于给我遇上了。

虽然数据在年前已经备份过了。不过我想到的是如果这台机救不回来,要我重新安装这个gitlab服务就真的疼苦了。虽然当初安装的时候有把关键点都记录下来。不过再安装一次的确痛苦。关键是迁移数据的问题。我还发现一个问题就是我没有记录当时安装的gitlab的版本,低级错误。不过经过维护部门的努力,机器是可以重新启动,gitlab服务也正常。不过在等待维护部门的修复,就等待了好几天。好在影响不大,其实这些东西本应不用我操心的。不过公司一共4个开发团队,就我一个团队使用代码管理。其他几个部门还是原始社会的手工管理。所以这个代码服务器想移交去维护部门都不行。

虽然这次救活了,但是我还是需要准备万一下次再出问题的时候,修复不了机器的时候做好准备了。作为快速搭建服务,首选是使用docker进行部署。目前已经有人做好了docker-gitlab的image镜像。目前这个image的版本使用gitlab 7.8.1,不过我们使用的gitlab的版本是6.6.5的版本。不知道数据库是否可以平滑升级。

找了一台Ubuntu 14.04机器进行测试。其实使用这个docker-gitlab的container比较简单,他的github页面说明比较详细。如果新建的gitlab服务,参照他的说明就可以了。比较简单。但是有一个坑,这个可能是docker-compose(原有的fig)的bug。

继续阅读“使用docker重建Gitlab服务”

golang的包管理–godep

golang没有提供包管理工具,只是提供了一个全局的包管理。不过对于一些项目来说,需要一个包管理工具,经过一番google后,最后选择了godep这个工具。

对于这个工具的使用觉得并不是很满意。经常有一些问题,不知道如何解决。有时候昨天不成功,今天有Ok了。真是搞到头大。目前对于一些问题还是不太确认是什么问题。估计是对这个工具的理解不够。

 

这里讲一下使用技巧和一些注意事项。

1、建立依赖json文件。在项目的根目录下运行下边命令。

godep save  或者用 godep save ./…

注意你需要在这个目录运行go build 可以成功编译。就可以。另外你需要把文件Godeps/Godeps.json添加到代码管理中,那样才方便别人下载项目和更新依赖包。,godep save 同时把依赖包的代码都copy到Godeps/_workspace/src目录下,而且把依赖包的git管理目录.git去掉了。你可以把这些依赖包一并上传到你的项目代码管理中,这样别人下载你的代码库的时候就可以直接编译,不需要下载更新依赖包。但是你的代码库会相对大一些,同时也会出现一些其他一些版本问题。

2、下载依赖包

godep restore

这个命令是根据Godeps/Godeps.json文件把项目的依赖包下载到$GOPATH目录下。另外看一看下边的脚本,千万别学他。这个脚本我是参考wandoulabs/codis的项目中的一个编译脚本编写的。就因为这个,我踩坑了。

make clean

echo “downloading dependcies, it may take a few minutes…”
# Test godep install, steal it from LedisDB project 😛
godep path > /dev/null 2>&1
if [ “$?” = 0 ]; then
GOPATH=`godep path`:$GOPATH
godep restore
go build || exit $?
exit 0
fi

继续阅读“golang的包管理–godep”

Filco minila air 茶轴机械键盘使用感受

想买好的键盘好久了,不过一路都没有进购。不过早几个星期就终于买了filco minila air 茶轴。

先讲讲我的候选键盘,全部都是60%的小键盘。因为我觉得占位置少,全键盘,多出来的键也没有什么用。

1、HHKB pro 认识这个键盘是因为听了一个程序员的podcasts。认识了HHKB。对这个键盘布局太爱了。因为小巧。没有多余的键。不过由于价格太贵了。一路都没有狠心买下来。而且他还有一个不太喜欢的地方是方向键的排布不是喜欢。

2、HHKB lite 2,这个产品是HHKB的低端产品,是薄膜键盘,在一些玩家眼中是不值得一提的,但是价格也比较亲民。不过我还是觉得薄膜键盘也有好的产品,不一定需要机械键盘才好打的。产品寿命也是薄膜键盘的弱点,不过这些大品牌,产品质量过关。不会这么容易坏的。加上我也不大游戏。估计这辈子也用不坏。之前在旧公司用dell的原装机的时候,发觉他的键盘比较好打。现在估计那个就是传说中的8115键盘

3、poker 2 或者 KBT RACE 2这个两个产品没有太多特别。

4、Filco minila air ,这个键盘几乎满足了我90%的需求了。这个键盘有一个比较好的特点是,在空格键左右分别有两个fn键,这样组合按方向键就超级爽了。还有一个大爱的地方就是有蓝牙版本。

filco minila air

继续阅读“Filco minila air 茶轴机械键盘使用感受”

golang cgo编译问题与坑

golang这个语言最大的好处就是和c结合得非常好,非常方便与c互相调用。虽然其他语言也可以调用c的库,但是调用没有golang这个语言这么方便。其实想讲,golang就是现代版的c语言。

首先golang如何调用c的库,文档写得比较清楚。请参照文档cgo编译cgo命令。这个看来之后基本就大概明白了。而且讲解了一些基本的类型转换。例如string的转换等。不过真实使用的时候,会用到char**的。这个问题如何解决。stackoverflow上有解,请自行观看。

看完这些问题,大家觉得是不是就没有问题。我也是这样想的,不过真实的时候就遇到一个非常恼火的问题。就是golang对格式的一些严格要求。

问题来源,在调试cgo的程序的时候。发觉本来调试好的程序,后来也没有改什么,突然编译不了。找了很久也没有找出原因。由于是测试代码,没有放入代码管理,回滚不了。看来看去也没有看出什么问题。最后只能从最开始重新编写这个代码。最后发现是一个空行引发的血案。悲哀啊,搞了我大半天。

看下边的代码吧:

package main

/*
#cgo CFLAGS: -I .
#cgo LDFLAGS: -L . -lclibrary

#include "clibrary.h"

int callOnMeGo_cgo(int in); // Forward declaration.
*/
import "C"  //这里不能与上边注释的c代码有任何空行。

import (
        "fmt"
        "unsafe"
)

//export callOnMeGo
func callOnMeGo(in int) int {
        fmt.Printf("Go.callOnMeGo(): called with arg = %d\n", in)
        return in + 1
}

func main() {
        fmt.Printf("Go.main(): calling C function with callback to us\n")
        C.some_c_func((C.callback_fcn)(unsafe.Pointer(C.callOnMeGo_cgo)))
}

大家可以尝试在import “C”上边插入空行。你就发现会不能编译了。真是不太明白golang为什么搞怎么严格的格式检查。真的服了它了。多一个空行而已。

还有一个问题是,目前我使用cgo与ffmpeg的库进行编译,经常出现编译问题。但是重新编译多一次就成功了。也搞不懂什么原因。