Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
edx-platform
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
OpenEdx
edx-platform
Commits
467e7ece
Commit
467e7ece
authored
Sep 26, 2017
by
Clinton Blackburn
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fixup! WIP: Added Chromecast support to video XModule
parent
8267597b
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
227 additions
and
40 deletions
+227
-40
common/lib/xmodule/xmodule/js/src/video/02_html5_video.js
+225
-0
lms/templates/video.html
+2
-40
No files found.
common/lib/xmodule/xmodule/js/src/video/02_html5_video.js
View file @
467e7ece
...
...
@@ -330,6 +330,231 @@ function(_) {
// Place the <video> element on the page.
this
.
videoEl
.
appendTo
(
el
.
find
(
'.video-player > div:first-child'
));
// $.getScript('https://www.gstatic.com/cv/js/sender/v1/cast_sender.js?loadCastFramework=1');
window
[
'__onGCastApiAvailable'
]
=
this
.
onGCastApiAvailable
.
bind
(
this
);
};
Player
.
prototype
.
onGCastApiAvailable
=
function
(
isAvailable
)
{
debugger
;
if
(
isAvailable
)
{
cast
.
framework
.
CastContext
.
getInstance
().
setOptions
({
receiverApplicationId
:
chrome
.
cast
.
media
.
DEFAULT_MEDIA_RECEIVER_APP_ID
,
autoJoinPolicy
:
chrome
.
cast
.
AutoJoinPolicy
.
ORIGIN_SCOPED
});
this
.
remotePlayer
=
new
cast
.
framework
.
RemotePlayer
();
this
.
remotePlayerController
=
new
cast
.
framework
.
RemotePlayerController
(
this
.
remotePlayer
);
this
.
remotePlayerController
.
addEventListener
(
cast
.
framework
.
RemotePlayerEventType
.
IS_CONNECTED_CHANGED
,
this
.
switchPlayer
.
bind
(
this
)
);
}
};
Player
.
prototype
.
switchPlayer
=
function
()
{
// this.stopProgressTimer();
// this.resetVolumeSlider();
// this.playerHandler.stop();
// this.playerState = PLAYER_STATE.IDLE;
if
(
cast
&&
cast
.
framework
)
{
if
(
this
.
remotePlayer
.
isConnected
)
{
this
.
setupRemotePlayer
();
return
;
}
}
this
.
setupLocalPlayer
();
};
/**
* Makes human-readable message from chrome.cast.Error
* @param {chrome.cast.Error} error
* @return {string} error message
*/
Player
.
getErrorMessage
=
function
(
error
)
{
switch
(
error
.
code
)
{
case
chrome
.
cast
.
ErrorCode
.
API_NOT_INITIALIZED
:
return
'The API is not initialized.'
+
(
error
.
description
?
' :'
+
error
.
description
:
''
);
case
chrome
.
cast
.
ErrorCode
.
CANCEL
:
return
'The operation was canceled by the user'
+
(
error
.
description
?
' :'
+
error
.
description
:
''
);
case
chrome
.
cast
.
ErrorCode
.
CHANNEL_ERROR
:
return
'A channel to the receiver is not available.'
+
(
error
.
description
?
' :'
+
error
.
description
:
''
);
case
chrome
.
cast
.
ErrorCode
.
EXTENSION_MISSING
:
return
'The Cast extension is not available.'
+
(
error
.
description
?
' :'
+
error
.
description
:
''
);
case
chrome
.
cast
.
ErrorCode
.
INVALID_PARAMETER
:
return
'The parameters to the operation were not valid.'
+
(
error
.
description
?
' :'
+
error
.
description
:
''
);
case
chrome
.
cast
.
ErrorCode
.
RECEIVER_UNAVAILABLE
:
return
'No receiver was compatible with the session request.'
+
(
error
.
description
?
' :'
+
error
.
description
:
''
);
case
chrome
.
cast
.
ErrorCode
.
SESSION_ERROR
:
return
'A session could not be created, or a session was invalid.'
+
(
error
.
description
?
' :'
+
error
.
description
:
''
);
case
chrome
.
cast
.
ErrorCode
.
TIMEOUT
:
return
'The operation timed out.'
+
(
error
.
description
?
' :'
+
error
.
description
:
''
);
}
};
Player
.
prototype
.
setupRemotePlayer
=
function
()
{
var
castSession
=
cast
.
framework
.
CastContext
.
getInstance
().
getCurrentSession
();
// Add event listeners for player changes which may occur outside sender app
this
.
remotePlayerController
.
addEventListener
(
cast
.
framework
.
RemotePlayerEventType
.
IS_PAUSED_CHANGED
,
function
()
{
if
(
this
.
remotePlayer
.
isPaused
)
{
this
.
onPause
();
}
else
{
this
.
onPlay
();
}
}.
bind
(
this
)
);
// this.remotePlayerController.addEventListener(
// cast.framework.RemotePlayerEventType.IS_MUTED_CHANGED,
// function () {
// if (this.remotePlayer.isMuted) {
// this.playerHandler.mute();
// } else {
// this.playerHandler.unMute();
// }
// }.bind(this)
// );
//
// this.remotePlayerController.addEventListener(
// cast.framework.RemotePlayerEventType.VOLUME_LEVEL_CHANGED,
// function () {
// var newVolume = this.remotePlayer.volumeLevel * FULL_VOLUME_HEIGHT;
// var p = document.getElementById('audio_bg_level');
// p.style.height = newVolume + 'px';
// p.style.marginTop = -newVolume + 'px';
// }.bind(this)
// );
// This object will implement PlayerHandler callbacks with
// remotePlayerController, and makes necessary UI updates specific
// to remote playback
var
playerTarget
=
{};
playerTarget
.
play
=
function
()
{
if
(
this
.
remotePlayer
.
isPaused
)
{
this
.
remotePlayerController
.
playOrPause
();
}
var
vi
=
document
.
getElementById
(
'video_image'
);
vi
.
style
.
display
=
'block'
;
var
localPlayer
=
document
.
getElementById
(
'video_element'
);
localPlayer
.
style
.
display
=
'none'
;
}.
bind
(
this
);
playerTarget
.
pause
=
function
()
{
if
(
!
this
.
remotePlayer
.
isPaused
)
{
this
.
remotePlayerController
.
playOrPause
();
}
}.
bind
(
this
);
playerTarget
.
stop
=
function
()
{
this
.
remotePlayerController
.
stop
();
}.
bind
(
this
);
playerTarget
.
load
=
function
(
mediaIndex
)
{
console
.
log
(
'Loading...'
+
this
.
mediaContents
[
mediaIndex
][
'title'
]);
var
mediaInfo
=
new
chrome
.
cast
.
media
.
MediaInfo
(
this
.
config
.
videoSources
[
0
],
'video/mp4'
);
mediaInfo
.
metadata
=
new
chrome
.
cast
.
media
.
GenericMediaMetadata
();
mediaInfo
.
metadata
.
metadataType
=
chrome
.
cast
.
media
.
MetadataType
.
GENERIC
;
// mediaInfo.metadata.title = this.mediaContents[mediaIndex]['title'];
// mediaInfo.metadata.images = [
// {'url': MEDIA_SOURCE_ROOT + this.mediaContents[mediaIndex]['thumb']}];
var
request
=
new
chrome
.
cast
.
media
.
LoadRequest
(
mediaInfo
);
castSession
.
loadMedia
(
request
).
then
(
this
.
playerHandler
.
loaded
.
bind
(
this
.
playerHandler
),
function
(
errorCode
)
{
this
.
playerState
=
PLAYER_STATE
.
ERROR
;
console
.
log
(
'Remote media load error: '
+
Player
.
getErrorMessage
(
errorCode
));
}.
bind
(
this
));
}.
bind
(
this
);
playerTarget
.
getCurrentMediaTime
=
function
()
{
return
this
.
remotePlayer
.
currentTime
;
}.
bind
(
this
);
playerTarget
.
getMediaDuration
=
function
()
{
return
this
.
remotePlayer
.
duration
;
}.
bind
(
this
);
playerTarget
.
updateDisplayMessage
=
function
()
{
document
.
getElementById
(
'playerstate'
).
style
.
display
=
'block'
;
document
.
getElementById
(
'playerstatebg'
).
style
.
display
=
'block'
;
document
.
getElementById
(
'video_image_overlay'
).
style
.
display
=
'block'
;
document
.
getElementById
(
'playerstate'
).
innerHTML
=
this
.
mediaContents
[
this
.
currentMediaIndex
][
'title'
]
+
' '
+
this
.
playerState
+
' on '
+
castSession
.
getCastDevice
().
friendlyName
;
}.
bind
(
this
);
playerTarget
.
setVolume
=
function
(
volumeSliderPosition
)
{
// Add resistance to avoid loud volume
var
currentVolume
=
this
.
remotePlayer
.
volumeLevel
;
var
p
=
document
.
getElementById
(
'audio_bg_level'
);
if
(
volumeSliderPosition
<
FULL_VOLUME_HEIGHT
)
{
var
vScale
=
this
.
currentVolume
*
FULL_VOLUME_HEIGHT
;
if
(
volumeSliderPosition
>
vScale
)
{
volumeSliderPosition
=
vScale
+
(
pos
-
vScale
)
/
2
;
}
p
.
style
.
height
=
volumeSliderPosition
+
'px'
;
p
.
style
.
marginTop
=
-
volumeSliderPosition
+
'px'
;
currentVolume
=
volumeSliderPosition
/
FULL_VOLUME_HEIGHT
;
}
else
{
currentVolume
=
1
;
}
this
.
remotePlayer
.
volumeLevel
=
currentVolume
;
this
.
remotePlayerController
.
setVolumeLevel
();
}.
bind
(
this
);
playerTarget
.
mute
=
function
()
{
if
(
!
this
.
remotePlayer
.
isMuted
)
{
this
.
remotePlayerController
.
muteOrUnmute
();
}
}.
bind
(
this
);
playerTarget
.
unMute
=
function
()
{
if
(
this
.
remotePlayer
.
isMuted
)
{
this
.
remotePlayerController
.
muteOrUnmute
();
}
}.
bind
(
this
);
playerTarget
.
isMuted
=
function
()
{
return
this
.
remotePlayer
.
isMuted
;
}.
bind
(
this
);
playerTarget
.
seekTo
=
function
(
time
)
{
this
.
remotePlayer
.
currentTime
=
time
;
this
.
remotePlayerController
.
seek
();
}.
bind
(
this
);
this
.
playerHandler
.
setTarget
(
playerTarget
);
// Setup remote player volume right on setup
// The remote player may have had a volume set from previous playback
if
(
this
.
remotePlayer
.
isMuted
)
{
this
.
playerHandler
.
mute
();
}
var
currentVolume
=
this
.
remotePlayer
.
volumeLevel
*
FULL_VOLUME_HEIGHT
;
var
p
=
document
.
getElementById
(
'audio_bg_level'
);
p
.
style
.
height
=
currentVolume
+
'px'
;
p
.
style
.
marginTop
=
-
currentVolume
+
'px'
;
this
.
hideFullscreenButton
();
this
.
playerHandler
.
play
();
};
return
Player
;
...
...
lms/templates/video.html
View file @
467e7ece
...
...
@@ -17,6 +17,8 @@ from openedx.core.djangolib.js_utils import js_escaped_string
tabindex=
"-1"
>
<div
class=
"focus_grabber first"
></div>
<!-- TODO Integrate into video player UI -->
<script
type=
"text/javascript"
src=
"https://www.gstatic.com/cv/js/sender/v1/cast_sender.js?loadCastFramework=1"
></script>
<button
is=
"google-cast-button"
></button>
<div
class=
"tc-wrapper"
>
<div
class=
"video-wrapper"
>
...
...
@@ -87,46 +89,6 @@ from openedx.core.djangolib.js_utils import js_escaped_string
% endif
</div>
<!-- BEGIN Chromecast -->
<script
type=
"text/javascript"
src=
"https://www.gstatic.com/cv/js/sender/v1/cast_sender.js?loadCastFramework=1"
></script>
<script>
window
[
'__onGCastApiAvailable'
]
=
function
(
isAvailable
)
{
initializeCastApi
=
function
()
{
cast
.
framework
.
CastContext
.
getInstance
().
setOptions
({
receiverApplicationId
:
chrome
.
cast
.
media
.
DEFAULT_MEDIA_RECEIVER_APP_ID
,
autoJoinPolicy
:
chrome
.
cast
.
AutoJoinPolicy
.
ORIGIN_SCOPED
});
};
if
(
isAvailable
)
{
initializeCastApi
();
$
(
'button.video_control.play'
).
on
(
'click'
,
function
()
{
var
castSession
=
cast
.
framework
.
CastContext
.
getInstance
().
getCurrentSession
();
var
mediaInfo
=
new
chrome
.
cast
.
media
.
MediaInfo
(
'https://d2f1egay8yehza.cloudfront.net/BERGG101/BERGG101T314-V011300_DTH.mp4'
,
'video/mp4t'
);
var
request
=
new
chrome
.
cast
.
media
.
LoadRequest
(
mediaInfo
);
castSession
.
loadMedia
(
request
).
then
(
function
()
{
console
.
log
(
'Load succeed'
);
},
function
(
errorCode
)
{
console
.
log
(
'Error code: '
+
errorCode
);
});
});
/*var castSession = cast.framework.CastContext.getInstance().getCurrentSession();
var mediaInfo = new chrome.cast.media.MediaInfo('CCxmtcICYNc', 'yt');
var request = new chrome.cast.media.LoadRequest(mediaInfo);
castSession.loadMedia(request).then(
function () {
console.log('Load succeed');
},
function (errorCode) {
console.log('Error code: ' + errorCode);
});*/
}
};
</script>
<!-- END Chromecast -->
% if cdn_eval:
<script>
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment