This post is also available in: Russian
For media portals delivering lengthy video content (such as feature films), it may be relevant to remember when viewing was last interrupted to later offer to resume it. In this post, we’ll discuss several ways of doing it.
This task would be very simple, if playback has been always interrupted by pressing the player’s stop button. In reality, there is usually no stop button in an online player, and interruption may occur by several reasons:
- The user has left for another page
- The user has closed the player page
- The user’s browser has abnormally terminated,
- The user stayed on the player page, but the video failed to load by technical issues related to the server or user network connection.
Let’s now discuss in detail the features to save viewing position, so as to resume playback from the time of interruption.
DOM Events: onbeforeunload or onunload
Onbeforeunload and onunload events occur to the Window object. Onbeforeunload occurs prior to the onunload event, and onunload occurs when the user leaves the page. Here is an example of event handling:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <HTML> <head> <script> function closeIt() { return "Any string value here forces a dialog box to \n" + "appear before closing the window."; } window.onbeforeunload = closeIt; </script> </head> <body> </body> </html> |
Prior to closing the pages, we have a last chance to send the current position of the video to the server.
Downsides: not supported by all browsers (e.g., Opera). You have to use a synchronous AJAX-query, which is not applicable to all cases listed above.
Periodically send current position to the server
Also we can, at regular intervals during the video playback, send the current position to the server. Here is an example written in ActionScript:
1 2 3 4 5 | setTimeout(function () { if (video.playing) { sendPosition(video.position); } }, 5000); |
In addition, to increase accuracy, you can also send the current position on various events like pause, rewind or buffering.
A downside of this approach is the compromise between the accuracy of position saved and the server load generated by requests.
Analyze Flash Media Server log files
Adobe FMS maintains a detailed access.log for all events of video playback, including interruption for whatever reason. Here is an example of access.log entry:
1 2 3 4 5 6 | #Version: 1.0 #Start-Date: 2011-01-17 00:01:13 #Software: Adobe Flash Media Server 4.0.0 r1121 x64 #Date: 2011-01-17 #Fields: x-category x-event date time x-pid c-ip c-client-id cs-bytes c-referrer sc-bytes x-sname x-spos sc-stream-bytes x-file-size x-file-length x-trans-sname x-status x-comment stream stop 2011-01-17 11:03:57 16877 94.25.145.221 4702111234508538223 3567 http://www.example.com/player_test/fl_player.swf?sid=4r01p81fvvooj20bumhggevu12&uniqid=4ac11015f655b9335fe246a8ed24ae55&uid=136 1378700 8ca9dc3d48cab6e5f8a8d42844c5c91d 5990 1210365 343845829 5111.269043 - 210 - |
When analyzing the log file for the purposes of this article, we should first of all pay attention to the stream pause and stream stop events, containing a breakpoint. Also, the connection connect and disconnect events will help to separate previous browsing sessions from still running sessions. You can group log file rows related to a single session by various fields (note that the field combination must be unique for each session). In FMS, there is a special field for this c-client-id, but you should not rely on it completely, as its value can be identical for different sessions. To get a truly unique identifier, you can generate it on the client side and add it to the player URL.
The log also stores the type of event, playback position when the event occurred, and name of the content file. Any additional information not supported by FMS, can be sent to the log using the c-referrer field. This field contains the URL used to load the content player. Such information as user ID, session ID, and various attributes of paid content (price, tariff, etc.) can be encoded in the player URL string in any processable format. The simplest and most obvious option is to use the GET string format.
Benefits: the accurate position can be obtained for any interruption reason.
Downsides: The position in the logs is actually not linked to playback, but to the position in the player’s buffer, so it needs adjustment. The data is saved to the portal database at an offset needed to process the logs.
Use Web sockets
In case when neither Flash Media Server nor even Flash Player is used to play back videos, we can emulate FMS behavior, maintaining a constant connection to the server during video playback. This connection will be used to send the current position. In the event this connection is terminated, which is likely to occur when the user leaves the page, we can quite accurately determine the interruption position.
Here is an example of using Web sockets (Socket.io library).
1 2 3 4 | var socket = new io.Socket(); function playerSendEventCallback(position) { socket.send(position); } |
The server part:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | var http = require('http'), io = require('socket.io'), server = http.createServer(function(req, res){ res.writeHeader(200, {'Content-Type': 'text/html'}); res.writeBody('Hello world'); res.finish(); }); server.listen(80); var socket = io.listen(server); socket.on('connection', function(client){ client.on('message', function(message){ savePosition(message); }); client.on('disconnect', function(){ … }); }); function savePosition(position) { ... } |
Downside: The Web socket technology is quite new and not yet supported by all the common browser versions.
Заключение
There is no single ideal way to solve this problem, as every solution has its own substantial downsides. Therefore, in reality, to ensure the maximum quality of service, a mix of the above should be used.