- objective-c - iOS 5 : Can you override UIAppearance customisations in specific classes?
- iphone - 如何将 CGFontRef 转换为 UIFont?
- ios - 以编程方式关闭标记的信息窗口 google maps iOS
- ios - Xcode 5 - 尝试验证存档时出现 "No application records were found"
我正在尝试实现 mod_verto在 IOS 上(从 iPhone 调用到桌面)。我正在使用 Google's libjingle library对于 RTC 端,使用 this excellent tutorial 启动并运行它.
如果我使用 2 个浏览器窗口(使用 Verto Communicator)进行调用,一切正常。
完全披露,我正在使用 ws://
不安全的 websocket 连接FreeSwitch
这是我的 JSONRPC 日志:
发送登录请求:
{"jsonrpc":"2.0","method":"login","id":1,"params":{"login":"1000@MY-IP-ADDRESS","loginParams":{},"userVariables":{},"passwd":"1234","sessid":"53FB0781-B586-4CDA-98C6-558680663B46"}}
登录响应:
{"jsonrpc":"2.0","id":1,"result":{"message":"logged in","sessid":"53FB0781-B586-4CDA-98C6-558680663B46"}}
verto.invite(包括iPhone sdp):
{"jsonrpc":"2.0","method":"verto.invite","id":2,"params":{"dialogParams":{"remote_caller_id_number":"1008","useVideo":false,"useMic":"any","useStereo":false,"tag":"webcam","login":"1000@159.203.164.7","useCamera":"any","videoParams":{"minFrameRate":30,"minWidth":"1280","minHeight":"720"},"destination_number":"1008","screenShare":false,"caller_id_name":"FreeSWITCH User","caller_id_number":"1000","callID":"0CD433FC-A909-4DF2-BC46-0A4A94E9B800","remote_caller_id_name":"Outbound Call","useSpeak":"any"},"sessid":"53FB0781-B586-4CDA-98C6-558680663B46","sdp":"v=0\r\no=- 8564086442942257834 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=group:BUNDLE audio video\r\na=msid-semantic: WMS\r\nm=audio 58157 UDP\/TLS\/RTP\/SAVPF 111 103 104 9 102 0 8 106 105 13 127 126\r\nc=IN IP4 82.166.93.197\r\na=rtcp:52576 IN IP4 82.166.93.197\r\na=candidate:3168280865 1 udp 2122260223 11.0.0.244 58157 typ host generation 0\r\na=candidate:1260196625 1 udp 2122194687 10.134.172.254 58951 typ host generation 0\r\na=candidate:3168280865 2 udp 2122260222 11.0.0.244 52576 typ host generation 0\r\na=candidate:1260196625 2 udp 2122194686 10.134.172.254 58945 typ host generation 0\r\na=candidate:4066106833 1 tcp 1518280447 11.0.0.244 60562 typ host tcptype passive generation 0\r\na=candidate:94302177 1 tcp 1518214911 10.134.172.254 60563 typ host tcptype passive generation 0\r\na=candidate:4066106833 2 tcp 1518280446 11.0.0.244 60564 typ host tcptype passive generation 0\r\na=candidate:94302177 2 tcp 1518214910 10.134.172.254 60565 typ host tcptype passive generation 0\r\na=candidate:1610196941 1 udp 1686052607 82.166.93.197 58157 typ srflx raddr 11.0.0.244 rport 58157 generation 0\r\na=candidate:1610196941 2 udp 1686052606 82.166.93.197 52576 typ srflx raddr 11.0.0.244 rport 52576 generation 0\r\na=candidate:2274372738 2 udp 1685987070 176.13.15.205 5834 typ srflx raddr 10.134.172.254 rport 58945 generation 0\r\na=candidate:2274372738 1 udp 1685987071 176.13.15.205 5840 typ srflx raddr 10.134.172.254 rport 58951 generation 0\r\na=ice-ufrag:g8lHDtPwH7m5xRex\r\na=ice-pwd:Q6jcBJNTWAyu0JTuIaQAeNI3\r\na=fingerprint:sha-256 0F:A1:68:51:87:3E:B4:C1:0D:33:97:40:78:22:2A:8C:D2:B6:46:23:F5:99:C9:88:5D:34:DB:E2:C5:94:B3:DD\r\na=setup:actpass\r\na=mid:audio\r\na=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\na=extmap:3 http:\/\/www.webrtc.org\/experiments\/rtp-hdrext\/abs-send-time\r\na=recvonly\r\na=rtcp-mux\r\na=rtpmap:111 opus\/48000\/2\r\na=fmtp:111 minptime=10; useinbandfec=1\r\na=rtpmap:103 ISAC\/16000\r\na=rtpmap:104 ISAC\/32000\r\na=rtpmap:9 G722\/8000\r\na=rtpmap:102 ILBC\/8000\r\na=rtpmap:0 PCMU\/8000\r\na=rtpmap:8 PCMA\/8000\r\na=rtpmap:106 CN\/32000\r\na=rtpmap:105 CN\/16000\r\na=rtpmap:13 CN\/8000\r\na=rtpmap:127 red\/8000\r\na=rtpmap:126 telephone-event\/8000\r\na=maxptime:60\r\nm=video 61966 UDP\/TLS\/RTP\/SAVPF 100 101 116 117 96\r\nc=IN IP4 82.166.93.197\r\na=rtcp:63816 IN IP4 82.166.93.197\r\na=candidate:3168280865 1 udp 2122260223 11.0.0.244 61966 typ host generation 0\r\na=candidate:1260196625 1 udp 2122194687 10.134.172.254 50435 typ host generation 0\r\na=candidate:3168280865 2 udp 2122260222 11.0.0.244 63816 typ host generation 0\r\na=candidate:1260196625 2 udp 2122194686 10.134.172.254 63396 typ host generation 0\r\na=candidate:4066106833 1 tcp 1518280447 11.0.0.244 60566 typ host tcptype passive generation 0\r\na=candidate:94302177 1 tcp 1518214911 10.134.172.254 60567 typ host tcptype passive generation 0\r\na=candidate:4066106833 2 tcp 1518280446 11.0.0.244 60568 typ host tcptype passive generation 0\r\na=candidate:94302177 2 tcp 1518214910 10.134.172.254 60569 typ host tcptype passive generation 0\r\na=candidate:1610196941 1 udp 1686052607 82.166.93.197 61966 typ srflx raddr 11.0.0.244 rport 61966 generation 0\r\na=candidate:1610196941 2 udp 1686052606 82.166.93.197 63816 typ srflx raddr 11.0.0.244 rport 63816 generation 0\r\na=candidate:2274372738 1 udp 1685987071 176.13.15.205 5879 typ srflx raddr 10.134.172.254 rport 50435 generation 0\r\na=candidate:2274372738 2 udp 1685987070 176.13.15.205 5860 typ srflx raddr 10.134.172.254 rport 63396 generation 0\r\na=ice-ufrag:g8lHDtPwH7m5xRex\r\na=ice-pwd:Q6jcBJNTWAyu0JTuIaQAeNI3\r\na=fingerprint:sha-256 0F:A1:68:51:87:3E:B4:C1:0D:33:97:40:78:22:2A:8C:D2:B6:46:23:F5:99:C9:88:5D:34:DB:E2:C5:94:B3:DD\r\na=setup:actpass\r\na=mid:video\r\na=extmap:2 urn:ietf:params:rtp-hdrext:toffset\r\na=extmap:3 http:\/\/www.webrtc.org\/experiments\/rtp-hdrext\/abs-send-time\r\na=extmap:4 urn:3gpp:video-orientation\r\na=recvonly\r\na=rtcp-mux\r\na=rtpmap:100 VP8\/90000\r\na=rtcp-fb:100 ccm fir\r\na=rtcp-fb:100 nack\r\na=rtcp-fb:100 nack pli\r\na=rtcp-fb:100 goog-remb\r\na=rtcp-fb:100 transport-cc\r\na=rtpmap:101 VP9\/90000\r\na=rtcp-fb:101 ccm fir\r\na=rtcp-fb:101 nack\r\na=rtcp-fb:101 nack pli\r\na=rtcp-fb:101 goog-remb\r\na=rtcp-fb:101 transport-cc\r\na=rtpmap:116 red\/90000\r\na=rtpmap:117 ulpfec\/90000\r\na=rtpmap:96 rtx\/90000\r\na=fmtp:96 apt=100\r\n"}}
调用创建响应:
{"jsonrpc":"2.0","id":2,"result":{"message":"CALL CREATED","callID":"0CD433FC-A909-4DF2-BC46-0A4A94E9B800","sessid":"53FB0781-B586-4CDA-98C6-558680663B46"}}
verto.media 调用:
{"jsonrpc":"2.0","method":"verto.media","id":637,"params":{"sdp":"v=0\no=FreeSWITCH 1457232832 1457232833 IN IP4 159.203.164.7\ns=FreeSWITCH\nc=IN IP4 159.203.164.7\nt=0 0\na=msid-semantic: WMS TcxpBqoS0j04fOIzkIArKYrlV7LCs9Ub\nm=audio 30784 UDP/TLS/RTP/SAVPF 111 126\na=rtpmap:111 opus/48000/2\na=fmtp:111 useinbandfec=1; minptime=10\na=rtpmap:126 telephone-event/8000\na=silenceSupp:off - - - -\na=ptime:20\na=sendonly\na=fingerprint:sha-256 FE:CD:54:3E:2A:D7:DB:00:57:B7:D4:55:A8:EB:79:08:16:BB:B0:EA:43:44:42:9A:90:01:49:37:7B:31:48:F8\na=setup:active\na=rtcp-mux\na=rtcp:30784 IN IP4 159.203.164.7\na=ice-ufrag:qLh1zzclxONPNyQO\na=ice-pwd:G7g4Drkist37beYsP5jfvlqS\na=candidate:9922185636 1 udp 659136 159.203.164.7 30784 typ host generation 0\na=ssrc:1323504502 cname:bhqCyFkpPbjUPSk0\na=ssrc:1323504502 msid:TcxpBqoS0j04fOIzkIArKYrlV7LCs9Ub a0\na=ssrc:1323504502 mslabel:TcxpBqoS0j04fOIzkIArKYrlV7LCs9Ub\na=ssrc:1323504502 label:TcxpBqoS0j04fOIzkIArKYrlV7LCs9Uba0\nm=video 31380 UDP/TLS/RTP/SAVPF 100\na=rtpmap:100 VP8/90000\na=sendonly\na=fingerprint:sha-256 FE:CD:54:3E:2A:D7:DB:00:57:B7:D4:55:A8:EB:79:08:16:BB:B0:EA:43:44:42:9A:90:01:49:37:7B:31:48:F8\na=setup:active\na=rtcp-mux\na=rtcp:31380 IN IP4 159.203.164.7\nb=AS:1024\na=rtcp-fb:100 ccm fir\na=rtcp-fb:100 nack\na=rtcp-fb:100 nack pli\na=ssrc:594893571 cname:bhqCyFkpPbjUPSk0\na=ssrc:594893571 msid:TcxpBqoS0j04fOIzkIArKYrlV7LCs9Ub v0\na=ssrc:594893571 mslabel:TcxpBqoS0j04fOIzkIArKYrlV7LCs9Ub\na=ssrc:594893571 label:TcxpBqoS0j04fOIzkIArKYrlV7LCs9Ubv0\na=ice-ufrag:2KDK4wDMYuAuVdAZ\na=ice-pwd:YTpxObqpLuBEfig7TKHN6bqU\na=candidate:7508673635 1 udp 659136 159.203.164.7 31380 typ host generation 0\n","callID":"0CD433FC-A909-4DF2-BC46-0A4A94E9B800"}}
verto.answer 被调用:
{"jsonrpc":"2.0","method":"verto.answer","id":638,"params":{"callID":"0CD433FC-A909-4DF2-BC46-0A4A94E9B800"}}
问:我缺少什么才能在浏览器端听到音频?
任何信息表示赞赏:)
更新,添加了freeswitch log
更新 2 IOS:音频流代码
...
let audioTrack = self.factory.audioTrackWithID("Local-Audio")
self.localMediaStream?.addAudioTrack(audioTrack);
self.peerConnection!.addStream(self.localMediaStream)
...
更新 3 - 部分解决方案在检查我的代码时,我发现了用于将视频轨道添加到我的本地媒体流的旧代码,禁用此部分可以解决音频问题,但是为什么?该代码有什么问题?
P.S Promise 类是 friend 创建的,模仿了 JS Promise 方法。
func getUserMedia(mediaOptions:Dictionary<String , Any>? = nil) -> Promise<RTCMediaStream>{
return Promise<RTCMediaStream>(executor: { (resolve, reject) -> () in
var cameraID:String?
self.localMediaStream = self.factory.mediaStreamWithLabel("Local-Meida")
//if video option is enabled (default true)
//-------------- Disabling this section solves the audio issues --------------
if(mediaOptions?["video"] as? Bool ?? true){
for captureDevice in AVCaptureDevice.devicesWithMediaType(AVMediaTypeVideo){
if (captureDevice.position == mediaOptions?["devicePosition"] as? AVCaptureDevicePosition ?? AVCaptureDevicePosition.Front){
cameraID = captureDevice.localizedName
break
}
}
if(cameraID == nil){
reject(NSError(domain: "No cammera detected", code: 0, userInfo: nil))
}
let capturer = RTCVideoCapturer.init(deviceName: cameraID)
let videoSource = self.factory.videoSourceWithCapturer(capturer, constraints: mediaOptions?["constraints"] as? RTCMediaConstraints ?? nil)
if let localVideoTrack = self.factory.videoTrackWithID("Local-Video", source: videoSource){
//!!!! THIS IS THE PROBLEMATIC LINE !!!!
self.localMediaStream?.addVideoTrack(localVideoTrack)
}else{
reject(NSError(domain: "No Video track", code: 0, userInfo: nil))
}
}
//-------------- Disabling this section solves the audio issues --------------
if(mediaOptions?["audio"] as? Bool ?? true){
let audioTrack = self.factory.audioTrackWithID("Local-Audio")
self.localMediaStream?.addAudioTrack(audioTrack);
}
self.peerConnection!.addStream(self.localMediaStream)
resolve(self.localMediaStream!)
})
}
最佳答案
除非检查媒体服务器、Web 客户端 和iOS 客户端,否则很难理解 WebRTC 实现出了什么问题在我们的案例中。
您的情况是音频通话,因此您的localStream 中不需要包含任何视频流,但如果您仔细观察,您会发现< em>你实际上是在你的移动流上添加一个 videoTrack:
if(mediaOptions?["video"] as? Bool ?? true){
for captureDevice in AVCaptureDevice.devicesWithMediaType(AVMediaTypeVideo){
if (captureDevice.position == mediaOptions?["devicePosition"] as? AVCaptureDevicePosition ?? AVCaptureDevicePosition.Front){
cameraID = captureDevice.localizedName
break
}
}
if(cameraID == nil){
reject(NSError(domain: "No cammera detected", code: 0, userInfo: nil))
}
let capturer = RTCVideoCapturer.init(deviceName: cameraID)
let videoSource = self.factory.videoSourceWithCapturer(capturer, constraints: mediaOptions?["constraints"] as? RTCMediaConstraints ?? nil)
if let localVideoTrack = self.factory.videoTrackWithID("Local-Video", source: videoSource){
//!!!! THIS IS THE PROBLEMATIC LINE !!!!
self.localMediaStream?.addVideoTrack(localVideoTrack)
}else{
reject(NSError(domain: "No Video track", code: 0, userInfo: nil))
}
}
因此导致问题的行是:self.localMediaStream?.addVideoTrack(localVideoTrack)
,因为您将视频附加到 localStream。
我们可能会遇到不同的场景,正如我所说的,这里我根据我在构建类似系统时的经验列出一些意见:
MediaServer
可能没有可以在成功状态下重定向和处理您的调用的实现,因为当您附加视频时会添加其他内容(请查看您的 session 描述您实际发送的内容那里),它只是拒绝创建调用。MediaServer
可以处理这种情况,这也将包括 Client
的正确实现(Desktop 和 Mobile) 以符合其协议(protocol)的信号。去掉localStream里面添加localTrack的部分,这样即使有错误也不是你创建localStream引起的,所以这一步目前已经解决了。
我这里有一个我的工作版本,但由于您只使用音频,因此可以根据您的需要进行调整。
// Connecting to the socket
.........
// Create PeerConnectionFactory
self.peerConnectionFactory = [[RTCPeerConnectionFactory alloc] init];
RTCMediaConstraints *constraints = [self defaultPeerConnectionConstraints];
// Initialize peerConnection based on a list of ICE Servers
self.peerConnection = [self.peerConnectionFactory peerConnectionWithICEServers:[self getICEServers] constraints:constraints delegate:self];
// Create the localStram which contains the audioTrack
RTCMediaStream *localStream = [self createLocalMediaStream];
// Add this stream to the peerConnection
[self.peerConnection addStream:localStream];
// Please be aware here that I am using blocks, as I created a wrapper for easier maintenance, but you can use createOfferWithDelegate: which will go back at your delegation
NSLog(@"Creating peer offer");
RTCManager *strongSelf = self;
[strongSelf.peerConnection createOfferWithCallback:^(RTCSessionDescription *sdp, NSError *error) {
if (!error) {
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"Success at creating offer, now setting local description");
[strongSelf.peerConnection setLocalDescriptionWithCallback:^(NSError *error) {
if (!error) {
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"Success at setting local description");
// On my type of signalization here I am connected, but yours is based on what type of signalization requires
});
}
} sessionDescription:sdp];
});
}
} constraints:[strongSelf defaultPeerConnectionConstraints]];
// Now here we create the stream which contains the audio (Please note the ID)
- (RTCMediaStream *)createLocalMediaStream {
RTCMediaStream *localStream = [self.peerConnectionFactory mediaStreamWithLabel:@"ARDAMS"];
[localStream addAudioTrack:[self.peerConnectionFactory audioTrackWithID:@"ARDAMSa0"]];
return localStream;
}
- (RTCMediaConstraints *)defaultPeerConnectionConstraints {
// DtlsSrtpKeyAgreement is required for Chrome and Firefox to interoperate.
NSArray *optionalConstraints = @[[[RTCPair alloc] initWithKey:@"DtlsSrtpKeyAgreement" value:@"true"]];
RTCMediaConstraints *constraints = [[RTCMediaConstraints alloc] initWithMandatoryConstraints:nil optionalConstraints:optionalConstraints];
return constraints;
}
请注意,您的问题也可能是由于未在主线程 上调用内容引起的。
关于ios - WebRTC + IOS + Freeswitch : Can't hear audio,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35826464/
是WebRTC Web 开发人员可以免费在网页上设置视频通话吗?为什么 Twilio 的视频通话定价为每分钟 25 美分,在网络托管服务器上管理视频通话对小家伙来说会不会太贵了? 任何深入 WebRT
webRTC 是根据 https://apprtc.appspot.com/ 实现的 PeerConnection webRTC 如何实现远程音视频流的同步? 最佳答案 使用 RTCP SR/RR 报
我正在尝试使用 webRTC,似乎对每条消息中可以发送的字节数有任意限制。 This guy我使用的示例选择了 100(加上一些)字节的限制。在我的测试中,它似乎接近 200 字节。但是从阅读 TCP
我目前正在测试 WebRTC 的功能,但我有一些脑逻辑问题。 WebRTC 究竟是什么? 我只读了“STUN”、“P2P”和其他...但是在技术方面什么是正确的 WebRTC(见下一个) 我需要什么
我目前正在使用 opentok 构建实时视频聊天医疗保健应用程序api,其技术主要建立在 WebRTC 上,并想知道如何处理整体安全方面。 最佳答案 简而言之,是的。所有 WebRTC 媒体流都经过加
WebRTC Reference App --> var errorMessages = []; var channelToken = 'AHRlWroGHj6YqW
我对浏览器中的点对点连接感兴趣。由于这对于 WebRTC 来说似乎是可能的,我想知道它是如何精确工作的。 我已经阅读了一些解释并看到了相关图表,现在我很清楚,连接建立是通过服务器进行的。服务器似乎在愿
我是 WebRTC 的初学者,我想知道是否需要导入任何内容才能使用 JavaScript API。 最佳答案 不,您不需要导入任何库。 webRTC 包含在 Chrome 和 Firefox 中(以及
我正在使用 WebRTC 来开发我的应用程序之一。 WebRTC 是否原生支持视频数据包的自适应比特率流,目前尚不清楚? VP8/VP9 是否支持自适应比特率编码? bitrate_controlle
是否可以通过 webRTC 捕获桌面屏幕共享。我们知道它只是捕获浏览器选项卡上的屏幕,但是否可以捕获整个桌面屏幕,例如浏览计算机上的文件或打开和查看文件,例如pdf等.. 最佳答案 目前,RTCWeb
我可以有两个单独的服务器用于托管和发送信号吗?还是仅在托管服务器中配置信令服务器更好? 最佳答案 托管 webrtc 信令服务器没有具体限制。如果需要,您可以将信令服务器与 Web 应用程序服务器分开
我想知道 WebRTC api 是否会自动更改带宽以增加体验。据我所知,WebRTC 具有更改和限制最大值的功能。带宽如我们所愿。我寻求答案的问题是我们应该手动执行此操作还是 WebRTC 无论如何都
如果在本地网络中的两个对等方之间建立了 WebRTC 连接,我们可以在失去与互联网的连接后维持它吗?这似乎是可能的,因为它是点对点的。 最佳答案 是的,有可能。对等方使用同一网络中的专用 IP 地址直
我正在尝试创建一个应用程序,该应用程序要求用户使用 webRTC 将其本地视频流发送到多个对等方。据我所知,我负责管理多个 PeerConnection 对象,因为 PeerConnection 一次
我想创建自己的视频聊天应用程序。我使用 WebRTC 框架。我阅读了一些教程,每个主题都假定存在信令 channel 。如何实现自己的信令 channel ? 最佳答案 由于目前没有为 WebRTC
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 想改进这个问题?将问题更新为 on-topic对于堆栈溢出。 6年前关闭。 Improve this qu
假设我有 2 个同行与 webRTC 交换视频。现在我需要将两个流都保存为中央服务器中的视频文件。是否可以实时进行? (存储/上传来自同行的视频不是一种选择)。 我想建立一个 3 节点 webRTC
WebRTC 信号让我发疯。我的用例非常简单:信息亭和控制室 webapp 之间的双向音频对讲。两台计算机都在同一个网络上。两者都没有互联网访问权限,所有机器都有已知的静态 IP。 我阅读的所有内容都
我知道我可以将宽度和高度设置为本地视频的约束。但是,我不确定如何通过 RTCPeerConnection 获取远程视频的宽度和高度。我用谷歌搜索了很多,但似乎没有得到任何有用的信息。我认为这应该是一个
我是 WebRTC 的新手,并试图弄清楚如何在浏览器之外创建一个程序,该程序接收 WebRTC 音频流并将其输出到扬声器上。 是否有适用于 Java 或 C# 的 WebRTC 库? 该接收器将在 l
我是一名优秀的程序员,十分优秀!