Нет iceServers
- это нормально для локальной сети, но одноранговые узлы все равно должны обмениваться хотя бы одним кандидатом: их хост кандидат (в зависимости от IP-адреса локальной сети их машины).
Либо:
Поток кандидатов, использующих onicecandidate
-> сигнализация -> addIceCandidate
как обычно, или
Ожидание процесса ICE (aнесколько секунд) перед обменом pc.localDescription
.
Похоже, вы пытаетесь последнее.Этот подход работает, потому что ...
Trickle ICE - это оптимизация.
Сигнализация (просачивание) отдельных кандидатов на лед, использующих onicecandidate
, - это оптимизация, предназначенная для ускорения переговоров.После успешного выполнения setLocalDescription
запускается встроенный в браузер Агент ICE браузера, который вставляет кандидатов ICE, как они были обнаружены, в сам localDescription
.Подождите несколько секунд, чтобы договориться, и в этом нет необходимости: все предложения ICE будут в предложении и ответ будет передан.
Ваш код
Из вашего кода onicecandidate
он выглядиткак будто вы уже пытаетесь собрать localDescription
после завершения ICE (и вы написали его для работы с обоих концов):
pc.onicecandidate = ({ candidate }) => {
if (!candidate) {
const { offer } = this.state;
const field = !offer ? 'offer' : 'data';
this.setState({
[field]: JSON.stringify(pc.localDescription)
});
}
};
На стороне отправителя вы правильно закомментировали эквиваленткод в createOffer
:
pc.createOffer()
.then(offer => pc.setLocalDescription(offer))
.catch(this.logError);
// .then(() => {
// this.setState({
// offer: JSON.stringify(pc.localDescription)
// });
// });
Но на стороне ответчика у вас нет, и это, вероятно, проблема:
createAnswer() {
const { pc } = this;
const { data } = this.state;
if (data) {
const sd = new RTCSessionDescription(JSON.parse(data));
pc.setRemoteDescription(sd)
.then(() => pc.createAnswer())
.then(answer => pc.setLocalDescription(answer))
.then(() => {
this.setState({
offer: JSON.stringify(pc.localDescription)
});
})
.catch(this.logError);
}
}
Это означает, что он отправляет ответ немедленно, до того, какагент ICE ответчика успел вставить в ответ кандидатов. Возможно, именно поэтому он не работает.
На дополнительном примечании: Ничто не может дождаться завершения getUserMedia
, поэтому ответы скорее всего не будут содержатьлюбое видео, в зависимости от времени вашей функции getUserMediaSuccess
, которая не может добавить какие-либо дорожки или потоки к соединению.Но при условии, что вы просто делаете каналы данных, это должно работать с моими рекомендуемыми исправлениями.