整合一款基于WebRTC技术的跨平台视频通话方案应用后记

整合一款基于WebRTC技术的跨平台视频通话方案应用后记

背景

2020年10月份,从上家公司出来,抱着感恩的心,进入了新的公司(yt)(上个东家,我也是挺感恩,尤其是从作为一个职场老兵,能从我们领导身上学到那股对问题锲而不舍,滋滋追寻的精神,我很佩服,我们在一起搞了两个多月的WebRTC,Windows /Android 端的代码重构、调试、优化、以及疑难问题修复,我都收益匪浅,我也想找个机会坐下来陪你喝二两,但还是相见不如怀念,敬你,也敬岁月,干杯!,跑题了……),本着在以前工作,和在上家公司(mlxjt)的积累,应承下来这份工作,在这段时间,每当想懈怠的时候,总怕辜负了你的信任,在这三个月内,也是鞭策自己完不断完善,不断优化自己的程序,也算是完成了音视频通话的的视频这款应用,虽然最后我遵从了自己的内心,没有继续留在yt,但我很想把这个特殊的时间,录小文一遍,存之。

新的改变

需求背景:

替换公司目前现有的通话方案,当前采用linphone方案,在设备的适配、通话音质,以及QoS等多个方面都表现都没有WebRTC表现得优秀,所以自研一套RTC的通话方案,也对公司的产品算是一个功能的优化。某种程度上也是互联网公司对技术的一种追求。

  • [补充]
    视频通话作为一种通用的音视频场景,虽然在万民直播的滚滚洪流下,仍然占有自己的一席之地,一些对讲、门禁、局域网点对点呼叫、以及普通视频通话方面占用了一席之地。

基本框架介绍

在这里插入图片描述
上图是以Android 的基本框图介绍

  • WebRTC Call SDK:
    主要利用WebRTC native层的API接口包装了webrtc的Offer/Answer 模型
    主要提供以下功能
    • 音频设备选择和切换
    • 视频camera选择,分辨率、帧率、码率的设置
    • 本地和远端音视频的mute/unmute操作
    • 通话详情的上报
    • 音频外部设备被作为采集和播放
    • 提供本地录制以及rtmp转发
    • 桌面共享
  • RTCRouter:
    提供一种路由,可供上层调用,优先使用直连的方式,避免走服务器主机产生的流量费用。在无法直连成功的情况下,才选择走服务器转发模式
  • WebSocket:
    主要提供网络消息的收发
    - 房间的创建、销毁
    - sdp和ice参数的交互
    - 流的控制和参数的设置
  • P2P (LAN Slotuion):
    主要是提供点对点的数据传输方案
  • WebRTC native layer:
    webrtc C++ 源码

平台特点

  • windows
    支持使用WebRTC Call SDK的提供的接口和库接入
  • Android
    使用jni和WebRTC Call SDK 进行二次封装后,提供java版本的接口和库接入
  • iOS
    使用Objective-C和WebRTC Call SDK 进行二次封装后, 提供Objective-C版本的接口和库接入

客户端技术

class RTCEngineContext {
 public:
  char* userId;
  char* nickname;
  char* logFilePath;
  bool videoCallEnable;
  bool recordable;
  int logLevel;
  int reserve;
};
enum {
  ACCT_ALREADY_TAKEN = -1,
  ACCT_DOES_NOT_EXIST = -3,
  ACCT_NOT_REGISTERED = -2,
};

class CallStatus {
 public:
  int rxVideoFps;
  int rxAudioBitrate;
  int rxVideoVitrate;
  int rxVolume;
  int rxVideoDecWidth;
  int rxVideoDecHeight;
  int rxAudioLostrate;
  int rxVideoLostrate;
  int rxAudioDelayMs;
  int rxVideoDelayMs;

  int txVideoFps;
  int txAudioBitrate;
  int txVideoBitrate;
  int txVolume;
  int txVideoEncWidth;
  int txVideoEncHeight;
  int txAudioLostrate;
  int txVideoLostrate;

  int rtt;
};

class RTCEngineEventHandler {
 public:
  RTCEngineEventHandler() {}
  virtual ~RTCEngineEventHandler() {}

