Cannot make transition of my Youtube broadcast to live using Youtube API - youtube

Right now I'm trying to figure out what i'm doing wrong when making transition of my YT broadcast to live.
So I make the request and get the following response:
{
"code" : 403,
"errors" : [ {
"domain" : "youtube.liveBroadcast",
"message" : "Invalid transition",
"reason" : "invalidTransition",
"extendedHelp" : "https://developers.google.com/youtube/v3/live/docs/liveBroadcasts/transition#params"
} ],
"message" : "Invalid transition"
}
Of course i've read docs many times so I've monitored the LiveStream and was waiting for its "active" state (and my Broadcast has lifeCycleStatus="ready").
Error message doesn't explain real reason why cannot I do the transition.
And... of course I do not have access to logs of Youtube servers :)
What can you suggest?
How to find out where am I wrong?
So even if i've missed something, docs and error message do not help me to understand anything. So anyway it is kind of a "bug" for YT LiveStreaming API...

So a bit unclear rule is:
ensure you have broadcast and livestream created and ready.
and ensure that broadcast lifecycle status is not COMPLETE,
otherwise recreate broadcast
... so ensure that your broadcast lifecycle status is ready
bind broadcast to livestream
start publishing video to livestream
wait for livestream status active
transition to testing (yes, you have to do it instead of moving to live)
wait for broadcast lifeCycleStatus to become testing
transition to live
wait for broadcast lifeCycleStatus to become live
You cannot skip testing and cannot transition from complete to testing or ready.

You can leave 4-7 steps if:
the broadcast's monitor stream was disabled by setting the contentDetails.monitorStream.enableMonitorStream property to false when creating or updating that broadcast.

I meet the same question, finally I found the problem. After post command transiton to testing, the lifeCycleStatus is: liveStarting, we need to wait lifeCycleStatus to become testing. So we should get broadcast status.
here is my code:
liveStreamRequest = youtube.liveStreams()
.list("id,status")
.setId(liveBroadcast.getContentDetails()
.getBoundStreamId());
LiveStreamListResponse returnedList = liveStreamRequest.execute();
List<LiveStream> liveStreams = returnedList.getItems();
if (liveStreams != null && liveStreams.size() > 0) {
LiveStream liveStream = liveStreams.get(0);
if (liveStream != null)
while (!liveStream.getStatus().getStreamStatus()
.equals("active")) {
Thread.sleep(1000);
returnedList = liveStreamRequest.execute();
liveStreams = returnedList.getItems();
liveStream = liveStreams.get(0);
}
}
hope to help someone care about this problem!

Related

Python script end Youtube live stream

i have an AJA HELO media streaming device and from time to time it stops streaming. What i want to do it automate some kind of streaming reset. I am able to issue command to the AJA to stop and start streaming, but i need help figuring out how to "End Stream" on my current Youtube Live stream. Just doing so on the AJA does nothing since Youtube still thinks the stream will be back shortly.
Does anyone know of a way to achieve this?
P.S. i am able to retrieve the exact stream identifier via a Python script, as i am monitoring the state in an NMS.
Thanks
I'm not sure if this is directly related, but to end a livestream using the Python google-api-python-client library:
youtube = build("youtube", "v3", credentials = [YOUR CREDENTIALS])
request = youtube.liveBroadcasts().transition(
part = 'snippet',
id = [VIDEO ID OF THE LIVESTREAM],
broadcastStatus = 'complete'
#Setting the 'broadcastStatus' to 'complete' ends the stream
)
response = request.execute()
You can find more details about this in the docs here (including POST): https://developers.google.com/youtube/v3/live/docs/liveBroadcasts/transition

Twilio Target Worker Expression--blocking voice calls while on a text

