-
Notifications
You must be signed in to change notification settings - Fork 11k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[NEW] Youtube Broadcasting #10127
Merged
Merged
[NEW] Youtube Broadcasting #10127
Changes from all commits
Commits
Show all changes
60 commits
Select commit
Hold shift + click to select a range
2b190f2
POC - YT oauth
gdelavald ff69f69
youtube auth
gdelavald 4e2e1e2
Merge remote-tracking branch 'origin/develop' into youtube-broadcast
ggazzo 3c2830e
Merge branch 'develop' of https://github.com/RocketChat/Rocket.Chat i…
gdelavald cfef679
livestream from broadcast tab
gdelavald 3b09839
Merge branch 'youtube-broadcast' of github.com:RocketChat/Rocket.Chat…
ggazzo 21f9932
almos done
ggazzo c78df8a
Kill ffmpeg process
gdelavald faa372b
change methods
ggazzo 50ee736
refactor
ggazzo 74698f5
undo problems
ggazzo ca1a858
refactoring some logs
gdelavald 7968d7a
Merge branch 'youtube-broadcast' of https://github.com/RocketChat/Roc…
gdelavald 6bc9f0d
tests
ggazzo 1450107
Merge branch 'youtube-broadcast' of github.com:RocketChat/Rocket.Chat…
ggazzo b32e214
Customize popout for streaming
gdelavald 0337941
actions buttons
ggazzo af2263b
stop media on destroy popout
gdelavald 6c7dfb3
Add transition steps
gdelavald a6f58a2
remove logs
gdelavald b86df53
fix errors
gdelavald 5d7dd43
fix
ggazzo 05a3354
Finishing UI and improvments to broadcast flow
gdelavald eebe4a5
Finishing UId improvments to broadcast flow
gdelavald 96d59cc
lint fix
gdelavald bb728a0
Merge branch 'youtube-broadcast' of https://github.com/RocketChat/Roc…
gdelavald 29acd17
update localhost urls for auth
gdelavald a67e449
update site url
gdelavald 8e70694
remove encoder and add media server url settings
gdelavald d7bd7df
Merge branch 'develop' of https://github.com/RocketChat/Rocket.Chat i…
gdelavald f606fec
Adds livestream notifier and clears tab when closing broadcast
gdelavald 4f8fdef
Merge branch 'develop' of https://github.com/RocketChat/Rocket.Chat i…
gdelavald 0003526
Adds configurable message when livestream is not available
gdelavald 1471263
Fix classes starting with -- and remove npm folder
gdelavald 0bbdbd9
Adds basic API for RoomAnnouncement
gdelavald 447d0c3
Adds Announcement to default lib
gdelavald e3bc802
Adds style
gdelavald f90e85f
Adds announcement styles and colors for warning/error
gdelavald debb021
Merge branch 'develop' of https://github.com/RocketChat/Rocket.Chat i…
gdelavald 8ba5dbd
Merge branch 'room-announcements' of https://github.com/RocketChat/Ro…
gdelavald b50f25f
Adds announcement when starting broadcast on room
gdelavald 82f7dd8
fixing lint errors
gdelavald 52d5d36
Remove unused deps and console.log
gdelavald 31ab23d
Merge branch 'develop' into youtube-broadcast
karlprieb b19df38
Merge branch 'develop' into youtube-broadcast
gdelavald 23f1a7e
Fixing deps (maybe)
gdelavald 9375aab
Merge branch 'develop' of https://github.com/RocketChat/Rocket.Chat i…
gdelavald eddcb66
update package-lock
gdelavald 1b17e42
Merge branch 'develop' of https://github.com/RocketChat/Rocket.Chat i…
gdelavald 911cd26
Fix gettting room announcement and route for livestream oauth callback
gdelavald 3a2391d
Save audio only option when clearing details
gdelavald c7c2306
Fix broken callback url
gdelavald af3bb99
Reorder livestream icon
gdelavald 5bf1917
Syncing from develop
gdelavald 4e26e71
Merge branch 'develop' of https://github.com/RocketChat/Rocket.Chat i…
gdelavald a5c525a
Adds check to display broadcast camera button
gdelavald 477b6d1
Merge remote-tracking branch 'origin/develop' into youtube-broadcast
ggazzo c51709d
Merge remote-tracking branch 'origin/youtube-broadcast' into youtube-…
ggazzo 192903e
livestream order
ggazzo cf7af91
Merge branch 'develop' into youtube-broadcast
ggazzo File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
.npm/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
export const close = (popup) => { | ||
return new Promise(function(resolve) { | ||
const checkInterval = setInterval(() => { | ||
if (popup.closed) { | ||
clearInterval(checkInterval); | ||
resolve(); | ||
} | ||
}, 300); | ||
}); | ||
}; | ||
|
||
export const auth = async() => { | ||
const oauthWindow = window.open(`${ RocketChat.settings.get('Site_Url') }/api/v1/livestream/oauth?userId=${ Meteor.userId() }`, 'youtube-integration-oauth', 'width=400,height=600'); | ||
return await close(oauthWindow); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,16 +1,21 @@ | ||
Meteor.startup(function() { | ||
Tracker.autorun(function() { | ||
RocketChat.TabBar.removeButton('livestream'); | ||
if (RocketChat.settings.get('Livestream_enabled')) { | ||
const live = RocketChat.models.Rooms.findOne({ _id: Session.get('openedRoom'), 'streamingOptions.id': {$exists :1} }, { fields: { streamingOptions: 1 } }); | ||
RocketChat.TabBar.size = live ? 5 : 4; | ||
return RocketChat.TabBar.addButton({ | ||
groups: ['channel', 'group'], | ||
id: 'livestream', | ||
i18nTitle: 'Livestream', | ||
icon: 'podcast', | ||
template: 'liveStreamTab', | ||
order: 3 | ||
order: live ? -1 : 15, | ||
class: () => { | ||
const roomWithStream = RocketChat.models.Rooms.findOne({ _id: Session.get('openedRoom'), 'streamingOptions.id': {$exists :1} }, { fields: { streamingOptions: 1 } }) || ''; | ||
return roomWithStream && 'live'; | ||
} | ||
}); | ||
} else { | ||
RocketChat.TabBar.removeButton('livestream'); | ||
} | ||
}); | ||
}); |
5 changes: 5 additions & 0 deletions
5
packages/rocketchat-livestream/client/views/broadcastView.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
<template name="broadcastView"> | ||
<div class="streaming-popup"> | ||
<video id="player" src={{ broadcastSource }} muted autoplay width="380px" ></video> | ||
</div> | ||
</template> |
150 changes: 150 additions & 0 deletions
150
packages/rocketchat-livestream/client/views/broadcastView.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,150 @@ | ||
const getMedia = () => navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia; | ||
const createAndConnect = (url) => { | ||
if (!'WebSocket' in window) { // eslint-disable-line no-negated-in-lhs | ||
return false; | ||
} | ||
|
||
const ws = new WebSocket(url); | ||
ws.onerror = (evt) => console.error(`Error: ${ evt.data }`); | ||
return ws; | ||
}; | ||
const sendMessageToWebSocket = (message, ws) => { | ||
if (ws != null) { | ||
if (ws.readyState === 1) { ws.send(message); } | ||
} | ||
}; | ||
export const call = (...args) => new Promise(function(resolve, reject) { | ||
Meteor.call(...args, function(err, result) { | ||
if (err) { | ||
handleError(err); | ||
reject(err); | ||
} | ||
resolve(result); | ||
}); | ||
}); | ||
|
||
const delay = (time) => new Promise((resolve) => setTimeout(resolve, time)); | ||
|
||
const waitForStreamStatus = async(id, status) => { | ||
const streamActive = new Promise(async(resolve) => { | ||
while (true) { //eslint-disable-line no-constant-condition | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. <3 |
||
const currentStatus = await call('livestreamStreamStatus', { streamId: id }); | ||
if (currentStatus === status) { | ||
return resolve(status); | ||
} | ||
await delay(1500); | ||
} | ||
}); | ||
await streamActive; | ||
}; | ||
const waitForBroadcastStatus = async(id, status) => { | ||
const broadcastActive = new Promise(async(resolve) => { | ||
while (true) { //eslint-disable-line no-constant-condition | ||
const currentStatus = await call('getBroadcastStatus', { broadcastId: id }); | ||
if (currentStatus === status) { | ||
return resolve(status); | ||
} | ||
await delay(1500); | ||
} | ||
}); | ||
await broadcastActive; | ||
}; | ||
|
||
Template.broadcastView.helpers({ | ||
broadcastSource() { | ||
return Template.instance().mediaStream.get() ? window.URL.createObjectURL(Template.instance().mediaStream.get()) : ''; | ||
}, | ||
mediaRecorder() { | ||
Template.instance().mediaRecorder.get(); | ||
} | ||
}); | ||
|
||
Template.broadcastView.onCreated(async function() { | ||
const connection = createAndConnect(`${ RocketChat.settings.get('Broadcasting_media_server_url') }/${ this.data.id }`); | ||
this.mediaStream = new ReactiveVar(null); | ||
this.mediaRecorder = new ReactiveVar(null); | ||
this.connection = new ReactiveVar(connection); | ||
|
||
if (!connection) { | ||
return; | ||
} | ||
}); | ||
Template.broadcastView.onDestroyed(function() { | ||
if (this.connection.get()) { | ||
this.connection.get().close(); | ||
} | ||
if (this.mediaRecorder.get()) { | ||
this.mediaRecorder.get().stop(); | ||
this.mediaRecorder.set(null); | ||
} | ||
if (this.mediaStream.get()) { | ||
this.mediaStream.get().getTracks().map((track) => track.stop()); | ||
this.mediaStream.set(null); | ||
} | ||
}); | ||
Template.broadcastView.onRendered(async function() { | ||
navigator.getMedia = getMedia(); | ||
if (!navigator.getMedia) { | ||
return alert('getUserMedia() is not supported in your browser!'); | ||
} | ||
const localMediaStream = await new Promise((resolve, reject) => navigator.getMedia({video: true, audio: true}, resolve, reject)); | ||
|
||
const connection = this.connection.get(); | ||
|
||
this.mediaStream.set(localMediaStream); | ||
let options = {mimeType: 'video/webm;codecs=vp9'}; | ||
if (!MediaRecorder.isTypeSupported(options.mimeType)) { | ||
options = {mimeType: 'video/webm;codecs=vp8'}; | ||
if (!MediaRecorder.isTypeSupported(options.mimeType)) { | ||
options = {mimeType: 'video/webm'}; | ||
if (!MediaRecorder.isTypeSupported(options.mimeType)) { | ||
options = {mimeType: ''}; | ||
} | ||
} | ||
} | ||
try { | ||
const mediaRecorder = new MediaRecorder(localMediaStream, options); | ||
mediaRecorder.ondataavailable = (event) => { | ||
if (!(event.data || event.data.size > 0)) { | ||
return; | ||
} | ||
sendMessageToWebSocket(event.data, connection); | ||
}; | ||
mediaRecorder.start(100); // collect 100ms of data | ||
this.mediaRecorder.set(mediaRecorder); | ||
|
||
await waitForStreamStatus(this.data.stream.id, 'active'); | ||
await call('setLivestreamStatus', { broadcastId: this.data.broadcast.id, status: 'testing' }); | ||
await waitForBroadcastStatus(this.data.broadcast.id, 'testing'); | ||
document.querySelector('.streaming-popup').dispatchEvent(new Event('broadcastStreamReady')); | ||
|
||
} catch (e) { | ||
console.log(e); | ||
} | ||
}); | ||
|
||
Template.broadcastView.events({ | ||
async 'startStreaming .streaming-popup'(e, i) { | ||
await call('setLivestreamStatus', {broadcastId: i.data.broadcast.id, status: 'live'}); | ||
document.querySelector('.streaming-popup').dispatchEvent(new Event('broadcastStream')); | ||
await call('saveRoomSettings', Session.get('openedRoom'), 'streamingOptions', {id: i.data.broadcast.id, url: `https://www.youtube.com/embed/${ i.data.broadcast.id }`, thumbnail: `https://img.youtube.com/vi/${ i.data.broadcast.id }/0.jpg`}); | ||
}, | ||
async 'stopStreaming .streaming-popup'(e, i) { | ||
await call('setBroadcastStatus', { broadcastId: i.data.broadcast.id, status: 'complete' }); | ||
await call('saveRoomSettings', Session.get('openedRoom'), 'streamingOptions', {}, (err) => { | ||
if (err) { | ||
return handleError(err); | ||
} | ||
i.editing.set(false); | ||
i.streamingOptions.set({}); | ||
}); | ||
if (i.mediaRecorder.get()) { | ||
i.mediaRecorder.get().stop(); | ||
i.mediaRecorder.set(null); | ||
} | ||
if (i.mediaStream.get()) { | ||
i.mediaStream.get().getTracks().map((track) => track.stop()); | ||
i.mediaStream.set(null); | ||
} | ||
} | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
❤️