OpenTok: Video Element Paused warning, can't unpublish - live-streaming

I'm trying to unpublish a video but keep getting the warning
"Video element paused, auto-resuming. If you intended to do this, use publishVideo(false) or subscribeToVideo(false) instead."
I'm unpublishing with:
clientPublisher.publishAudio(false);
clientPublisher.publishVideo(false);
clientSession.unpublish(clientPublisher, handleError);
The "streamDestoryed" function is firing so it seems like it should be unpublished. But if I subscribe to it using:
o.subscriber = clientSession.subscribe(stream, vid, {... subscribeToAudio: false...}, function(error) {
if (error) {
}
else {
o.subscriber.subscribeToAudio(false);
}
}
I still get audio. What exactly does this message mean and how do I stop publishing?
EDIT:
If I subscribe first WITHOUT audio, I can toggle it on and off and it works fine. However, if the client publishes and I don't set subscribeToAudio to false, I can no longer toggle the audio on and off... it's always on.

Related

Cannot resume AudioContext in Safari

I'm running into an issue where calling resume on an AudioContext never resolves when attempting to play audio in Safari. I'm creating an AudioContext on page load, thus it starts in a suspended state.
According to this chromium issue, calling resume will not resolve if blocked by the browser's autoplay policy. I have a click event bound to a <button> that will resume the context if it's suspended. This works in both Firefox and Chrome, and will work in Safari if I change the autoplay settings for the site.
Below is how I would normally resume the context:
await context.resume();
For Safari, I've tried calling resume without waiting for the promise to resolve, and instead register a callback for onstatechange, which is then wrapped in a Promise:
if (window.webkitAudioContext) {
await new Promise((accept, reject) => {
this.context.onstatechange = async () => {
if ((await this.context.state) === "playing") {
accept();
} else {
reject();
}
};
this.context.resume();
});
}
However, nothing has changed: the Promise never resolves, which means that the context state isn't changing.
Am I missing something?
iOS will only allow audioContext to be resumed if it is running within the call-stack of a UI Event Handler. Running it within a Promise moves the call to another call-stack.
Also, audioContext.resume() returns a promise, which must be awaited.
Try this:
onPlayHandler() {
alert("State before: " + this.audioContext.state);
await this.audioContext.resume();
alert("State after: " + this.audioContext.state);
}
I finally managed to get audio playing on Safari.
The "fix" was rather simple: I had to call resume within the event handler that is bound to the element being used to initiate playback. In my scenario, I was using Redux with React, so a dispatch would be made, and resuming the context would happen at a later time within another component. I'm guessing that Safari didn't see this as a direct response to a user interaction event, so it kept the context in a suspended state.

Service Worker - Wait for clients.openWindow to complete before postMessage

I am using service worker to handle background notifications. When I receive a message, I'm creating a new Notification using self.registration.showNotification(title, { icon, body }). I'm watching for the click event on the notification using self.addEventListener('notificationclick', ()=>{}). On click I'm checking to see if any WindowClient is open, if it is, I'm getting one of those window clients and calling postMessage on it to send the data from the notification to the app to allow the app to process the notification. Incase there is no open window I'm calling openWindow and once that completes I'm sending the data to that window using postMessage.
event.waitUntil(
clients.matchAll({ type: 'window' }).then((windows) => {
if (windows.length > 0) {
const window = windows[0];
window.postMessage(_data);
window.focus();
return;
}
return clients.openWindow(this.origin).then((window) => {
window.postMessage(_data);
return;
});
})
);
The issue I am facing is that the postMessage call inside the openWindow is never delivered. I'm guessing this is because the postMessage call on the WindowClient happens before the page has finished loading, so the eventListener is not registered to listen for that message yet? Is that right?
How do I open a new window from the service worker and postMessage to that new window.
I stumble this issue as well, using timeout is anti pattern and also might cause delay larger then the 10 seconds limit of chrome that could fail.
what I did was checking if I need to open a new client window.
If I didn't find any match in the clients array - which this is the bottle neck, you need to wait until the page is loaded, and this can take time and postMessage will just not work.
For that case I created in the service worker a simple global object that is being populated in that specific case for example:
const messages = {};
....
// we need to open new window
messages[randomId] = pushData.message; // save the message from the push notification
await clients.openWindow(urlToOpen + '#push=' + randomId);
....
In the page that is loaded, in my case React app, I wait that my component is mounted, then I run a function that check if the URL includes a '#push=XXX' hash, extracting the random ID, then messaging back to the service worker to send us the message.
...
if (self.location.hash.contains('#push=')) {
if ('serviceWorker' in navigator && 'Notification' in window && Notification.permission === 'granted') {
const randomId = self.locaiton.hash.split('=')[1];
const swInstance = await navigator.serviceWorker.ready;
if (swInstance) {
swInstance.active.postMessage({type: 'getPushMessage', id: randomId});
}
// TODO: change URL to be without the `#push=` hash ..
}
Then finally in the service worker we add a message event listener:
self.addEventListener('message', function handler(event) {
if (event.data.type === 'getPushMessage') {
if (event.data.id && messages[event.data.id]) {
// FINALLY post message will work since page is loaded
event.source.postMessage({
type: 'clipboard',
msg: messages[event.data.id],
});
delete messages[event.data.id];
}
}
});
messages our "global" is not persistent which is good, since we just need this when the service worker is "awaken" when a push notification arrives.
The presented code is pseudo code, to point is to explain the idea, which worked for me.
clients.openWindow(event.data.url).then(function(windowClient) {
// do something with the windowClient.
});
I encountered the same problem. My error was that I registered event handler on the window. But it should be registered on service worker like this:
// next line doesn't work
window.addEventListener("message", event => { /* handler */ });
// this one works
navigator.serviceWorker.addEventListener('message', event => { /* handler */ });
See examples at these pages:
https://developer.mozilla.org/en-US/docs/Web/API/Clients
https://developer.mozilla.org/en-US/docs/Web/API/Client/postMessage
UPD: to clarify, this code goes into the freshly opened window. Checked in Chromium v.66.

WatchConnectivity Framework : WKSession is maintain the queue which I requested To Watch

I have create an application which is sending data to watch for showing.
When the watch is screen is active then it sending data perfectly, but when watch sleeps then an error occurred that device is not active.
My question is that when the watch is active any how it will get that data which send via using WKSession sendMessage method from my iPhone?
If the watch screen is off, the calling sendMessage on the iPhone won't work. You can only send data in real time when the watch screen is on. This is different than when you are using sendMessage from the watch to the iPhone (iPhone screen can be off). This is the block of code I use anytime I call sendMessage from my iPhone code:
// Send messages to any paired apple watch.
func tryWatchSendMessage(message: [String : AnyObject]) {
if self.session != nil && self.session.paired && self.session.watchAppInstalled {
self.session.sendMessage(message, replyHandler: nil) { (error) -> Void in
// If the message failed to send, queue it up for future transfer
self.session.transferUserInfo(message)
}
}
}
Then I setup the apple watch app to have the same handler if it gets the data via sendMessage or transferUserInfo.

How to catch local notification onclick event in phonegap

Thank you very much for the plugin!
I'm having a bit of a problem: My onclick doesn't seem to be getting called
window.plugin.notification.local.add({
id: 1,
date: dateobj,
message: 'Test Notification',
title: 'MyApp',
repeat: 'daily',
badge: 1,
autoCancel: true
});
window.plugin.notification.local.onclick = function(id, state, json){
console.log("SUCCESS");
alert("success");
};
I also tried the oncancel just now and it is the same... Nothing happens.
Edit: onadd seems to work fine though. Probably because app is already open when I do an add?
The notification appears fine and the app loads when I click it, but I don't see anything in console and don't see the alert. Am I correct in assuming the onclick should be fired after user clicks notification and the app loads?
I'm using phonegap build 3.1, plugin 0.7.0, android 4.3. Am I missing anything?
Your assumption is correct, the click event will be called after device ready. It seems something wrong on assigning click event to the notification. Try to use the following one. Hope it will help to you.
cordova.plugins.notification.local.on("click", function (notification) {
joinMeeting(notification.data.meetingId);});

WL.Client.Push.isSubscribed() returns false if app reloaded

I have a simple Worklight V6 app using Push on Android. When the app starts up, it does a form based login against the SampleAppRealm. Then it subscribes if necessary:
function checkSubscribed() {
var subscribed = WL.Client.Push.isSubscribed("myPush");
alert("Is subscribed: " + subscribed);
return subscribed;
}
WL.Client.Push.onReadyToSubscribe = function() {
WL.Client.Push.registerEventSourceCallback("myPush", "PushAdapter",
"MyEventSource", function(props, payload) {
alert("Received message: " + props.alert);
});
if (!checkSubscribed()) {
WL.Client.Push.subscribe("myPush", {
onSuccess : function() {
alert("subscription succeeded!");
},
onFailure : function() {
alert("subscription failed!");
}
});
}
};
This all works swell. The app starts up, it logs in, onReadyToSubscribe() fires, it registers the callback, checks the subscription (which is false), and subscribes (which succeeds)
I can see the client subscription in the Worklight console, and if I call the adapter, I get the notification in the app.
If I hit the home button to do something else on the phone, and then return to the app, it still knows that it is subscribed. If I push a message when the app is in the background, I see it in the Android notification area, and see it in the app when I return to it. All good.
The problem is when I am running the app, it is subscribed, and I hit the Android back button. The app closes, but the Admin console still shows a subscribed client, and in fact if I push a message with the app closed, it shows up in the Android notification area. (so far so good)
But when I start the app, it goes through the authentication steps, onReadyToSubscribe() fires, checkSubscribed() gets called and WLClient.Push.isSubscribed() returns false.
If I restart the phone with the app subscribed, when the app restarts, WLClient.Push.isSubscribed() returns false.
How do I get the correct subscription state when an app restarts?
Answering my own question.
It turns out that the problem was that My app was explicitly calling WL.Client.login("SampleAppRealm") when it started. The application descriptor environment setting of a security test on the environment was not configured.
When I add the security test to the application descriptor, isSubscribed() returns the correct answer after an app is restarted. The funny bit is that everything else having to do with Push worked fine with authentication simply triggered by WL.Client.login()
I can't find any documentation around this requirement for the setting in the application descriptor, so it is hard to make out whether this is user error. At the least, the docs could be punched up in this area.