Skip to content

Commit

Permalink
VID-656: Improve publishing interface
Browse files Browse the repository at this point in the history
  • Loading branch information
dthies committed Sep 6, 2023
1 parent c80781c commit 0732e81
Show file tree
Hide file tree
Showing 10 changed files with 154 additions and 66 deletions.
4 changes: 2 additions & 2 deletions mod_form.php
Original file line number Diff line number Diff line change
Expand Up @@ -261,10 +261,10 @@ public function validation($data, $files) {

if (!isset($data['vimeo_url']) || empty($data['vimeo_url'])) {
$fs = get_file_storage();
if (
if (empty($data['livefeed']) && (
empty($data['mediafile'])
|| !$files = $fs->get_area_files(context_user::instance($USER->id)->id, 'user', 'draft', $data['mediafile'])
) {
)) {
$errors['vimeo_url'] = get_string('required');
}
} else if (!filter_var($data['vimeo_url'], FILTER_VALIDATE_URL)) {
Expand Down
2 changes: 1 addition & 1 deletion plugin/live/amd/build/videotime.min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion plugin/live/amd/build/videotime.min.js.map

Large diffs are not rendered by default.

115 changes: 94 additions & 21 deletions plugin/live/amd/src/videotime.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ class Publish extends PublishBase {
* Stop video feed
*/
unpublish() {
document.querySelectorAll('#video-controls-camera, #video-controls-display').forEach(video => {
video.srcObject = null;
video.parentNode.classList.add('hidden');
});
return Ajax.call([{
args: {
id: Number(this.feed),
Expand Down Expand Up @@ -91,7 +95,7 @@ class Publish extends PublishBase {
].forEach(videoInput => {
videoInput.then(videoStream => {
if (videoStream) {
videoStream.getVideoTracks().forEach(track => {
videoStream.getTracks().forEach(track => {
track.enabled = false;
track.stop();
});
Expand Down Expand Up @@ -119,14 +123,15 @@ class Publish extends PublishBase {
handleClick(e) {
const button = e.target.closest(
'[data-contextid="' + this.contextid + '"][data-action="publish"], [data-contextid="'
+ this.contextid + '"][data-action="close"], [data-contextid="'
+ this.contextid + '"][data-action="mute"], [data-contextid="'
+ this.contextid + '"][data-action="unmute"], [data-contextid="'
+ this.contextid + '"][data-action="switch"], [data-contextid="'
+ this.contextid + '"][data-action="unpublish"]'
);
if (button) {
const action = button.getAttribute('data-action'),
type = button.getAttribute('data-type') || 'camera',
transceiver = this.getTransceiver('audio');
type = button.getAttribute('data-type') || 'camera';
e.stopPropagation();
e.preventDefault();
document.querySelectorAll(
Expand All @@ -137,15 +142,24 @@ class Publish extends PublishBase {
}
});
switch (action) {
case 'mute':
if (transceiver) {
transceiver.sender.track.enabled = false;
case 'close':
document.getElementById('video-controls-' + type).srcObject = null;
document.getElementById('video-controls-' + type).parentNode.classList.add('hidden');
if (this.tracks[this.selectedTrack.id] == type) {
this.unpublish();
}
break;
case 'mute':
case 'unmute':
if (transceiver) {
transceiver.sender.track.enabled = true;
}
((type == 'display') ? this.currentDisplay : this.currentCamera)
.then(videoStream => {
if (videoStream) {
videoStream.getAudioTracks().forEach(track => {
track.enabled = (action == 'unmute');
});
}
return videoStream;
}).catch(Notification.exception);
break;
case 'publish':
Log.debug(type);
Expand All @@ -154,9 +168,43 @@ class Publish extends PublishBase {
} else {
this.shareCamera();
}
document.querySelectorAll('#video-controls-camera, #video-controls-display').forEach(video => {
video.parentNode.classList.remove('selected');
});
document
.getElementById('video-controls-' + type)
.parentNode
.classList
.remove('hidden');
document
.getElementById('video-controls-' + type)
.parentNode
.classList
.add('selected');

this.processStream([]);
break;
case 'switch':
document.querySelectorAll('#video-controls-camera, #video-controls-display').forEach(video => {
video.parentNode.classList.remove('selected');
});
if (type == 'display') {
this.videoInput = this.currentDisplay;
} else {
this.videoInput = this.currentCamera;
}
document
.getElementById('video-controls-' + type)
.parentNode
.classList
.remove('hidden');
document
.getElementById('video-controls-' + type)
.parentNode
.classList
.add('selected');
this.processStream([]);
break;
case 'unpublish':
this.unpublish();
}
Expand Down Expand Up @@ -262,8 +310,14 @@ class Publish extends PublishBase {
videotransceiver = this.getTransceiver('video');
videoStream.getVideoTracks().forEach(track => {
track.addEventListener('ended', () => {
if (this.selectedTrack != track.id) {
if (this.selectedTrack.id == track.id) {
this.unpublish();
} else {
document
.getElementById('video-controls-' + this.tracks[track.id])
.parentNode
.classList
.add('hidden');
}
});
this.selectedTrack = track;
Expand All @@ -286,12 +340,10 @@ class Publish extends PublishBase {
});
});
videoStream.getAudioTracks().forEach(track => {
track.addEventListener('ended', () => {
if (this.selectedTrack != track.id) {
this.unpublish();
}
});
if (document.querySelector('.hidden[data-action="mute"][data-contextid="' + this.contextid + '"]')) {
if (
document.querySelector('.hidden[data-action="mute"][data-contextid="' + this.contextid + '"][data-type="'
+ this.tracks[this.selectedTrack.id] + '"]'
)) {
track.enabled = false;
}

Expand Down Expand Up @@ -462,17 +514,26 @@ export default class VideoTime extends VideoTimeBase {
}
Log.debug('[data-contextid="' + this.contextid + '"] img.poster-img');
if (Number(source)) {
document.querySelectorAll('[data-contextid="' + this.contextid + '"] img.poster-img').forEach(img => {
document.querySelectorAll(
'[data-contextid="' + this.contextid + '"] .videotime-embed img.poster-img'
).forEach(img => {
img.classList.add('hidden');
});
document.querySelectorAll('[data-contextid="' + this.contextid + '"] video').forEach(video => {
document.querySelectorAll(
'[data-contextid="' + this.contextid + '"] .videotime-embed video'
).forEach(video => {
video.classList.remove('hidden');
});
} else {
document.querySelectorAll('[data-contextid="' + this.contextid + '"] img.poster-img').forEach(img => {
document.querySelectorAll(
'[data-contextid="' + this.contextid + '"] .videotime-embed img.poster-img'
).forEach(img => {
img.classList.remove('hidden');
});
document.querySelectorAll('[data-contextid="' + this.contextid + '"] video').forEach(video => {
document.querySelectorAll(
'[data-contextid="' + this.contextid + '"] .videotime-embed video'
).forEach(video => {
video.srcObject = null;
video.classList.add('hidden');
});
}
Expand All @@ -487,7 +548,7 @@ export default class VideoTime extends VideoTimeBase {
this.subscribeTo(source);
}, 500);
} else if (source) {
this.remoteFeed = new Subscribe(this.contextid, this.iceservers, this.roomid, this.server, this.peerid, source);
this.remoteFeed = new Subscribe(this.contextid, this.iceservers, this.roomid, this.server, this.peerid);
this.remoteFeed.remoteVideo = document.getElementById(this.elementId);
this.remoteFeed.remoteAudio = document.getElementById(this.elementId).parentNode.querySelector('audio');
this.remoteFeed.muteAudio = room.publish && (room.publish.feed === source);
Expand All @@ -505,6 +566,8 @@ export default class VideoTime extends VideoTimeBase {
const handleClick = function(e) {
const button = e.target.closest(
'[data-roomid] [data-action="publish"], [data-roomid] [data-action="unpublish"],'
+ '[data-roomid] [data-action="close"], '
+ '[data-roomid] [data-action="switch"], '
+ '[data-roomid] [data-action="mute"], [data-roomid] [data-action="unmute"]'
);
if (button) {
Expand All @@ -526,6 +589,16 @@ const handleClick = function(e) {
room.publish.shareCamera();
}
room.publish.startConnection();
document
.getElementById('video-controls-' + (type || 'camera'))
.parentNode
.classList
.remove('hidden');
document
.getElementById('video-controls-' + (type || 'camera'))
.parentNode
.classList
.add('selected');
} else {
if ((action == 'mute') || (action == 'unmute')) {
button.classList.add('hidden');
Expand Down
6 changes: 0 additions & 6 deletions plugin/live/classes/external/publish_feed.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@

namespace videotimeplugin_live\external;

use block_deft\janus;
use videotimeplugin_live\socket;
use context;
use context_module;
Expand Down Expand Up @@ -84,11 +83,6 @@ public static function execute($id, $publish, $room): array {
require_capability('videotimeplugin/live:sharevideo', $context);
}

$janus = new janus($session);
$janusroom = new janus_room($record->itemid);

$token = $janusroom->get_token();

$data = json_decode($record->data) ?? new stdClass();
if (!$publish && !empty($data->feed) && $data->feed == $id) {
$data->feed = 0;
Expand Down
21 changes: 17 additions & 4 deletions plugin/live/classes/janus_room.php
Original file line number Diff line number Diff line change
Expand Up @@ -86,11 +86,24 @@ public function __construct (int $id) {
$this->roomid = $record->roomid ?? 0;
$this->secret = $record->secret ?? '';
$this->server = $record->server ?? '';
$this->session = new janus();
$this->audiobridge = $this->session->attach('janus.plugin.audiobridge');
$this->textroom = $this->session->attach('janus.plugin.textroom');
$this->videoroom = $this->session->attach('janus.plugin.videoroom');

$this->init_room();
}

/**
* Check room availabity and create if necessary
*/
protected function init_room() {
$exists = [
'request' => 'exists',
'room' => $this->roomid,
];

$response = $this->videoroom_send($exists);
if (!$response->plugindata->data->exists) {
return $this->create_room();
}

$this->set_token();
}
}
3 changes: 3 additions & 0 deletions plugin/live/lang/en/videotimeplugin_live.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@

$string['deft:moderate'] = 'Moderate venue';
$string['deft:sharevideo'] = 'Share video';
$string['enabledeftvideo'] = 'The Video Time live player requires the
admin to install Deft response block and enable video bridging in the
site settings';
$string['livefeed'] = 'Live feed';
$string['livefeed_help'] = 'Live feed can be supplied by a teacher';
$string['mediafile_help'] = 'Upload an audio or video file to use';
Expand Down
16 changes: 12 additions & 4 deletions plugin/live/lib.php
Original file line number Diff line number Diff line change
Expand Up @@ -257,10 +257,18 @@ function videotimeplugin_live_setup_page($instance, $cm) {
$bc = new block_contents();
$bc->title = get_string('sharedvideo', 'videotimeplugin_live');
$bc->attributes['class'] = 'block block_book_toc';
$bc->content = $OUTPUT->render_from_template('videotimeplugin_live/controls', [
'contextid' => $context->id,
'instance' => $instance,
]);
if (get_config('block_deft', 'enablevideo')) {
$bc->content = $OUTPUT->render_from_template('videotimeplugin_live/controls', [
'contextid' => $context->id,
'instance' => $instance,
'types' => [
['type' => 'camera'],
['type' => 'display'],
],
]);
} else {
$bc->content = get_string('enabledeftvideo', 'videotimeplugin_live');
}

$defaultregion = $PAGE->blocks->get_default_region();
$PAGE->blocks->add_fake_block($bc, $defaultregion);
Expand Down
15 changes: 7 additions & 8 deletions plugin/live/styles.css
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
.videotime-embed .vjs-layout-tiny,
.videotime-embed .vjs-layout-x-small,
.videotime-embed .vjs-layout-large,
.videotime-embed .vjs-layout-small,
.videotime-embed .vjs-layout-medium,
.videotime-embed .vjs-layout-x-large,
.videotime-embed .vjs-layout-huge {
width: 100%;
.videotime-local-stream .fa-toggle-on,
.videotime-local-stream .selected .fa-toggle-off {
display: none;
}

.videotime-local-stream .selected .fa-toggle-on {
display: inline;
}
36 changes: 17 additions & 19 deletions plugin/live/templates/controls.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -36,29 +36,28 @@

}}
{{# instance }}
<div {{^responsive}}class="vimeo-container justify-content-center"{{/responsive}} data-roomid="{{ roomid }}" data-contextid="{{ contextid }}">
<div class="">
{{# posterurl }}
<img src="{{ posterurl }}" class="poster-img w-100">
{{/ posterurl }}
<video class="w-100"
id="video-controls-camera"
autoplay
controls {{# playsinline }} playsinline {{/ playsinline }}
>
</video>
</div>
<div class="display">
{{# posterurl }}
<img src="{{ posterurl }}" class="poster-img w-100">
{{/ posterurl }}
<div class="videotime-local-stream justify-content-center" data-roomid="{{ roomid }}" data-contextid="{{ contextid }}">
{{# types }}
<div class="{{ type }} hidden position-relative">
<div class="bg-info mt-2 p-1">
<a href="#" class="card-link m-0 p-1" data-action="switch" data-type="{{ type }}" data-roomid="{{ roomid }}" data-contextid="{{ contextid }}" title="{{# str }} sharevideo, block_deft {{/ str }}">
<i class="icon fa fa-toggle-on bg-secondary rounded-circle m-0 p-2"></i>
<i class="icon fa fa-toggle-off bg-secondary rounded-circle m-0 p-2"></i>
</a>
<a href="#" class="card-link hidden m-0 p-1" data-action="mute" data-type="{{ type }}" data-roomid="{{ roomid }}" data-contextid="{{ contextid }}" title="{{# str }} mute, block_deft {{/ str }}"><i class="icon fa fa-microphone bg-secondary rounded-circle m-0 p-2"></i></a><a href="#" class="card-link m-0 p-1" data-action="unmute" data-type="{{ type }}" data-roomid="{{ roomid }}" data-contextid="{{ contextid }}" title="{{# str }} unmute, block_deft {{/ str }}"><i class="icon fa fa-microphone-slash bg-warning rounded-circle m-0 p-2"></i></a>
<a href="#" class="card-link m-0 p-1" data-action="close" data-type="{{ type }}" data-roomid="{{ roomid }}" data-contextid="{{ contextid }}" title="{{# str }} sharevideo, block_deft {{/ str }}">
<i class="icon fa fa-sign-out bg-secondary rounded-circle m-0 p-2"></i>
</a>
</div>
<video class="w-100"
id="video-controls-display"
id="video-controls-{{ type }}"
autoplay
controls {{# playsinline }} playsinline {{/ playsinline }}
{{# playsinline }} playsinline {{/ playsinline }}
<a href="#" class="card-link hidden m-0 p-1" data-action="mute" data-roomid="{{ roomid }}" data-contextid="{{ contextid }}" title="{{# str }} mute, block_deft {{/ str }}"><i class="icon fa fa-microphone bg-secondary rounded-circle m-0 p-2"></i></a><a href="#" class="card-link m-0 p-1" data-action="unmute" data-roomid="{{ roomid }}" data-contextid="{{ contextid }}" title="{{# str }} unmute, block_deft {{/ str }}"><i class="icon fa fa-microphone-slash bg-warning rounded-circle m-0 p-2"></i></a>
>
</video>
</div>
{{/ types }}
<div class="videotime-control hidden">
<div class="text-center">
<a href="#" class="card-link m-0 p-1" data-action="publish" data-roomid="{{ roomid }}" data-contextid="{{ contextid }}" title="{{# str }} sharevideo, block_deft {{/ str }}">
Expand All @@ -70,7 +69,6 @@
<a href="#" class="card-link m-0 p-1" data-action="publish" data-type="display" data-roomid="{{ roomid }}" data-contextid="{{ contextid }}" title="{{# str }} sharevideo, block_deft {{/ str }}">
<i class="icon fa fa-television bg-secondary rounded-circle m-0 p-2"></i>
</a>
<a href="#" class="card-link hidden m-0 p-1" data-action="mute" data-roomid="{{ roomid }}" data-contextid="{{ contextid }}" title="{{# str }} mute, block_deft {{/ str }}"><i class="icon fa fa-microphone bg-secondary rounded-circle m-0 p-2"></i></a><a href="#" class="card-link m-0 p-1" data-action="unmute" data-roomid="{{ roomid }}" data-contextid="{{ contextid }}" title="{{# str }} unmute, block_deft {{/ str }}"><i class="icon fa fa-microphone-slash bg-warning rounded-circle m-0 p-2"></i></a>
</div>
</div>
</div>
Expand Down

0 comments on commit 0732e81

Please sign in to comment.