WebRTC iPad Testing #36

Merged
kirsle merged 3 commits from ipad-testing into master 2023-09-01 00:24:08 +00:00
Showing only changes of commit f3a917ec04 - Show all commits

View File

@ -687,6 +687,17 @@ const app = Vue.createApp({
return; return;
} }
// DEBUGGING: test whether the page thinks you're Apple Webkit.
if (this.message.toLowerCase().indexOf("/ipad") === 0) {
if (this.isAppleWebkit()) {
this.ChatClient("I have detected that you are probably an iPad or iPhone browser.");
} else {
this.ChatClient("I have detected that you <strong>are not</strong> an iPad or iPhone browser.");
}
this.message = "";
return;
}
// console.debug("Send message: %s", this.message); // console.debug("Send message: %s", this.message);
this.ws.conn.send(JSON.stringify({ this.ws.conn.send(JSON.stringify({
action: "message", action: "message",
@ -1016,7 +1027,7 @@ const app = Vue.createApp({
this.disconnectCount++; this.disconnectCount++;
if (this.disconnectCount > this.disconnectLimit) { if (this.disconnectCount > this.disconnectLimit) {
this.ChatClient(`It seems there's a problem connecting to the server. Please try some other time. Note that iPhones and iPads currently have issues connecting to the chat room in general.`); this.ChatClient(`It seems there's a problem connecting to the server. Please try some other time.`);
return; return;
} }
@ -1227,32 +1238,23 @@ const app = Vue.createApp({
}) })
}; };
// If we were already broadcasting video, send our stream to // ANSWERER: add our video to the connection so that the offerer (the one who
// the connecting user. // clicked on our video icon to watch us) can receive it.
// TODO: currently both users need to have video on for the connection
// to succeed - if offerer doesn't addTrack it won't request a video channel
// and so the answerer (who has video) won't actually send its
if (!isOfferer && this.webcam.active) { if (!isOfferer && this.webcam.active) {
this.ChatClient(`Sharing our video stream to ${username}.`);
let stream = this.webcam.stream; let stream = this.webcam.stream;
stream.getTracks().forEach(track => { stream.getTracks().forEach(track => {
pc.addTrack(track, stream) pc.addTrack(track, stream)
}); });
} }
// iPad test: if we are the offerer and are already broadcasting, add our cam. // OFFERER: If we were already broadcasting our own video, and the answerer
// TODO: only do this if the answerer has auto-open videos enabled, because adding // has the "auto-open your video" setting enabled, attach our video to the initial
// our video on the offer will force open our video on their side // offer right now.
if (isOfferer && this.webcam.active) { //
this.ChatClient("Adding my camera pre-emptively to the call now"); // NOTE: this will force open our video on the answerer's side, and this workflow
let stream = this.webcam.stream; // is also the only way that iPads/iPhones/Safari browsers can make a call
stream.getTracks().forEach(track => { // (two-way video is the only option for them; send-only/receive-only channels seem
pc.addTrack(track, stream) // not to work in Safari).
});
}
// If we are the offerer, and this member wants to auto-open our camera
// then add our own stream to the connection.
if (isOfferer && (this.whoMap[username].video & this.VideoFlag.MutualOpen) && this.webcam.active) { if (isOfferer && (this.whoMap[username].video & this.VideoFlag.MutualOpen) && this.webcam.active) {
let stream = this.webcam.stream; let stream = this.webcam.stream;
stream.getTracks().forEach(track => { stream.getTracks().forEach(track => {
@ -1271,32 +1273,16 @@ const app = Vue.createApp({
// Common handler function for // Common handler function for
localDescCreated(pc, username) { localDescCreated(pc, username) {
this.ChatClient("localDescCreated called: " + username);
return (desc) => { return (desc) => {
this.ChatClient(`setLocalDescription ${JSON.stringify(desc)}`);
pc.setLocalDescription(desc).then(() => { pc.setLocalDescription(desc).then(() => {
this.ChatClient(`Sending SDP message to server!`);
this.ws.conn.send(JSON.stringify({ this.ws.conn.send(JSON.stringify({
action: "sdp", action: "sdp",
username: username, username: username,
//description: JSON.stringify(desc),
description: JSON.stringify(pc.localDescription), description: JSON.stringify(pc.localDescription),
})); }));
this.ChatClient(`(pc.localDescription was: ${pc.localDescription})`);
}).catch(e => { }).catch(e => {
this.ChatClient(`Error sending sdp: ${e}`); this.ChatClient(`Error sending WebRTC negotiation message (SDP): ${e}`);
}); });
/*pc.setLocalDescription(
desc, // new RTCSessionDescription(desc),
() => {
this.ws.conn.send(JSON.stringify({
action: "sdp",
username: username,
description: JSON.stringify(pc.localDescription),
}));
},
console.error,
)*/
}; };
}, },
@ -1314,14 +1300,6 @@ const app = Vue.createApp({
let candidate = JSON.parse(msg.candidate); let candidate = JSON.parse(msg.candidate);
// Add the new ICE candidate. // Add the new ICE candidate.
/*pc.addIceCandidate(
new RTCIceCandidate(
candidate,
() => { },
console.error,
)
);
*/
pc.addIceCandidate(candidate).catch(e => { pc.addIceCandidate(candidate).catch(e => {
this.ChatClient(`addIceCandidate: ${e}`); this.ChatClient(`addIceCandidate: ${e}`);
}); });
@ -1845,10 +1823,20 @@ const app = Vue.createApp({
delete(this.WebRTC.openTimeouts[user.username]); delete(this.WebRTC.openTimeouts[user.username]);
} }
this.WebRTC.openTimeouts[user.username] = setTimeout(() => { this.WebRTC.openTimeouts[user.username] = setTimeout(() => {
// It timed out. // It timed out. If they are on an iPad, offer additional hints on
// how to have better luck connecting their cameras.
if (this.isAppleWebkit()) {
this.ChatClient(
`There was an error opening <strong>${user.username}</strong>'s camera.<br><br>` +
"<strong>Advice:</strong> You appear to be on an iPad-style browser. Webcam sharing " +
"may be limited and only work if:<br>A) You are sharing your own camera first, and<br>B) "+
"The person you view has the setting to auto-open your camera in return.<br>Best of luck!",
);
} else {
this.ChatClient( this.ChatClient(
`There was an error opening <strong>${user.username}</strong>'s camera.`, `There was an error opening <strong>${user.username}</strong>'s camera.`,
); );
}
delete(this.WebRTC.openTimeouts[user.username]); delete(this.WebRTC.openTimeouts[user.username]);
}, 10000); }, 10000);
@ -1930,8 +1918,10 @@ const app = Vue.createApp({
// - May be a crossed-out video if isVideoNotAllowed // - May be a crossed-out video if isVideoNotAllowed
// - Or an eyeball for cameras already opened // - Or an eyeball for cameras already opened
// - Or a spinner if we are actively trying to open the video // - Or a spinner if we are actively trying to open the video
// Current user sees their own self camera always.
if (user.username === this.username && this.webcam.active) { if (user.username === this.username && this.webcam.active) {
return 'fa-eye'; // user sees their own self camera always return 'fa-eye';
} }
// In spinner mode? (Trying to open the video) // In spinner mode? (Trying to open the video)
@ -1944,6 +1934,21 @@ const app = Vue.createApp({
return 'fa-eye'; return 'fa-eye';
} }
// iPad test: they will have very limited luck opening videos unless
// A) the iPad camera is already on, and
// B) the person they want to watch has mutual auto-open enabled.
if (this.isAppleWebkit()) {
if (!this.webcam.active) {
return 'fa-video-slash'; // can not open any cam w/o local video on
}
if (!(this.whoMap[user.username].video & this.VideoFlag.MutualOpen)) {
// the user must have mutual auto-open on: the iPad has to offer
// their video which will force open their cam on the other side,
// and this is only if the user expects it.
return 'fa-video-slash';
}
}
if (this.isVideoNotAllowed(user)) return 'fa-video-slash'; if (this.isVideoNotAllowed(user)) return 'fa-video-slash';
return 'fa-video'; return 'fa-video';
}, },
@ -2555,6 +2560,25 @@ const app = Vue.createApp({
// Set the "reported" flag. // Set the "reported" flag.
this.reportModal.origMessage.reported = true; this.reportModal.origMessage.reported = true;
}, },
// Miscellaneous utility methods.
isAppleWebkit() {
// Try and detect whether the user is on an Apple Safari browser, which has
// special nuances in their WebRTC video sharing support. This is intended to
// detect: iPads, iPhones, and Safari on macOS.
// By User-Agent.
if (/iPad|iPhone|iPod/.test(navigator.userAgent)) {
return true;
}
// By (deprecated) navigator.platform.
if (navigator.platform === 'iPad' || navigator.platform === 'iPhone' || navigator.platform === 'iPod') {
return true;
}
return false;
},
} }
}); });