Не могу установить соединение с собеседниками WebRTC. Собеседники не могут подключиться

Возникла проблема с установлением аудиовызовов между пользователями. На Android есть приложение, в котором аудиосвязь между пользователями работает идеально. Однако при попытке позвонить из веб-браузера на Android возникает ошибка подключения. Вот мой HTML-код, который я использую:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>AudioCall</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.5.0/socket.io.js"></script>
</head>
<body>
    <h1>AudioCall</h1>
    <label for="myId">you ID:</label>
    <input type="text" id="myId" value="243"><br><br>
    <label for="recipientId">ID users for:</label>
    <input type="text" id="recipientId" value="3039"><br><br>
    <button id="callButton">Call</button>
    <button id="endCallButton">End Call</button>

    <script>
    const socket = io('https://srv1-node-call-jakarta.dkon.app', {
        query: { token: "7d3d3b6c2d3683bf25bbb51533ec6dab" }
    });

    let localStream;
    let peerConnection;
    let DkonCalls =socket.id;    
        
        let globalSocketId;
        let pizda;

    const configuration = {
        iceServers: [
            { urls: 'stun:stun.cloudflare.com:3478' },
            {
                urls: "turn:global.relay.metered.ca:80",
                username: "688db195aa1c5ae4555d3fb5",
                credential: "x9XGuSBKLsedMYoe",
            },
            {
                urls: "turn:global.relay.metered.ca:443",
                username: "688db195aa1c5ae4555d3fb5",
                credential: "x9XGuSBKLsedMYoe",
            },
        ]
    };

        
        socket.on('connect', () => {
            const myId = document.getElementById('myId').value;
            socket.emit('socket_user_connect', { connectedId: myId, connected: true, userToken: "7d3d3b6c2d3683bf25bbb51533ec6dab", socketId: socket.id });
            console.log(`Подключен с сокет ID: ${socket.id}`);
        });
    document.getElementById('callButton').addEventListener('click', () => {
        if (peerConnection) {
            console.log("Уже есть активный вызов. Пожалуйста, завершите его перед началом нового.");
            return;
        }

        const myId = document.getElementById('myId').value;
        const recipientId = document.getElementById('recipientId').value;

        console.log(`Попытка позвонить пользователю с ID: ${recipientId} от пользователя с ID: ${myId}`);

        socket.emit('socket_call_user_ping', { recipientId: recipientId }, (data) => {
            if (data.socketId) {
                console.log(`Пользователь с ID ${recipientId} доступен. Socket ID: ${data.socketId}`);
                globalSocketId = data.socketId;
                socket.emit('make_new_call', {
                    to: data.socketId,
                    from: socket.id,
                    callerID: myId,
                    isAudioCall: true
                });
            } else {
                console.log(`Пользователь с ID ${recipientId} не доступен`);
            }
        });
    });
        
        socket.on('receive_new_call', (data) => {
    const { callerID, from } = data;
            console.dir(data);
            pizda = data.from;
            pizdato = data.to;
            console.log('PP',pizdato);
         

    console.log(`Входящий звонок от пользователя с ID ${callerID}`);

    const callDiv = document.createElement('div');
    callDiv.innerHTML = `
        <p>Входящий звонок от пользователя с ID ${callerID}</p>
        <button id="acceptCall">Принять</button>
        <button id="rejectCall">Отклонить</button>
    `;
    document.body.appendChild(callDiv);

    document.getElementById('acceptCall').onclick = () => {
        console.log(`Вы приняли звонок от пользователя с ID ${callerID}`);
        
        // Отправка сигнала о принятии вызова
        socket.emit('accept_new_call', { callerSocketId: from, userSocketId: socket.id });
        
        if (from) {
            socket.emit('signaling_server', { to: from, from: socket.id, type:'init', payload:'payload'});
            
            
         
            console.dir(data);
        } else {
            console.error('from is undefined, cannot emit signaling_server');
        }
        
        startCall(from);
        document.body.removeChild(callDiv);
    };

    document.getElementById('rejectCall').onclick = () => {
        console.log(`Вы отклонили звонок от пользователя с ID ${callerID}`);
        socket.emit('reject_new_call', { userSocketId: socket.id, callerSocketId: from, reason: "IGNORED" });
        endCall(); // Завершите вызов
        document.body.removeChild(callDiv);
    };
});

    function startCall(callerSocketId) {
        console.log(`Начинаем звонок с Caller Socket ID: ${callerSocketId}`);

        if (peerConnection) {
            peerConnection.close();
            peerConnection = null;
        }

        peerConnection = new RTCPeerConnection(configuration);

        navigator.mediaDevices.getUserMedia({ audio: true })
            .then(stream => {
                localStream = stream;
                localStream.getTracks().forEach(track => peerConnection.addTrack(track, localStream));

                peerConnection.onicecandidate = event => {
                    if (event.candidate) {
                        console.log('Отправка ICE-кандидата:', event.candidate);
                        
                     
                        console.log('Отправка ICE-кандидатаssss:', event.candidate.sdpMLineIndex);
                        
                       
                        socket.emit('signaling_server', { to: globalSocketId, from: socket.id, type:"offer", payload: {type: "offer", sdpMLineIndex: 0, sdpMid: "audio", sdp:event.candidate.candidate} });
                        
                    
                        
                        socket.emit('ice_candidate', {
    candidate: {
        candidate: event.candidate.candidate,
        sdpMid: event.candidate.sdpMid,
        sdpMLineIndex: event.candidate.sdpMLineIndex
    },
    to: globalSocketId,
    from: socket.id
});

                   
                        
                       console.dir(event);
                        console.log(socket.id);
                  
                        
                    }
                };

                peerConnection.ontrack = event => {
                    const remoteAudio = document.createElement('audio');
                    remoteAudio.srcObject = event.streams[0];
                    remoteAudio.autoplay = true; // Автоматическое воспроизведение
                    document.body.appendChild(remoteAudio);
                    console.log('Удаленный поток подключен.');
                };

                // Создание предложения
                peerConnection.createOffer()
                    .then(offer => {
                        console.log('Создано предложение:', offer);
                        return peerConnection.setLocalDescription(offer);
                    })
                    .then(() => {
                        console.log('Отправка предложения вызова:', peerConnection.localDescription);
                       // console.dir(userSocketId);
                        socket.emit('call_answer', {
                            sdp: peerConnection.localDescription.sdp,
                            to: globalSocketId,
                            type: peerConnection.localDescription.type// peerConnection.candidate
                        });
                    
                    socket.emit('signaling_server', { to: globalSocketId, from: socket.id, type:peerConnection.localDescription.type, payload:peerConnection.localDescription.sdp});
                    
                     console.log('Оdfggrа:', globalSocketId);
                    console.log('candidatess:', peerConnection.localDescription.sdp);
                   
                    })
                    .catch(error => {
                        console.error('Ошибка при создании предложения:', error);
                    });

            })
            .catch(error => {
                console.error('Ошибка доступа к аудиоустройству:', error);
            });
    }

    // Обработка предложения вызова
    socket.on('call_offer', (data) => {
        const offer = data.offer;
        const callerSocketId = data.from;
console.dir(data);
        console.log(`Получено предложение вызова от ${callerSocketId}:`, offer);
console.dir(data);
        if (!peerConnection) {
            peerConnection = new RTCPeerConnection(configuration);
        }

        peerConnection.setRemoteDescription(new RTCSessionDescription(offer))
            .then(() => {
                console.log('Удаленное описание установлено.');
            
                return peerConnection.createAnswer();
            })
            .then(answer => {
                return peerConnection.setLocalDescription(answer);
            })
            .then(() => {
                console.log('Отправка ответа на вызов:', peerConnection.localDescription);
                socket.emit('call_answer', {
                    answer: peerConnection.localDescription,
                    to: callerSocketId
                });
            
            })
            .catch(error => {
                console.error('Ошибка при обработке предложения вызова:', error);
            });
        console.dir(data);
    });

    socket.on('ice_candidate', (data) => {
    const candidate = data.candidate;
    console.log('Получен ICE-кандидат:', candidate); // Логирование кандидата для отладки
    
    // Проверка на наличие необходимых полей
    if (candidate && candidate.sdpMid !== null && candidate.sdpMLineIndex !== null) {
        peerConnection.addIceCandidate(new RTCIceCandidate(candidate))
            .then(() => {
                console.log('ICE-кандидат добавлен успешно');
            })
            .catch(error => {
                console.error('Ошибка при добавлении ICE-кандидата:', error);
            });
    } else {
        console.error('Получен некорректный ICE-кандидат:', candidate);
    }
});
        
        socket.on('signaling_server', (data) => {
    console.log('Получено сообщение:', data);
    console.dir(data);
    console.error('signaling_server Pl',data);
    // Проверка на наличие необходимых полей
    if (data.type === 'offer') {
        // Обработка предложения
        const offer = data.payload;
        console.log('Получено предложение:', offer);
        
        if (offer.sdp) {
            // Установка удаленного описания
            peerConnection.setRemoteDescription(new RTCSessionDescription(offer))
                .then(() => {
                    console.log('Удаленное описание установлено.');
                    // Создание ответа на предложение
                    return peerConnection.createAnswer();
                })
                .then(answer => {
                    return peerConnection.setLocalDescription(answer);
                })
                .then(() => {
                    console.log('Ответ на предложение отправлен:', peerConnection.localDescription);
                    socket.emit('call_answer', {
                        answer: peerConnection.localDescription,
                        to: data.from // Отправка ответа обратно
                    });
                })
                .catch(error => {
                    console.error('Ошибка при обработке предложения:', error);
                });
        }
    } else if (data.type === 'candidate') {
        // Обработка ICE-кандидата
        const candidate = data.payload;
        console.log('Получен ICE-кандидат:', candidate);
        
        if (candidate && candidate.sdpMid !== null && candidate.sdpMLineIndex !== null) {
            peerConnection.addIceCandidate(new RTCIceCandidate({
                candidate: candidate.candidate,
                sdpMid: candidate.sdpMid,
                sdpMLineIndex: candidate.sdpMLineIndex
            }))
            .then(() => {
                console.log('ICE-кандидат добавлен успешно');
            })
            .catch(error => {
                console.error('Ошибка при добавлении ICE-кандидата:', error);
            });
        } else {
            console.error('Получен некорректный ICE-кандидат:', candidate);
        }
    } else if (data.type === 'init') {
        // Обработка типа "init"
        console.log('Получено сообщение типа "init":', data);
        
        // Отправка сообщения типа "init" обратно
        console.dir(data);
        socket.emit('signaling_server', {
         
            
            type: 'init',
            from: socket.id,//socket.id,// Укажите, от кого отправляется сообщение
            to: data.from
            
         
        });
       // console.error('ssss:', data.from);
        console.dir(data);
        console.log('Полdfddd":', pizda);

    } else {
        console.error('Неизвестный тип сообщения:', data.type);
    }
});

        
      
        socket.on('ice_candidate', (data) => {
    const candidate = data.candidate;
    console.log('Получен ICE-кандидат:', candidate); // Логирование кандидата для отладки
    
    // Проверка на наличие необходимых полей
    if (candidate && candidate.sdpMid !== null && candidate.sdpMLineIndex !== null) {
        peerConnection.addIceCandidate(new RTCIceCandidate(candidate))
            .then(() => {
                console.log('ICE-кандидат добавлен успешно');
            })
            .catch(error => {
                console.error('Ошибка при добавлении ICE-кандидата:', error);
            });
    } else {
        console.error('Получен некорректный ICE-кандидат:', candidate);
    }
});

    // Функция для завершения вызова
    function endCall() {
        if (peerConnection) {
            socket.emit('hang_up_call', { callerSocketId: socket.id });
            peerConnection.close();
            peerConnection = null;
            console.log('Звонок завершен.');
        }
    }

    // Обработка завершения звонка
    socket.on('hang_up_call', (data) => {
        console.log(`Получено событие завершения вызова от ${data.callerSocketId}`);
        if (peerConnection) {
            peerConnection.close();
            peerConnection = null;
            console.log('Соединение закрыто.');
            console.dir(data);
        }
    });

    // Обработка отклонения звонка
    socket.on('reject_new_call', (data) => {
       // const { callerSocketId, rejectedBy } = data;
        console.log(`Звонок отклонен пользователем с ID: ${rejectedBy} от пользователя с ID: ${callerSocketId}`);
               if (peerConnection) {
            peerConnection.close();
            peerConnection = null;
            console.log('Соединение закрыто после отклонения вызова.');
        }
    });

    // Обработка принятия звонка
    socket.on('accept_new_call', (data) => {
      //  const { callerID, from } = data;
        const { callerID, from } = data;
        console.log(`Звонок принят пользователем с ID: ${data.callerSocketId}`);
       
         socket.emit('signaling_server', { to: data.userSocketId, from: data.callerSocketId, type:'init', payload:'payload'});
        
                    
        
        startCall(data.callerSocketId);
    });

    // Обработка завершения вызова по кнопке
    document.getElementById('endCallButton').addEventListener('click', () => {
        endCall();
    });

    </script>
