Skip to content

Commit

Permalink
Merge pull request #10 from bbc/add_mixers
Browse files Browse the repository at this point in the history
Ability to create and delete mixers
  • Loading branch information
matthew1000 authored Nov 15, 2018
2 parents 0bf3c52 + cbc0844 commit cf28f0e
Show file tree
Hide file tree
Showing 13 changed files with 185 additions and 118 deletions.
17 changes: 17 additions & 0 deletions brave/api/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,21 @@ def __init__(self, session):
async def not_found(request, exception):
return sanic.response.json({'error': 'Not found'}, 404)

@app.middleware('request')
async def give_session_to_each_route_handler(request):
request['session'] = session

@app.middleware('request')
async def ensure_objects_always_provided_in_json(request):
if request.method in ['POST', 'PUT'] and not isinstance(request.json, dict):
return sanic.response.json({'error': 'Invalid JSON'}, 400)

@app.exception(brave.exceptions.InvalidConfiguration)
async def invalid_cf(request, exception):
msg = 'Invalid configuration from user: ' + str(exception)
logger.debug(msg)
return sanic.response.json({'error': msg}, 400)

app.add_route(route_handler.all, "/api/all")
app.add_route(route_handler.inputs, "/api/inputs")
app.add_route(route_handler.outputs, "/api/outputs")
Expand All @@ -43,6 +58,7 @@ async def not_found(request, exception):
app.add_route(route_handler.create_input, '/api/inputs', methods=['PUT'])
app.add_route(route_handler.create_output, '/api/outputs', methods=['PUT'])
app.add_route(route_handler.create_overlay, '/api/overlays', methods=['PUT'])
app.add_route(route_handler.create_mixer, '/api/mixers', methods=['PUT'])

app.add_route(route_handler.update_input, '/api/inputs/<id:int>', methods=['POST'])
app.add_route(route_handler.update_output, '/api/outputs/<id:int>', methods=['POST'])
Expand All @@ -52,6 +68,7 @@ async def not_found(request, exception):
app.add_route(route_handler.delete_input, '/api/inputs/<id:int>', methods=['DELETE'])
app.add_route(route_handler.delete_output, '/api/outputs/<id:int>', methods=['DELETE'])
app.add_route(route_handler.delete_overlay, '/api/overlays/<id:int>', methods=['DELETE'])
app.add_route(route_handler.delete_mixer, '/api/mixers/<id:int>', methods=['DELETE'])

app.add_route(route_handler.cut_to_source, '/api/mixers/<id:int>/cut_to_source', methods=['POST'])
app.add_route(route_handler.overlay_source, '/api/mixers/<id:int>/overlay_source', methods=['POST'])
Expand Down
169 changes: 62 additions & 107 deletions brave/api/route_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,73 +7,70 @@


async def all(request):
session = brave.session.get_session()
return sanic.response.json({
'inputs': session.inputs.summarise(),
'overlays': session.overlays.summarise(),
'outputs': session.outputs.summarise(),
'mixers': session.mixers.summarise()
'inputs': request['session'].inputs.summarise(),
'overlays': request['session'].overlays.summarise(),
'outputs': request['session'].outputs.summarise(),
'mixers': request['session'].mixers.summarise()
})


async def inputs(request):
session = brave.session.get_session()
return sanic.response.json(session.inputs.summarise())
return sanic.response.json(request['session'].inputs.summarise())


async def outputs(request):
session = brave.session.get_session()
return sanic.response.json(session.outputs.summarise())
return sanic.response.json(request['session'].outputs.summarise())


async def overlays(request):
session = brave.session.get_session()
return sanic.response.json(session.overlays.summarise())
return sanic.response.json(request['session'].overlays.summarise())


async def mixers(request):
session = brave.session.get_session()
return sanic.response.json(session.mixers.summarise())
return sanic.response.json(request['session'].mixers.summarise())


async def elements(request):
show_inside_bin_elements = 'show_inside_bin_elements' in request.args
session = brave.session.get_session()
return sanic.response.json({
'inputs': session.inputs.get_pipeline_details(show_inside_bin_elements),
'overlays': session.overlays.get_pipeline_details(show_inside_bin_elements),
'outputs': session.outputs.get_pipeline_details(show_inside_bin_elements),
'mixers': session.mixers.get_pipeline_details(show_inside_bin_elements)
'inputs': request['session'].inputs.get_pipeline_details(show_inside_bin_elements),
'overlays': request['session'].overlays.get_pipeline_details(show_inside_bin_elements),
'outputs': request['session'].outputs.get_pipeline_details(show_inside_bin_elements),
'mixers': request['session'].mixers.get_pipeline_details(show_inside_bin_elements)
})


async def delete_input(request, id):
session = brave.session.get_session()
if id not in session.inputs:
if id not in request['session'].inputs:
return _user_error_response('No such input ID')
session.inputs[id].delete()
request['session'].inputs[id].delete()
return _status_ok_response()


async def delete_output(request, id):
session = brave.session.get_session()
if id not in session.outputs:
if id not in request['session'].outputs:
return _user_error_response('No such output ID')
run_on_master_thread_when_idle(session.outputs[id].delete)
run_on_master_thread_when_idle(request['session'].outputs[id].delete)
return _status_ok_response()


