1.PJSIP源码探究 pjmedia-videodev模块
2.sipåè®®å¦ä½ç¨Cè¯è¨å®ç°
3.å¦ä½å¨ android 设å¤ä¸ä½¿ç¨ pjsip G.729 ç¼è§£ç çåè½
4.webrtc linphone å°åºåªä¸ª
5.pjsip 本地视频预览怎么改变内容源的大小 iOS
PJSIP源码探究 pjmedia-videodev模块
PJMEDIA-Videodev模块详解:在PJSIP中的视频捕获功能实现
PJSIP中,pjmedia-videodev模块扮演着关键角色,它负责视频捕获功能,让开发者能够在应用中集成自定义画面捕获设备。为了深入了解,首先需要理解pjsua2中的红绿灯源码工作流程,包括Endpoint对象的使用和相关c++函数的调用,如pjsua_create、pjsua_start和pjsua_init等。
在pjsip的源码中,视频捕获设备的初始化过程始于pjsua_media_subsys_init,这个函数通过pjsua_media_config_default参数,初始化了媒体子系统,其中包括视频和音频子系统。其中,pjmedia_vid_subsys_init在pjmedia-videodev模块的pjmedia_vid.c中被调用,用于初始化视频捕获设备子系统。
在Android环境下,pjmedia_and_factory是淘宝仙女源码关键,它会在编译时根据平台特性注册到视频子系统中。当需要视频捕获时,会通过这个工厂创建具体设备,如摄像头,并获取画面。pjmedia-videodev-factory在android_dev.c文件中实现,包含了设备查找、参数设置和流创建等功能,如and_factory_init、跟庄BOLL源码and_factory_create_stream等。
视频流的管理主要通过pjmedia_vid_dev_stream结构体和对应的stream_op函数,如and_stream_get_param、and_stream_set_cap等,它们控制摄像头的设置和画面捕获。在自定义捕获中,可以通过这些接口添加时间水印,创造出更为丰富的视频体验。
总之,物流商业源码pjmedia-videodev模块为PJSIP提供了灵活的视频捕获能力,开发者可以根据需求定制捕获设备和功能。理解并掌握这一模块的工作原理,将有助于在实际项目中实现个性化的视频通话体验。
sipåè®®å¦ä½ç¨Cè¯è¨å®ç°
1ãå¼æºçsipæå¡å¨ç«¯ï¼æ¯è¾å¥½ç¨çæ¯Asteriskï¼æ åCç¨åºå®ç°ï¼ä»£ç æ¸ æ°ã
2ãsipçclientç¸å¯¹æ¯è¾å¤ï¼ä¸»è¦æexosip,pjsipåopalãexosipç®åæç¨ï¼å¨PCä¸ç¨æ¯è¾æ¹ä¾¿ãä½æ¯æ¶åçç¸å ³èµæºå¤ªå¤ï¼ç¨äºosip,srtp,ms2çä¼å¤çå¼æºåºï¼ms2ä¸é¢è¿ç¨å°äºffmpegï¼å«çä¸è¯´ï¼å ç¼è¯å°±æ¯å©æ¢¦ãopalåè½æ强ï¼è½ç¶ä¹ç¨å°äºffmpeg ï¼ä½æ¯èªå·±å°è£ çé常好ï¼éç¨æ件æ¹å¼ï¼è°ç¨çµæ´»ãopaléç¨classæ¹å¼æä¾å°è£ ï¼æ¥å£é常å好ãæè§å¯ä¸ä¸ç½çå°æ¹ï¼å°±æ¯ä½å±ä½¿ç¨äºptlibï¼è½ç¶å¤å¹³å°ä¸é½å¾å¥½ç¨ï¼ä½æ¾å¨åµå ¥å¼ä¸æè§ç¨åºå¤§äºä¸äºãpjsip精巧ï¼æ¹ä¾¿ç§»æ¤ï¼åµå ¥å¼ä¸åºè¯¥æ¯é¦éãä¸è¿è§é¢é¢æ¯ææ¹é¢æ©å±èµ·æ¥æ¯opal麻ç¦ã个人æè§ï¼å¯¹äºwindowså¼åè æ¥è¯´ï¼pjsipæ大ç好å¤å°±æ¯ä»£ç è°è¯æ¹ä¾¿ãæ´ä¸ªå·¥ç¨ä¸æ¬¡ç¼è¯éè¿ï¼å¦å¤ä¸¤ä¸ªåºè¿è¦æ¾å¾å¤ç¸å ³çèµæº
ã
3ãå ¶ä»çä¸äºåè®®æ ä¹è°è¯è¿ï¼æ¯å¦reSipphoneï¼å¥½è±¡æ¯è¿ä¸ªååï¼è¿æYateï¼ä¸è¿ä»å¿«éå¼åè§åº¦çï¼é½ä¸å¤ªåéãç°å¨æsipå¼åçï¼ä¸å¼å§å°±æ¯å æ¾å¥½åè®®æ ãlinphone,ekigaä»ä¹çï¼ä½åºå¤§ã对äºåå¼å§åçï¼æ好æ¯ä¸ä¸ªç²¾ç®çdemoãåæ¥æ¾å°pjsipä¸é¢çå 个ä¾åï¼æ ¢æ ¢å°äºè§£äºsipçå·¥ä½æµç¨ï¼å½ç¶å°ä¸äºæå å·¥å ·åtcpdumpã
ä¸è¿ï¼å ¶å®ï¼sip没ææ³è±¡ä¸çé£ä¹éº»ç¦ãç°å¨å头çï¼åå¼å§å项ç®ï¼ä½¿ç¨åè®®æ ç»å¯¹ä¸æ¯å¥½æ³æ³ãå¦ææ¢ä¸ªæ¹åï¼å çæSIPåºæ¬åè®®ï¼ç¶åèªå·±æ¹é ä¸ä¸ªï¼æå®å ¨åä¸ä¸ªï¼å¯è½æææ´å¥½ã
å¦ä½å¨ android 设å¤ä¸ä½¿ç¨ pjsip G. ç¼è§£ç çåè½
ã第ä¸æ¥æ¯çæ pjsip 为 Android ï¼æ¥éª¤ä¸º Ubuntu Linuxï¼ çæºä»£ç ï¼
ãã1.设置 ANDROID_NDK_ROOT ç¯å¢åéè®¾ç½®ä¸ºæ¨ NDK æ ¹æ件夹ã
ãã2.è½¬å° pjsip 2.x æ件夹并å建 pjlib/include/pj/config_site.h å æ¬ config_site_sample.h ( #include <pj/config_site_sample.h> )
ãã3.è¿è¡./configure-android
ãã4.è¿è¡make clean && make depend && make
ããä¹åè¿äºæ¥éª¤ï¼å°æå 个éæåºä¸çå 个æ件夹ã建议å°å®ä»¬åç»ç¸åçæ件夹 ï¼æ好å¨æ¨ç项ç®ä¸ï¼ ä¸çï¼
ããmkdir <your_project_path>/pjsip_libs
ããfind . -name *.a | xargs -I % cp % <your_project_path>/pjsip_libs/
ããä¸æ¦èªå·±çææåºï¼æ¨éè¦å°è¿äºåºæ·»å å°æ¨çé¡¹ç® Android.mk æ件ï¼è¿æ¯ç±å æ¬ä¸ä¸ªæ°ç模åèæ¯ä¸ªå¾ä¹¦é¦ãæ¤æ¨¡åé¨ååºè¯¥æ¯ä¸æ ·çä¸è¥¿ï¼
ããinclude $(CLEAR_VARS)
ããLOCAL_MODULE := pjsua-arm-unknown-linux-androideabi
ããLOCAL_SRC_FILES := $(MY_PJLIB_PATH)/libpjsua-arm-unknown-linux-androideabi.a
ããinclude $(PREBUILT_STATIC_LIBRARY)
ããï¼å ¶å®æ¯ä¸èä¸æ建æ¨ç JNI 项ç®çæºä»£ç ï¼ææ模åé½æ·»å å°æ¨çéæåºçå¼ç¨ï¼
ããLOCAL_STATIC_LIBRARIES := pjsua-arm-unknown-linux-androideabi ...
ããè¿å°å æ¬ pjsip çå¼ç¨å å ¥æ¨ç JNI åºãç°å¨ï¼æ¨éè¦é ç½® pjsip UA å®ä¾ã
ããæä¸ä¸ªå ³äº init åå¼å§ç解é pjsip ç UA (pjsua) å¨ pjsip/include/pjsua-lib/pjsua.h ä½è¦éµå¾ªç主è¦æ¥éª¤æ¯ï¼
ãã1.å建ä¸ä¸ªå ·æ UA å®ä¾pjsua_create
ãã2.å建ä¸ä¸ªå·¥ä½çº¿ç¨ä¸pj_thread_create
ãã3.UA å®ä¾ç设置çé»è®¤é ç½®ï¼
ããpjsua_config cfg æ¡© ï¼pjsua_logging_config log_cfg ï¼pjsua_media_config media_cfg ï¼
ããpj_cli_cfg_default(&app_config.cli_cfg.cfg) ï¼pjsua_logging_config_default(&log_cfg) ï¼pjsua_media_config_default(&media_cfg) ï¼
ãã4.åå§åå æ ä¸pjsua_init
ãã5.å¯å¨ä¸å æ pjsua_start
ããä»è¿éï¼æå 足çé ç½®é项 ï¼æ¥å¿ã åªä½ã 交éå·¥å ·çï¼
ããæ¨å¯ä»¥æ¾å°åºæ¬ PJSIP æç¨å¨è¿éï¼åéé¢ pjsip çæºçæ ¹è·¯å¾ï¼æä¸ä¸ªåºæ¬ ï¼ä½ä¸å¤å®æ´ï¼åºæ¬ç SIP 使ç¨æ åµï¼ å¨ï¼pjsip-apps/src/samples/simple_pjsua.c
ããç¼è¾ï¼å¨çææ¶å¨ pjsip åºç¨ç¨åºç android 项ç®ï¼å¯ä»¥é¢ä¸´ä¸ä¸ªé®é¢ï¼å 为 pjsua app ä¸çæé»è®¤æ åµä¸ï¼å¯¹ä¸è¬çæ ï¼æ´å ·ä½å°è¯´ï¼pjsuaï¼ ç®æ ä¸å æ¬ææä¸ï¼ å¨ pjsip-åºç¨ç¨åº/çæ/çææ件çç®æ )ãè¥è¦ä¿®å¤è¿åªæ¯è½¬å° pjsip-åºç¨ç¨åº/å建åè¿è¡ï¼
ãã使 pjsua
ããè¿å°å建å¨æ£ç¡®ç对象æ件: pjsip-apps/build/output/pjsua-arm-unknown-linux-androideabi/ (éè¦æ建 android æ ·æ¬æ¶)ã
ããä¸æ¦ææç¸åºç对象æ件ï¼æ¨å¯ä»¥å¨ pjsip-åºç¨ç¨åº/src/pjsua/android ç³»ç»å次è¿è¡ ndk çæ
webrtc linphone å°åºåªä¸ª
ææ°è¦åä¸ä¸ªç§»å¨ç«¯è§é¢éè¯è½¯ä»¶ï¼å¤§è´çäºä¸ç°æçå¼æºè½¯ä»¶
ä¸) sipdroid
1ï¼æ¶æ
sipåè®®æ 使ç¨JAVAå®ç°ï¼é³é¢Codec使ç¨skypeçsilkï¼Silkç¼è§£ç æ¯Skypeå第ä¸æ¹å¼å人åå硬件å¶é åæä¾å çç¨è®¤è¯(RF)çSilk宽带é³é¢ç¼ç å¨ï¼å®ç°ãNATä¼ è¾æ¯æstun server.
2ï¼ä¼ç¼ºç¹ï¼
NATæ¹é¢åªæ¯æSTUNï¼æ ICEæ¡æ¶ï¼å¦éè¦å®å ¨å®ç°P2Pè§é¢éè¯éè¦å®ç°ç¬¦åICEæ åç客æ·ç«¯,é³é¢æ¹é¢æ²¡çå°AECçææ¯ï¼è§é¢æ¹é¢è¿ä¸æ¯å¤ªå®åï¼ç®ååªçå°è°ç¨çæ¯ç³»ç»èªå¸¦çMediaRecorderï¼å¹¶æ²¡æèªå·±ç第ä¸æ¹é³è§é¢ç¼è§£ç åºã
3ï¼å®é æµè¯ï¼
åºäºsipdroidæ¶æçè¯ï¼æ们è¦åçå·¥ä½ä¼æ¯è¾å¤ï¼ï¼ICEæ¯æï¼æ·»å åé³æ¶é¤ï¼NetEQçgipsé³é¢ææ¯ï¼æ·»å è§é¢ç¡¬ä»¶ç¼è§£ç codec.ï¼,æ以就ä¸åæµè¯äºã
äº) imsdroid
1)æ¶æï¼
åºäºdoubango(Doubango æ¯ä¸ä¸ªåºäº3GPP IMS/RCS 并è½ç¨äºåµå ¥å¼åæ¡é¢ç³»ç»çå¼æºæ¡æ¶ã该æ¡æ¶ä½¿ç¨ANSCI-Cç¼åï¼å ·æå¾å¥½çå¯ç§»æ¤æ§ã并ä¸å·²ç»è¢«è®¾è®¡æé常轻便ä¸è½ææçå·¥ä½å¨ä½å ååä½å¤çè½åçåµå ¥å¼ç³»ç»ä¸ãè¹æç³»ç»ä¸çidoubsåè½å°±æ¯åºäºæ¤æ¡æ¶ç¼å) .é³è§é¢ç¼ç æ ¼å¼å¤§é¨åé½æ¯æï¼H(video)ï¼VP8(video)ï¼iLBC(audio),PCMA,PCMU,G,Gï¼ãNATæ¯æICEï¼stun+turnï¼
2ï¼ææå®æµ
æµè¯ç¯å¢ï¼å ¬å¸å±åç½å 两å°æºå¨äºéï¼æå¡å¨èµ°å¤ç½sip2sip
é³é¢è´¨éå¯ä»¥ï¼ä½æ¯AECæå¼äºè¿æ¯æç¹åé³ï¼åºè¯¥å¯ä»¥ä¿®å¤ï¼ãè§é¢é©¬èµå æ¯è¾ä¸¥éï¼å»¶è¿1ç§å·¦å³ã
3ï¼ä¼ç¼ºç¹
imsdroidç®åæ¥è¯´è¿æ¯ç®æ¯è¾å ¨é¢çï¼å æ¬é³è§é¢ç¼è§£ç ï¼ä¼ è¾ï¼RTSPï¼ICEï¼ï¼é³é¢å¤çææ¯çé½ææ¶çãdoubango使ç¨äºwebrtcçAECææ¯ï¼ä½æ¯å ¶è°ç¨webrtcé¨å没æå¼æºï¼æ¯ç¨çç¼è¯åºæ¥çwebrtcçåºãå¦æè¦æ¹åé³é¢çè¯ä¸å¤ªæ¹ä¾¿ï¼Demoçé³é¢ææå¯ä»¥ï¼è§é¢ææè¿æ¯ä¸å¤ªçæ³ã
ä¸ï¼csipsimple
1ï¼sipåè®®æ ç¨çæ¯pjsip,é³è§é¢ç¼è§£ç ç¨å°ç第ä¸æ¹åºæffmpegï¼videoï¼,silk(audio),webrtc.é»è®¤ä½¿ç¨äºwebrtcçå声ç®æ³ãæ¯æICEåè®®ã
2ï¼ä¼ç¼ºç¹ï¼
csipsimpleæ¶ææ¯è¾æ¸ æ°ï¼sipåè®®ç±Cå®ç°ï¼javaéè¿JNIè°ç¨ï¼SIPåè®®è¿ä¸åä¼æ¯è¾é«æãå ¶VOIPå个åè½ä¹é½å ·å¤ï¼å æ¬NATä¼ è¾ï¼é³è§é¢ç¼è§£ç ã并ä¸è¯¥é¡¹ç®è·è¿æ°ææ¯æ¯è¾å¿«ï¼å®æ¹æ´»è·ç¨åº¦ä¹æ¯è¾é«ãå¦æåäºæ¬¡å¼åå¯ä»¥æ¨èè¿ä¸ªã
3ï¼å®æµææ
æµè¯ç¯å¢ï¼å ¬å¸å±åç½å 两å°æºå¨äºéï¼æå¡å¨èµ°å¤ç½sip2sip
é³é¢è´¨éå¯ä»¥ï¼æ ææ¾åé³ï¼è§é¢éè¦ä¸æ件ï¼é©¬èµå æ¯imsdroidæ´ä¸¥éã
åï¼Linphone
è¿ä¸ªæ¯èççsipï¼æ¯æå¹³å°å¹¿æ³ windows, mac,ios,android,linuxï¼ææ¯ä¼æ¯è¾æçãä½æ¯æ®ç©è¿çåäºè¯´linphoneå¨Androidä¸çbugæç¹å¤ï¼ç±äºå ¶ä»£ç å®å¨åºå¤§ï¼æ以æææ¶æ¾å¼èèLinphone.ä¸è¿å¦æè°æ跨平å°çéè¦ï¼å¯ä»¥èèLinphoneæè imsdroidåä¸é¢çwebrtc.ããã好åç°å¨å¼æºè½¯ä»¶é½è·¨å¹³å°äºããã
äº) webrtc
imsdroid,csipsimple,linphoneé½æ³æ³è®¾æ³è°ç¨webrtcçé³é¢ææ¯ï¼æ¬äººä¹æµè¯è¿Android端çwebrtcå ç½è§é¢éè¯ï¼æææ¯è¾æ»¡æãä½æ¯è¦æwebrtcåæä¸ä¸ªç§»å¨ç«¯çIM软件çè¯è¿æä¸äºè·¯è¦èµ°ï¼ä¸è¿webrtcåºæ¬ææ¯é½å·²ç»æäºï¼å æ¬p2pä¼ è¾ï¼é³è§é¢codec,é³é¢å¤çææ¯ãä¸è¿å ¶å 为ç®åä» æ¯æVP8çè§é¢ç¼ç æ ¼å¼ï¼QQä¹æ¯ï¼æ³åé«æ¸ è§é¢éè¯çè¦æ³¨æäºãVP8å¨ç§»å¨ç«¯ç硬件ç¼è§£ç æ¯æçå¹³å°æ²¡å 个ï¼RKå¯ä»¥æ¯æVP8硬件ç¼è§£ç ï¼ãä¸è¿webrtc代ç éçå°å¯ä»¥ä½¿ç¨å¤é¨codec,è¿ä¸ªè¿æ¯æå¸æè°å°Hçã
æ»ç»ï¼sipdroidæ¯è¾è½»é级ï¼çéåºäºjavaå¼åï¼é³é¢codecé¤å¤ï¼ï¼ç±äºå ¶é³è§é¢ç¼ç 以åP2Pä¼ è¾è¿ä¸åç¥æ¾ä¸è¶³ï¼ä¸å¤ªå¥½åå®å¶åå¼ååä¼åãimsdroid,éæ¾å°±æ¯ç´æ¥è°ç¨webrtcçåºï¼èæè¿webrtcæ´æ°çæ¯è¾é¢ç¹ï¼å¼åæ¯è¾æ´»è·ãå¦æè¦èªå·±å¨imsdroidä¸æ´æ°webrtcæ å¿å ¼å®¹æ§é®é¢ï¼å¸æimsdroidå¯ä»¥ç´æ¥æéè¦çwebrtcç¸å ³æºç å è¿å»ãcsipsimpleçè¯ï¼é½æ¯å´ç»pjsipçï¼webrtcçé½æ¯ä»¥pjsipæ件形å¼æ©å ç,类似gstreamer. webrtcå¦ææææ¯å®åçå¼åå ¬å¸ä¸ªäººè¿æ¯è§å¾å¯ä»¥éæ©è¿ä¸ªæ¥åï¼ä¸ä¸ªæ¯googleçåå ï¼ä¸ä¸ªæ¯å ¶è§é¢éè¯ç¸å ³å ³é®ææ¯é½æ¯è¾æççåå ã个人è§å¾å¦æè½ååºæ¥ï¼ææä¼ä¸éçã
pjsip 本地视频预览怎么改变内容源的大小 iOS
1 把视频源当然文件来处理,sample有。不过这种方法用的不多。
2 修改vid_stream.c,在put_frame和get_frame里,彩虹互联源码换上我们自己的视频源。这种方法使用的最多,很多人在1.x版本里支持视频,就用这种方法。
3 重新构造sdp,自己创建rtp通道。
在sdp上,pjsua_call_make_call这个函数非常方便,直接呼叫对方。不过它在底层做了太多工作,比如启动了声卡。而不用这个函数,直接用比较底层的pjsip_inv_send_msg,自己处理的工作相对比较多(但不难,不过这样就不需要pjsua这个现成的程序了,所以我们继续用pjsua_call_make_call)。
不过还好,pj库提供了大量的回调,其中一个:on_call_sdp_created,就是在创建sdp后回调上来,由我们自己再修改。比如我们自己定义rtp的端口g_local_port。
void on_call_sdp_created(pjsua_call_id call_id,
pjmedia_sdp_session *sdp,
pj_pool_t *pool,
const pjmedia_sdp_session *rem_sdp)
{
int nPort;
if (sdp != NULL)
{
pjmedia_sdp_media *m = sdp->media[sdp->media_count-1];
m->desc.port = g_local_port;
pjmedia_sdp_conn *c = sdp->conn;
char* addr;
if (c)
addr= c->addr.ptr;
else
{
const pj_str_t *hostname;
pj_sockaddr_in tmp_addr;
char *addr;
hostname = pj_gethostname();
pj_sockaddr_in_init(&tmp_addr, hostname, 0);
addr = pj_inet_ntoa(tmp_addr.sin_addr);
sdp->conn = (pjmedia_sdp_conn *)pj_pool_zalloc (pool, sizeof(pjmedia_sdp_conn));
sdp->conn->net_type = pj_str("IN");
sdp->conn->addr_type = pj_str("IP4");
sdp->conn->addr = pj_str(addr);
}
sdp->origin.addr = *pj_gethostname();
}
}
同样,这里还可以修改payload type等。
这是发起呼叫时的,接收方收到后的回应之后,也会触发这个回调,自己设定RTP端口,payload type就可以了。
2
呼叫成功后,双方建立起连接关系,这时需要传rtp数据了。pjsua把这些工作都放在底层了,不做任何修改,只需要在发送和接收时,自己做一些处理就行。
先说接收方(参考siprtp.c源码):
pj_status_t init_local_rtp()
{
if (m_bInitMedia)
{
destroy_media();
}
//g_local_port = local_port;
pj_caching_pool_init(&cp, &pj_pool_factory_default_policy, 0);
pool = pj_pool_create(&(cp.factory), "test", , , NULL);
int status;
//status = pjmedia_endpt_create(&cp.factory, pjsip_endpt_get_ioqueue(pjsua_get_pjsip_endpt()), 0, &med_endpt);
status = pjmedia_endpt_create(&cp.factory, NULL, 1, &med_endpt);
status = pjmedia_rtp_session_init(&video.out_sess, , pj_rand());
status = pjmedia_rtp_session_init(&video.in_sess, , 0);
status = pjmedia_transport_udp_create(med_endpt, NULL, g_local_port, 0, &video.transport);
m_bInitMedia = true;
video.active = true;
return 0;
}
这段代码是本地启动rtp一个端口用来接收视频数据。
然后,从sdp得到对方发送的ip和端口,调用pjmedia_transport_attach,建立关联就可以了。