I am new to RTCPeerConnection (WEbRTC), so please bear with me.
So far I am able to get to the point where I can replace tracks on the run by switching camera or screen sharing in my app. But I noticed it in 2 browser tabs that newly replaced track stream is captured in partner/remote peer only, not on initiator's tab. It just keep showing old stream even though stream has been replaced.
It should've been nice if initiator can also see what he/she is sharing. I tried but no luck so far. Looking for some assistance.
My code looks like:
function screenShare(){
(async () => {
try {
await navigator.mediaDevices.getDisplayMedia(
{
cursor: true
}).then(stream => {
// localStream = stream;
let videoTrack = stream.getVideoTracks()[0];
var sender = senders.find(function(s) {
return s.track.kind == videoTrack.kind;
});
sender.replaceTrack(videoTrack);
videoTrack.onended = function(){
sender.replaceTrack(localStream.getTracks()[1]);
}
});
} catch (err) {
console.log('(async () =>: ' + err);
}
})();
}
Thanks in advance.
By design replaceTrack replaces the stream on the RTCPeerConnection. This does not affect the local video object. Reset the srcObject on the local video element to change it.
Related
have found that in my electron application the following code from the main.js only returns a device list of length 1 (filled with one device) even though there are many devices around.
mainWindow.webContents.on('select-bluetooth-device', (event, deviceList, callback) => {
event.preventDefault();
console.log(deviceList);
bluetoothSelection.selectBluetoothDevice(deviceList, mainWindow, (deviceId) => {
callback(deviceId);
});
If I call
navigator.bluetooth.requestDevice({
acceptAllDevices: true,
optionalServices: [serviceUuid]
})
multiple times, the device returned changes and if I cycle through it often enough, I get the device I want eventually.. But I built a device Picker window and all that stuff and now the window opens for only one device, which makes everything quite annoying:P
Any ideas on what could cause this or even how I could fix it?
If you have a look at https://www.electronjs.org/docs/latest/api/web-contents#event-select-bluetooth-device you will find the example code provided by electron you probably already know:
win.webContents.on('select-bluetooth-device', (event, deviceList, callback) => {
event.preventDefault()
const result = deviceList.find((device) => {
return device.deviceName === "test"
})
if (!result) {
callback('')
} else {
callback(result.deviceId)
}
})
You have to prevent the callback until you have found the device you are looking for. I suggest to open a second window and pass in the deviceList. Now you can display the devices and let the user choose one. If the user has chosen a device, you can close the second window and call the callback with this deviceId.
To communicate between the windows you can use the “contextBridge” with “ipcRenderer” and “ipcMain” and to call the callback you can make a global variable
var callbackForBluetoothEvent = null;
and fill it int the
mainWindow.webContents.on(
// stuff
callbackForBluetoothEvent = callback; //to make it accessible outside
// stuff
);
With a “ipcMain.on”
ipcMain.on("BLEScannFinished", (event, args) => {
console.log(args);
console.log(BLEDevicesList.find((item) => item.deviceId === args));
let BLEDevicesChoosen = BLEDevicesList.find((item) => item.deviceId === args);
callbackForBluetoothEvent(BLEDevicesChoosen.deviceId);
});
You can than call the callback
Unfortunately this is a bit to much code for a forum post but you can find a rudimentary solution of this suggestion at the link:
https://github.com/grosdode/Electron-multible-BLE-devices
The electron issues 11865 was also helpful and there is a page which shows alternative code for the suggested solution. Unfortunately also to much code to post it here.
https://technoteshelp.com/electron-web-bluetooth-api-requestdevice-error/
following the instructions from:
https://codingwithjoe.com/playing-audio-from-the-web-and-http/ (using his example and AudioProvider class)
I have been using:
audioplayer: ^0.8.1
audioplayer_web: ^0.7.1
to play audio from https link.
The problem it has some weird inconsistent effect.
- after playing few audio, it keeps on playing the same audio eventhough new url is loaded
- after playing few audio, the sound is weird like some part is cut with other audio.
What is a good audio player that accepts url link for flutter that can produce a consistent result ?
the provided audioplayer from your example works great and has good features. From what you are describing for me it seems like you're not closing the session when you play a sound. It seems like you are stacking the sounds which causes weird sounds.
You have to close the instance then. even though the article is outdated (march 2018) the audioplayer has developed further. check their offical guide here:
https://pub.dev/packages/audioplayer
This is version audioplayer 0.8.1 not 3.0 or something..
Example from docs:
Instantiate an AudioPlayer instance
//...
AudioPlayer audioPlugin = AudioPlayer();
//...
Player controls:
audioPlayer.play(url);
audioPlayer.pause();
audioPlayer.stop();
status and current position:
//...
_positionSubscription = audioPlayer.onAudioPositionChanged.listen(
(p) => setState(() => position = p)
);
_audioPlayerStateSubscription = audioPlayer.onPlayerStateChanged.listen((s) {
if (s == AudioPlayerState.PLAYING) {
setState(() => duration = audioPlayer.duration);
} else if (s == AudioPlayerState.STOPPED) {
onComplete();
setState(() {
position = duration;
});
}
}, onError: (msg) {
setState(() {
playerState = PlayerState.stopped;
duration = new Duration(seconds: 0);
position = new Duration(seconds: 0);
});
});
Like I said most of the audio plugins are running in singleton mode with instances. To provide getting weird effects you have to load the next song in the same instance, don't open another new instance, and you wont get any weird effects.
If you want to switch to a different audio player another great one which I used in an app project is the following:
https://pub.dev/packages/audio_manager#-readme-tab-
Hope it helps.
I have an Ionic app that is a metronome. Using Web Audio API I have made everything work using the oscillator feature, but when switching to use a wav file no audio is playing on a real device (iPhone).
When testing in the browser using Ionic Serve (chrome) the audio plays fine.
Here is what I have:
function snare(e) {
var audioSource = 'assets/audio/snare1.wav';
var request = new XMLHttpRequest();
request.open('GET', audioSource, true);
request.responseType = 'arraybuffer';
// Decode asynchronously
request.onload = function() {
audioContext.decodeAudioData(request.response, function(theBuffer) {
buffer = theBuffer;
playSound(buffer);
});
}
request.send();
}
function playSound(buffer) {
var source = audioContext.createBufferSource();
source.buffer = buffer;
source.connect(audioContext.destination);
source.start(0);
}
The audio sample is in www/assets/audio.
Any ideas where this could be going wrong?
I believe iOS devices require a user-gesture of some sort to allow playing of audio.
It's July 2017, iOS 10.3.2 and we're still finding this issue on Safari on iPhones. Interestingly Safari on a MacBook is fine.
#Raymond Toy's general observation still appears to be true. But #padenot's approach (via https://gist.github.com/laziel/7aefabe99ee57b16081c) did not work for me in a situation where I wanted to play a sound in response to some external event/trigger.
Using the original poster's code, I've had some success with this
var buffer; // added to make it work with OP's code
// keep the original function snare()
function playSound() { // dropped the argument for simplicity.
var source = audioContext.createBufferSource();
source.buffer = buffer;
source.connect(audioContext.destination);
source.start(0);
}
function triggerSound() {
function playSoundIos(event) {
document.removeEventListener('touchstart', playSoundIos);
playSound();
}
if (/iPad|iPhone/.test(navigator.userAgent)) {
document.addEventListener('touchstart', playSoundIos);
}
else { // Android etc. or Safari, but not on iPhone
playSound();
}
}
Now calling triggerSound() will produce the sound immediately on Android and will produce the sound on iOS after the browser page has been touched.
Still not ideal, but better than no sound at all...
I had a similar issue in current iOS (15). I tried to play base64 encoded binary data which worked in all browsers, but not on iOS.
Finally reordering of the statements solved my issue:
let buffer = Uint8Array.from(atob(base64), c => c.charCodeAt(0));
let context = new AudioContext();
// these lines were within "play()" before
audioSource = context.createBufferSource();
audioSource.connect(context.destination);
audioSource.start(0);
// ---
context.decodeAudioData(buffer.buffer, play, (e) => {
console.warn("error decoding audio", e)
});
function play(audioBuffer) {
audioSource.buffer = audioBuffer;
}
Also see this commit in my project.
I assume that calling audioSource.start(0) within the play() method was somehow too late because it's within a callback after context.decodeAudioData() and therefore maybe "too far away" from a user interaction for the standards of iOS.
I am working on a Chrome app that switches between medias shown in a webview tag. The medias must be updated when they change on my web server and it must keep playing when the internet or the server go down. My solution was to play the media from a programmatically managed local cache.
I programmed the Chrome app to download the content with webkitRequestFileSystem into persistent local storage and I try to access the files from there. The content ends up with URLs like this filesystem:chrome-extension://kbjjicmijilgpdpkicpbnceofdpfbjcb/persistent/my_file.html.
No matter what I do, I cannot access the local files. Neither the webview nor navigating directly to the file displays it in Chrome. It only shows a ERR_FILE_NOT_FOUND error.
How should I go about showing this local content in my webview?
Here is my saveAsset() code (strongly inspired by this answer) :
function saveAsset(fs, url, filename, callback, failCallback) {
// Set callback when not defined
if (!callback) {
callback = function(cached_url) {
console.log('download ok: ' + cached_url);
};
}
if (!failCallback) {
failCallback = function() {
console.log('download failed');
};
}
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.responseType = 'arraybuffer';
xhr.addEventListener('load', function() {
fs.root.getFile(filename, {create: true, exclusive: false}, function(fileEntry) {
fileEntry.createWriter(function(writer) {
writer.onwrite = function(e) {
callback(fileEntry.toURL());
};
writer.onerror = failCallback;
console.log(xhr.response);
var blob = new Blob([xhr.response], {type: ''});
writer.write(blob);
}, failCallback);
}, failCallback);
});
xhr.addEventListener('error', failCallback);
xhr.send();
}
And this is the code that sets the src attribute of the webview to that URL.
window.webkitRequestFileSystem(window.PERSISTENT, 1024*1024, function (fs) {
saveAsset(fs, url, filename, function(localUrl) {
console.log(localUrl);
$(contentSelector).attr("src", localUrl);
});
});
I never managed make the webview work with local content, but switching to an iframe does work perfectly. I have both cached and uncached content so it makes some confusing code, but I fixed my issue by using both a webview and an iframe and hiding the one which is not in use.
PS. For anyone trying to do this, the webview won't load its content correctly if it is hidden with display:none . I had to move it outside of the screen instead.
I'm facing a problem using this 2 PhoneGap plugins: "BarcodeScanner" & "ChildBrowser" (inside an iOS app, with XCode 4 & PhoneGap 2.0).
I've a button "Scan" on my app UI. When the user clic on this button, the barcode scanner is launched.
So, in the Success function of the barcode scanner callback, I need to open the recovered URL from the scan in a new Childbrowser window (inner the app).
But the new Childbrowser window is never been opened, while the console displays "Opening Url : http://fr.wikipedia.org/" (for example).
Here is my JS part of code:
$("#btnStartScan").click(function() {
var scanBarcode = window.plugins.barcodeScanner.scan(
function(result) {
if (!result.cancelled){
openUrl(result.text);
}
},
function(error) {
navigator.notification.alert("scanning failed: " + error);
});
});
function openUrl(url)
{
try {
var root = this;
var cb = window.plugins.childBrowser;
if(cb != null) {
cb.showWebPage(url);
}
else{
alert("childbrowser is null");
}
}
catch (err) {
alert(err);
}
}
And all works fine if I call my openURL() function inside a Confirm alert callback for example, like this:
if (!result.cancelled){
navigator.notification.confirm("Confirm?",
function (b) {
if (b === 1) {
openUrl(result.text);
}
},
'Test',
'Yes, No');
}
But I need to launch the ChildBrowser window directly after a scan, without any confirm alert etc.
Does anybody know how to solve this please?
I also have this same problem.
Solve it by set timeout.
var scanBarcode = window.plugins.barcodeScanner.scan(
function(result) {
if (!result.cancelled){
setTimeout(function(){ openUrl(result.text); },500);
}
},
function(error) {
navigator.notification.alert("scanning failed: " + error);
});
I'm running into the exact same problem.
My application also has another mechanism to show a webpage besides the barcode reader and when I do that action I can see that the barcode-related page HAD loaded, but it never was shown.
In ChildBrowserViewController.m, I'm looking at the last line of loadURL() which is webView.hidden = NO; and I'm thinking that the child browser is set visible after we barcode but something about the barcode reader window caused the child browser to get set to the wrong z-order, but I'm not familiar enough with the sdk to know how to test that or try to bring it to the front.
Hope this helps target a potential area.