summaryrefslogtreecommitdiff
path: root/src/sound_node.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/sound_node.py')
-rwxr-xr-xsrc/sound_node.py192
1 files changed, 50 insertions, 142 deletions
diff --git a/src/sound_node.py b/src/sound_node.py
index a96a098..7d8ba1a 100755
--- a/src/sound_node.py
+++ b/src/sound_node.py
@@ -3,110 +3,16 @@ import os
from typing import Optional
-from home.config import config
from home.util import parse_addr
-from home.sound import (
- amixer,
- Recorder,
- RecordStatus,
- RecordStorage
-)
+from home.config import config
+from home.audio import amixer
+from home.media import MediaNodeServer, SoundRecordStorage, SoundRecorder
from home import http
-"""
-This script must be run as root as it runs arecord.
-
-This script implements HTTP API for amixer and arecord.
-"""
-
-
-# some global variables
-# ---------------------
-
-recorder: Optional[Recorder]
-routes = http.routes()
-storage: Optional[RecordStorage]
-
-
-# recording methods
-# -----------------
-
-@routes.get('/record/')
-async def do_record(request):
- duration = int(request.query['duration'])
- max = Recorder.get_max_record_time()*15
- if not 0 < duration <= max:
- raise ValueError(f'invalid duration: max duration is {max}')
-
- record_id = recorder.record(duration)
- return http.ok({'id': record_id})
-
-
-@routes.get('/record/info/{id}/')
-async def record_info(request):
- record_id = int(request.match_info['id'])
- info = recorder.get_info(record_id)
- return http.ok(info.as_dict())
-
-
-@routes.get('/record/forget/{id}/')
-async def record_forget(request):
- record_id = int(request.match_info['id'])
-
- info = recorder.get_info(record_id)
- assert info.status in (RecordStatus.FINISHED, RecordStatus.ERROR), f"can't forget: record status is {info.status}"
-
- recorder.forget(record_id)
- return http.ok()
-
-
-@routes.get('/record/download/{id}/')
-async def record_download(request):
- record_id = int(request.match_info['id'])
-
- info = recorder.get_info(record_id)
- assert info.status == RecordStatus.FINISHED, f"record status is {info.status}"
-
- return http.FileResponse(info.file.path)
-
-
-@routes.get('/storage/list/')
-async def storage_list(request):
- extended = 'extended' in request.query and int(request.query['extended']) == 1
-
- files = storage.getfiles(as_objects=extended)
- if extended:
- files = list(map(lambda file: file.__dict__(), files))
-
- return http.ok({
- 'files': files
- })
-
-
-@routes.get('/storage/delete/')
-async def storage_delete(request):
- file_id = request.query['file_id']
- file = storage.find(file_id)
- if not file:
- raise ValueError(f'file {file} not found')
-
- storage.delete(file)
- return http.ok()
-
-
-@routes.get('/storage/download/')
-async def storage_download(request):
- file_id = request.query['file_id']
- file = storage.find(file_id)
- if not file:
- raise ValueError(f'file {file} not found')
-
- return http.FileResponse(file.path)
-
-
-# ALSA mixer methods
-# ------------------
+# This script must be run as root as it runs arecord.
+# Implements HTTP API for amixer and arecord.
+# -------------------------------------------
def _amixer_control_response(control):
info = amixer.get(control)
@@ -117,57 +23,56 @@ def _amixer_control_response(control):
})
-@routes.get('/amixer/get-all/')
-async def amixer_get_all(request):
- controls_info = amixer.get_all()
- return http.ok(controls_info)
-
-
-@routes.get('/amixer/get/{control}/')
-async def amixer_get(request):
- control = request.match_info['control']
- if not amixer.has_control(control):
- raise ValueError(f'invalid control: {control}')
+class SoundNodeServer(MediaNodeServer):
+ def __init__(self, *args, **kwargs):
+ super().__init__(*args, **kwargs)
- return _amixer_control_response(control)
+ self.get('/amixer/get-all/', self.amixer_get_all)
+ self.get('/amixer/get/{control}/', self.amixer_get)
+ self.get('/amixer/{op:mute|unmute|cap|nocap}/{control}/', self.amixer_set)
+ self.get('/amixer/{op:incr|decr}/{control}/', self.amixer_volume)
+ async def amixer_get_all(self, request: http.Request):
+ controls_info = amixer.get_all()
+ return self.ok(controls_info)
-@routes.get('/amixer/{op:mute|unmute|cap|nocap}/{control}/')
-async def amixer_set(request):
- op = request.match_info['op']
- control = request.match_info['control']
- if not amixer.has_control(control):
- raise ValueError(f'invalid control: {control}')
+ async def amixer_get(self, request: http.Request):
+ control = request.match_info['control']
+ if not amixer.has_control(control):
+ raise ValueError(f'invalid control: {control}')
- f = getattr(amixer, op)
- f(control)
+ return _amixer_control_response(control)
- return _amixer_control_response(control)
+ async def amixer_set(self, request: http.Request):
+ op = request.match_info['op']
+ control = request.match_info['control']
+ if not amixer.has_control(control):
+ raise ValueError(f'invalid control: {control}')
+ f = getattr(amixer, op)
+ f(control)
-@routes.get('/amixer/{op:incr|decr}/{control}/')
-async def amixer_volume(request):
- op = request.match_info['op']
- control = request.match_info['control']
- if not amixer.has_control(control):
- raise ValueError(f'invalid control: {control}')
+ return _amixer_control_response(control)
- def get_step() -> Optional[int]:
- if 'step' in request.query:
- step = int(request.query['step'])
- if not 1 <= step <= 50:
- raise ValueError('invalid step value')
- return step
- return None
+ async def amixer_volume(self, request: http.Request):
+ op = request.match_info['op']
+ control = request.match_info['control']
+ if not amixer.has_control(control):
+ raise ValueError(f'invalid control: {control}')
- f = getattr(amixer, op)
- f(control, step=get_step())
+ def get_step() -> Optional[int]:
+ if 'step' in request.query:
+ step = int(request.query['step'])
+ if not 1 <= step <= 50:
+ raise ValueError('invalid step value')
+ return step
+ return None
- return _amixer_control_response(control)
+ f = getattr(amixer, op)
+ f(control, step=get_step())
+ return _amixer_control_response(control)
-# entry point
-# -----------
if __name__ == '__main__':
if not os.getegid() == 0:
@@ -175,9 +80,12 @@ if __name__ == '__main__':
config.load('sound_node')
- storage = RecordStorage(config['node']['storage'])
+ storage = SoundRecordStorage(config['node']['storage'])
- recorder = Recorder(storage=storage)
+ recorder = SoundRecorder(storage=storage)
recorder.start_thread()
- http.serve(parse_addr(config['node']['listen']), routes)
+ server = SoundNodeServer(recorder=recorder,
+ storage=storage,
+ addr=parse_addr(config['node']['listen']))
+ server.run()