livekit / python-sdks

LiveKit real-time and server SDKs for Python
https://docs.livekit.io
Apache License 2.0
70 stars 23 forks source link

Timeout context manager should be used inside a task #189

Open TheNha opened 3 months ago

TheNha commented 3 months ago

Hello,

I used Livekit Egress API, when I called start_track_composite_egress function. I got the following error :

[ERROR]   File "/usr/local/lib/python3.9/site-packages/livekit/api/egress_service.py", line 51, in start_track_composite_egress
[ERROR]     return await self._client.request(
[ERROR]
[ERROR]   File "/usr/local/lib/python3.9/site-packages/livekit/api/twirp_client.py", line 93, in request
[ERROR]     async with self._session.post(
[ERROR]
[ERROR]   File "/usr/local/lib/python3.9/site-packages/aiohttp/client.py", line 1194, in __aenter__
[ERROR]     self._resp = await self._coro
[ERROR]
[ERROR]   File "/usr/local/lib/python3.9/site-packages/aiohttp/client.py", line 504, in _request
[ERROR]     with timer:
[ERROR]
[ERROR]   File "/usr/local/lib/python3.9/site-packages/aiohttp/helpers.py", line 715, in __enter__
[ERROR]     raise RuntimeError(
[ERROR]
[ERROR] RuntimeError: Timeout context manager should be used inside a task

I used async_to_sync function of asgiref library from django.

async def start_track_composite_egress(start):
    return await self.lvk_api.egress.start_track_composite_egress(start)
from asgiref.sync import async_to_sync
res_track_composite = async_to_sync(start_track_composite_egress)(start)

Please help me. Thank you.

xiaokang00010 commented 3 weeks ago

the same error occured to me.

here's my code:

@app.route("/api/v1/rtvc/establish", methods=["POST"])
async def establishRealTimeVoiceChat():
    if not authenticateSession():
        return {'data': 'not authenticated', 'status': False}
    if not dProvider.checkIfInitialized():
        return {'data': 'not initialized', 'status': False}

    charName = ''
    try:
        data = flask.request.get_json()
        charName = data['charName']
    except:
        return {'data': 'invalid form', 'status': False}

    sessionName = uuid.uuid4().hex
    session = webFrontend.chatbotManager.VoiceChatSession(sessionName, charName, dProvider)
    userName = dProvider.getUserName()

    userToken = livekit.api.AccessToken(
            webFrontend.config.LIVEKIT_API_KEY, webFrontend.config.LIVEKIT_API_SECRET).with_identity(
                'user').with_name(userName).with_grants(livekit.api.VideoGrants(room_join=True, room=sessionName)).to_jwt()

    botToken = livekit.api.AccessToken(
            webFrontend.config.LIVEKIT_API_KEY, webFrontend.config.LIVEKIT_API_SECRET).with_identity(
                'model').with_name(charName).with_grants(livekit.api.VideoGrants(room_join=True, room=sessionName)).to_jwt()

    # livekit api is in this file, so we can't put this logic into createRtSession
    await livekitApi.room.create_room(create=livekit.api.CreateRoomRequest(name=sessionName, empty_timeout=10*60, max_participants=2))

Update:

I came up with a solution. Define a event loop by asyncio.new_event_loop() and use it like

    # livekit api is in this file, so we can't put this logic into createRtSession
    async def f():
        await livekitApi.room.create_room(create=livekit.api.CreateRoomRequest(name=sessionName, empty_timeout=10*60, max_participants=2))
        session.start(botToken)

    asyncio.run_coroutine_threadsafe(f(), asyncEventLoop)

It took me at least 1 hour to solve it.

Update:

Fk it. I didn't solve it. However, it just stuck there and refused to create room. I gonna to sleep now.

Update:

My final solution is to use

async def getLiveKitAPI():
    return livekit.api.LiveKitAPI(webFrontend.config.LIVEKIT_API_URL, webFrontend.config.LIVEKIT_API_KEY, webFrontend.config.LIVEKIT_API_SECRET)

Which livekitApi should be initialized in an async def function and can't be initialized globally.

This explained.

theomonnom commented 3 weeks ago

maybe you can use an asyncio event_loop and using run_until_complete?