Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 34 additions & 1 deletion recording/src/nextcloud/talk/recording/Service.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
from datetime import datetime
from pyvirtualdisplay import Display
from secrets import token_urlsafe
from threading import Thread
from threading import Event, Thread

from . import BackendNotifier
from .Config import config
Expand Down Expand Up @@ -169,6 +169,9 @@ def __init__(self, backend, token, status, owner):
self.status = status
self.owner = owner

self._started = Event()
self._stopped = Event()

self._display = None
self._audioModuleIndex = None
self._participant = None
Expand Down Expand Up @@ -213,10 +216,16 @@ def start(self, actorType, actorId):
self._display = Display(size=(width, height), manage_global_env=False)
self._display.start()

if self._stopped.is_set():
raise Exception("Display started after recording was stopped")

# Start new audio sink for the audio output of the browser.
self._audioModuleIndex, audioSinkIndex = newAudioSink(sanitizedBackend, self.token)
audioSinkIndex = str(audioSinkIndex)

if self._stopped.is_set():
raise Exception("Audio sink started after recording was stopped")

env = self._display.env()
env['PULSE_SINK'] = audioSinkIndex

Expand All @@ -226,6 +235,14 @@ def start(self, actorType, actorId):
self._logger.debug("Joining call")
self._participant.joinCall(self.token)

if self._stopped.is_set():
# Not strictly needed, as if the participant is started or the
# call is joined after the recording was stopped there will be
# no display and it will automatically fail, but just in case.
raise Exception("Call joined after recording was stopped")

self._started.set()

BackendNotifier.started(self.backend, self.token, self.status, actorType, actorId)

extensionlessFileName = f'{fullDirectory}/recording-{datetime.now().strftime("%Y%m%d-%H%M%S")}'
Expand All @@ -240,6 +257,12 @@ def start(self, actorType, actorId):
# Log recorder output.
Thread(target=recorderLog, args=[self.backend, self.token, self._process.stdout], daemon=True).start()

if self._stopped.is_set():
# Not strictly needed, as if the recorder is started after the
# recording was stopped there will be no display and it will
# automatically fail, but just in case.
raise Exception("Call joined after recording was stopped")

returnCode = self._process.wait()

# recorder process will be explicitly terminated when needed, which
Expand All @@ -250,6 +273,14 @@ def start(self, actorType, actorId):
except Exception as exception:
self._stopHelpers()

if self._stopped.is_set() and not self._started.is_set():
# If the service fails before being started but it was already
# stopped the error does not need to be notified; the error was
# probably caused by stopping the helpers, and even if it was
# something else it does not need to be notified either given
# that the recording was not started yet.
raise

try:
BackendNotifier.failed(self.backend, self.token)
except:
Expand All @@ -271,6 +302,8 @@ def stop(self, actorType, actorId):
:raise Exception: if the file could not be uploaded.
"""

self._stopped.set()

self._stopHelpers()

BackendNotifier.stopped(self.backend, self.token, actorType, actorId)
Expand Down