Share screen and send audio with two publishers - opentok

I am trying to share screen and send audio at the same time, I have managed to follow the instructions of Adam Ullman from this link Opentok Screen Sharing with Audio but the sound is quite bad , it is heard doubled and with very poor quality.
I have asked the technical support of tokbox and they tell me that another option is to use the same person with two publishers (one for screen and another to share audio). The problem is that when I do this or share a screen or share the camera + microphone, how can I make the other person see the shared screen and listen to me?
Another option I have is: is there any way to improve the sound of setusermedia? or avoid duplicating sound?
I have the following code:
screenSharingPublisher = Promise.all ([
                        OT.getUserMedia ({
                            videoSource: 'screen'
                        }),
                        OT.getUserMedia ({
                            videoSource: null
                        })
                    ])
                        .then (([screenStream, micStream]) => {
                        return OT.initPublisher (null, {
                            videoSource: screenStream.getVideoTracks () [0],
                            audioSource: micStream.getAudioTracks () [0]
                        });
                });
                    screenSharingPublisher.then (publisher => {
                        l.publish (publisher, handleErrorScreen);
                }). catch (handleErrorScreen);
Thanks for your help

Tokbox QA staff here,
I think what you need is to create two publishers, one with just video (screensharing) and another one with audio and video (camera + microphone), against the same session. With that, other users subscribing to that sessionId would see your screen, and hear your voice.
If your sound is heard doubled, maybe you're publishing your microphone twice.
I hope this helps.

Related

Combining samples quickly in tone.js (or another framework)

I need to programatically combine a bunch of music tracks in a sequence, one after the other, with some overlap between them, based on some rules.
I was looking at tone.js today which is great, and I've just about managed to make work (with players feeding into a recorder), but I realised right at the end that you have to wait for the whole sequence to play out in real time before it can be saved.
I don't want to have to wait an hour to get the file, I need it within a minute maximum. Is this possible with tone.js and if not is there any other programmatic way to do this?
You should be able to use OfflineContext rendering for this. Basically what you have to do is calling Tone.Offline and then get the audioBuffer of the result and save it to a file. You don't need a Recorder node. So something like this:
const audioBufferNode = await Tone.Offline(({ transport }) => {
// Do all your player scheduling along the transport here.
transport.start(0.5); // Start the transport to trigger all scheduled players
}, 4 /* The length of the resulting file */);
To download the audio buffer as a file requires you to read the raw data and write it into a format you wish to download.
A audio buffer to wave writer can be found here:
https://www.russellgood.com/how-to-convert-audiobuffer-to-audio-file

Is there a way to detect when a participant has muted their audio in opentok.js?

I went through the publisher docs which has the methods publishVideo(value) and publishAudio(value).
Corresponding to the video part, the subscriber receives the event videoDisabled or videoEnabled with the reason publishVideo which allows me to determine whether the subscribed participant has intentionally turned off their video or not, but I can't find something similar for audio such as audioDisabled or audioEnabled. audioBlocked event supposedly only covers blocks by browser's autoplay policy: Dispatched when the subscriber's audio is blocked because of the browser's autoplay policy.
The audioLevelUpdated event provides the current audio level, but that could just be silence, not an intentional mute, so that doesn't look ideal for this purpose.
I want to show a audio muted icon on the subscribed participants element when they have intentionally turned off their audio by calling publishAudio() method. How can that be achieved?
Referenced docs:
Subscriber events: https://tokbox.com/developer/sdks/js/reference/Subscriber.html#events
Publisher methods: https://tokbox.com/developer/sdks/js/reference/Publisher.html#methods
Each stream has an hasAudio attribute that returns false if the user's audio is muted or their microphone is muted. Similarly, streams also have a hasVideo attribute. You can reference the stream docs at https://tokbox.com/developer/sdks/js/reference/Stream.html.
I personally use it like so:
session.streams.forEach((stream) => {
const name = stream.name;
const video = stream.hasVideo;
const audio = stream.hasAudio;
});
You can listen for these changes with the session.on('streamPropertyChanged') event: https://tokbox.com/developer/sdks/js/reference/StreamPropertyChangedEvent.html
Hav u tried audioLevelUpdated and checking the level of audio
If level is 0 then its muted.
https://tokbox.com/developer/sdks/js/reference/Subscriber.html#getAudioVolume
So steps are listen audioLevelUpdated and check AudioVolume, audio volume should get u the subscriber level point.
Set OTSubscriberKitNetworkStatsDelegate to subscriber as
subscriber.networkStatsDelegate = self
Then you can call the below function to get simultaneous changes on subscribers' microphone status
func subscriber(_ subscriber: OTSubscriberKit, audioNetworkStatsUpdated stats: OTSubscriberKitAudioNetworkStats) {
// call stream.hasAudio
}
You can also check from opentok audioNetworkStatsUpdated

Google Play in-app billing version 3: crash on "item already owned" and missing failure notifications