 public:
  virtual void onCalling(std::string userName,
                         std::string peerName,
                         std::string nickName,
                         std::string domain) = 0;
  virtual void onIncomingCall(std::string userName,
                              std::string peerName,
                              std::string nickName,
                              std::string domain,
                              bool audioEnable,
                              bool videoEnable) = 0;
  virtual void onAccepted(std::string username,
                          std::string peerName,
                          bool audioEnable,
                          bool videoEnable) = 0;
  virtual void onRegistered(std::string token, bool result) = 0;
  virtual void onMissingCall(std::string userName,
                             std::string peerName,
                             bool audioEnable,
                             bool videoEnable) = 0;
  virtual void onCallStatus(CallStatus& status) = 0;
  virtual void onHangup(std::string userName,
                         std::string peerName) = 0;
  virtual void onApiError(const char* file,
                              const int line,
                              const char* desc) = 0;
  virtual void onError(std::string userName, std::string peerName, int errNo, std::string desc) = 0;
  virtual void onAccountError(std::string accountId, int error, std::string reason) = 0;
  virtual void onStartPlaying(const char* file, bool repeat) = 0;
  virtual void onStopPlaying() = 0;
  virtual void onCallEstablished(std::string userName,
                                 std::string peerName,
                                 bool audio,
                                 bool video,
                                 bool remoteAudio,
                                 bool remoteVideo) = 0;
  virtual void onStreamRunning(std::string username,
                                std::string peerName) = 0;
  virtual void onCallLog(std::string callId,
                         int direction,
                         int status,
                         std::string loacl,
                         std::string localDisplayName,
                         std::string remote,
                         std::string remoteDisplayName,
                         int time,
                         int duration,
                         int callType) = 0;
  virtual void onKeepAlive(int elapsed) = 0;
  virtual void onUpdating(std::string userName,
                           std::string peerName,
                           bool audio, 
                           bool video) = 0;
  virtual void onUpdateByRemote(std::string userName,
                                std::string peerName,
                                bool audio,
                                bool video) = 0;

#ifdef TEST_PERF
  void onAcctRegistedForTest(int index);
  void onAcctOccupiedForTest(int index);
#endif
};

struct VideoFrame {
  int type;
  int width;
  int height;
  int yStride;
  int uStride;
  int vStride;
  const char* yBuffer;
  const char* uBuffer;
  const char* vBuffer;

  long long captureTimeMs;
  long long renderTimeMs;
  int rotation;
};

class VideoRenderer {
 public:
  VideoRenderer(){};
  virtual ~VideoRenderer(){};
  virtual void onFrame(const VideoFrame* frame) = 0;
};

class RTCEngine {
 public:
  virtual int callPeer(const char* peerName,
                       const char* nickName,
                       bool audio,
                       bool video) = 0;
  virtual int listPeers() = 0;
  virtual int hangup() = 0;
  virtual int accept(bool audio, bool video) = 0;
  virtual int reject(const char* peerName) = 0;
  virtual int connectToServer(const char* url,
                              const char* username,
                              const char* nickname) = 0;
  virtual int setRingingMs(int ms) = 0;
  virtual int setLocalRenderer(VideoRenderer* renderer) = 0;
  virtual int setRemoteRenderer(VideoRenderer* renderer) = 0;
  virtual int updateCall(bool audio, bool video) = 0;
#ifdef WEBRTC_ANDROID
  virtual int addVideoTrackSource(
      webrtc::JavaVideoTrackSourceInterface* trackSource) = 0;
#endif
  // virtual int initialize() = 0;
  // virtual void deInitialize() = 0;

#ifdef TEST_PERF
  virtual void testWebSocketInstanceStart(const char* url, int num) = 0;
  virtual void testWebSocketInstanceStop() = 0;
#endif
};

rtc与sip相比优缺点

优点:

  • 利用现有WebRTC强大的音频处理技术以及在传输层的细节优化,能够提供更优质的通话服务,尤其在端口占用、音频音质等方面都有很大的优势。
  • WebRTC对SVC的分层编码支持也在一些特殊的场景还是有其独特的作用。
  • 如果产品中有要用Chrome/FireFox, RTC肯定是最优的选择方案。

缺点:
RTC方案和SIP相比,RTC一般都是私有的,SIP作为业界的通话标准,如果要走标准,SIP一定是最优的选择。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值