Closed csturiale closed 5 years ago
Confirmed that by getting a local video track from a RTCPeerConnection
and calling enabled=false
or stop()` on it does nothing...
I've open a detailed issue in the WebRTC project. There is little I can do (unless there is a bug in my code):
Google WebRTC developers will ignore my bug report because I don't "reproduce it with AppRTCDemo". So if somebody can reproduce the issue in the f**king AppRTCDemo please report into the issue. I won't do it.
@ibc We think that we should set the source state to ended. In the libWebRTC code it is found here: https://chromium.googlesource.com/external/webrtc/+/refs/heads/master/webrtc/api/videotracksource.cc#24 Is it possible from the JS side to call this setState and set it to ended? This should clean up the tracks and streams and set it all to ended to our opinion.
What about if the same source feeds two tracks (for example once clone()
is implemented)? Calling stop()
on a track should NOT also close the cloned track.
Hmm.. Indeed if you clone()
a track and you just want to stop one track you would have an issue with this implementation.
Is there any way at all to end/clear the tracks/streams? I won't be using clone()
so that part isn't an issue for me. I noticed in PluginMediaStreamTrack.swift
that is says // NOTE: There is no setState() anymore
. Does this mean that there is no way to clear them? I also noticed that after a call, CPU usage is still rather high (~80%), I assume this is because the tracks are still there?
@MonsterKiller please read this full history. Obviously there is no a easy solution for this problem. Otherwise the issue would no longer exist.
@ibc Hey, I have read this issue and it was mentioned by @mark-veenstra that you may be able to set the source state to ended, but this would affect the use of clone(), I was enquiring as to if this could still be used for people who don't need to use clone() (who could modify the plugin locally) or whether this functionality does not work for ending the stream at all. Thanks.
Got a response with good rationale in the chromium tracker:
Can you summarize what the issue you're still seeing is?
setState()
isn't intended to be a public API, butsetEnabled(false)
should definitely cause muted (black) video to be sent. Is that not happening?Or is the issue that the source is still alive after calling
setEnabled(false)
? That seems expected since you could callsetEnabled(true)
later. If you remove all references to the track, the tracks (along with the source) should be destroyed. Is that not working, or is it not sufficient?
Ok, currently MediaStreamTrack.stop()
does the following (in Swift land):
func stop() {
NSLog("PluginMediaStreamTrack#stop() [kind:%@, id:%@]", String(self.kind), String(self.id))
self.rtcMediaStreamTrack.setEnabled(false)
}
self.rtcMediaStreamTrack
is the native Obj-C object.
I cannot check this for long time, so I hope someone can answer the following questions regarding what currently happens when calling track.stop()
with this plugin:
If the answer is yes, then the Swift stop()
method above should also set self.rtcMediaStreamTrack = nil
(or similar) and fire a close
event. Or may be all the Swift PluginMediaStream
instances holding this track should remove it from their map of tracks, so this track is garbage collected (and also the native Obj-C track object).
I hope I'm right and also hope that someone can work on it and send a PR if interested.
We just did some tests and what we see is that the PluginMediaStream
and PluginMediaStreamTrack
of the PluginGetUserMedia
are not released after closing all PeerConnections and closing all tracks etc.
When I do a dump()
when having a call between 2 devices, it displays:
2016-11-04 13:52:11.483585 MyCallApp[1369:1183872] iosrtcPlugin#dump()
2016-11-04 13:52:11.483718 MyCallApp[1369:1183872] - PluginRTCPeerConnection [id:26273]
2016-11-04 13:52:11.483786 MyCallApp[1369:1183872] - PluginRTCPeerConnection [id:28582]
2016-11-04 13:52:11.484176 MyCallApp[1369:1183872] - PluginMediaStream [97659D53-388F-4533-8F2D-3ED39CADC339:A=1:V=1]
2016-11-04 13:52:11.484388 MyCallApp[1369:1183872] - PluginMediaStream [default:A=1:V=1]
2016-11-04 13:52:11.484475 MyCallApp[1369:1183872] - PluginMediaStreamTrack [id:23B1E761-CA00-44D6-82DD-90A2E440B44E, kind:video]
2016-11-04 13:52:11.484610 MyCallApp[1369:1183872] - PluginMediaStreamTrack [id:F03A4D41-6812-406F-B213-3514FD9AC2B1, kind:audio]
2016-11-04 13:52:11.484688 MyCallApp[1369:1183872] - PluginMediaStreamTrack [id:dsKLOozW, kind:video]
2016-11-04 13:52:11.484802 MyCallApp[1369:1183872] - PluginMediaStreamTrack [id:vXyFpbIU, kind:audio]
2016-11-04 13:52:11.484922 MyCallApp[1369:1183872] - PluginMediaStreamRenderer [id:52925]
2016-11-04 13:52:11.485016 MyCallApp[1369:1183872] - PluginMediaStreamRenderer [id:88121]
After I hangup the call only the following tracks and streams are still there:
2016-11-04 13:52:47.597683 MyCallApp[1369:1183872] iosrtcPlugin#dump()
2016-11-04 13:52:47.598276 MyCallApp[1369:1183872] - PluginMediaStream [97659D53-388F-4533-8F2D-3ED39CADC339:A=1:V=1]
2016-11-04 13:52:47.598577 MyCallApp[1369:1183872] - PluginMediaStreamTrack [id:23B1E761-CA00-44D6-82DD-90A2E440B44E, kind:video]
2016-11-04 13:52:47.598869 MyCallApp[1369:1183872] - PluginMediaStreamTrack [id:F03A4D41-6812-406F-B213-3514FD9AC2B1, kind:audio]
These seem to be related to the created getUserMedia
labels here:
https://github.com/eface2face/cordova-plugin-iosrtc/blob/master/src/PluginGetUserMedia.swift#L83
https://github.com/eface2face/cordova-plugin-iosrtc/blob/master/src/PluginGetUserMedia.swift#L164
https://github.com/eface2face/cordova-plugin-iosrtc/blob/master/src/PluginGetUserMedia.swift#L174
So eacht new call I start, will do a new call to the getUserMedia and recreate a stream and audio/video track for getUserMedia. So after each call all connections and all remote streams/tracks are removed. But the getUserMedia remain.
Maybe the main question is why are they not removed even when the rtcPeerConnection is removed and all other references? I am not really into Swift so I can't answer.
I did try to reuse the same ids for the getUserMedia so they won't create new ones, like this:
Changed https://github.com/eface2face/cordova-plugin-iosrtc/blob/master/src/PluginGetUserMedia.swift#L6 to:
var rtcPeerConnectionFactory: RTCPeerConnectionFactory
var getUserMediaId : String = NSUUID().UUIDString
var getUserMediaAudioId : String = NSUUID().UUIDString
var getUserMediaVideoId : String = NSUUID().UUIDString
Changed https://github.com/eface2face/cordova-plugin-iosrtc/blob/master/src/PluginGetUserMedia.swift#L83 to:
rtcMediaStream = self.rtcPeerConnectionFactory.mediaStreamWithLabel(getUserMediaId)
Changed https://github.com/eface2face/cordova-plugin-iosrtc/blob/master/src/PluginGetUserMedia.swift#L164 to:
rtcVideoTrack = self.rtcPeerConnectionFactory.videoTrackWithID(getUserMediaVideoId,
Changed https://github.com/eface2face/cordova-plugin-iosrtc/blob/master/src/PluginGetUserMedia.swift#L174 to:
rtcAudioTrack = self.rtcPeerConnectionFactory.audioTrackWithID(getUserMediaAudioId)
With these changes the same tracks are used and I am not getting new tracks after each getUserMedia. But the stream is still duplicated.
So eacht new call I start, will do a new call to the getUserMedia and recreate a stream and audio/video track for getUserMedia. So after each call all connections and all remote streams/tracks are removed. But the getUserMedia remain.
Maybe the main question is why are they not removed even when the rtcPeerConnection is removed and all other references? I am not really into Swift so I can't answer.
The fact that you close a PeerConnection does not mean, at all, that you close the local MediaStream. This is true even in a browser.
Local streams must be closed by the user, and here is where we are, because calling track.stop()
does not currently work.
However, what I need to know is a response to my previous question:
Does it cause muted audio or black video? or absolutely nothing changes and the remote peer still can hear/see us?
Does it cause muted audio or black video? or absolutely nothing changes and the remote peer still can hear/see us?
I had a quick go with this today with a call between an iPhone and a web browser version. If I run the following on the iPhone using this plugin, during a call:
localStream.getAudioTracks().forEach(function(track) { track.stop(); }); localStream.getVideoTracks().forEach(function(track) { track.stop(); });
The remote party does see black/blank video and no longer hears the audio.
@MonsterKiller good to know, thanks.
I've read the entire thread, and I apologize if the answer is "obviously not", but just to be sure:
Barring a proper fix for this, is it possible for us to somehow completely re-initialize iosrtc/libwebrtc when we need to bring things back to a clean state (free resources, etc)?
FWIW: I've found that, if I've attached a local stream to an HTML video element (using el.src = window.URL.createObjectURL(stream)
), then I need to ensure that said element gets deleted (i.e. detached from my document body) before I can successfully open up a new webrtc stream using getUserMedia... Even if the old stream was already "stopped" as per the above discussion.
Barring a proper fix for this, is it possible for us to somehow completely re-initialize iosrtc/libwebrtc when we need to bring things back to a clean state (free resources, etc)?
Not that I know of.
FWIW: I've found that, if I've attached a local stream to an HTML video element (using el.src = window.URL.createObjectURL(stream)), then I need to ensure that said element gets deleted (i.e. detached from my document body) before I can successfully open up a new webrtc stream using getUserMedia... Even if the old stream was already "stopped" as per the above discussion.
Hum, that's extrange. At any rate, doesn't el.src = '';
work for you?
I'm new in swift but, I used capture session to remove all inputs and outputs and it work for me.
dispatch_async(self.queue) { [weak pluginMediaStreamTrack] in
pluginMediaStreamTrack?.stop()
if self.m_captureSession != nil {
for input in self.m_captureSession.inputs{
self.m_captureSession.removeInput(input as! AVCaptureInput);
}
for output in self.m_captureSession.outputs{
self.m_captureSession.removeOutput(output as! AVCaptureOutput);
}
self.m_captureSession.stopRunning();
self.m_captureSession = nil;
}
}
@ibc @saghul Why don't you just create a patch that adds the setState method again?
- (BOOL)setState:(RTCTrackState)state {
return self.mediaTrack->set_state(
[RTCEnumConverter convertTrackStateToNative:state]);
}
@dmarcus1 what is that supposed to accomplish?
@saghul Take a look at https://github.com/BasqueVoIPMafia/cordova-plugin-iosrtc/blob/1c543747697d24691c58ed3e6f82484fc2600dd2/src/PluginMediaStreamTrack.swift#L84
Right now the MediaStreamTrack stop function is as follows:
// TODO: No way to stop the track.
// Check https://github.com/BasqueVoIPMafia/cordova-plugin-iosrtc/issues/140
func stop() {
NSLog("PluginMediaStreamTrack#stop() [kind:%@, id:%@]", String(self.kind), String(self.id))
NSLog("PluginMediaStreamTrack#stop() | stop() not implemented (see: https://github.com/BasqueVoIPMafia/cordova-plugin-iosrtc/issues/140")
// NOTE: There is no setState() anymore
// self.rtcMediaStreamTrack.setState(RTCTrackStateEnded)
// Let's try setEnabled(false), but it also fails.
self.rtcMediaStreamTrack.setEnabled(false)
}
When you call MediaStreamTrack.stop() right now, it only makes the track not enabled. The track can be enabled in the future, so setEnabled is meant to be toggled. That's what a WebRTC employee explained to Iñaki: https://bugs.chromium.org/p/webrtc/issues/detail?id=5784. Here's the relevant response:
Can you summarize what the issue you're still seeing is? setState isn't intended to be a public API, but setEnabled(false) should definitely cause muted (black) video to be sent. Is that not happening?
Or is the issue that the source is still alive after calling setEnabled(false)? That seems expected since you could call setEnabled(true) later. If you remove all references to the track, the tracks (along with the source) should be destroyed. Is that not working, or is it not sufficient?
He's saying that you can no longer call setState in libwebrtc. Without setState, it's not possible to change the state of the track. setEnabled(false)
is not a good solution because it does not stop the MediaStreamTrack. If you modify the libwebrtc library by adding a setState function, then you can call setState(RTCTrackStateEnded)
and this bug will be solved.
Earlier in this thread, @ibc suggested self.rtcMediaStreamTrack = nil
. The WebRTC employee says that this is how you destroy the track properly. Aside from creating a patch with the setState
function, this might be the best solution as it frees the camera.
As the code stands right now there is a huge problem because once you start a MediaStreamTrack, there's no way to destroy it. That's a problem because the camera never "lets go" of the tracks. This is likely to be the cause of #298. I was able to reproduce that bug and fix it by calling self.rtcMediaStreamTrack = nil
. I made a function called freeCamera
which sets all MediaStreamTracks and MediaStreams to nil, effectively destroying them. Let me know if you want me to make a PR for this. The downside to this is that iosRTC is supposed to be identical to WebRTC on the computer. Obviously there is no freeCamera
function in WebRTC. Calling stop on a MediaStreamTrack on the computer does not remove the MediaStreamTrack, so it shouldn't in iosRTC.
Calling stop on a MediaStreamTrack on the computer does not remove the MediaStreamTrack, so it shouldn't in iosRTC.
But calling track.stop()
on the plugin may set to nil
the native rtcMediaStreamTrack
(regardless the associated JS MediaStreamTrack
still exists). A PR doing that would make more sense IMHO.
Interesting idea. I didn't think of that, but it makes a lot of sense.
@dmarcs can you provide the code that dereferences the tracks? i would like to fork it and make it work...
@vertazzar I'm guessing you ran into the same issue I ran into where there's a problem with switching from the front to back camera after turning off the phone. As iosRTC stands right now, there's no way to use it in production because of that bug. I got it to work, but in a very hacky way. Iñaki probably won't accept it if you make a pull request because I added the method freeCamera
which isn't a WebRTC method, but here it is:
func freeCamera(_ command: CDVInvokedUrlCommand) {
NSLog("iosrtcPlugin#freeCamera()")
var localId:String?
var pcId:Int?
for (id, _) in self.pluginRTCPeerConnections {
localId = String(describing: self.pluginRTCPeerConnections[id]!.rtcPeerConnection.localStreams[0])
pcId = id
}
var localVideoId:String?
var localAudioId:String?
for (id, pluginMediaStream) in self.pluginMediaStreams {
NSLog("- PluginMediaStream %@", String(pluginMediaStream.rtcMediaStream.description))
if(String(pluginMediaStream.rtcMediaStream.description) == localId) {
localVideoId = self.pluginMediaStreams[id]!.videoTracks.values.first?.id
localAudioId = self.pluginMediaStreams[id]!.audioTracks.values.first?.id
localId = id
}
}
if(self.pluginMediaStreams.count < 1 || self.pluginMediaStreamTracks.count < 1 || self.pluginMediaStreams.count < 1) {
return;
}
if let yourStream = self.pluginMediaStreams[localId!]?.rtcMediaStream {
if let yourAudioTrack = self.pluginMediaStreamTracks[localAudioId!]?.rtcMediaStreamTrack {
yourStream.removeAudioTrack(yourAudioTrack as! RTCAudioTrack)
}
if let yourVideoTrack = self.pluginMediaStreamTracks[localVideoId!]?.rtcMediaStreamTrack {
yourStream.removeVideoTrack(yourVideoTrack as! RTCVideoTrack)
}
}
if let yourPC = self.pluginRTCPeerConnections[pcId!]?.rtcPeerConnection {
if let yourMediaStream = self.pluginMediaStreams[localId!]?.rtcMediaStream {
yourPC.remove(yourMediaStream as! RTCMediaStream)
}
}
}
I wrote this code a while ago, so I can't remember why I didn't set variables equal to nil, but I think doing that caused more issues even though it's the correct way to dereference.
I was hoping that by now Safari would support WebRTC, which it does on mobile Safari, but not in UIWebView or WKWebView.
@dmarcs thank you very much for the code, I will test it out tonight
generally I don't see the problem of adding a non-standard way of freeing the resources since the entire purpose of the plugin is to provide WebRTC for ios UIWebView. Writing some wrapper with few if-s like isCordovaIOS()
is no big deal for the case where the bug cannot be fixed according to the standard RTC implementation
@vertazzar Okay sounds good. Let me know if it works. If not you can try setting some variables above equal to nil which will definitely free your camera, but potentially cause other issues.
@dmarcs I have tested it and it seems that it's working without any problems. Even if I drop the call, and re-initiate the call
@vertazzar That's good to hear 😃 Someone using my Cordova CallKit plugin also used it, and it worked.
I'm having this same issue, I've added @dmarcs freecamera method in iosrtcPlugin.swift, how do I call it in javascript to release the camera?
@fuub You need to add this function to iosrtc.js. It allow you to call the swift function from javascript:
function freeCamera() {
exec(null, null, 'iosrtcPlugin', 'freeCamera', []);
}
Hope this helps.
Hello David,
Thanks for the quick response!
I was able to call the freeCamera function from javascript now, but after calling it after the call is ended it is giving me the error on the image below. Is this anything you know the cause?
[image: Inline image 1]
On Thu, Dec 28, 2017 at 12:24 AM, David Marcus notifications@github.com wrote:
@fuub https://github.com/fuub You need to add this function to iosrtc.js https://github.com/BasqueVoIPMafia/cordova-plugin-iosrtc/blob/d38fe4dabb6d433b20ec6fe4efd65fa86aa710a4/js/iosrtc.js. It allow you to call the swift function from javascript:
function freeCamera() { exec(null, null, 'iosrtcPlugin', 'freeCamera', []); }
Hope this helps.
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/BasqueVoIPMafia/cordova-plugin-iosrtc/issues/140#issuecomment-354202624, or mute the thread https://github.com/notifications/unsubscribe-auth/ARu1DfPNLgHev7aIQjlCc6Q3EZBlONRlks5tEt_VgaJpZM4Hq0Xq .
@fuub Sorry but I can't see the image.
I solved by calling the freecamera sooner and now it frees the camera.
but still didn't fixed my main issue, which is after the first call the local video doesn't show up, or show up just minutes later of the ongoing call, totally random. In the first call it always shows up perfectly.
Although it doesn't show up the local video, the video is being sent and working fine, maybe it is some problem with rendering I dont know.
Have you experienced something similar?
Sorry for asking this is just there really isn't much documentation to search for this problems..
On Fri, Dec 29, 2017 at 11:32 PM, David Marcus notifications@github.com wrote:
@fuub https://github.com/fuub Sorry but I can't see the image.
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/BasqueVoIPMafia/cordova-plugin-iosrtc/issues/140#issuecomment-354512692, or mute the thread https://github.com/notifications/unsubscribe-auth/ARu1DaCgo-_viAHnd2ZMbZaSmH9UKdrLks5tFXaZgaJpZM4Hq0Xq .
@fuub I also had the problem of not being able to see the local video (The first call always worked perfectly for me too). See #298 for more details. The freeCamera method fixed that problem for me, but I only called it at the end of a call. I'm not sure why you have to call it earlier. That might be part of your problem. I would use xCode to analyze the webRTC variables, and see if you can get to the bottom of the issue that way.
Ok I will try to check webRTC variables, btw the previous image and the error it gives when calling freecamera after call ending is this: https://imgur.com/a/b4M9s
On Thu, Jan 4, 2018 at 1:37 AM, David Marcus notifications@github.com wrote:
@fuub https://github.com/fuub I also had the problem of not being able to see the local video (The first call always worked perfectly for me too). See #298 https://github.com/BasqueVoIPMafia/cordova-plugin-iosrtc/issues/298 for more details. The freeCamera method fixed that problem for me, but I only called it at the end of a call. I'm not sure why you have to call it earlier. That might be part of your problem. I would use xCode to analyze the webRTC variables, and see if you can get to the bottom of the issue that way.
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/BasqueVoIPMafia/cordova-plugin-iosrtc/issues/140#issuecomment-355176700, or mute the thread https://github.com/notifications/unsubscribe-auth/ARu1Dcej1NgtvovOK5fW_hxDdzL8XP-Jks5tHCtwgaJpZM4Hq0Xq .
We also implemented the freeCamera
function in our fork and it works splendid. We did however had to make one change. The first for loop in the function assumes there is at least 1 localStream which, for us, was not the case and it made the app crash. A small if
around it fixed that problem. The final code we implemented is as follows:
func freeCamera(_ command: CDVInvokedUrlCommand) {
NSLog("iosrtcPlugin#freeCamera()")
var localId:String?
var pcId:Int?
for (id, _) in self.pluginRTCPeerConnections {
if self.pluginRTCPeerConnections[id]!.rtcPeerConnection.localStreams.count >= 1 {
localId = String(describing: self.pluginRTCPeerConnections[id]!.rtcPeerConnection.localStreams[0])
pcId = id
}
}
var localVideoId:String?
var localAudioId:String?
for (id, pluginMediaStream) in self.pluginMediaStreams {
NSLog("- PluginMediaStream %@", String(pluginMediaStream.rtcMediaStream.description))
if(String(pluginMediaStream.rtcMediaStream.description) == localId) {
localVideoId = self.pluginMediaStreams[id]!.videoTracks.values.first?.id
localAudioId = self.pluginMediaStreams[id]!.audioTracks.values.first?.id
localId = id
}
}
if(self.pluginMediaStreams.count < 1 || self.pluginMediaStreamTracks.count < 1 || self.pluginMediaStreams.count < 1) {
return;
}
if let yourStream = self.pluginMediaStreams[localId!]?.rtcMediaStream {
if let yourAudioTrack = self.pluginMediaStreamTracks[localAudioId!]?.rtcMediaStreamTrack {
yourStream.removeAudioTrack(yourAudioTrack as! RTCAudioTrack)
}
if let yourVideoTrack = self.pluginMediaStreamTracks[localVideoId!]?.rtcMediaStreamTrack {
yourStream.removeVideoTrack(yourVideoTrack as! RTCVideoTrack)
}
}
if let yourPC = self.pluginRTCPeerConnections[pcId!]?.rtcPeerConnection {
if let yourMediaStream = self.pluginMediaStreams[localId!]?.rtcMediaStream {
yourPC.remove(yourMediaStream as! RTCMediaStream)
}
}
}
Hi Alko,
Did that change and now I get a similar error below: https://imgur.com/a/UJyQb
On Thu, Jan 4, 2018 at 1:54 PM, Alko notifications@github.com wrote:
We also implemented the freeCamera function in our fork and it works splendid. We did however had to make one change. The first for loop in the function assumes there is at least 1 localStream which, for us, was not the case and it made the app crash. A small if around it fixed that problem. The final code we implemented is as follows:
func freeCamera(_ command: CDVInvokedUrlCommand) { NSLog("iosrtcPlugin#freeCamera()")
var localId:String? var pcId:Int? for (id, _) in self.pluginRTCPeerConnections { if self.pluginRTCPeerConnections[id]!.rtcPeerConnection.localStreams.count >= 1 { localId = String(describing: self.pluginRTCPeerConnections[id]!.rtcPeerConnection.localStreams[0]) pcId = id } } var localVideoId:String? var localAudioId:String? for (id, pluginMediaStream) in self.pluginMediaStreams { NSLog("- PluginMediaStream %@", String(pluginMediaStream.rtcMediaStream.description)) if(String(pluginMediaStream.rtcMediaStream.description) == localId) { localVideoId = self.pluginMediaStreams[id]!.videoTracks.values.first?.id localAudioId = self.pluginMediaStreams[id]!.audioTracks.values.first?.id localId = id } } if(self.pluginMediaStreams.count < 1 || self.pluginMediaStreamTracks.count < 1 || self.pluginMediaStreams.count < 1) { return; } if let yourStream = self.pluginMediaStreams[localId!]?.rtcMediaStream { if let yourAudioTrack = self.pluginMediaStreamTracks[localAudioId!]?.rtcMediaStreamTrack { yourStream.removeAudioTrack(yourAudioTrack as! RTCAudioTrack) } if let yourVideoTrack = self.pluginMediaStreamTracks[localVideoId!]?.rtcMediaStreamTrack { yourStream.removeVideoTrack(yourVideoTrack as! RTCVideoTrack) } } if let yourPC = self.pluginRTCPeerConnections[pcId!]?.rtcPeerConnection { if let yourMediaStream = self.pluginMediaStreams[localId!]?.rtcMediaStream { yourPC.remove(yourMediaStream as! RTCMediaStream) } } }
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/BasqueVoIPMafia/cordova-plugin-iosrtc/issues/140#issuecomment-355287665, or mute the thread https://github.com/notifications/unsubscribe-auth/ARu1DX-4UNQWBXFyfA4VdvCMmjISecwEks5tHNgngaJpZM4Hq0Xq .
@fuub Don't know why this is happening on your end. You can probably find out more if you look at the debug data available, but just by looking at the code, maybe changing it to this will fix it for you:
func freeCamera(_ command: CDVInvokedUrlCommand) {
NSLog("iosrtcPlugin#freeCamera()")
var localId:String?
var pcId:Int?
for (id, _) in self.pluginRTCPeerConnections {
if self.pluginRTCPeerConnections[id]!.rtcPeerConnection.localStreams.count >= 1 {
localId = String(describing: self.pluginRTCPeerConnections[id]!.rtcPeerConnection.localStreams[0])
pcId = id
}
}
if localId == nil {
return;
}
var localVideoId:String?
var localAudioId:String?
var streamId:String?
for (id, pluginMediaStream) in self.pluginMediaStreams {
NSLog("- PluginMediaStream %@", String(pluginMediaStream.rtcMediaStream.description))
if(String(pluginMediaStream.rtcMediaStream.description) == localId) {
localVideoId = self.pluginMediaStreams[id]!.videoTracks.values.first?.id
localAudioId = self.pluginMediaStreams[id]!.audioTracks.values.first?.id
streamId = id
}
}
if(self.pluginMediaStreams.count < 1 || self.pluginMediaStreamTracks.count < 1 || self.pluginMediaStreams.count < 1 || streamId == nil) {
return;
}
if let yourStream = self.pluginMediaStreams[streamId!]?.rtcMediaStream {
if let yourAudioTrack = self.pluginMediaStreamTracks[localAudioId!]?.rtcMediaStreamTrack {
yourStream.removeAudioTrack(yourAudioTrack as! RTCAudioTrack)
}
if let yourVideoTrack = self.pluginMediaStreamTracks[localVideoId!]?.rtcMediaStreamTrack {
yourStream.removeVideoTrack(yourVideoTrack as! RTCVideoTrack)
}
}
if let yourPC = self.pluginRTCPeerConnections[pcId!]?.rtcPeerConnection {
if let yourMediaStream = self.pluginMediaStreams[streamId!]?.rtcMediaStream {
yourPC.remove(yourMediaStream as! RTCMediaStream)
}
}
}
Thanks for the help Alko,
It doesn't give any error now with that code but also doesn't free camera :)
But I discovered something... if I use the code right before call ends it is releasing the camera, and if I background the app and then foreground it, it works again nicely. Only if it stays foreground on the second try the local video doesn't work... Maybe it is a different issue afterall...
On Fri, Jan 5, 2018 at 10:01 AM, Alko notifications@github.com wrote:
@fuub https://github.com/fuub Don't know why this is happening on your end. You can probably find out more if you look at the debug data available, but just by looking at the code, maybe changing it to this will fix it for you:
func freeCamera(_ command: CDVInvokedUrlCommand) { NSLog("iosrtcPlugin#freeCamera()")
var localId:String? var pcId:Int? for (id, _) in self.pluginRTCPeerConnections { if self.pluginRTCPeerConnections[id]!.rtcPeerConnection.localStreams.count >= 1 { localId = String(describing: self.pluginRTCPeerConnections[id]!.rtcPeerConnection.localStreams[0]) pcId = id } } if localId == nil { return; } var localVideoId:String? var localAudioId:String? var streamId:String? for (id, pluginMediaStream) in self.pluginMediaStreams { NSLog("- PluginMediaStream %@", String(pluginMediaStream.rtcMediaStream.description)) if(String(pluginMediaStream.rtcMediaStream.description) == localId) { localVideoId = self.pluginMediaStreams[id]!.videoTracks.values.first?.id localAudioId = self.pluginMediaStreams[id]!.audioTracks.values.first?.id streamId = id } } if(self.pluginMediaStreams.count < 1 || self.pluginMediaStreamTracks.count < 1 || self.pluginMediaStreams.count < 1 || streamId == nil) { return; } if let yourStream = self.pluginMediaStreams[streamId!]?.rtcMediaStream { if let yourAudioTrack = self.pluginMediaStreamTracks[localAudioId!]?.rtcMediaStreamTrack { yourStream.removeAudioTrack(yourAudioTrack as! RTCAudioTrack) } if let yourVideoTrack = self.pluginMediaStreamTracks[localVideoId!]?.rtcMediaStreamTrack { yourStream.removeVideoTrack(yourVideoTrack as! RTCVideoTrack) } } if let yourPC = self.pluginRTCPeerConnections[pcId!]?.rtcPeerConnection { if let yourMediaStream = self.pluginMediaStreams[streamId!]?.rtcMediaStream { yourPC.remove(yourMediaStream as! RTCMediaStream) } } }
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/BasqueVoIPMafia/cordova-plugin-iosrtc/issues/140#issuecomment-355516808, or mute the thread https://github.com/notifications/unsubscribe-auth/ARu1DeshadPclY2nb84UET78ogxGr7ziks5tHfL6gaJpZM4Hq0Xq .
@saghul @ibc What do you think of what was done here by @alkoschuster ?
Right now my solution is force the user to kill and restart the app after the calls... :(
@alkoschuster @dmarcs
I tried to use the freeCamera function on iosrtc plugin. I added the function to iosrtcPlugin.swift, and also added function: freeCamera() { exec(null, null, 'iosrtcPlugin', 'freeCamera', []); } to iosrtc.js
When calling cordova.plugins.iosrtc.freeCamera(), it said freeCamera function is undefined.
Could anyone point me to the right way of using the function? Thanks.
@Bernard-Ip if you're just doing as I was, modifying the content in the xcode project to test it out, if you do a cordova build you'll find that the contents of the plugin's .js
will be replaced, so double check that your changes are still there..
related but not directly
What a fucking mess, I will consider implementing MediaStreamMediaStreamTrack Stop instead. freeCamera does not make sense in WebRTC land.
calling localStream.stop()
or localStream.getTracks().forEach(function (track) { track.stop() })
or pc1.getSenders().forEach(function (track) { track.stop() })
work on 5.0.2+ and has been tested again on 5.0.4.
See used test scripts with localStream global used to call stop functions.
Hi, I'm having an issue with stopping the tracks.
After I first call the track.stop() function when switching between camera the old track stops after few seconds, but if a try to switch again the function won't work and there's no error or something to check if I do something wrong
const streamRef = useRef<MediaStream | null>(null);
.....
.....
if (streamRef.current) {
console.log('xxxx', streamRef.current.getVideoTracks());
streamRef.current
.getTracks()
.forEach((track: MediaStreamTrack) => {
track.stop();
});
streamRef.current = null;
}
.......
.......
streamRef.current = currentStream;
@Mihai-github due to the nature of this plugin webrtc async track stop, you may want to try to add a setTimeout , or wait for stream end event before adding the next stream. Alternatively using RTCSender remove track and removeTrack on stream may also improve the issue caused by async nature of the SHIM.
During a call/video call stopping the video stream does nothing and the remote peer follows to hear me.Stream transmission is not stopped.