async def delete_overlay(request, id):
session = brave.session.get_session()
if id not in session.overlays:
if id not in request['session'].overlays:
return _user_error_response('No such overlay ID')
session.overlays[id].delete()
request['session'].overlays[id].delete()
return _status_ok_response()


async def delete_mixer(request, id):
if id not in request['session'].mixers:
return _user_error_response('No such mixer ID')
request['session'].mixers[id].delete()
return _status_ok_response()


async def cut_to_source(request, id):
session = brave.session.get_session()
if id not in session.mixers or session.mixers[id] is None:
if id not in request['session'].mixers or request['session'].mixers[id] is None:
return _user_error_response('No such mixer ID')
if not request.json:
return _user_error_response('Invalid JSON')
Expand All @@ -83,11 +80,11 @@ async def cut_to_source(request, id):
return _user_error_response('Only inputs can be added to a mixer')

input_id = request.json['id']
if input_id not in session.inputs or session.inputs[input_id] is None:
if input_id not in request['session'].inputs or request['session'].inputs[input_id] is None:
return _user_error_response('No such input ID')

mixer = session.mixers[id]
source = mixer.sources.get_for_input_or_mixer(session.inputs[input_id])
mixer = request['session'].mixers[id]
source = mixer.sources.add(request['session'].inputs[input_id])
if not source:
return _user_error_response('Input is not source on mixer')

Expand All @@ -96,8 +93,7 @@ async def cut_to_source(request, id):


async def overlay_source(request, id):
session = brave.session.get_session()
if id not in session.mixers or session.mixers[id] is None:
if id not in request['session'].mixers or request['session'].mixers[id] is None:
return _user_error_response('No such mixer ID')
if not request.json:
return _user_error_response('Invalid JSON')
Expand All @@ -107,11 +103,11 @@ async def overlay_source(request, id):
return _user_error_response('Only inputs can be added to a mixer')

input_id = request.json['id']
if input_id not in session.inputs or session.inputs[input_id] is None:
if input_id not in request['session'].inputs or request['session'].inputs[input_id] is None:
return _user_error_response('No such input ID')

mixer = session.mixers[id]
source = mixer.sources.get_for_input_or_mixer(session.inputs[input_id])
mixer = request['session'].mixers[id]
source = mixer.sources.add(request['session'].inputs[input_id])
if not source:
return _user_error_response('Input is not source on mixer')

Expand All @@ -120,8 +116,7 @@ async def overlay_source(request, id):


async def remove_source(request, id):
session = brave.session.get_session()
if id not in session.mixers or session.mixers[id] is None:
if id not in request['session'].mixers or request['session'].mixers[id] is None:
return _user_error_response('No such mixer ID')
if not request.json:
return _user_error_response('Invalid JSON')
Expand All @@ -131,11 +126,11 @@ async def remove_source(request, id):
return _user_error_response('Only inputs can be added to a mixer')

input_id = request.json['id']
if input_id not in session.inputs or session.inputs[input_id] is None:
if input_id not in request['session'].inputs or request['session'].inputs[input_id] is None:
return _user_error_response('No such input ID')

mixer = session.mixers[id]
source = mixer.sources.get_for_input_or_mixer(session.inputs[input_id])
mixer = request['session'].mixers[id]
source = mixer.sources.get_for_input_or_mixer(request['session'].inputs[input_id])
if not source:
return _user_error_response('Input is not source on mixer')

Expand All @@ -144,114 +139,78 @@ async def remove_source(request, id):


async def update_input(request, id):
session = brave.session.get_session()
if not request.json:
return _invalid_json_response()
if id not in session.inputs or session.inputs[id] is None:
if id not in request['session'].inputs or request['session'].inputs[id] is None:
return _user_error_response('No such input ID')

if 'state' in request.json:
request.json['state'] = state_string_to_constant(request.json['state'])
if not request.json['state']:
return _user_error_response('Invalid state')
try:
session.inputs[id].update(request.json)
except brave.exceptions.InvalidConfiguration as e:
return _invalid_configuration_response(e)
request['session'].inputs[id].update(request.json)
return _status_ok_response()


async def update_output(request, id):
session = brave.session.get_session()
if not request.json:
return _user_error_response('Not valid JSON')
if id not in session.outputs or session.outputs[id] is None:
if id not in request['session'].outputs or request['session'].outputs[id] is None:
return _user_error_response('no such output id')
if 'state' in request.json:
request.json['state'] = state_string_to_constant(request.json['state'])
if not request.json['state']:
return _user_error_response('Invalid state')
try:
session.outputs[id].update(request.json)
except brave.exceptions.InvalidConfiguration as e:
return _invalid_configuration_response(e)
request['session'].outputs[id].update(request.json)
return _status_ok_response()