I've read the documentation here: https://www.twilio.com/docs/taskrouter/multitasking#preventing-a-worker-from-receiving-chat-tasks-if-on-a-voice-task on how to block an agent from getting chats while they are on a voice call, but I want to do the reverse with a twist.
I successfully managed to stop workers from getting a voice call while they have an active chat going using "worker.channel.chat.assigned_tasks == 0" as the Expression. However, it also prevents a second chat, SMS, Facebook, or WhatsApp message coming in even though the worker's capacity is higher than 1.
Would love suggestions on what the expression should be so that the additional SMS or chats can come through up to the worker's capacity but not any voice calls when they have an active chat or SMS going.
The following filter should do the trick. The expression will only apply to voice tasks and the target routes to workers with no assigned chats.
{
"filter_friendly_name": "Do not assign Voice Tasks if assigned Chat",
"expression": "(task_channel_unique_name=='voice')",
"targets": [
{
"queue": <default queue sid>,
"expression": "worker.channel.chat.assigned_tasks == 0"
}
]
},

Zendesk Chat widget status check

I am using the Zendesk chat widget on my web portal. My requirement is whenever the widget goes down from server "Zendesk site" check the status and send notification to site owner.
On the research I found the $zopim.livechat.setOnStatus(callback); method. But the disadvantage of this gives only the offline and online status.
The "Status" that is checked with the callback function setOnStatus will only ever refer to the actual chat status rather than a technical health check status.
It's a little clunky, but if you're expecting the widget to load, but it doesn't due to the service being down, you could do a manual check after a given time, and have a reporting callback (Dummy function your_error_callback):
// Check Zopim (Zendesk Chat) status after 10 seconds
var ZopimHealthCheck = setInterval(function () {
if (window.$zopim === undefined || window.$zopim.livechat === undefined) {
your_error_callback("Zendesk Chat not available");
}
clearInterval(ZopimHealthCheck);
}, 10000);

How do you "resolve" a GKTurnBasedExchange?