</body>
</html>


My WebRTC server

app.js

/**
 * Created by abderrahimelimame on 9/24/16.
 */

var app = require('express')();
var server = require('http').Server(app);
//var server = require('https').Server(app);
var users = require('./users.js')();
var pingInterval = 25000;
var Socket = require('socket.io');
var io = Socket(server, {'pingInterval': pingInterval, 'pingTimeout': 60000});

/**
 * You can control those variables as you want
 */

var serverPort = 44333;
var app_key_secret = "7d3d3b6c2d3683bf25bbb51533ec6dab";
var debugging_mode = true;


/**
 * server listener
 */

var port = process.env.PORT || serverPort;
server.listen(port, function () {
    console.log('Server listening at port %d', port);
    

});


/**
 * this for check if the user connect from the app
 */
io.use(function (socket, next) {
        var token = socket.handshake.query.token;
        if (token === app_key_secret) {
            if (debugging_mode) {
                console.log("token valid  authorized", token);
            }
            next();
        } else {
            if (debugging_mode) {
                console.log("not a valid token Unauthorized to access ");
            }
            next(new Error("not valid token"));
        }
    }
);

/**
 * Socket.io event handling
 */
require('./socketHandler.js')(io, users, debugging_mode, pingInterval);

socketHandler.js

/**
 * Created by abderrahimelimame on 4/7/17.
 */

