ytplayer api event when reaching a position in a video? - youtube

Is there a way to cause an event when a video reaches a specific time? I want to get to a callback function at the time when the video has reached to a certain time, and the time it takes for the video to reach that time is unpredictable, since the user can skip part of the video, or buffering might take some time before the video resumes, or something like that, so simply setting a timed event wont work because the video might reach specific time earlier.
I can query the time of the video, but what I want is to get a callback when the video has reached a certain time. Is there a way to do this?

I'm not going to write the full code, but you should set up an interval, like this:
var time = 70; // Time in seconds, e.g. this one is one minute and 10 seconds
var reached = false;
var interval = setInterval(function(){
if(player.getCurrentTime() >= time && !reached) {
clearInterval(interval);
reached = true;
timeReached();
}
},1000);
function timeReached() {
// Do what you have to
}

You can use this Javascript wrapper for the YouTube player API.
The API provides very simple event handling. E.g:
youtubePlayer.at('5000', function() {
alert("You're five seconds into this Youtube clip");
});

use player.getCurrentTime()!
https://developers.google.com/youtube/iframe_api_reference#Playback_status

Related

Audio duration sometimes changes to near-zero in Safari

I am encountering a strange issue on Safari, both on MacOS and iOS. Initially it seemed like audio would sometimes just not play, but not emit any errors. After adding much logging I found that when when I call audio.play() the audio.duration property would accurately reflect the duration of the clip. The pause and then ended events will then almost immediately be emitted and, after that the duration for the same clip is suddenly somewhere between 0.001 and 0.003 seconds.
I am retaining a reference to the audio element and reusing it to play the same audio multiple times. It almost always works the first time, but after the first playthrough, on about 50% of subsequent plays the symptoms described above will present themselves.
The code where I play the audio is below:
// In the constructor for the class managing audio playback:
this.mediaElement.addEventListener('pause', e => {
console.log('Media paused', this.mediaElement.duration); // This shows the very short duration if the audio did not play
});
// In the function in the class that plays the media.
try {
await this.mediaElement.play();
console.log('Media is playing', this.mediaElement.duration); // This shows an accurate duration
this.state = Playable.state.PLAYING;
} catch(e) {
console.error('Playing media failed:', e);
if (e && e.name === 'NotAllowedError') {
ErrorHandler.playbackNotAllowed(e);
this.state = Playable.state.PAUSED;
return;
} else {
this._fail(e);
this._fakePlay();
}
}
As you can see, I'm not doing anything strange or complicated here. So far I haven't been able to figure out why the duration would change in this way only after playing the audio. Is this a known bug, or is there something I may be doing that could cause this behavior. The closest thing I can think of is that sometimes I will set the currentTime to 0 if I need to start playing the audio from the beginning, but that should not change the duration.

Get a callback from AKPlayer at a user specified time

