diff --git a/README.md b/README.md index b19fae5fcd7d1eb3ea28406be16612ce0bcd26ad..136b96db7459b2254e6e2eec97e3c916fefb5b5d 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,10 @@ You need to set some environment variables to run the container. #### Optional settings * BBB_AS_MODERATOR - if set to "true" the meeting will be joined as moderator +* BBB_START_MEETING - start meeting +* 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_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) @@ -32,7 +36,7 @@ You need to set some environment variables to run the container. * BBB_CHAT_NAME - the username to join the meeting for chatting. (Default: Chat) ### Starting liveStreaming -* wget -O docker-compose.yml https://raw.github.com/aau-zid/BigBlueButton-liveStreaming/1.0.0-beta.3/examples/docker-compose.yml.example +* wget -O docker-compose.yml https://raw.github.com/aau-zid/BigBlueButton-liveStreaming/1.0.0-beta.4/examples/docker-compose.yml.example * (change configuration) * docker-compose up -d * docker-compose down @@ -68,4 +72,4 @@ Always be transparent and act upon privacy rights and federal law Regulations. 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/) + along with BigBlueButton-liveStreaming. If not, see [GNU website](https://www.gnu.org/licenses) diff --git a/chat.py b/chat.py index bae8a4aa05f16ce5f44f7212c9a34203aacfd85d..2e908e8ced51915c69a8ecba288c83320cd1199f 100644 --- a/chat.py +++ b/chat.py @@ -60,7 +60,7 @@ def bbb_browser(): element = EC.invisibility_of_element((By.CSS_SELECTOR, '.ReactModal__Overlay')) WebDriverWait(browser, selelnium_timeout).until(element) - browser.find_element_by_id('message-input').send_keys("Viewers can send messages to this meeting") + browser.find_element_by_id('message-input').send_keys("Viewers of the live stream can now send messages to this meeting") browser.find_elements_by_css_selector('[aria-label="Send message"]')[0].click() redis_r = redis.Redis(host=args.redis,charset="utf-8", decode_responses=True) diff --git a/examples/.env.chat_example b/examples/.env.chat_example index bc844e9c41fcd7529a76b5e5347e8ac7c23c4064..a8e319f32d9841515c65984d1bbf92c7d46f0b1b 100644 --- a/examples/.env.chat_example +++ b/examples/.env.chat_example @@ -8,6 +8,8 @@ BBB_MEETING_ID=your_meetingID BBB_STREAM_URL=rtmp://media_server_url/stream/stream_key # Enable chat functionality BBB_ENABLE_CHAT=true +# show chat in live stream +BBB_SHOW_CHAT=false # Set REDIS host (default: 'redis') BBB_REDIS_HOST=redis # Set REDIS channel to subscribe (default: 'chat') diff --git a/examples/.env.example b/examples/.env.example index fc6defa5a355435f5971a0dcdcdd6ec30b112164..af4fa4f6dcc4a5920869e195b88e5d4d7a6d6c0d 100644 --- a/examples/.env.example +++ b/examples/.env.example @@ -4,5 +4,13 @@ BBB_URL=https://your_BigBlueButton_server/bigbluebutton/api BBB_SECRET=your_secret # BigBlueButton meetingID: BBB_MEETING_ID=your_meetingID +# start meeting (optional): +BBB_START_MEETING=false +# 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_ATTENDEE_PASSWORD=IVLHwOBSVmYP +# 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_MODERATOR_PASSWORD=JjeQYksarqLQ +# meeting title (optional): +BBB_MEETING_TITLE=liveStreaming Test # Media server url: BBB_STREAM_URL=rtmp://media_server_url/stream/stream_key diff --git a/examples/docker-compose.yml.chat_example b/examples/docker-compose.yml.chat_example index db09b67e8c1d36ad05c930274b473b6ade6ed690..41fb0d2deabffa04af8c98bd4a84b953d24d9d66 100644 --- a/examples/docker-compose.yml.chat_example +++ b/examples/docker-compose.yml.chat_example @@ -17,6 +17,8 @@ services: - BBB_STREAM_URL=rtmp://media_server_url/stream/stream_key # Enable chat functionality -BBB_ENABLE_CHAT=true + # show chat in live stream + -BBB_SHOW_CHAT=false # Set REDIS host (default: 'redis') -BBB_REDIS_HOST=redis # Set REDIS channel to subscribe (default: 'chat') diff --git a/examples/docker-compose.yml.example b/examples/docker-compose.yml.example index 923db5aa096a69d166118cfd283f9c54dffa72a1..a564f8fff7fdf38a1109d74725479f32001a67aa 100644 --- a/examples/docker-compose.yml.example +++ b/examples/docker-compose.yml.example @@ -10,5 +10,13 @@ services: - BBB_SECRET=your_secret # BigBlueButton meetingID: - BBB_MEETING_ID=your_meetingID + # start meeting (optional): + - BBB_START_MEETING=false + # 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_ATTENDEE_PASSWORD=IVLHwOBSVmYP + # 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_MODERATOR_PASSWORD=JjeQYksarqLQ + # meeting title (optional): + - BBB_MEETING_TITLE=liveStreaming Test # Media server url: - BBB_STREAM_URL=rtmp://media_server_url/stream/stream_key diff --git a/examples/get_meetings.py b/examples/get_meetings.py new file mode 100755 index 0000000000000000000000000000000000000000..60045754d49ab803515dc86a74be4a2f9148fe06 --- /dev/null +++ b/examples/get_meetings.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import argparse, sys, os, logging, yaml, urllib, json +from bigbluebutton_api_python import BigBlueButton + +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("-p","--secret", help="Big Blue Button Secret") +args = parser.parse_args() + +def get_config_item(list_item): + try: + with open(args.config) as file: + config = yaml.load(file) + except FileNotFoundError as ERR: + logging.error(ERR) + sys.exit() + + docker_environment = config['services']['bbb-streamer']['environment'] + for line in docker_environment: + if line.strip().startswith(list_item): + return line.partition('=')[2] + +def get_meetings(): + logging.info("fetching meetings from {}".format(args.server)) + try: + return bbb.get_meetings() + except urllib.error.URLError as ERR: + logging.error(ERR) + sys.exit() + +if args.config: + args.server = get_config_item('BBB_URL') + args.secret = get_config_item('BBB_SECRET') +if not args.server and not args.secret: + logging.error("Error: Please specify server and password or the path to the config file") + 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'])) + print("") diff --git a/startStream.sh b/startStream.sh index 8aed46c5a5bd78522d51cd85d75b7bc3e603859a..51b5ecc49ca7f19a510c2ea4437c9af82edd4da7 100644 --- a/startStream.sh +++ b/startStream.sh @@ -12,10 +12,34 @@ then SHOW_CHAT="-c"; fi +START_MEETING=""; +if [ "${BBB_START_MEETING}" != "" ] +then + START_MEETING="-S"; +fi + +ATTENDEE_PASSWORD=""; +if [ "${BBB_ATTENDEE_PASSWORD}" != "" ] +then + ATTENDEE_PASSWORD="-A ${BBB_ATTENDEE_PASSWORD}"; +fi + +MODERATOR_PASSWORD=""; +if [ "${BBB_MODERATOR_PASSWORD}" != "" ] +then + MODERATOR_PASSWORD="-M ${BBB_MODERATOR_PASSWORD}"; +fi + +MEETING_TITLE=""; +if [ "${BBB_MEETING_TITLE}" != "" ] +then + MEETING_TITLE="${BBB_MEETING_TITLE}"; +fi + if [ "${BBB_ENABLE_CHAT}" = "true" ] then - xvfb-run -n 133 --server-args="-screen 0 1920x1080x24" python3 chat.py -s ${BBB_URL} -p ${BBB_SECRET} -i ${BBB_MEETING_ID} -r ${BBB_REDIS_HOST} -u ${BBB_CHAT_NAME} -c ${BBB_REDIS_CHANNEL} $JOIN_AS_MODERATOR & + xvfb-run -n 133 --server-args="-screen 0 1920x1080x24" python3 chat.py -s ${BBB_URL} -p ${BBB_SECRET} -i ${BBB_MEETING_ID} -r ${BBB_REDIS_HOST} -u ${BBB_CHAT_NAME} -c ${BBB_REDIS_CHANNEL} $START_MEETING $ATTENDEE_PASSWORD $MODERATOR_PASSWORD -T "$MEETING_TITLE" $JOIN_AS_MODERATOR & 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} $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} -t ${BBB_STREAM_URL} -u ${BBB_USER_NAME} ${SHOW_CHAT} $START_MEETING $ATTENDEE_PASSWORD $MODERATOR_PASSWORD -T "$MEETING_TITLE" $JOIN_AS_MODERATOR; diff --git a/stream.py b/stream.py index bf17bafc07315388af1c68f2d17e4f3878cd1c77..b2e7db7ca2323929daceb5efa15e6131f741dd22 100644 --- a/stream.py +++ b/stream.py @@ -3,7 +3,7 @@ import sys, argparse, time, subprocess, shlex, logging, os -from bigbluebutton_api_python import BigBlueButton +from bigbluebutton_api_python import BigBlueButton, exception from selenium import webdriver from selenium.webdriver.common.keys import Keys @@ -23,6 +23,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("-t","--target", help="RTMP Streaming URL") parser.add_argument("-c","--chat", help="Show the chat",action="store_true") @@ -50,8 +54,14 @@ def set_up(): def bbb_browser(): global browser - logging.info('Open BBB and hide elements!!') + if args.startMeeting is True: + try: + logging.info("create_meeting...") + create_meeting() + except exception.bbbexception.BBBException as ERR: + logging.info(ERR) + logging.info("get_join_url...") browser.get(get_join_url()) element = EC.presence_of_element_located((By.CSS_SELECTOR, '[aria-label="Listen only"]')) WebDriverWait(browser, selelnium_timeout).until(element) @@ -59,7 +69,7 @@ def bbb_browser(): element = EC.invisibility_of_element((By.CSS_SELECTOR, '.ReactModal__Overlay')) WebDriverWait(browser, selelnium_timeout).until(element) - browser.find_element_by_id('message-input').send_keys("This meeting will be stream to the following address: %s" % args.target) + browser.find_element_by_id('message-input').send_keys("This meeting is streamed to: %s" % args.target) browser.find_elements_by_css_selector('[aria-label="Send message"]')[0].click() if args.chat: @@ -73,13 +83,23 @@ def bbb_browser(): browser.execute_script("document.querySelector('[aria-label=\"Actions bar\"]').style.display='none';") browser.execute_script("document.getElementById('container').setAttribute('style','margin-bottom:30px');") +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: pwd = minfo.get_meetinginfo().get_moderatorpw() else: pwd = minfo.get_meetinginfo().get_attendeepw() - return bbb.get_join_meeting_url(args.user,args.id,pwd) + return bbb.get_join_meeting_url(args.user,args.id, pwd) def watch(): while True: @@ -93,11 +113,10 @@ def stream(): ffmpeg_args = shlex.split(ffmpeg_stream) p = subprocess.Popen(ffmpeg_args) - - -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) +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) set_up() bbb_browser() stream()