module.exports = function(io, users, debugging_mode, pingInterval) {

  io.on('connection', function(socket) {


    /*****************************************************************************************************************************************
     ********************************************* Users Connection Methods  *****************************************************************
     *****************************************************************************************************************************************/

    /**
     * Ping/Pong methods
     * */

    socket.on('socket_pong', function(data) {


      if (debugging_mode) {
        //    console.log("Pong received from client ");
      }
    });

    setTimeout(sendHeartbeat, pingInterval);

    function sendHeartbeat() {

      setTimeout(sendHeartbeat, pingInterval);
      io.sockets.emit('socket_ping', {
        beat: 1
      });
    }


    /**
     * method to save user as connected
     */
    socket.on('socket_user_connect', function(data) {
      if (debugging_mode) {
        console.log("the user with id " + data.connectedId + " connected " + +data.connected + " token " + data.userToken + "socket.id " + socket.id);
      }
      if (data.connectedId != null && data.connectedId != 0) {
        var user = users.getUser(data.connectedId);
        if (user != null) {
          users.updateUser(data.connectedId, data.connected, socket.id);
        } else {
          users.addUser(data.connectedId, data.connected, socket.id);
        }

        io.sockets.emit('socket_user_connect', {
          connectedId: data.connectedId,
          connected: true,
          socketId: data.socketId
        });

      }


    });


    /**
     * method if a user is disconnect from sockets
     * and then remove him from array of current users connected
     */
    socket.on('disconnect', function() {
      var usersArray = users.getUsers();
      if (usersArray.length != 0) {
        for (var i = 0; i < usersArray.length; i++) {
          var user = usersArray[i];
          if (user != null) {

            if (user.socketID == socket.id) {
              if (debugging_mode) {
                console.log("the user with id  " + user.ID + " is disconnect 1 ");
              }
              io.sockets.emit('socket_user_connect', {
                connectedId: user.ID,
                connected: false,
                socketId: user.socketID
              });

              users.removeUser(user.ID);
              if (debugging_mode) {
                console.log("the users list size disconnect " + usersArray.length);
              }
              break;
            }

          } else {
            if (debugging_mode) {
              console.log("the user is null disconnect ");
            }
          }


        }
      }
    });

    socket.on('socket_user_disconnect', function(data) {

      if (data.connectedId != null && data.connectedId != 0) {
        if (debugging_mode) {
          console.log("the user with id  " + data.connectedId + " is disconnect  2");
        }

        var user = users.getUserBySocketID(data.socketId);
        if (user != null) {

          io.sockets.emit('socket_user_connect', {
            connectedId: user.ID,
            connected: false,
            socketId: user.socketID
          });

          users.removeUser(user.ID);

        }
      }
    });


    /**
     * method to check if recipient is Online
     */
    socket.on('socket_is_online', function(data) {
      io.sockets.emit('socket_is_online', {
          senderId: data.senderId,
       //    senderId: "55536890679",
        connected: data.connected
      });
    });
    /**
     * method to check status last seen
     */
    /*      socket.on('socket_last_seen', function (data) {
              io.sockets.emit('socket_last_seen', {
                  lastSeen: data.lastSeen,
                  senderId: data.senderId,
                  recipientId: data.recipientId
              });
          });*/


    /*****************************************************************************************************************************************
     ********************************************* Single User Messages Methods  *****************************************************************
     *****************************************************************************************************************************************/



    socket.on('socket_update_register_id', function(data) {
      var user = users.getUser(data.recipientId);
      if (user != null) {
        socket.to(user.socketID).emit('socket_update_register_id', data);
      }
    });


    /*****************************************************************************************************************************************
     ********************************************* Users Call Methods  *****************************************************************
     *****************************************************************************************************************************************/

    /**
     * method to check if user is connected  before call him (do a ping and get a callback)
     */
    socket.on('socket_call_user_ping', function(data, callback) {
      if (debugging_mode)
        console.log("socket_call_user_ping called ");

      var user = users.getUser(data.recipientId);
      var pingedData;
      if (user != null) {
        console.log("socket id " + user.socketID);
        pingedData = {
          socketId: user.socketID,
          recipientId: data.recipientId,
          connected: true
        };
        callback(pingedData);
      } else {
        pingedData = {
          socketId: null,
          recipientId: data.recipientId,
          connected: false
        };
        callback(pingedData);
      }

    });

    /**
     * method to check if user is already on users array
     */
    socket.on('reset_socket_id', function(data, callback) {
      if (debugging_mode)
        console.log("reset_socket_id called " + data.userSocketId);
      var pingedData = {
        userSocketId: data.userSocketId
      };
      callback(pingedData);
    });

    /**
     * method make the connection between the too peer
     */
    socket.on('signaling_server', function(data) {
      if (debugging_mode)
        console.log("signaling_server called " + data.to);
      var socketId = data.to;
      /*var user = users.getUserBySocketID(data.to);
       if (user != null) {*/
      delete data.to;
      socket.to(socketId).emit('signaling_server', data);
      /*} else {
       console.log("user is null  signaling_server function ");
       //kolo adasnt skergh bach ighiga null nrj3 request bach ndir dialog this person is not available like whatsapp
       }*/

    });

    var makeCall = function(data) {
      if (debugging_mode)
        console.log("make_new_call function " + data.to);
      /* var user = users.getUserBySocketID(data.to);
       if (user != null) {*/
      socket.to(data.to).emit('receive_new_call', data);
      /*} else {
       console.log("user is null  make_new_call function ");
       //kolo adasnt skergh bach ighiga null nrj3 request bach ndir dialog this person is not available like whatsapp
       }*/

    };
    /**
     * method to initialize the new call
     */
    socket.on('make_new_call', makeCall);

    /**
     * method to Reject a call
     */
    socket.on('reject_new_call', function(data) {
      if (debugging_mode)
        console.log("reject_new_call function ");
      /* var user = users.getUserBySocketID(data.callerSocketId);
       if (user != null) {*/
      socket.to(data.callerSocketId).emit("reject_new_call", data);
      /*} else {
       console.log("user is null reject_new_call function ");
       }*/
    });


    /**
     * method to Accept a call
     */
    socket.on('accept_new_call', function(data) {
      if (debugging_mode)
        console.log("accept_new_call function ");
      /*var user = users.getUserBySocketID(data.callerSocketId);
       if (user != null) {
       */
      socket.to(data.callerSocketId).emit("accept_new_call", data);
      /*} else {
       console.log("user is null  accept_new_call function ");
       }*/
    });
    /**
     * method to HangUp a call
     */
    socket.on('hang_up_call', function(data) {
      if (debugging_mode)
        console.log("hang_up_call function ");
      /*      var user = users.getUserBySocketID(data.callerSocketId);
       if (user != null) {*/
      socket.to(data.callerSocketId).emit("hang_up_call", data);
      /*} else {
       console.log("user is null  hang_up_call function ");
       }*/
    });


  });
};

