【owt】WebrtcNode, publish-sdp offer 流程(3)

流程图

在这里插入图片描述

  1. 因为erizon::VideoFrameConstructor(继承于VideoFrameSource)作为视频源,从mediaStream把数据接收过来,VideoFrameSource中,然后分别存到owt_base.InternalServer的m_sourceMap(以publicTrackId = transportId + ‘-’ + track.id 为key,addon.VideoFrameSource 为value)(这里什么时候使用???)中和Connections中(这里是子在视频订阅的时候用,linkup的时候使用)
VideoFrameSource存放在connections中
/*{ConnectionID: {type: 'webrtc' | 'avstream' | 'recording' | 'internal',
direction: 'in' | 'out',
audioFrom: ConnectionID | undefined,
videoFrom: ConnectionID | undefined,
connnection: WebRtcConnection | InternalOut | RTSPConnectionOut
}
}
*/
connection 存放的就是VideoFrameSource
  1. mediaUpdate, 通过RpcClient.remoteCast, 消息广播给controller, ConferenceAgent

  2. trackUpdate, 通过RpcClient.remoteCast, 消息广播给controller,ConferenceAgent

1. track-added

dist/webrtc_agent/webrtc/wrtcConnection.js

const setupTransport = function (mid) {
    ...

    if (rids) {
        ...
    } else {
        // 走这里的代码
      // No simulcast
      if (!trackMap.has(mid)) {
        // 1. Connection wrtc
        trackMap.set(mid, new WrtcStream(mid, wrtc, direction, trackSettings));
        ...
        // 3. Notify new track
        on_track({
          type: 'track-added',
          track: trackMap.get(mid),
          operationId: opSettings.operationId,
          mid: mid
        });
      } else {
        log.warn(`Conflict trackId ${mid} for ${wrtcId}`);
      }
    }

    return opSettings.operationId;
  };

trackMap 属性——存放了WrtcStream

  // composedId => WrtcStream
  var trackMap = new Map();

composeId

  const composeId = function (mid, rid) {
    return mid + ':' + rid;
  };

1.1 on_track

dist/webrtc_agent/webrtc/wrtcConnection.js

module.exports = function (spec, on_status, on_track) {
...
}

1.2 on_track= function onTrack(trackInfo)

dist/webrtc_agent/webrtc/index.js

var connection = new WrtcConnection({
            connectionId: transportId,
            threadPool: threadPool,
            ioThreadPool: ioThreadPool,
            network_interfaces: global.config.webrtc.network_interfaces,
            owner,
        }, function onTransportStatus(status) {
            notifyTransportStatus(controller, transportId, status);
        }, function onTrack(trackInfo) {
            handleTrackInfo(transportId, trackInfo, controller);
        });

2. ======WebrtcNode.handleTrackInfo

dist/webrtc_agent/webrtc/index.js

