Unverified Commit 2007d2e2 authored by mtsonline's avatar mtsonline Committed by GitHub
Browse files

Merge pull request #24 from mtsonline/intro

preparing beta5
parents d0a84c03 a9604708
......@@ -49,6 +49,9 @@ ENV BBB_SHOW_CHAT false
ENV BBB_ENABLE_CHAT false
ENV BBB_REDIS_HOST redis
ENV BBB_REDIS_CHANNEL chat
RUN DEBIAN_FRONTEND="noninteractive" apt-get -y install tzdata
ENV TZ Europe/Vienna
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
COPY stream.py ./
COPY chat.py ./
......
......@@ -18,7 +18,7 @@ You need to set some environment variables to run the container.
* BBB_URL - URL to BBB including http/https e.g. https://your_BigBlueButton_server/bigbluebutton/api
* BBB_MEETING_ID - ID of the BBB Meeting (You can get the ID via an API call: https://your_bbb_server/bigbluebutton/api/getMeetings?checksum=<checksum>)
* BBB_SECRET - Secret of your BBB installation (You can get the secret with: bbb-conf --secret)
* BBB_STREAM_URL - Stream URL to your streaming server including rtmp. (e.g. rtmp://media_server_url/stream/stream_key)
* BBB_STREAM_URL - URL of your streaming server including rtmp. Leave out to disable streaming. (e.g. rtmp://media_server_url/stream/stream_key)
#### Optional settings
* BBB_AS_MODERATOR - if set to "true" the meeting will be joined as moderator
......@@ -26,8 +26,13 @@ You need to set some environment variables to run the container.
* BBB_ATTENDEE_PASSWORD - attendee password (optional - has to be set to the attendee password of moodle/greenlight or any other frontend to allow joining via their links)
* BBB_MODERATOR_PASSWORD - moderator password (optional - has to be set to the moderator password of moodle/greenlight or any other frontend to allow joining via their links)
* BBB_MEETING_TITLE - meeting title (optional - only works if the meeting is started by the liveStreaming)
* BBB_DOWNLOAD_MEETING= - download / save BigBlueButton meeting in lossless mkv format
* BBB_INTRO= - play intro file (can be a local file in videodata folder e.g. /video/intro.mp4 or a url of a mediastream e.g. https://my.intro.stream)
* BBB_BEGIN_INTRO_AT=04:40 - begin the intro at position (optional, e.g. 00:00:05)
* BBB_END_INTRO_AT= - end intro after (optional, e.g. 01:00:00 - after one hour)
* BBB_USER_NAME - the username to join the meeting. (Default: Live)
* BBB_SHOW_CHAT - shows the chat on the left side of the window (Default: false)
* TZ - Timezone (Default: Europe/Vienna)
#### Chat settings
* BBB_ENABLE_CHAT - Enable Chat feedback channel
......@@ -42,8 +47,6 @@ You need to set some environment variables to run the container.
* docker-compose down
## Known Limitations
* You must extract and provide the meetingID, which is not visible within the room.
* the streamer cannot join meetings, that where not started yet
* the streamer does not reconnect, if the connection to BigBlueButton gets lost
* when using breakoutrooms, the streamer will show the popup of the invitation and not be able to get back to the conference
......@@ -61,15 +64,15 @@ Similar to the GDPR and the CCPA, other local privacy law principles also may
Always be transparent and act upon privacy rights and federal law Regulations.
## License
BigBlueButton-liveStreaming is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
BigBlueButton-liveStreaming is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with BigBlueButton-liveStreaming. If not, see [GNU website](https://www.gnu.org/licenses)
BigBlueButton-liveStreaming is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
BigBlueButton-liveStreaming is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with BigBlueButton-liveStreaming. If not, see [GNU website](https://www.gnu.org/licenses)
......@@ -21,6 +21,10 @@ parser.add_argument("-s","--server", help="Big Blue Button Server URL")
parser.add_argument("-p","--secret", help="Big Blue Button Secret")
parser.add_argument("-i","--id", help="Big Blue Button Meeting ID")
parser.add_argument("-m","--moderator", help="Join the meeting as moderator",action="store_true")
parser.add_argument("-S","--startMeeting", help="start the meeting if not running",action="store_true")
parser.add_argument("-A","--attendeePassword", help="attendee password (required to create meetings)")
parser.add_argument("-M","--moderatorPassword", help="moderator password (required to create a meeting)")
parser.add_argument("-T","--meetingTitle", help="meeting title (required to create a meeting)")
parser.add_argument("-u","--user", help="Name to join the meeting",default="Live")
parser.add_argument("-r","--redis", help="Redis hostname",default="redis")
parser.add_argument("-c","--channel", help="Redis channel",default="chat")
......@@ -51,6 +55,13 @@ def bbb_browser():
global browser
logging.info('Open BBB for chat!!')
if args.startMeeting is True:
try:
logging.info("create_meeting...")
create_meeting()
except exception.bbbexception.BBBException as ERR:
logging.info(ERR)
browser.get(get_join_url())
element = EC.presence_of_element_located((By.CSS_SELECTOR, '[aria-label="Listen only"]'))
......@@ -74,6 +85,16 @@ def chat_handler(message):
browser.find_elements_by_css_selector('[aria-label="Send message"]')[0].click()
logging.info(message['data'])
def create_meeting():
create_params = {}
if args.moderatorPassword:
create_params['moderatorPW'] = args.moderatorPassword
if args.attendeePassword:
create_params['attendeePW'] = args.attendeePassword
if args.meetingTitle:
create_params['name'] = args.meetingTitle
return bbb.create_meeting(args.id, params=create_params)
def get_join_url():
minfo = bbb.get_meeting_info(args.id)
if args.moderator:
......
......@@ -18,5 +18,18 @@ services:
- BBB_MODERATOR_PASSWORD=JjeQYksarqLQ
# meeting title (optional):
- BBB_MEETING_TITLE=liveStreaming Test
# download / save BigBlueButton meeting
- BBB_DOWNLOAD_MEETING=false
# play intro file (can be a local file in videodata folder e.g. /video/intro.mp4 or a url of a mediastream e.g. https://my.intro.stream)
- BBB_INTRO=false
# begin the intro at position (optional, e.g. 00:00:05)
- BBB_BEGIN_INTRO_AT=04:40
# end intro after (optional, e.g. 01:00:00 - after one hour)
- BBB_END_INTRO_AT=
# Media server url:
- BBB_STREAM_URL=rtmp://media_server_url/stream/stream_key
# Timezone (default: Europe/Vienna):
- TZ=Europe/Vienna
volumes:
- ./videodata:/video
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
### to use this script you will need to ###
# apt install pip3
# pip3 install bigbluebutton_api_python
# pip3 install pyyaml
import argparse, sys, os, logging, yaml, urllib, json
from bigbluebutton_api_python import BigBlueButton
......@@ -8,7 +13,7 @@ logging.basicConfig(level=os.environ.get("LOGLEVEL", "INFO"))
parser = argparse.ArgumentParser()
parser.add_argument("-s","--server", help="Big Blue Button Server URL")
parser.add_argument("-c","--config", help="path to config file in yaml format e.g. your docker-compose.yml", default="../docker-compose.yml")
parser.add_argument("-c","--config", help="path to config file in yaml format e.g. your docker-compose.yml", default="./docker-compose.yml")
parser.add_argument("-p","--secret", help="Big Blue Button Secret")
args = parser.parse_args()
......@@ -41,10 +46,17 @@ if not args.server and not args.secret:
sys.exit()
bbb = BigBlueButton(args.server,args.secret)
meetings = get_meetings()
for meeting in meetings['xml']['meetings']:
print(meetings['xml']['meetings'][meeting]['meetingName'])
print("ID: {}".format(meetings['xml']['meetings'][meeting]['meetingID']))
print("ATTENDEE_PASSWORD: {}".format(meetings['xml']['meetings'][meeting]['attendeePW']))
print("MODERATOR_PASSWORD: {}".format(meetings['xml']['meetings'][meeting]['moderatorPW']))
meetingsXML = get_meetings()
rawMeetings = meetingsXML['xml']['meetings']['meeting']
meetings = []
if isinstance(rawMeetings, list):
meetings = rawMeetings
else:
meetings.append(rawMeetings)
for meeting in meetings:
print(meeting['meetingName'])
print("ID: {}".format(meeting['meetingID']))
print("ATTENDEE_PASSWORD: {}".format(meeting['attendeePW']))
print("MODERATOR_PASSWORD: {}".format(meeting['moderatorPW']))
print("")
......@@ -6,12 +6,42 @@ then
JOIN_AS_MODERATOR="-m";
fi
STREAM_MEETING="";
if [ "${BBB_STREAM_URL}" != "" ]
then
STREAM_MEETING="-l -t ${BBB_STREAM_URL}";
fi
DOWNLOAD_MEETING="";
if [ "${BBB_DOWNLOAD_MEETING}" = "true" ]
then
DOWNLOAD_MEETING="-d";
fi
SHOW_CHAT="";
if [ "${BBB_SHOW_CHAT}" = "true" ]
then
SHOW_CHAT="-c";
fi
INTRO="";
if [ "${BBB_INTRO}" != "" ]
then
INTRO="-I ${BBB_INTRO}";
fi
BEGIN_INTRO="";
if [ "${BBB_BEGIN_INTRO_AT}" != "" ]
then
BEGIN_INTRO="-B ${BBB_BEGIN_INTRO_AT}";
fi
END_INTRO="";
if [ "${BBB_END_INTRO_AT}" != "" ]
then
END_INTRO="-E ${BBB_END_INTRO_AT}";
fi
START_MEETING="";
if [ "${BBB_START_MEETING}" != "" ]
then
......@@ -42,4 +72,4 @@ then
sleep 10
fi
xvfb-run -n 122 --server-args="-screen 0 1920x1080x24" python3 stream.py -s ${BBB_URL} -p ${BBB_SECRET} -i ${BBB_MEETING_ID} -t ${BBB_STREAM_URL} -u ${BBB_USER_NAME} ${SHOW_CHAT} $START_MEETING $ATTENDEE_PASSWORD $MODERATOR_PASSWORD -T "$MEETING_TITLE" $JOIN_AS_MODERATOR;
xvfb-run -n 122 --server-args="-screen 0 1920x1080x24" python3 stream.py -s ${BBB_URL} -p ${BBB_SECRET} -i ${BBB_MEETING_ID} -u ${BBB_USER_NAME} ${SHOW_CHAT} $START_MEETING $ATTENDEE_PASSWORD $MODERATOR_PASSWORD -T "$MEETING_TITLE" $STREAM_MEETING $INTRO $BEGIN_INTRO $END_INTRO $JOIN_AS_MODERATOR $DOWNLOAD_MEETING;
......@@ -12,6 +12,9 @@ from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from datetime import datetime
downloadProcess = None
browser = None
selelnium_timeout = 30
connect_timeout = 5
......@@ -22,6 +25,11 @@ parser = argparse.ArgumentParser()
parser.add_argument("-s","--server", help="Big Blue Button Server URL")
parser.add_argument("-p","--secret", help="Big Blue Button Secret")
parser.add_argument("-i","--id", help="Big Blue Button Meeting ID")
parser.add_argument("-I","--intro", help="Intro file to play before streaming")
parser.add_argument("-B","--beginIntroAt", help="begin intro at position (e.g. 00:01:05)")
parser.add_argument("-E","--endIntroAt", help="End intro at position (e.g. 01:00:04)")
parser.add_argument("-l","--stream", help="live stream a BigBlueButton meeting",action="store_true")
parser.add_argument("-d","--download", help="download / save a BigBlueButton meeting",action="store_true")
parser.add_argument("-m","--moderator", help="Join the meeting as moderator",action="store_true")
parser.add_argument("-S","--startMeeting", help="start the meeting if not running",action="store_true")
parser.add_argument("-A","--attendeePassword", help="attendee password (required to create meetings)")
......@@ -101,24 +109,57 @@ def get_join_url():
pwd = minfo.get_meetinginfo().get_attendeepw()
return bbb.get_join_meeting_url(args.user,args.id, pwd)
def watch():
while True:
time.sleep(60)
def stream_intro():
audio_options = '-f alsa -i pulse -ac 2 -c:a aac -b:a 160k -ar 44100'
video_options = '-c:v libx264 -x264-params "nal-hrd=cbr" -profile:v high -level:v 4.2 -vf format=yuv420p -b:v 4000k -maxrate 4000k -minrate 2000k -bufsize 8000k -g 60 -preset ultrafast'
introBegin = ""
if args.beginIntroAt:
introBegin = "-ss %s"%(args.beginIntroAt)
introEnd = ""
if args.endIntroAt:
introEnd = "-to %s"%(args.endIntroAt)
ffmpeg_stream = 'ffmpeg -re %s %s -thread_queue_size 1024 -i %s -thread_queue_size 1024 %s -threads 0 %s -f flv "%s"' % ( introBegin, introEnd, args.intro, audio_options, video_options, args.target)
ffmpeg_args = shlex.split(ffmpeg_stream)
logging.info("streaming intro...")
p = subprocess.call(ffmpeg_args)
def stream():
audio_options = '-f alsa -i pulse -ac 2 -c:a aac -b:a 160k -ar 44100'
#video_options = ' -c:v libvpx-vp9 -b:v 2000k -crf 33 -quality realtime -speed 5'
video_options = '-c:v libx264 -x264-params "nal-hrd=cbr" -profile:v high -level:v 4.2 -vf format=yuv420p -b:v 4000k -maxrate 4000k -minrate 2000k -bufsize 8000k -g 60 -preset ultrafast -tune zerolatency'
ffmpeg_stream = 'ffmpeg -thread_queue_size 1024 -f x11grab -draw_mouse 0 -s 1920x1080 -i :%d %s -threads 0 %s -f flv -flvflags no_duration_filesize "%s"' % ( 122, audio_options, video_options, args.target)
ffmpeg_stream = 'ffmpeg -thread_queue_size 1024 -f x11grab -draw_mouse 0 -s 1920x1080 -i :%d -thread_queue_size 1024 %s -threads 0 %s -f flv -flvflags no_duration_filesize "%s"' % ( 122, audio_options, video_options, args.target)
ffmpeg_args = shlex.split(ffmpeg_stream)
p = subprocess.Popen(ffmpeg_args)
logging.info("streaming meeting...")
p = subprocess.call(ffmpeg_args)
def download():
downloadFile = "/video/meeting-%s.mkv" % fileTimeStamp
audio_options = '-f alsa -i pulse -ac 2'
video_options = '-c:v libx264rgb -crf 0 -preset ultrafast'
ffmpeg_stream = 'ffmpeg -thread_queue_size 1024 -f x11grab -draw_mouse 0 -s 1920x1080 -i :%d -thread_queue_size 1024 %s %s %s' % ( 122, audio_options, video_options, downloadFile)
ffmpeg_args = shlex.split(ffmpeg_stream)
logging.info("saving meeting as %s" % downloadFile)
return subprocess.Popen(ffmpeg_args)
if args.startMeeting is False:
while bbb.is_meeting_running(args.id).is_meeting_running() != True:
logging.info("Meeting isn't running. We will try again in %d seconds!" % connect_timeout)
time.sleep(connect_timeout)
# current date and time
now = datetime.now()
fileTimeStamp = now.strftime("%Y%m%d%H%M%S")
set_up()
bbb_browser()
stream()
watch()
browser.quit()
\ No newline at end of file
if args.stream and args.intro:
stream_intro()
if args.stream or args.download:
bbb_browser()
if args.download:
downloadProcess = download()
if args.stream:
stream()
if downloadProcess:
downloadProcess.communicate(input=None)
if browser:
browser.quit()
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment