openBridgeChannel: 'websocket' degrades video quality

I enabled openbridgechannel: websockets, the video quality/resolution degraded. going back to openbridgechannel: true, quality/resolution improved. seems like its reproduceble. as I switched back and forth many times with the same results. Has anyone else experienced this?

Did you actually have working WebSockets? Part of the communication used through the bridge channel is to select the received video quality for each participant. If they don’t work you may not “upgrade” to HD when the active specaker changes. You’ll get 240p for everyone, which is the thumbnail size, but stretched out, hence the perception of poor quality.

Why ddidd you change the bridge channel mode?

I thought I read somewhere on the forum that it was recommened, so I thought I would give it a try. As far as I could tell, websockets was working. its no big deal to me, I just thought Id report it here. If I’m the only one with the issue, than its likely a me issue only! :smiley:

In order to use WebSockets you need to also configure the JVB, since that’s where the connection will be established. Did you do that? Do you see any errors in the JS console about the bridge channel being closed?

I believe so. I uncommented the websocket: line, and enabled websockets on the prosody side. I was given the hint to try updated bosh: url to wss to see if that made any difference. is there something else I may be missing. I’ll reconfig today and see if I there are any errors in JS console

@saghul
Here are the only errors I’m seeing.

Logger.js:154 2020-04-05T14:54:53.579Z [JitsiConference.js] <e.sendMessage>:  Failed to send E2E ping request or response. undefined
o @ Logger.js:154
(anonymous) @ JitsiConference.js:337
value @ e2eping.js:92
setInterval (async)
e @ e2eping.js:62
value @ e2eping.js:298
c.emit @ events.js:151
oe.onMemberJoined @ JitsiConference.js:1487
c.emit @ events.js:146
value @ ChatRoom.js:545
value @ strophe.emuc.js:103
run @ strophe.umd.js:1875
(anonymous) @ strophe.umd.js:3157
forEachChild @ strophe.umd.js:830
_dataRecv @ strophe.umd.js:3146
_onMessage @ strophe.umd.js:5836

Logger.js:154 2020-04-05T14:55:10.607Z [modules/xmpp/XmppConnection.js] <t.value>:  Scheduling next WebSocket keep-alive in 95066.1905758738ms
Logger.js:154 2020-04-05T14:55:12.578Z [JitsiConference.js] <e.sendMessage>:  Failed to send E2E ping request or response. undefined

Hi speedy01,
Do you have enable the websocket proxy to videobridge in your nginx configuration like describe here : https://github.com/jitsi/jitsi-videobridge/blob/master/doc/web-sockets.md.
You talk about prosody configuration but openbridgechannel is not related to prosody.
There are 2 different communication channel which can be configured to use websocket :

  • client to prosody connexion (bosh or websocket)
  • client to videobridge connexion (stcp or websocket)

Which one have you configured ?

gotcha. this may be my problem. Is there a benefit to using websockets over stcp on the videobridge?

I don’t know what is the current recommendation with jvb2.
For the old bridge websocket was more stable than stcp (stcp could crash the v1 of videobridge in some corner case).

Hello guys,

I’m trying to figure out the websocket implementation.
I followed the guide and edited the videobridge2 sip-communicator-properties.
Also edited the nginx config (as you can see below) and the my.domain.config.js in meet.

Everything is on the same machine (installed the default jitsi-meet with apt-install).

When trying to connect to a room, i can see some errors in the Chrome’s console:
Error during WebSocket handshake: Unexpected response code: 200

Searched for this issue and found something here and setted everything like that.

Here is my nginx.conf (/etc/nginx/sites-enabled/my.domain.conf):

server_names_hash_bucket_size 64;

server {
    listen 80;
    listen [::]:80;
    server_name my.domain;

    location ^~ /.well-known/acme-challenge/ {
       default_type "text/plain";
       root         /usr/share/jitsi-meet;
    }
    location = /.well-known/acme-challenge/ {
       return 404;
    }
    location / {
       return 301 https://$host$request_uri;
    }
}
server {
    listen 443 ssl;
    listen [::]:443 ssl;
    server_name my.domain;

    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_prefer_server_ciphers on;
    ssl_ciphers "EECDH+ECDSA+AESGCM:EECDH+aRSA+AESGCM:EECDH+ECDSA+SHA256:EECDH+aRSA+SHA256:EECDH+ECDSA+SHA384:EECDH+ECDSA+SHA256:EECDH+aRSA+SHA384:EDH+aRSA+AESGCM:EDH+aRSA+SHA256:EDH+aRSA:EECDH:!aNULL$

    add_header Strict-Transport-Security "max-age=31536000";

    ssl_certificate /etc/letsencrypt/live/my.domain/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/my.domain/privkey.pem;

    root /usr/share/jitsi-meet;

    # ssi on with javascript for multidomain variables in config.js
    ssi on;
    ssi_types application/x-javascript application/javascript;

    index index.html index.htm;
    error_page 404 /static/404.html;

    gzip on;
    gzip_types text/plain text/css application/javascript application/json;
    gzip_vary on;

    location = /config.js {
        alias /etc/jitsi/meet/my.domain-config.js;
    }

    location = /external_api.js {
        alias /usr/share/jitsi-meet/libs/external_api.min.js;
    }

    #ensure all static content can always be found first
    location ~ ^/(libs|css|static|images|fonts|lang|sounds|connection_optimization|.well-known)/(.*)$
    {
        add_header 'Access-Control-Allow-Origin' '*';
        alias /usr/share/jitsi-meet/$1/$2;
    }

    # BOSH
    location = /http-bind {
        proxy_pass      http://localhost:5280/http-bind;
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_set_header Host $http_host;
    }

    # xmpp websockets
    location = /xmpp-websocket {
        proxy_pass http://127.0.0.1:5280/xmpp-websocket?prefix=$prefix&$args;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host my.domain;
        tcp_nodelay on;
    }

    location ~ ^/([^/?&:'"]+)$ {
        try_files $uri @root_path;
    }
 location @root_path {
        rewrite ^/(.*)$ / break;
    }

    location ~ ^/([^/?&:'"]+)/config.js$
    {
       set $subdomain "$1.";
       set $subdir "$1/";

       alias /etc/jitsi/meet/my.domain-config.js;
    }

    #Anything that didn't match above, and isn't a real file, assume it's a room name and redirect to /
    location ~ ^/([^/?&:'"]+)/(.*)$ {
        set $subdomain "$1.";
        set $subdir "$1/";
        rewrite ^/([^/?&:'"]+)/(.*)$ /$2;
    }
    # BOSH for subdomains
    location ~ ^/([^/?&:'"]+)/http-bind {
        set $subdomain "$1.";
        set $subdir "$1/";
        set $prefix "$1";

        rewrite ^/(.*)$ /http-bind;
    }

    # websockets for subdomains
    location ~ ^/([^/?&:'"]+)/xmpp-websocket {
        set $subdomain "$1.";
        set $subdir "$1/";
        set $prefix "$1";

        rewrite ^/(.*)$ /xmpp-websocket;
    }

      # colibri (JVB) websockets for jvb1
   location ~ ^/colibri-ws/jvb1/(.*) {
       proxy_pass http://127.0.0.1:9090/colibri-ws/jvb1/$1$is_args$args;
       proxy_http_version 1.1;
       proxy_set_header Upgrade $http_upgrade;
       proxy_set_header Connection "upgrade";
       tcp_nodelay on;
       proxy_set_header Host my.domain;
   }

}

And here the JVB2 sip-communicator:

org.ice4j.ice.harvest.DISABLE_AWS_HARVESTER=true
org.ice4j.ice.harvest.STUN_MAPPING_HARVESTER_ADDRESSES=meet-jit-si-turnrelay.jitsi.net:443
org.jitsi.videobridge.ENABLE_STATISTICS=true
org.jitsi.videobridge.STATISTICS_TRANSPORT=muc
org.jitsi.videobridge.xmpp.user.shard.HOSTNAME=my.domain
org.jitsi.videobridge.xmpp.user.shard.DOMAIN=auth.my.domain
org.jitsi.videobridge.xmpp.user.shard.USERNAME=jvb
org.jitsi.videobridge.xmpp.user.shard.PASSWORD=5tSPZ0ar
org.jitsi.videobridge.xmpp.user.shard.MUC_JIDS=JvbBrewery@internal.auth.my.domain
org.jitsi.videobridge.xmpp.user.shard.MUC_NICKNAME=a08c909c-c358-4549-a966-a381bdfaa69a

org.jitsi.videobridge.rest.jetty.port=9090
org.jitsi.videobridge.rest.COLIBRI_WS_TLS=true
org.jitsi.videobridge.rest.COLIBRI_WS_DOMAIN=my.domain:443
1 Like

Not sure if this is the same thing but I also faced the same issue…
I solved it by moving the collibri-ws proxy configuration in nginx config from bottom to after xmpp-websocket. It seemed to work for me. So the new nginx conf in your case would be:

 server_names_hash_bucket_size 64;    
server {
        listen 80;
        listen [::]:80;
        server_name my.domain;

        location ^~ /.well-known/acme-challenge/ {
           default_type "text/plain";
           root         /usr/share/jitsi-meet;
        }
        location = /.well-known/acme-challenge/ {
           return 404;
        }
        location / {
           return 301 https://$host$request_uri;
        }
    }
    server {
        listen 443 ssl;
        listen [::]:443 ssl;
        server_name my.domain;

        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
        ssl_prefer_server_ciphers on;
        ssl_ciphers "EECDH+ECDSA+AESGCM:EECDH+aRSA+AESGCM:EECDH+ECDSA+SHA256:EECDH+aRSA+SHA256:EECDH+ECDSA+SHA384:EECDH+ECDSA+SHA256:EECDH+aRSA+SHA384:EDH+aRSA+AESGCM:EDH+aRSA+SHA256:EDH+aRSA:EECDH:!aNULL$

        add_header Strict-Transport-Security "max-age=31536000";

        ssl_certificate /etc/letsencrypt/live/my.domain/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/my.domain/privkey.pem;

        root /usr/share/jitsi-meet;

        # ssi on with javascript for multidomain variables in config.js
        ssi on;
        ssi_types application/x-javascript application/javascript;

        index index.html index.htm;
        error_page 404 /static/404.html;

        gzip on;
        gzip_types text/plain text/css application/javascript application/json;
        gzip_vary on;

        location = /config.js {
            alias /etc/jitsi/meet/my.domain-config.js;
        }

        location = /external_api.js {
            alias /usr/share/jitsi-meet/libs/external_api.min.js;
        }

        #ensure all static content can always be found first
        location ~ ^/(libs|css|static|images|fonts|lang|sounds|connection_optimization|.well-known)/(.*)$
        {
            add_header 'Access-Control-Allow-Origin' '*';
            alias /usr/share/jitsi-meet/$1/$2;
        }

        # BOSH
        location = /http-bind {
            proxy_pass      http://localhost:5280/http-bind;
            proxy_set_header X-Forwarded-For $remote_addr;
            proxy_set_header Host $http_host;
        }

        # xmpp websockets
        location = /xmpp-websocket {
            proxy_pass http://127.0.0.1:5280/xmpp-websocket?prefix=$prefix&$args;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
            proxy_set_header Host my.domain;
            tcp_nodelay on;
        }
    # colibri (JVB) websockets for jvb1
       location ~ ^/colibri-ws/jvb1/(.*) {
           proxy_pass http://127.0.0.1:9090/colibri-ws/jvb1/$1$is_args$args;
           proxy_http_version 1.1;
           proxy_set_header Upgrade $http_upgrade;
           proxy_set_header Connection "upgrade";
           tcp_nodelay on;
           proxy_set_header Host my.domain;
       }

        location ~ ^/([^/?&:'"]+)$ {
            try_files $uri @root_path;
        }
     location @root_path {
            rewrite ^/(.*)$ / break;
        }

        location ~ ^/([^/?&:'"]+)/config.js$
        {
           set $subdomain "$1.";
           set $subdir "$1/";

           alias /etc/jitsi/meet/my.domain-config.js;
        }

        #Anything that didn't match above, and isn't a real file, assume it's a room name and redirect to /
        location ~ ^/([^/?&:'"]+)/(.*)$ {
            set $subdomain "$1.";
            set $subdir "$1/";
            rewrite ^/([^/?&:'"]+)/(.*)$ /$2;
        }
        # BOSH for subdomains
        location ~ ^/([^/?&:'"]+)/http-bind {
            set $subdomain "$1.";
            set $subdir "$1/";
            set $prefix "$1";

            rewrite ^/(.*)$ /http-bind;
        }

        # websockets for subdomains
        location ~ ^/([^/?&:'"]+)/xmpp-websocket {
            set $subdomain "$1.";
            set $subdir "$1/";
            set $prefix "$1";

            rewrite ^/(.*)$ /xmpp-websocket;
        }

    }

because there’s an nginx rule in your configuration which is superceding the websocket configuration. Hopefully this helps. Thank you