I’m trying to get a callback at a given point in an AKPlayer’s file playback (currently, just before the end). I see the Apple docs on addBoundaryTimeObserver(), which would work, but it doesn’t seem to be accessible from AKPlayer (I guess an AVAudioPlayerNode vs AVPlayer thing). Any suggestions? I see a few callbacks in AVAudioPlayerNode… maybe I could determine the buffer based on the desired time and use dataConsumed?
The goal is to trigger another event just before the file finishes playing (there is a callback on completion, but obviously that's too late).
If anybody has done something similar, or knows of something similar (a gist, etc), that would be great.
There's an AudioKit playground called AKPlaygroundLoop that shows you how to call an arbitrary handler periodically, based on CADisplayLink. In your handler you could check the AKPlayer's currentTime and if it's close to the end (say 1 second before) you could trigger whatever event you want.
This is a rough outline:
var player: AKPlayer!
var loop: AKPlaygroundLoop!
func play() {
// ...
playgroundLoop = AKPlaygroundLoop(frequency: 10.0, handler: myHandler)
}
func myHandler() {
if player.currentTime >= player.duration - 1.0 {
// trigger some event
}
}
See also this answer for advice on how to synchronize events with AudioKit.

Youtube API on clicking a different times does BUFFERING (state=3) always occur?

I am using the Youtube API and was wondering if anyone knew if when you click the youtube player's time (at the bottom of the video) to progress/or go back to an earlier point in the video if the BUFFERING, or state=3 value always occur?
For example:
function onPlayerStateChange(event) {
//video is buffering, one cause is the user
//clicked to progress/go back in the video.
//Does buffering state always happen in this case?
if (event.data == 3) {
//BUFFERING
}
}
It is intended to fire 3 (buffering) due to onStateChange when pressing play button or player's time. As stated here, event fires whenever the player's state changes. The data property of the event object that the API passes your evnt listener function will specifiy an integer that corresponds to the new player state. Below are the possible values:
-1 (unstarted)
0 (ended)
1 (playing)
2 (paused)
3 (buffering)
5 (video cued).

Web Audio API on iOS Safari do not play even after user interaction

I know that there is a limitation in iOS Safari where the audio is not playing until user triggers an interaction. So I have placed the code inside a touchstart event. But unfortunately, I have tried almost every combination, and I couldn't get it to play on iOS Safari.
Here are the things I have tried:
putting the audio load outside the touchstart callback
try adding a gain node
use 0.01 as the start time
and none of the above works in iOS Safari, but they can all play in desktop Chrome and Safari. Here is the link to the gist, you can see the versions where I made the changes (P.S. the click event is used for testing on desktop)
https://gist.github.com/angelathewebdev/32e0fbd817410db5dea1
Sounds play only when currentTime starts to run, but scheduling sounds exactly at currentTime doesn't seem to work. They need to be a little bit into the future (ex: 10ms). You can use the following createAudioContext function to wait until the context is ready to make noise. User action doesn't seem to be required on iPhone, but no such success on iPad just yet.
function createAudioContext(callback, errback) {
var ac = new webkitAudioContext();
ac.createGainNode(); // .. and discard it. This gets
// the clock running at some point.
var count = 0;
function wait() {
if (ac.currentTime === 0) {
// Not ready yet.
++count;
if (count > 600) {
errback('timeout');
} else {
setTimeout(wait, 100);
}
} else {
// Ready. Pass on the valid audio context.
callback(ac);
}
}
wait();
}
Subsequently, when playing a note, don't call .noteOn(ac.currentTime), but do .noteOn(ac.currentTime + 0.01) instead.

Get current duration of YouTube Live Event

Is there a way to get the current time of a the recorded stream when broadcasting to YouTube live? I want to be able to send an API request at certain points throughout a live stream to get the current minute/second of the stream. The end result I am trying to achieve is to be able to log a list of highlights. Essentially, a user presses a button and it gets the current time of the stream at that moment, then the user can add a note for what happened at that time. From reading all the docs though, I cannot find a way to get the current time of the recorded stream.
Looks like you can do this with the iFrame API's getDuration() method.
https://developers.google.com/youtube/iframe_api_reference#getDuration
Check out the special note for live events:
If the currently playing video is a live event, the getDuration() function will return the elapsed time since the live video stream began. Specifically, this is the amount of time that the video has streamed without being reset or interrupted. In addition, this duration is commonly longer than the actual event time since streaming may begin before the event's start time.
You didn't specify a language, so I'll post code examples in two different languages. Both utilize the iFrame API.
JavaScript:
window.onYouTubePlayerReady = function(playerId) {
window.ytplayer = document.getElementById("ytPlayer");
console.log(window.ytplayer.getDuration());
}
Objective-C (using YouTube's youtube-ios-player-helper class)
#property (weak, nonatomic) IBOutlet YTPlayerView *playerView;
// ...
- (void)viewDidLoad {
[super viewDidLoad];
[[self.playerView loadWithVideoId:#"iGTIK_8ydoI"] // live at the time answer was posted
}
// ...
- (void)getDurationOfPlayingVideo {
NSLog(#"duration: %d", [self.playerView duration]);
}
Just as a disclaimer from my personal testing: the Live Streaming API is extraordinary temperamental and unstable, and I've found that some Live Events return a duration of 0.
this is old but you can get the liveStreamingDetails.actualStartTime through the youtube API.
With the actualStartTime in hands, you can calculate how much time elapsed.
"https://www.googleapis.com/youtube/v3/videos"
"?part=liveStreamingDetails"
"&id=$id&key=$_key"

Resources