// trackInfo 就是on__track 回调回来
var handleTrackInfo = function (transportId, trackInfo, controller) {
        var publicTrackId;
        var updateInfo;
        if (trackInfo.type === 'track-added') {
            // Generate public track ID
            const track = trackInfo.track; // track是WrtcStream
            // track.id 就是mid
            publicTrackId = transportId + '-' + track.id;
            if (mediaTracks.has(publicTrackId)) {
                log.error('Conflict public track id:', publicTrackId, transportId, track.id);
                return;
            }
            mediaTracks.set(publicTrackId, track);
            mappingPublicId.get(transportId).set(track.id, publicTrackId);
            if (track.direction === 'in') {
                // 1. source, 返回的是addon.Source
                // WrtcStream.sender()
                // WrtcStream 就是在小结4中创建
                const trackSource = track.sender();
                // 2. add source
                 // InternalConnectionRouter router
                router.addLocalSource(publicTrackId, 'webrtc', trackSource)
                .catch(e => log.warn('Unexpected error during track add:', e));
            } else {
                router.addLocalDestination(publicTrackId, 'webrtc', track)
                .catch(e => log.warn('Unexpected error during track add:', e));
            }

            // 3. Bind media-update handler
            track.on('media-update', (jsonUpdate) => {
                log.debug('notifyMediaUpdate:', publicTrackId, jsonUpdate);
                notifyMediaUpdate(controller, publicTrackId, track.direction, JSON.parse(jsonUpdate));
            });
            // 4. Notify controller
            const mediaType = track.format('audio') ? 'audio' : 'video';
            updateInfo = {
                type: 'track-added',
                trackId: publicTrackId,
                mediaType: track.format('audio') ? 'audio' : 'video',
                mediaFormat: track.format(mediaType),
                direction: track.direction,
                operationId: trackInfo.operationId,
                mid: trackInfo.mid,
                rid: trackInfo.rid,
                active: true,
            };
            log.debug('notifyTrackUpdate', controller, publicTrackId, updateInfo);
            notifyTrackUpdate(controller, transportId, updateInfo);

        } else if (trackInfo.type === 'track-removed') {
            ...
        } else if (trackInfo.type === 'tracks-complete') {
            updateInfo = {
                type: 'tracks-complete',
                operationId: trackInfo.operationId
            };
            notifyTrackUpdate(controller, transportId, updateInfo);
        }
    };
track==WrtcStream
publicTrackId = transportId + ‘-’ + track.id;
track.id, (rids不空,composedId=mid:rids)
track.id, (rids为空,composedId=mid)
mediaTracks——{ publicTrackId => WrtcTrack }
 // Map { publicTrackId => WrtcTrack }
 var mediaTracks = new Map();
 mediaTracks.set(publicTrackId, track);
mappingPublicId——{ transportId => Map { trackId => publicTrackId } }
// Map { transportId => Map { trackId => publicTrackId } }
var mappingPublicId = new Map();
mappingPublicId.get(transportId).set(track.id, publicTrackId);
??? var router = new InternalConnectionRouter(global.config.internal);

2.1 ==========WrtcStream.sender——获取source,VideoFrameSource

dist-debug/webrtc_agent/webrtc/wrtcConnection.js

sender(track) {
    let sender = null;
    if (track === 'audio' && this.audioFrameConstructor) {
...
    } else if (track === 'video' && this.videoFrameConstructor) {
...
    // track = null
    } else if (!track) {
    // 走这里的流程
      let parent = (this.audioFrameConstructor || this.videoFrameConstructor);
        // parent.source() 返回addon.VideoFrameSource, 调用native
        // addon.VideoFrameSource sender,子类FrameSource    
      sender = parent.source();
       //
      // 这里赋值了parent
      sender.parent = parent;
    } else {
      log.error('sender error');
    }
    if (sender) {   
      
       //  定义两个函数        
      sender.addDestination = (track, dest) => {
        // parent 就是VideoFrameConstructor
        sender.parent.addDestination(dest);
      };
      sender.removeDestination = (track, dest) => {
        sender.parent.removeDestination(dest);
      };
      ///
    }
    return sender;
  }
2.1.1 NAN_METHOD(VideoFrameConstructor::source)

source/agent/webrtc/rtcFrame/VideoFrameConstructorWrapper.cc

NAN_METHOD(VideoFrameConstructor::source) {
  const int argc = 1;
  v8::Local<v8::Value> argv[argc] = {info.Holder()};
  v8::Local<v8::Function> cons = Nan::New(VideoFrameSource::constructor);
  // 创建 VideoFrameSource对象
  info.GetReturnValue().Set(Nan::NewInstance(cons, 1, argv).ToLocalChecked());
}
2.1.2 =====NAN_METHOD(VideoFrameSource::New)

source/agent/webrtc/rtcFrame/VideoFrameConstructorWrapper.cc

