【发布时间】:2016-06-09 16:10:56
【问题描述】:
【问题讨论】:
【问题讨论】:
显然,SDK 中没有官方的方法可以做到这一点,但这里有一个可以按预期工作的 hack。
长话短说,通过一些运行时“魔法”,我们可以拦截 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.init 的实现替换为我们自己的 AVCaptureSession.hd_init(hd 只是任何前缀,以避免潜在的方法名称冲突)。
注意
在
hd_init中,我们调用hd_init。这有点令人费解,但这就是 swizzling 的工作方式:在我们执行那段代码时hd_init已被原始init替换,所以我们实际上调用的是原始实现,这就是我们想要。
我们对init 的自定义实现仅用于存储对实例的静态引用,我们将其称为hd_currentSession。
我们完成了!
现在,我们可以从应用程序的任何位置获取对当前 AVCaptureSession 的引用并随意停止/启动它。
例如
func toggleVideo() {
if let session = AVCapture.hd_currentSession {
if session.running {
session.stopRunning()
} else {
session.startRunning()
}
}
}
在Sinch视频流开始后的任何时候,我们都可以简单地拨打toggleVideo()
警告
停止捕获会话会导致视频“冻结”到最后一帧。我还没有在 iOS 端解决这个问题,但我注意到在 Javascript API 上你会在视频
MediaTrack上获得一个"muted"事件。鉴于此,您可以 - 例如 - 使用onmuted事件在另一客户端隐藏视频。
【讨论】: