如何在 Sinch 中禁用视频

How to disable video in Sinch

我正在使用 Sinch 实现视频聊天,但我找不到在通话开始后禁用传出视频的方法。

这在某处记录了吗?

如果 SDK 不支持它,是否有办法(即使是 hackish 的)"intercept" 视频流并阻止它被发送。

显然在 SDK 中没有官方方法可以做到这一点,但这里有一个可以按预期工作的 hack。

长话短说,通过一些运行时间 "magic" 我们可以拦截 Sinch 发起的 AVCaptureSessoin 并控制它。

方法如下:

extension AVCaptureSession {
  public override class func initialize() {
    struct Static {
      static var token: dispatch_once_t = 0
    }

    // make sure this isn't a subclass
    if self !== AVCaptureSession.self {
      return
    }

    dispatch_once(&Static.token) {
      let originalSelector = #selector(AVCaptureSession.init)
      let swizzledSelector = #selector(AVCaptureSession.hd_init)

      let originalMethod = class_getInstanceMethod(self, originalSelector)
      let swizzledMethod = class_getInstanceMethod(self, swizzledSelector)

      let didAddMethod = class_addMethod(self, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod))

      if didAddMethod {
        class_replaceMethod(self, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod))
      } else {
        method_exchangeImplementations(originalMethod, swizzledMethod);
      }
    }
  }

  @nonobjc static var hd_currentSession: AVCaptureSession? = nil

  func hd_init() {
    hd_init() // at runtime this is the original `init` implementation
    AVCaptureSession.hd_currentSession = self
  }

}

简要说明:第一部分只是两种方法的基本运行时调配,与此实现无关。

也就是说,我们正在用我们自己的 AVCaptureSession.hd_init 替换 AVCaptureSession.init 的实现(hd 只是避免方法名称潜在冲突的任何前缀)。

NOTE

In hd_init we're calling hd_init. This is a bit mind-bending, but it's how swizzling works: at the time we execute that piece of code hd_init has been replaced by the original init, so we're actually calling the original implementation, which is what we want.

我们对 init 的自定义实现只是为了存储对实例的静态引用,我们将其称为 hd_currentSession

大功告成!

现在我们可以从应用程序的任何位置获取对当前 AVCaptureSession 的引用并随意停止/启动它。

例如

func toggleVideo() {
  if let session = AVCapture.hd_currentSession {
    if session.running {
      session.stopRunning()
    } else {
      session.startRunning()
    }
  }  
}

在 Sinch 视频流开始后的任何时候,我们都可以简单地调用 toggleVideo()

CAVEAT

Stopping the capture session will cause the video to "freeze" to the last frame. I haven't worked around this issue on iOS side, but I've noticed that on the Javascript API you get a "muted" event on the video MediaTrack. Given this, you can - for example - hide the video on the other client's side using the onmuted event.