NAN_METHOD(VideoFrameSource::New) {
  if (info.Length() == 1) {
    VideoFrameConstructor* parent = Nan::ObjectWrap::Unwrap<VideoFrameConstructor>(
      Nan::To<v8::Object>(info[0]).ToLocalChecked());
    VideoFrameSource* obj = new VideoFrameSource();
    // VideoFrameConstructor* parent 的 me 就是owt_base::VideoFrameConstructor
    // VideoFrameSource* obj  me 就是owt_base::VideoFrameConstructor
    obj->me = parent->me;
    // obj->src 就是owt_base::FrameSource        
    // owt_base::VideoFrameConstructor 继承了owt_base::FrameSource 
    obj->src = obj->me;
    obj->Wrap(info.This());
    info.GetReturnValue().Set(info.This());
  }
}
2.1.3 addon.VideoFrameSource

source/agent/webrtc/rtcFrame/VideoFrameConstructorWrapper.h

class VideoFrameSource : public FrameSource {
 public:
  static NAN_MODULE_INIT(Init);
  owt_base::VideoFrameConstructor* me;

 private:
  VideoFrameSource() {};
  ~VideoFrameSource() {};

  static NAN_METHOD(New);

  static Nan::Persistent<v8::Function> constructor;

  friend class VideoFrameConstructor;
};
2.1.4 addon.FrameSource

source/agent/addons/common/MediaFramePipelineWrapper.h

/*
 * Wrapper class of owt_base::FrameSource
 */
class FrameSource : public node::ObjectWrap{
public:

  owt_base::FrameSource* src;
};
2.1.5 owt_base::FrameSource
======sender.parent = parent;

sender 就是VideoFrameSource

parent 就是VideoFrameConstructor

2.2 InternalConnectionRouter.addLocalSource

dist-debug/webrtc_agent/webrtc/internalConnectionRouter.js

/*
   * @param {string} id ID for source connection (stream),publicTrackId
   * @param {string} type Type description for connection
   * @param {FrameSource} source Wrapper class for FrameSource
   */
    // id = publicTrackId = transportId + '-' + track.id;
    // type = 'webrtc', 
    // trackSource 就是2.1 创建的VideoFrameSource
  addLocalSource(id, type, source) {
    const isNativeSource = (type === 'quic' || type === 'mediabridge');
    // addon.InternalServer internalServer
    // 1. 
    this.internalServer.addSource(id, source, isNativeSource);
    // 2. Connections connnections 
    return this.connections.addConnection(id, type, '', source, 'in');
  }
2.2.1 internalServer 赋值const {InternalServer, InternalClient} = internalIO;

dist-debug/webrtc_agent/webrtc/internalConnectionRouter.js

source/agent/addons/internalIO/InternalServerWrapper.h

source/agent/addons/internalIO/InternalClientWrapper.h

2.2.2 NAN_METHOD(addSource)

source/agent/addons/internalIO/InternalServerWrapper.cc

NAN_METHOD(InternalServer::addSource) {
  InternalServer* obj = ObjectWrap::Unwrap<InternalServer>(info.Holder());
  owt_base::InternalServer* me = obj->me;

  Nan::Utf8String param0(Nan::To<v8::String>(info[0]).ToLocalChecked());
  // streamId = publicTrackId
  std::string streamId = std::string(*param0);

  bool isNanSource(false);
  if (info.Length() >= 3) {
      isNanSource = Nan::To<bool>(info[2]).FromJust();
  }

  owt_base::FrameSource* src(nullptr);
  if (isNanSource) {
      NanFrameNode* param = Nan::ObjectWrap::Unwrap<NanFrameNode>(
          Nan::To<v8::Object>(info[1]).ToLocalChecked());
      src = param->FrameSource();
  } else {
        // 走了这里流程,FrameSource 就是 2.1 创建的VideoFrameSource
      FrameSource* param = ObjectWrap::Unwrap<FrameSource>(
          Nan::To<v8::Object>(info[1]).ToLocalChecked());
      // 从FrameSource中获取owt_base::FrameSource  src
      src = param->src;
  }

  // owt_base::InternalServer::addSource
  me->addSource(streamId, src);
}
2.2.3 owt_base::InternalServer::addSource