async def update_overlay(request, id):
session = brave.session.get_session()
if not request.json:
return _invalid_json_response('Not valid JSON')
if id not in session.overlays or session.overlays[id] is None:
if id not in request['session'].overlays or request['session'].overlays[id] is None:
return _user_error_response('No such overlay ID')
if 'state' in request.json:
request.json['state'] = state_string_to_constant(request.json['state'])
if not request.json['state']:
return _user_error_response('Invalid state')
try:
session.overlays[id].update(request.json)
except brave.exceptions.InvalidConfiguration as e:
return _invalid_configuration_response(e)
request['session'].overlays[id].update(request.json)
return _status_ok_response()


async def update_mixer(request, id):
session = brave.session.get_session()
if not request.json:
return _invalid_json_response()
if id not in session.mixers or session.mixers[id] is None:
if id not in request['session'].mixers or request['session'].mixers[id] is None:
return _user_error_response('No such mixer ID')
if 'state' in request.json:
request.json['state'] = state_string_to_constant(request.json['state'])
if not request.json['state']:
return _user_error_response('Invalid state')
try:
session.mixers[id].update(request.json)
except brave.exceptions.InvalidConfiguration as e:
return _invalid_configuration_response(e)
request['session'].mixers[id].update(request.json)
return _status_ok_response()


async def create_input(request):
session = brave.session.get_session()
if not request.json:
return _invalid_json_response()
try:
input = session.inputs.add(**request.json)
# TODO not hard-code mixer 0:
run_on_master_thread_when_idle(input.sources()[0].add_to_mix)
except brave.exceptions.InvalidConfiguration as e:
return _invalid_configuration_response(e)
return _status_ok_response()
input = request['session'].inputs.add(**request.json)
# TODO not hard-code mixer 0:
run_on_master_thread_when_idle(input.sources()[0].add_to_mix)
logger.info('Created input #%d with details %s' % (input.id, request.json))
return sanic.response.json({'id': input.id})


async def create_output(request):
session = brave.session.get_session()
if not request.json:
return _invalid_json_response()
try:
output = session.outputs.add(**request.json)
output.link_from_source()
except brave.exceptions.InvalidConfiguration as e:
return _invalid_configuration_response(e)
logger.info('Created output #' + str(output.id) + ' with details ' + str(request.json))
return sanic.response.json({'status': 'OK', 'id': output.id})
output = request['session'].outputs.add(**request.json)
logger.info('Created output #%d with details %s' % (output.id, request.json))
return sanic.response.json({'id': output.id})


async def create_overlay(request):
session = brave.session.get_session()
if not request.json:
return _invalid_json_response()
try:
overlay = session.overlays.add(**request.json)
except brave.exceptions.InvalidConfiguration as e:
return _invalid_configuration_response(e)
logger.info('Created overlay #' + str(overlay.id) + ' with details ' + str(request.json))
overlay = request['session'].overlays.add(**request.json)
logger.info('Created overlay #%d with details %s' % (overlay.id, request.json))
return _status_ok_response()


async def create_mixer(request):
mixer = request['session'].mixers.add(**request.json)
logger.info('Created mixer #%d with details %s' % (mixer.id, request.json))
return sanic.response.json({'id': mixer.id})


async def restart(request):
run_on_master_thread_when_idle(brave.session.get_session().end, restart=True)
run_on_master_thread_when_idle(request['session'].end, restart=True)
return _status_ok_response()


Expand All @@ -263,10 +222,6 @@ def _user_error_response(e):
return sanic.response.json({'error': str(e)}, 400)


def _invalid_json_response():
return _user_error_response('Invalid JSON')


def _invalid_configuration_response(e):
logger.info('Invalid configuration from user: ' + str(e))
return _user_error_response(e)
Expand Down
4 changes: 3 additions & 1 deletion brave/inputs/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ class InputCollection(AbstractCollection):
def add(self, **args):
args['id'] = self.get_new_id()

if args['type'] == 'uri':
if 'type' not in args:
raise brave.exceptions.InvalidConfiguration("Invalid input missing 'type'")
elif args['type'] == 'uri':
input = UriInput(**args, collection=self)
elif args['type'] == 'test_video':
input = TestVideoInput(**args, collection=self)
Expand Down
7 changes: 5 additions & 2 deletions brave/outputs/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,16 @@
from brave.outputs.file import FileOutput
from brave.outputs.webrtc import WebRTCOutput
from brave.abstract_collection import AbstractCollection
import brave.exceptions


class OutputCollection(AbstractCollection):
def add(self, **args):
args['id'] = self.get_new_id()

if args['type'] == 'local':
if 'type' not in args:
raise brave.exceptions.InvalidConfiguration("Invalid output missing 'type'")
elif args['type'] == 'local':
output = LocalOutput(**args, collection=self)
elif args['type'] == 'rtmp':
output = RTMPOutput(**args, collection=self)
Expand All @@ -24,7 +27,7 @@ def add(self, **args):
elif args['type'] == 'webrtc':
output = WebRTCOutput(**args, collection=self)
else:
raise Exception(f"Invalid output type '{str(args['type'])}'")
raise brave.exceptions.InvalidConfiguration("Invalid output type '%s'" % args['type'])

self._items[args['id']] = output
return output
Loading

0 comments on commit cf28f0e

Please sign in to comment.