users.js

/**
 * Created by abderrahimelimame on 9/24/16.
 */
module.exports = function () {
    /**
     * available users
     * the id value is considered unique (provided by socket.io)
     */
    var usersList = [];

    /**
     * User object
     */
    var User = function (id, connected, socketID) {
        this.connected = connected;
        this.ID = id;
        this.socketID = socketID
    };

    return {
        addUser: function (id, connected, socketID) {
            var user = new User(id, connected, socketID);
            usersList.push(user);
        },

        removeUser: function (id) {
            var index = 0;
            while (index < usersList.length && usersList[index].ID != id) {
                index++;
            }
            usersList.splice(index, 1);
        },

        updateUser: function (id, connected, socketID) {
            var user = usersList.find(function (element, i, array) {
                return element.ID == id;
            });
            user.connected = connected;
            user.socketID = socketID;
        },

        getUser: function (id) {
            return usersList.find(function (element, i, array) {
                return element.ID == id;
            });
        },
        getUserBySocketID: function (socketID) {
            return usersList.find(function (element, i, array) {
                return element.socketID == socketID;
            });
        },

        getUsers: function () {
            return usersList;
        }
    }
};

Logs


2025-07-12T12:36:00.151 app[e286e922c57228] waw [info] socket_call_user_ping called
2025-07-12T12:36:00.151 app[e286e922c57228] waw [info] socket id LVfqkk-RH4uryHvvAACU
2025-07-12T12:36:00.345 app[e286e922c57228] waw [info] make_new_call function LVfqkk-RH4uryHvvAACU
2025-07-12T12:36:03.383 app[e286e922c57228] waw [info] accept_new_call function
2025-07-12T12:36:03.486 app[e286e922c57228] waw [info] signaling_server called yc8BtNp93oZS-Bh7AACN
2025-07-12T12:36:03.517 app[e286e922c57228] waw [info] signaling_server called yc8BtNp93oZS-Bh7AACN
2025-07-12T12:36:03.578 app[e286e922c57228] waw [info] signaling_server called yc8BtNp93oZS-Bh7AACN
2025-07-12T12:36:03.797 app[e286e922c57228] waw [info] signaling_server called yc8BtNp93oZS-Bh7AACN
2025-07-12T12:36:03.797 app[e286e922c57228] waw [info] signaling_server called yc8BtNp93oZS-Bh7AACN
2025-07-12T12:36:11.341 app[e286e922c57228] waw [info] hang_up_call function
2025-07-12T12:36:14.476 app[e286e922c57228] waw [info] the user with id 3039 is disconnect 1
2025-07-12T12:36:14.476 app[e286e922c57228] waw [info] the users list size disconnect 2
2025-07-12T12:36:15.261 app[e286e922c57228] waw [info] token valid authorized 7d3d3b6c2d3683bf25bbb51533ec6dab
2025-07-12T12:36:15.570 app[e286e922c57228] waw [info] the user with id 3039 connected 1 token d85dc7ebbac3f646429d5e3aa313e783socket.id USZoAOTFmizo8n8lAACX

Тест приложения для Android https://dkon.app/dev/last_version/dkon.apk

Я попытался переставить переменные и изменить логику, но сам сервер я не трогал, так как серверный код нельзя изменить, только HTML-файл.


Ответы (0 шт):