2

I am attempting to setup an app that streams your webcam on a website (by following this tutorial with some modifications). When attempting to set it up through SocketIO, I get an error:

socketio.exceptions.BadNamespaceError: / is not a connected namespace.

I have seen people suggest that this error is due to the emit() function is called faster than the connect() function. However, my connect() function is done in such a manner:

    def setup(self):
    print('[INFO] Connecting to server http://{}:{}...'.format(
        self.server_addr, self.server_port))
    sio.connect(
            'http://{}:{}'.format(self.server_addr, self.server_port),
            transports=['websocket'],
            namespaces=['/cv'])
    time.sleep(1)
    return self

I tried to vary the sleep time (to allow for more time for connect to finish setting up) but the error still persists, and I was wondering how I could approach this problem.

My code is setup in 2 files, a server file that creates the server, and a cv file that sends the data. This is the server file:

from flask_socketio import SocketIO
from flask import Flask, render_template, request
from datetime import datetime

app = Flask(__name__)
socketio = SocketIO(app)


@app.route('/')
def index():
    """Home page."""
    return render_template('index.html')


@socketio.on('connect', namespace='/web')
def connect_web():
    print('[INFO @ {}] Web client connected: {}'.format(datetime.now(), request.sid))


@socketio.on('disconnect', namespace='/web')
def disconnect_web():
    print('[INFO @ {}] Web client disconnected: {}'.format(datetime.now(), request.sid))


@socketio.on('connect', namespace='/cv')
def connect_cv():
    print('[INFO @ {}] CV client connected: {}'.format(datetime.now(), request.sid))
    

@socketio.on('disconnect', namespace='/cv')
def disconnect_cv():
    print('[INFO @ {}] CV client disconnected: {}'.format(datetime.now(), request.sid))


@socketio.on('cv2server')
def handle_cv_message(message):
    socketio.emit('server2web', message, namespace='/web')


if __name__ == "__main__":
    print('[INFO @ {}] Starting server at http://localhost:5001'.format(datetime.now()))
    socketio.run(app=app, host='0.0.0.0', port=5001)

And this is the cv file that sends the data:

import time
import cv2

import argparse
import socketio
import base64

sio = socketio.Client()

@sio.event
def connect():
    print('[INFO] Successfully connected to server.')


@sio.event
def connect_error():
    print('[INFO] Failed to connect to server.')


@sio.event
def disconnect():
    print('[INFO] Disconnected from server.')


class CVClient(object):
    def __init__(self, server_addr, stream_fps):
        self.server_addr = server_addr
        self.server_port = 5001
        self._stream_fps = stream_fps
        self._last_update_t = time.time()
        self._wait_t = (1/self._stream_fps)

    def setup(self):
        print('[INFO] Connecting to server http://{}:{}...'.format(
            self.server_addr, self.server_port))
        sio.connect(
                'http://{}:{}'.format(self.server_addr, self.server_port),
                transports=['websocket'],
                namespaces=['/cv'])
        time.sleep(1)
        return self

    def _convert_image_to_jpeg(self, image):
        # Encode frame as jpeg
        frame = cv2.imencode('.jpg', image)[1].tobytes()
        # Encode frame in base64 representation and remove
        # utf-8 encoding
        frame = base64.b64encode(frame).decode('utf-8')
        return "data:image/jpeg;base64,{}".format(frame)

    def send_data(self, frame):
        cur_t = time.time()
        if cur_t - self._last_update_t > self._wait_t:
            self._last_update_t = cur_t
            cv2.resize(frame, (640,480))

            sio.emit(
                    'cv2server',
                    {
                        'image': self._convert_image_to_jpeg(frame)
                    })

    def check_exit(self):
        pass

    def close(self):
        sio.disconnect()


def main(use_streamer, server_addr, stream_fps):

    cap = cv2.VideoCapture(0)

    try:
        streamer = None
        streamer = CVClient(server_addr, stream_fps).setup()

        while True:
            success, img = cap.read()
            streamer.send_data(img)
            if streamer.check_exit():
                break

    finally:
        if streamer is not None:
            streamer.close()
        print("Program Ending")


if __name__ == "__main__":
    parser = argparse.ArgumentParser(description='Video Streamer')
    parser.add_argument(
        '--use-streamer', action='store_true',
        help='Use the embedded streamer instead of connecting to the server.')
    parser.add_argument(
        '--server-addr', type=str, default='localhost',
        help='The IP address or hostname of the SocketIO server.')
    parser.add_argument(
        '--stream-fps', type=float, default=20.0,
        help='The rate to send frames to the server.')
    args = parser.parse_args()
    main(args.use_streamer, args.server_addr, args.stream_fps)

Thanks in advance for any help you can provide!

1 Answer 1

2

You are connecting the /cv namespace. Then you are emitting on the default namespace /, which is not connected. Change your emit to use the /cv namespace and the error will go away. Or else also ask to connect the / namespace if that is what you need.

Also as a side note, the issue with not waiting enough time after the connect was a bug, and has been fixed. Current releases do not require a waiting period before emitting.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.