After (eventually) shipping a v2 implementation of the Google Play in-app billing, I've had nothing but problems with it post-launch. Dropped transactions, crashes, unable to restore, crazy errors like "can't download, you already own this item", and all sorts of other ridiculous things. Honestly, I've integrated IAB on iOS, Amazon App Store, Samsung Apps and Blackberry 10 now and the Google Play code has taken more time than all the others combined. Times ten. It's just terrible.
Anywayyyy, I've decided to try and implement v3 into my app. The integration process was much, much simpler, so kudos to Google for that. Also, restoring previous transactions now works as expected so that's great. However, I've got a couple of show-stopping problems:
When the user dismisses the IAB dialog (i.e. tapping outside of the dialog borders), I don't receive any notification of this. I would expect to receive some kind of "user cancelled" failure event, but nothing is fired to onIabPurchaseFinished, onConsumeFinished or onQueryInventoryFinished. As a result my app doesn't respond to this and I'm left with a dirty great unused Activity on the screen. Am I missing some kind of "dialogIsFinished" event?
When the user tries to purchase an item that they already own, the app crashes. Unbelievably it looks like this is the intended behaviour, as there's something alluding to this printed to the console ("In-app billing error: Unable to buy item, Error response: 7:Item Already Owned"). I understand that I'm supposed to query for restorable transactions at launch, but this isn't a solution as it's conceivable the user can navigate to the purchase flow of my UI before the restore operation finishes. Surely this should be a non-hard stop, like a dialog box or something? Am I doing something wrong here? I simply can't understand that somebody at Google thinks that this situation deserves a hard crash...
Thanks very much (in advance) for your help. I'm more than happy to share code if you think it's necessary, although my questions seem to be more about the functional design more than anything else. I'm hoping that I'm doing something wrong here, as it's inconceivable to me that a company as capable as Google would re-write this entire system and still have such massive holes all over the place... :-/
Thanks again,
Ben
Hmm, that was my mistake. When I wrote launchPurchaseFlow(), I ended up missing some cleanup code on failure cases. Not only there, but also on a couple of catch{} clauses after that. Thanks for pointing that out! This has just been fixed in the source repository: http://code.google.com/p/marketbilling
I had the same error, I accidentally forgot to consume the item after I purchased. But when I tried to purchase another of same item App crashed.
I dig through the Google IabHelper class and found out that this statement is not handled correctly. I made some small change and now it works. Instead of crashing send error message back with listener.
Here is the modified part of the code. It's in launchPurchaseFlow() method. I'm not sure that I did something good by changing the code it looked like needed. Hope it helps.
try {
logDebug("Constructing buy intent for " + sku);
Bundle buyIntentBundle = mService.getBuyIntent(3, mContext.getPackageName(), sku, ITEM_TYPE_INAPP, extraData);
int response = getResponseCodeFromBundle(buyIntentBundle);
if (response != BILLING_RESPONSE_RESULT_OK) {
logError("Unable to buy item, Error response: " + getResponseDesc(response));
result = new IabResult(response, "Unable to buy item");
if (listener != null) listener.onIabPurchaseFinished(result, null);
/* Finish Current Async Task*/
flagEndAsync();
} else {
PendingIntent pendingIntent = buyIntentBundle.getParcelable(RESPONSE_BUY_INTENT);
logDebug("Launching buy intent for " + sku + ". Request code: " + requestCode);
mRequestCode = requestCode;
mPurchaseListener = listener;
act.startIntentSenderForResult(pendingIntent.getIntentSender(),
requestCode, new Intent(),
Integer.valueOf(0), Integer.valueOf(0),
Integer.valueOf(0));
}

Listen to all html video events

Playing around with html5 video and was wondering if there was a way to list its events as it happens.
I have one for ended - myVideo.addEventListener('ended',videoEnded,false);
Which works fine but how can i create a a listener which will listen to every event and name them?
myVideo.addEventListener('ALL',AddToLog,false);
function AddToLog(){
console.log(eventname);
}
Any pointers welcome.
Dan.
Subscribe to all <video> or <audio> events at once:
function addListenerMulti(el, s, fn) {
s.split(' ').forEach(e => el.addEventListener(e, fn, false));
}
var video = document.getElementById('myVideo');
addListenerMulti(video, 'abort canplay canplaythrough durationchange emptied encrypted ended error interruptbegin interruptend loadeddata loadedmetadata loadstart mozaudioavailable pause play playing progress ratechange seeked seeking stalled suspend timeupdate volumechange waiting', function(e){
console.log(e.type);
});
It's also a good idea to study media events list from the specification.
Multiple events listener credits go to #RobG's solution.
You can't. You need to listen to specific events.
You can find a list of possibly available events from the specification

Pusher App Client Events

I'm writing a multiplayer chess game, and using Pusher for the websocket server part.
Anyways, if I have a list of users, and I select any one of them and challenge them, how do I send challenge to just that one user? I know I would use the client event like:
channel.trigger("client-challenge_member1", {some : "data"});
But this event would have to have already been created I think. So do I create this event dynamically after each member subscribes? as possibly in:
channel.bind("pusher:subscribed_completed", function(member) // not sure of correct syntax but...
{
channel.bind("client-challenge_" + member.memberID, function(data)
{
alert(data.Name + " is challenging you.");
});
});
I would think there'd be a overloaded method for trigger, like:
channel.trigger(eventName, data, memberID)
But I cannot see anything like this. Any ideas? Thanks.
I ran into this problem on my application. At this time Pusher does not provide methods for sending events to a specific user. I think the approach that you mentioned would work for your situation. For my application I had each user subscribe to a channel with their user id as the channel id, then I could send messages to a single user through that channel.
client = new Pusher(PUSHER_API_KEY);
channel = client.subscribe(user_id);
channel.bind('my_event',function(data){
//Do stuff
});
I talked this approach over with the pusher team and they assured me there was no real overhead in having the extra channels. The new Pusher() command is the code that creates a new socket connection so you don't have to worry about extra sockets per channel or anything like that. Hope this helps.
I'm from Pusher. As Braden says, you can easily make a channel per user. This is more efficient than having the user id in the event name which means you spam everyone with useless messages.
This is an area we want to improve on further, so thanks for the feedback.
If you're able to consider another service, Beaconpush has the ability to send messages to a specific user.
From their site:
POST /1.0.0/[API key]/users/[user]

Resources