source/core/owt_base/internal/InternalServer.cpp

// streamdId = publicTrackId
// source owt_base::FrameSource, 就是owt_base::VideoFrameConstructor
bool InternalServer::addSource(const std::string& streamId, FrameSource* src)
{
    ELOG_DEBUG("addSource %s, %p", streamId.c_str(), src);
    if (m_sourceMap.count(streamId)) {
        ELOG_WARN("Source for stream:%s already added", streamId.c_str());
        return false;
    }
    m_sourceMap[streamId] = src;
    return true;
}
owt.InternalServer - addSource 99649f7149c44673ad7c8338e1494c4f-0, 0x61c3d68
????? InternalServer::onSessionData

source/core/owt_base/internal/InternalServer.cpp

2.3.4 Connections.addConnection

dist-debug/webrtc_agent/webrtc/connections.js

// addConnection(id, type, '', source, 'in');

    // connectionId = id = publicTrackId
    // connectionType = type = 'webrtc'
    // connectionController = ''
    // conn = VideoFrameSource
    // direction = 'in'
that.addConnection =  function (connectionId, connectionType, connectionController, conn, direction) {
        log.debug('Add connection:', connectionId, connectionType, connectionController);
        if (connections[connectionId]) {
            log.error('Connection already exists:'+connectionId);
            return Promise.reject({type: 'failed', reason: 'Connection already exists:'+connectionId});
        }

        connections[connectionId] = {
            type: connectionType,
            direction: direction,
            audioFrom: undefined,
            videoFrom: undefined,
            connection: conn,
            controller: connectionController
        };

        return Promise.resolve('ok');
    };

这里存放在connections的数据包括VideoFrameSource,在linkupConnection 的时候调用

connections
/*{ConnectionID: {type: 'webrtc' | 'avstream' | 'recording' | 'internal',
                          direction: 'in' | 'out',
                          audioFrom: ConnectionID | undefined,
                          videoFrom: ConnectionID | undefined,
                          connnection: WebRtcConnection | InternalOut | RTSPConnectionOut
                         }
          }
        */
        connections = {};
log
2023-04-05T17:31:30.615  - DEBUG: Connections - Add connection: 99649f7149c44673ad7c8338e1494c4f-0 webrtc
log——conn
2023-04-26T21:23:41.396  - DEBUG: Connections - AudioFrameSource {
  parent: AudioFrameConstructor {},
  addDestination: [Function (anonymous)],
  removeDestination: [Function (anonymous)]
}

2023-04-26T21:23:41.399  - DEBUG: Connections - VideoFrameSource {
  parent: VideoFrameConstructor {},
  addDestination: [Function (anonymous)],
  removeDestination: [Function (anonymous)]
}

2.3 WebrtcNode.notifyMediaUpdate

从WrtcStream 注册回调到C++,然后C++回调到WrtcStream, 通过EventEmitter.emit 转发到WebrtcNode。

var notifyMediaUpdate = function (controller, publicTrackId, direction, mediaUpdate) {
        rpcClient.remoteCast(controller, 'onMediaUpdate', [publicTrackId, direction, mediaUpdate]);
       ...
    };
log
2023-04-26 21:54:07,908  - DEBUG: owt.VideoFrameConstructor - onVideoInfo {"video": {"parameters": {"resolution": {"width":0, "height":0}}}} 0x57708f0
2023-04-26T21:54:07.908  - INFO: WrtcConnection - _onMediaUpdate:{"video": {"parameters": {"resolution": {"width":0, "height":0}}}}
WrtcStream._onMediaUpdate

dist/webrtc_agent/webrtc/index.js

  _onMediaUpdate(jsonUpdate) {
    log.info('_onMediaUpdate:' + jsonUpdate);
    this.emit('media-update', jsonUpdate);
  }

dist/webrtc_agent/webrtc/wrtcConnection.js

