0

I tried to pass the sio instance to another class and send some calls from there to the client and when finished return back to the process_msg function.

But I guess since this is an async function, it won't work this way, I only get:

RuntimeWarning: coroutine 'AsyncServer.call' was never awaited

Is this even possible to emit or call from outside of the event handler? How could I accomplish something like this?

I've already tried and searched a lot, but couldn't find a solution.

Maybe this code helps to understand my problem:

import socketio
from aiohttp import web


class TestClass:
    def __init__(self):
        self.sio = socketio.AsyncServer(async_mode='aiohttp')
        self.response_functions()
        self.app = web.Application()
        self.sio.attach(self.app)
        web.run_app(self.app, host="0.0.0.0", port=5000, print=None, access_log=None)
        
    def response_functions(self):

        @self.sio.on("message")
        async def process_msg(sid, msg):
            ac = AnotherClass(self.sio, sid)
            ac.do_some_action_here()
            await self.sio.emit("my_event", "is_finished")

class AnotherClass:
    def __init__(self, sio, sid):
        self.sio = sio
        self.sid = sid

    def do_some_action_here(self):
        # send some calls to the client, and wait to finish
        self.sio.call("foo", "bar1", to=self.sid)
        self.sio.call("foo", "bar2", to=self.sid)
        self.sio.call("foo", "bar3", to=self.sid)
        # return back to the event handler

TestClass()

Edit: It does work when I do the following:

        async def process_msg(sid, msg):
            ac = AnotherClass(self.sio, sid)
            await ac.do_some_action_here()
            await self.sio.emit("my_event", "is_finished")

        async def do_some_action_here(self):
            # send some calls to the client, and wait to finish
            await self.sio.call("foo", "bar1", to=self.sid)

But unfortunately this is not an option for me because in my real code there are a dozen of other functions and classes before. I would like to set a method in a singleton threading helper class, which I can access from all over my code to send events to the client before the event is complete finished.

Edit 2:

I've finally found a way to accomplish what I need. I just need to run the "AnotherClass" in a separated thread and get the event loop, this way I can do some other stuff and still call the client and wait for an answer.

Thanks @Miguel Grinberg for the hint with "Mixing sync and async code", this made me think and I could find another solution and also got a bit more experience with async code.

Here my final example in case someone else needs a similar solution:

import socketio
from aiohttp import web
import asyncio
from threading import Thread

class TestClass:
    def __init__(self):
        self.sio = socketio.AsyncServer(async_mode='aiohttp')
        self.response_functions()
        self.app = web.Application()
        self.sio.attach(self.app)
        web.run_app(self.app, host="0.0.0.0", port=5000, print=None, access_log=None)
        
    def response_functions(self):
        @self.sio.on("message")
        async def process_msg(sid, msg):
            server_loop = asyncio.get_event_loop()
            AnotherClass(self.sio, sid, server_loop).start()

class AnotherClass(Thread):
    def __init__(self, sio, sid, server_loop):
        super(AnotherClass, self).__init__(daemon=True)
        self.sio = sio
        self.sid = sid
        self.server_loop = server_loop

    def run(self):
        # Do some calls and wait for each call to finish
        self.handler("foo", "bar1")
        self.handler("foo", "bar2")
        self.handler("foo", "bar3")

    def handler(self, event, msg):
        async def send(event, msg):
            await self.sio.call(event, msg, to=self.sid)
        asyncio.run_coroutine_threadsafe(send(event, msg), self.server_loop).result()

TestClass()
  • 1
    Mixing sync and async code is often a source of problems. If you are going to use the async Socket.IO server, then your functions have to be async, so that you can await the calls to the Socket.IO server. – Miguel Grinberg Apr 23 '23 at 21:17

1 Answers1

0

The problem is that you are passing the WAV header as if it was sound data. The JS Audio interface needs only raw audio data, the WAV header should not be included in the audio that you send from the server.

You aren't showing the server code here, but the bug is there. You have to properly parse the WAV file and extract the audio data. You should only send audio data over Socket.IO to your client.

Miguel Grinberg
  • 65,299
  • 14
  • 133
  • 152