I'm using a GKTurnBasedExchange to send data one way. It's a notification to the other players as certain triggers happen. However, the other players may not even be in the game at that time. The turns have 48 hour timeouts, so in theory if player1 sends said exchange, player3 might not pick it up for a couple of days. That's fine, player 1 doesn't require or expect any response.
But, when player1 tries to save the match data, end the turn or quit the match, I get an error:
Error Domain=GKErrorDomain Code=3 "The requested operation could not
be completed due to an error communicating with the server."
UserInfo=0x19317970 {GKServerStatusCode=5134,
NSUnderlyingError=0x16f15db0 "The operation couldn’t be completed.
status = 5134, Invalid operation for this session because the exchange
was not resolved. All exchanges must be resolved before the current
player can complete this operation.
OK, the bolded text seems pretty self-explanatory except for one little detail: I can't find any reference anywhere to what constitutes a "resolved" exchange. I don't expect a response back to this message. Even if I did, it could take days to receive it. The only option I can see is for the sender to cancel the exchange, which defeats the purpose of sending the exchange in the first place
So, how exactly does one finalize an exchange? What series of steps, besides canceling the exchange, will satisfy game center that the exchange has been "resolved?"
I'm just using:
[theMatch sendExchangeToParticipants:exchangeParticipants
data:exchangeData
localizableMessageKey:#"F1"
arguments:nil
timeout:600
completionHandler:^(GKTurnBasedExchange *exchange, NSError *error)
{
if (error)
{
VLOG(LOWLOG, #"%#", [error description]);
}
}
];
Followed by:
[theMatch saveCurrentTurnWithMatchData:dataCopy completionHandler:^(NSError *error)
{
if (error)
{
VLOG(LOWLOG, #"%#", [error description])
}
}];
The saveCurrentTurnWithMatchData call returns the aforementioned error.
Thanks!
I think I figured this out. Man oh man it's a slog making sense of Apple's documentation.
In the end I didn't make sense of it actually: this is the result of brute force trial and error.
So here's the deal: you can do a lot of things with exchanges, but to actually resolve them you have to call:
saveMergedMatch(matchData: Data, withResolvedExchanges: [GKTurnBasedExchange], completionHandler: ((Error?) -> Void))
There are several catches though.
Only the match's currentParticipant (the player who's turn it is) can call saveMergedMatch successflly.
It will only work for exchanges that are not in .active status.
There are only two ways, as far as I can tell, to programmatically get an exchange out of .active status.
The harder way: all recipients of the exchange have to act on the exchange--itself a murky process, can't help there. If all recipients do respond to it, Game Center itself will handle changing the status of the exchange, I think. Not sure though, because I don't do this. [The only help I can give here is that if you give an exchange a really short timeout when you send it, after the timeout passes Game Center will adjust the exchange's status automatically, and your recipients won't have to do anything.]
The not-much-easier way: the sender and only the sender of the exchange can cancel it, by calling the exchange's method cancel(withLocalizableMessageKey key: String, arguments: [String], completionHandler: ((Error?) -> Void)? = nil). The saving grace of this way is that it doesn't have to be the sender's turn for them to cancel it. This is one of the few times that the current turn-taker doesn't matter. Unfortunately this also has a catch: the exchange can't be cancelled if anyone has already responded to it.
So the upshot is that there is no way for any single player to be guaranteed to be able to resolve an exchange, for two reasons:
The process that moves active exchanges into completed exchanges is only programmatically accessable for the purpose of cancelling the exchange, and only by the player that originated it, and only if no one has responded yet.
The actual process that turns completed exchanges into resolved exchanges can only be triggered by the player in the match's currentParticipant property.
Personally, I can work with this, now that I understand it (I hope) , but without doubt it is quite a pain.
Well, turns out exchanges can't be used. Yet another limitation in Game Kit. For anyone that comes across this thread, I found WWDC 2013 session 506 says:
All participants have to respond for game center to mark the exchange as "completed"
You have to call:
[match saveMergedMatchData:dataCopy
withResolvedExchanges:match.completedExchanges
completionHandler:...];
So, you can't use exchanges for 1-way communications. There has to be a response (or wait for a timeout).
I guess I'll answer to the unasked question of: how to send 1-way communications With notifications.
I think the best API for that is setLocalizableMessageWithKey(key:arguments:) or sendReminderToParticipants(localizableMessageKey:arguments:completionHandler:) on your GKTurnBasedMatch instance.

GCKMediaControlChannel returning an invalid request id on loadMedia: (kGCKInvalidRequestID)

Our app uses the GCKMediaControlChannel control media playback on the receiver.
The initial media load request is honored, the media plays to completion - however any subsequent request to load media ends in an error with the loadMedia: method returning kGCKInvalidRequestID
NSInteger requestId = [self loadMedia:mediaInformation autoplay:autoplay playPosition:0];
if (requestId == kGCKInvalidRequestID) {
WARN(#"WARN loadMedia: the message could not be sent");
return NO ; // All subsequent requests go here
} else {
return YES ; // The first request to load media goes here
}
This looks like a situation where the GCKMediaControlChannel control channel might be out sync? We looked closely at the state of the Media Channel on the sender side and everything looks in order, with the sender acknowledging an "IDLE" status after the first media completes playback.
Not sure where else to look, the doc simply says of the loadMedia: method return value:
The request ID, or kGCKInvalidRequestID if the message could not be sent.
Any clues as to what could possibly cause a kGCKInvalidRequestID to be returned by loadMedia:?
At least in my case, a conflict with the player state is what caused the GCKMediaControlChannel to return kGCKInvalidRequestID.
Unfortunately I can't remember the exact details, but I know that after going through the first media, the player was in a state not compatible with loading a new media, hence the error.
In other words, the issue had nothing to do with the state of the GCKMediaControlChannel, and everything to do with the state of the cast.receiver.MediaManager in the receiver.
Hope that helps someone!

Resources