Skip to content

Commit ec49f4e

Browse files
committed
Start the demo's services with the server
Building them at import allocated a room and a composition before startup, and leaked the room when the composition failed.
1 parent 49eebe2 commit ec49f4e

2 files changed

Lines changed: 41 additions & 42 deletions

File tree

examples/composition/composition/app.py

Lines changed: 39 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from contextlib import asynccontextmanager
2+
13
from starlette.applications import Starlette
24
from starlette.middleware import Middleware
35
from starlette.middleware.cors import CORSMiddleware
@@ -9,41 +11,62 @@
911
from .config import COMPOSITION_URL, FISHJAM_ID, FISHJAM_TOKEN
1012
from .fishjam_service import FishjamService
1113

12-
fishjam = FishjamService(FISHJAM_ID, FISHJAM_TOKEN)
13-
composition = CompositionService(FISHJAM_TOKEN, COMPOSITION_URL)
14-
15-
16-
def start_composing() -> None:
17-
composition.register_assets()
18-
composition.play_movie()
19-
composition.camera()
20-
composition.stream_to(
21-
fishjam.livestream_whip_url(), fishjam.create_streamer_token()
22-
)
2314

15+
def clean_up(*services) -> None:
16+
for service in services:
17+
if service is None:
18+
continue
2419

25-
def cleanup() -> None:
26-
for service in (composition, fishjam):
2720
try:
2821
service.cleanup()
2922
except Exception as error:
3023
print(f"cleanup failed: {error}")
3124

3225

33-
async def streamer(_request: Request) -> Response:
34-
camera = composition.camera()
26+
@asynccontextmanager
27+
async def lifespan(app: Starlette):
28+
fishjam = composition = None
29+
30+
try:
31+
fishjam = FishjamService(FISHJAM_ID, FISHJAM_TOKEN)
32+
composition = CompositionService(FISHJAM_TOKEN, COMPOSITION_URL)
33+
composition.register_assets()
34+
composition.play_movie()
35+
composition.camera()
36+
composition.stream_to(
37+
fishjam.livestream_whip_url(), fishjam.create_streamer_token()
38+
)
39+
except Exception:
40+
clean_up(composition, fishjam)
41+
raise
42+
43+
app.state.fishjam = fishjam
44+
app.state.composition = composition
45+
46+
try:
47+
yield
48+
finally:
49+
clean_up(composition, fishjam)
50+
print("deleted the composition and the livestream room")
51+
52+
53+
async def streamer(request: Request) -> Response:
54+
camera = request.app.state.composition.camera()
3555

3656
return JSONResponse({"url": camera.url, "token": camera.bearer_token})
3757

3858

39-
async def viewer(_request: Request) -> Response:
59+
async def viewer(request: Request) -> Response:
60+
fishjam = request.app.state.fishjam
61+
4062
return JSONResponse({
4163
"url": fishjam.livestream_whep_url(),
4264
"token": fishjam.create_viewer_token(),
4365
})
4466

4567

4668
app = Starlette(
69+
lifespan=lifespan,
4770
routes=[
4871
Route("/streamer", streamer, methods=["GET"]),
4972
Route("/viewer", viewer, methods=["GET"]),

examples/composition/main.py

Lines changed: 2 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,8 @@
1-
import sys
2-
from contextlib import asynccontextmanager
3-
41
import uvicorn
5-
from composition.app import app, cleanup, start_composing
2+
from composition.app import app
63
from composition.config import HOST, PORT
74

8-
9-
@asynccontextmanager
10-
async def lifespan(_app):
11-
try:
12-
start_composing()
13-
except Exception as error:
14-
print(f"failed to start composing: {error}", file=sys.stderr)
15-
cleanup()
16-
raise SystemExit(1) from error
17-
5+
if __name__ == "__main__":
186
print(f"streamer credentials on http://{HOST}:{PORT}/streamer")
197
print(f"viewer token on http://{HOST}:{PORT}/viewer")
20-
21-
try:
22-
yield
23-
finally:
24-
cleanup()
25-
print("deleted the composition and the livestream room")
26-
27-
28-
app.router.lifespan_context = lifespan
29-
30-
31-
if __name__ == "__main__":
328
uvicorn.run(app, host=HOST, port=PORT, log_level="info")

0 commit comments

Comments
 (0)