WrtcStream
{
        this.videoFrameConstructor = new VideoFrameConstructor(
          this._onMediaUpdate.bind(this), video.transportcc, wrtc.callBase);
          ...
          }

source/agent/webrtc/rtcFrame/VideoFrameConstructorWrapper.cc

NAN_METHOD(VideoFrameConstructor::New) {
    .......
    // 第一个参数就是 this._onMediaUpdate.bind(this), 
     obj->Callback_ = new Nan::Callback(info[0].As<Function>());
 ...
 }
NAUV_WORK_CB(VideoFrameConstructor::Callback)

source/agent/webrtc/rtcFrame/VideoFrameConstructorWrapper.cc

NAUV_WORK_CB(VideoFrameConstructor::Callback) {
  Nan::HandleScope scope;
  VideoFrameConstructor* obj = reinterpret_cast<VideoFrameConstructor*>(async->data);
  if (!obj || obj->me == NULL)
    return;
  boost::mutex::scoped_lock lock(obj->mutex);
  // for循环,从queue中读取消息,调用Callback_,回调到js的_onMediaUpdate
  while (!obj->videoInfoMsgs.empty()) {
    Local<Value> args[] = {Nan::New(obj->videoInfoMsgs.front().c_str()).ToLocalChecked()};
    obj->asyncResource_->runInAsyncScope(Nan::GetCurrentContext()->Global(), obj->Callback_->GetFunction(), 1, args);
    obj->videoInfoMsgs.pop();
  }
}
VideoFrameConstructor::onVideoInfo

source/agent/webrtc/rtcFrame/VideoFrameConstructorWrapper.cc

void VideoFrameConstructor::onVideoInfo(const std::string& message) {
  boost::mutex::scoped_lock lock(mutex);
  // std::queue<std::string> videoInfoMsgs;
  // 把回调的消息放到queue中,
  this->videoInfoMsgs.push(message);
  async_.data = this;
  uv_async_send(&async_);
}

2.4 WebrtcNode.notifyTrackUpdate

dist/webrtc_agent/webrtc/index.js

 /* updateInfo = {
     *  event: ('track-added' | 'track-removed' | 'track-updated'),
     *  trackId, mediaType, mediaFormat, active }
     */
        // controller 就是WebrtcNode.publish的时候options传递的controller
    var notifyTrackUpdate = function (controller, transportId, updateInfo) {
          // 广播消息
        rpcClient.remoteCast(controller, 'onTrackUpdate', [transportId, updateInfo]);
           ...
    };
log
WebrtcNode - notifyTrackUpdate conference-9534c64ba3c0a7727a84@192.168.221.62_0 99649f7149c44673ad7c8338e1494c4f-0 {
  type: 'track-added',
  trackId: '99649f7149c44673ad7c8338e1494c4f-0',
  mediaType: 'audio',
  mediaFormat: { codec: 'opus', sampleRate: 48000, channelNum: 2 },
  direction: 'in',
  operationId: '99649f7149c44673ad7c8338e1494c4f',
  mid: '0',
  rid: undefined,
  active: true
WebrtcNode - notifyTrackUpdate conference-9534c64ba3c0a7727a84@192.168.221.62_0 99649f7149c44673ad7c8338e1494c4f-1 {
  type: 'track-added',
  trackId: '99649f7149c44673ad7c8338e1494c4f-1',
  mediaType: 'video',
  mediaFormat: { codec: 'av1' },
  direction: 'in',
  operationId: '99649f7149c44673ad7c8338e1494c4f',
  mid: '1',
  rid: undefined,
  active: true
}
RpcClient.remoteCast

dist/webrtc_agent/amqpClient.js

  remoteCast(to, method, args) {
    const channel = this.bus.channel;
    if (this.ready && channel) {
      const content = JSON.stringify({
        method,
        args,
      });
      try {
        channel.publish(RPC_EXC.name, to, Buffer.from(content));
      } catch (e) {
        log.warn('Failed to publish:', e);
      }
    } else {
      this.ready = false;
    }
  }
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值