Ich bin ein Downshifter. So kam es, dass meine Frau und ich in den letzten drei Jahren die ländliche Landschaft vor dem Fenster, die frische Luft und das Vogelgezwitscher genossen haben. Die Annehmlichkeiten im Haus, das optische Internet eines lokalen Anbieters, eine leistungsstarke unterbrechungsfreie Stromversorgung und eine plötzlich auftretende Covid machten die Idee, aus einer Metropole zu ziehen, nicht so seltsam.
Während ich mich irgendwo im Hintergrund mit Webentwicklung beschäftigte, beschwerte sich meine Frau regelmäßig über die Probleme bei der Auswahl einer Schule für mein Kind. Und dann (plötzlich) wuchs das Kind auf und die Schulfrage stand aufrecht. Okay, die Zeit ist gekommen. Lassen Sie uns gemeinsam herausfinden, was mit dem Bildungssystem im ehemaligen 1/6 des Landes nicht stimmt und was wir dagegen tun können.
Ich werde die traditionellen Unterrichtsmethoden von Angesicht zu Angesicht außerhalb des Rahmens dieses Artikels belassen. Ich möchte nur sagen, dass gewöhnliche Schulen sowohl unbestreitbare Vor- als auch schwerwiegende Nachteile haben, zu denen übrigens kürzlich eine erzwungene Selbstisolation hinzugefügt wurde. Hier betrachten wir Fern- und Familienbildungsmöglichkeiten, die aus verschiedenen Gründen in letzter Zeit immer mehr Eltern angezogen haben.
Um es klar auszudrücken: Fernunterricht bedeutet Unterricht in einer regulären Schule unter Verwendung von "Fernunterrichtstechnologien" (DOT), und Familienerziehung bedeutet, die Schule freiwillig zu verlassen und nur von der Familie zu lernen (in der Tat ist dies ein gutes altes externes Praktikum). In jedem Fall muss das Kind jedoch an eine der verfügbaren Schulen angeschlossen sein, zumindest um die Zwischenzertifizierung zu bestehen.
Und jetzt einige Beobachtungen aus dem Leben. Mit dem erzwungenen Übergang zum Fernunterricht von Kindern, die bereits eine reguläre Schule besucht haben, ist alles traurig. Schulkinder empfinden dieses Geschenk des Schicksals als eine Art Urlaub, Eltern sind es nicht gewohnt, während des Unterrichts Disziplin zu befolgen, und infolgedessen sinkt die schulische Gesamtleistung unweigerlich.
Bei Erstklässlern, insbesondere im Fall der Familienform, haben die Eltern möglicherweise die Möglichkeit, das Kind mit natürlichem Interesse und der Wirkung von Neuheiten „auf die Schiene“ zu bringen. Unabhängigkeit ist für mich persönlich die Hauptaufgabe. Wenn ich mit einem Kind sitze und Hausaufgaben mache, betrachte ich die
Komm zum Punkt. Eine öffentliche Schule wählen
Vielleicht mag ich Familienerziehung mehr, weil ich die Möglichkeit habe, ein Programm und einen Trainingsplan zu wählen. Und Sie können seltener physisch zur Schule gehen. Sie müssen sich jedoch für eine öffentliche Schule entscheiden, mit dem Direktor über die Unterbringung des Kindes sprechen und Ende des Winters einen Auftrag zur Einschreibung in die erste Klasse erhalten, damit es im September keine Überraschungen gibt. Obwohl das Gesetz über Bildung aus rechtlicher Sicht keine jährlichen Bescheinigungen zu verlangen scheint, sind "Fristen" meiner Erfahrung nach ausgezeichnete Motivatoren. Lassen Sie es also Bescheinigungen geben. Es ist unwahrscheinlich, dass eine Schule uns mit offenen Armen akzeptiert, aber ich bin sicher, dass wir in der nächsten Stadt eine würdige Option finden können.
Lehrplan auswählen
Wir wählen genau. Der Versuch, ein Programm ohne spezielle Ausbildung selbst zu erstellen, ist nicht sinnvoll. Es gibt zwar staatliche Bildungsressourcen wie die Russian Electronic School ( NES ) und die Moscow Electronic School ( MES ), die theoretisch ausreichen würden, aber ... Beide Optionen bieten Unterrichtspläne, Videos, Tests und Tutorials. Was ich nicht finden konnte, waren die Lehrbücher selbst, selbst für den obligatorischen Lehrplan.
Und hier fehlt das Wichtigste: Kommunikation. Ein Kind zu unterrichten, indem man ihm endlose Videos zeigt und es zwingt, die Tests anzukreuzen, funktioniert nicht. Dies bedeutet, dass Sie entweder den Unterricht völlig unabhängig durchführen oder eine der Online-Schulen auswählen müssen.
Eine Online-Schule wählen
Wir sind fast wieder da, wo wir angefangen haben. Fernbedienung? Okay, schauen wir sie uns genauer an. Wie können Sie den Bildungsprozess aus der Ferne organisieren? Dies wirft viele Fragen auf, ich werde nur die wichtigsten aufwerfen:
* Live-Kommunikation. Was bieten Schulen an? Skype, bestenfalls Tims. Skype-Unterricht? "Ja wirklich?" Wenn ich mich nicht irre, ist es 2020. Öffnen Sie mehrere Fenster mit schönen bunten Knöpfen vor dem Erstklässler und warten Sie, bis er sie nicht drückt, sondern einem halben Tag gehorsam einem langweiligen Onkel oder einer langweiligen Tante zuhört? Ich habe solche Kinder noch nie gesehen. Und Sie?
* Hausaufgaben. Genauer gesagt, wie kommt es zum Testen zum Lehrer? In der Tat ist dies eine wirklich schwierige Frage, die im Prinzip vielleicht nicht einmal gelöst ist. Bestehende Optionen:
- , . --, , , , - .
- . , - .
- . , .
- . , , , , ? . , , .
- . , , . , , , . , . . , , , , . .
* Schätzungen. Offensichtlich sollten die Noten in der Lektion und bei der Überprüfung der Hausaufgaben in ein elektronisches Tagebuch fallen, das den Eltern zur Verfügung steht. Und sie kommen dorthin. Aber nicht sofort. Ich fragte ältere Kinder, die eines der angesehenen Lyzeen mit einer goldenen Kuppel abgeschlossen hatten (ironischerweise mit einer informativen Tendenz), warum das so ist. Die Antwort hat mich ehrlich gesagt überrascht. Es stellt sich heraus, dass Lehrer Noten auf ein Blatt Papier schreiben und sie nach dem Unterricht in dieses sehr elektronische Tagebuch auf dem Staatsportal fahren. Und diesmal, während Tesla Elon Musk die Weite des Weltraums pflügt ...
Okay, es ist Zeit, ein wenig technische Forschung zu betreiben und zu prüfen, ob es objektive Gründe für diesen Zustand gibt?
Definieren wir die Anforderungen für eine hypothetische ideale Lernplattform. Tatsächlich ist alles einfach: Kinder sollten im Unterricht bleiben, sich auf das konzentrieren, was der Lehrer sagt und zeigt, bei Bedarf Fragen beantworten und auf Wunsch die Hand heben. Grundsätzlich möchten wir ein Vollbildfenster mit einem Stream von der Kamera, Präsentation oder dem Whiteboard des Lehrers. Der einfachste Weg, dies zu erreichen, ist die Verwendung der WebRTC- Technologie (Echtzeitkommunikation, Echtzeitkommunikation). Dieses Ding funktioniert in jedem mehr oder weniger modernen Browser, erfordert keine zusätzliche Ausrüstung und bietet darüber hinaus eine qualitativ hochwertige Verbindung. Und ja, dieser Standard erfordert eine asynchrone Programmierung, zumindest weil die erforderliche JS-Methode navigator.mediaDevices.getUserMedia () ein Versprechen zurückgibt . Alles scheint klar zu sein, ich fange an, es umzusetzen.
Lyrischer Exkurs über die Auswahl eines Frameworks
, «» JavaScript , .
jQuery. , JS :
, CSS «hidden», , opacity transition, fadeIn/fadeOut CSS. , JS !
. .. , JS , . , , «» JS !
//
element = $(selector);
element = document.querySelector(selector);
//
element2 = element.find(selector2);
element2 = element.querySelector(selector2);
//
element.hide(); // display: none
element.classList.add('hidden');
, CSS «hidden», , opacity transition, fadeIn/fadeOut CSS. , JS !
// onClick
element.click(e => { ... });
element.onclick = (e) => { ... }
//
element.toggleClass(class_name);
element.classList.toggle(class_name);
// div
div = $("<div>");
div = document.createElement("div");
// div element
// ( , )
element.append(div);
element.append(div);
. .. , JS , . , , «» JS !
WebRTC wurde für die direkte Kommunikation zwischen Browsern mithilfe der Punkt-zu-Punkt-Technologie (p2p) entwickelt. Um diese Verbindung herzustellen, müssen sich die Browser jedoch gegenseitig über ihre Kommunikationsabsicht informieren. Dies erfordert einen Alarmserver .
Ein Beispiel für eine grundlegende Implementierung eines einfachen Video-Chats unter Verwendung der "Full Mesh" -Topologie
'use strict';
(function () {
const selfView = document.querySelector('#self-view'),
remoteMaster = document.querySelector('#remote-master'),
remoteSlaves = document.querySelector('#remote-slaves');
let localStream,
selfStream = null,
socket = null,
selfId = null,
connections = {};
// ***********************
// UserMedia & DOM methods
// ***********************
const init = async () => {
try {
let stream = await navigator.mediaDevices.getUserMedia({
audio: true, video: {
width: { max: 640 }, height: { max: 480 }
}
});
localStream = stream;
selfStream = new MediaStream();
stream.getVideoTracks().forEach(track => {
selfStream.addTrack(track, stream); // track.kind == 'video'
});
selfView.querySelector('video').srcObject = selfStream;
} catch (e) {
document.querySelector('#self-view').innerHTML =
'<i> </i>';
console.error('Local stream not found: ', e);
}
wsInit();
}
const createRemoteView = (id, username) => {
let iDiv = document.querySelector('#pc' + id);
if (!iDiv) {
iDiv = document.createElement('div');
iDiv.className = 'remote-view';
iDiv.id = 'pc' + id;
let iVideo = document.createElement('video');
iVideo.setAttribute('autoplay', 'true');
iVideo.setAttribute('playsinline', 'true');
let iLabel = document.createElement('span');
iDiv.append(iVideo);
iDiv.append(iLabel);
if (!remoteMaster.querySelector('video')) {
remoteMaster.append(iDiv);
iLabel.textContent = '';
} else {
remoteSlaves.append(iDiv);
iLabel.textContent = username;
}
remoteMaster.style.removeProperty('display');
}
}
// *******************************
// Signaling (Web Socket) methods
// *******************************
const wsInit = () => {
socket = new WebSocket(SIGNALING_SERVER_URL);
socket.onopen = function (e) {
log('[socket open] ');
}
socket.onmessage = function (event) {
log('[socket message] ', event);
wsHandle(event.data);
}
socket.onclose = function (event) {
if (event.wasClean) {
log('[close] , ' +
`=${event.code} =${event.reason}`);
} else {
log('[socket close] ', event);
}
clearInterval(socket.timer);
}
socket.onerror = function (error) {
logError('[socket error]', error);
}
socket.timer = setInterval(() => {
socket.send('heartbeat');
}, 10000);
}
const wsHandle = async (data) => {
if (!data) {
return;
}
try {
data = JSON.parse(data);
} catch (e) {
return;
}
switch (data.type) {
case 'handshake':
selfId = data.uid;
if (!Object.keys(data.users).length) {
createRemoteView(selfId, '');
remoteMaster.querySelector('video').srcObject =
selfStream;
selfView.remove();
break;
} else {
selfView.style.removeProperty('display');
}
for (let id in data.users) {
await pcCreate(id, data.users[id]);
}
break;
case 'offer':
await wsHandleOffer(data);
break;
case 'answer':
await wsHandleAnswer(data)
break;
case 'candidate':
await wsHandleICECandidate(data);
break;
default:
break;
}
}
const wsHandleOffer = async (data) => {
let pc = null;
if (!connections[data.src]) {
await pcCreate(data.src, data.username);
}
pc = connections[data.src].pc;
// We need to set the remote description to the received SDP offer
// so that our local WebRTC layer knows how to talk to the caller.
let desc = new RTCSessionDescription(data.sdp);
pc.setRemoteDescription(desc).catch(error => {
logError('handleOffer', error);
});
await pc.setLocalDescription(await pc.createAnswer());
wsSend({
type: 'answer',
target: data.src,
sdp: pc.localDescription
});
connections[data.src].pc = pc; // ???
}
const wsHandleAnswer = async (data) => {
log('*** Call recipient has accepted our call, answer:', data);
let pc = connections[data.src].pc;
// Configure the remote description,
// which is the SDP payload in our 'answer' message.
let desc = new RTCSessionDescription(data.sdp);
await pc.setRemoteDescription(desc).catch((error) => {
logError('handleAnswer', error);
});
}
const wsHandleICECandidate = async (data) => {
let pc = connections[data.src].pc;
let candidate = new RTCIceCandidate(data.candidate);
log('*** Adding received ICE candidate', candidate);
pc.addIceCandidate(candidate).catch(error => {
logError('handleICECandidate', error);
});
}
const wsSend = (data) => {
if (socket.readyState !== WebSocket.OPEN) {
return;
}
socket.send(JSON.stringify(data));
}
// ***********************
// Peer Connection methods
// ***********************
const pcCreate = async (id, username) => {
if (connections[id]) {
return;
}
try {
let pc = new RTCPeerConnection(PC_CONFIG);
pc.onicecandidate = (event) =>
pcOnIceCandidate(event, id);
pc.oniceconnectionstatechange = (event) =>
pcOnIceConnectionStateChange(event, id);
pc.onsignalingstatechange = (event) =>
pcOnSignalingStateChangeEvent(event, id);
pc.onnegotiationneeded = (event) =>
pcOnNegotiationNeeded(event, id);
pc.ontrack = (event) =>
pcOnTrack(event, id);
connections[id] = {
pc: pc,
username: username
}
if (localStream) {
try {
localStream.getTracks().forEach(
(track) => connections[id].pc.addTransceiver(track, {
streams: [localStream]
})
);
} catch (err) {
logError(err);
}
} else {
// Start negotiation to listen remote stream only
pcOnNegotiationNeeded(null, id);
}
createRemoteView(id, username);
} catch (error) {
logError('Peer: Connection failed', error);
}
}
const pcOnTrack = (event, id) => {
let iVideo = document.querySelector('#pc' + id + ' video');
iVideo.srcObject = event.streams[0];
}
const pcOnIceCandidate = (event, id) => {
let pc = connections[id].pc;
if (event.candidate && pc.remoteDescription) {
log('*** Outgoing ICE candidate: ' + event.candidate);
wsSend({
type: 'candidate',
target: id,
candidate: event.candidate
});
}
}
const pcOnNegotiationNeeded = async (event, id) => {
let pc = connections[id].pc;
try {
const offer = await pc.createOffer();
// If the connection hasn't yet achieved the "stable" state,
// return to the caller. Another negotiationneeded event
// will be fired when the state stabilizes.
if (pc.signalingState != 'stable') {
return;
}
// Establish the offer as the local peer's current
// description.
await pc.setLocalDescription(offer);
// Send the offer to the remote peer.
wsSend({
type: 'offer',
target: id,
sdp: pc.localDescription
});
} catch(err) {
logError('*** The following error occurred while handling' +
' the negotiationneeded event:', err);
};
}
const pcOnIceConnectionStateChange = (event, id) => {
let pc = connections[id].pc;
switch (pc.iceConnectionState) {
case 'closed':
case 'failed':
case 'disconnected':
pcClose(id);
break;
}
}
const pcOnSignalingStateChangeEvent = (event, id) => {
let pc = connections[id].pc;
log('*** WebRTC signaling state changed to: ' + pc.signalingState);
switch (pc.signalingState) {
case 'closed':
pcClose(id);
break;
}
}
const pcClose = (id) => {
let remoteView = document.querySelector('#pc' + id);
if (connections[id]) {
let pc = connections[id].pc;
pc.close();
delete connections[id];
}
if (remoteView) {
remoteView.remove();
}
}
// *******
// Helpers
// *******
const log = (msg, data) => {
if (!data) {
data = ''
}
console.log(msg, data);
}
const logError = (msg, data) => {
if (!data) {
data = ''
}
console.error(msg, data);
}
init();
})();
Der Signalisierungsserver basiert auf dem Python-Aiohttp-Framework und ist eine einfache "Ansicht", die WebRTC-Anforderungen trivial weiterleitet. Die Verbindung zum Server in diesem Beispiel erfolgt über Web-Sockets . Außerdem werden einfache Text-Chat-Daten über den Signalisierungskanal übertragen.
Beispiel für die Implementierung eines Signalisierungsservers
import json
from aiohttp.web import WebSocketResponse, Response
from aiohttp import WSMsgType
from uuid import uuid1
from lib.views import BaseView
class WebSocket(BaseView):
""" Process WS connections """
async def get(self):
username = self.request['current_user'].firstname or ''
room_id = self.request.match_info.get('room_id')
if room_id != 'test_room' and
self.request['current_user'].is_anonymous:
self.raise_error('forbidden') # @TODO: send 4000
if (self.request.headers.get('connection', '').lower() != 'upgrade' or
self.request.headers.get('upgrade', '').lower() != 'websocket'):
return Response(text=self.request.path) # ???
self.ws = WebSocketResponse()
await self.ws.prepare(self.request)
self.uid = str(uuid1())
if room_id not in self.request.app['web_sockets']:
self.request.app['web_sockets'][room_id] = {}
self.room = self.request.app['web_sockets'][room_id]
users = {}
for id, data in self.room.items():
users[id] = data['name']
ip = self.request.headers.get(
'X-FORWARDED-FOR',
self.request.headers.get('X-REAL-IP',
self.request.remote))
msg = {
'type': 'handshake',
'uid': str(self.uid),
'users': users, 'ip': ip}
await self.ws.send_str(json.dumps(msg, ensure_ascii=False))
self.room[self.uid] = {'name': username, 'ws': self.ws}
try:
async for msg in self.ws:
if msg.type == WSMsgType.TEXT:
if msg.data == 'heartbeat':
print('---heartbeat---')
continue
try:
msg_data = json.loads(msg.data)
if 'target' not in msg_data or
msg_data['target'] not in self.room:
continue
msg_data['src'] = self.uid
if 'type' in msg_data and 'target' in msg_data:
if msg_data['type'] == 'offer':
msg_data['username'] = username
else:
print('INVALID DATA:', msg_data)
except Exception as e:
print('INVALID JSON', e, msg)
try:
await self.room[msg_data['target']]['ws'].send_json(
msg_data);
except Exception as e:
if 'target' in msg_data:
self.room.pop(msg_data['target'])
finally:
self.room.pop(self.uid)
return self.ws
Mit der WebRTC-Technologie können Sie dem Browser zusätzlich zur Videokommunikation die Berechtigung erteilen, den Inhalt einer Anzeige oder einer separaten Anwendung zu erfassen. Dies kann bei der Durchführung von Online-Lektionen, Webinaren oder Präsentationen unverzichtbar sein. Großartig, lass es uns benutzen.
Die modernen Möglichkeiten der Videokommunikation haben mich so beeindruckt, dass ich fast das wichtigste Thema der Klasse vergessen habe - das interaktive Whiteboard. Die grundlegende Implementierung ist jedoch so trivial, dass ich diesen Artikel nicht damit überladen werde. Wir fügen Sie einfach die Leinwand , hören für onmousemove (OnTouchMove für Tabletten) Mausbewegungsereignisse, und die resultierenden Koordinaten an alle verbundenen Punkte durch den gleichen Signalisierungsserver senden.
Testen Sie Ihr interaktives Whiteboard
Hier brauchen Sie ein Tablet, einen Digitalisierer und ein lebendes Kind. Gleichzeitig prüfen wir die Möglichkeit der Digitalisierung von Handschrifteingaben.
Zunächst nahm ich ein altes Galaxy Tab-Tablet für Android 4.4, einen selbstgemachten Stift und die ersten Rezepte, die ich als Hintergrund für die Leinwand fand. Ich habe keine zusätzlichen Programme installiert. Das Ergebnis hat mich entmutigt: Mein Tablet ist absolut nicht zum Schreiben geeignet! Das heißt, es ist kein Problem, den Finger darauf zu bewegen, aber es ist bereits ein Problem, den Stift in den Umriss eines Buchstabens zu bringen, selbst wenn er so groß ist wie im Bild unten. Außerdem wird das Gadget beim Zeichnen langweilig, wodurch die Linien unterbrochen werden. Außerdem konnte ich das Kind nicht dazu bringen, sein Handgelenk nicht auf dem Bildschirm abzulegen, was zusätzliche Flecken zur Hand hat, und das Tablet selbst wird noch langsamer. Fazit: Ein gewöhnliches Tablet zum Schreiben auf ein Whiteboard ist nicht geeignet. Das Maximum seiner Möglichkeiten besteht darin, Ihren Finger über den Bildschirm zu bewegen, ziemlich große Figuren. Aber es ist zu spät, dies Schulkindern anzubieten.
Okay, das ist rein theoretische Forschung, oder? Dann nehmen wir einen Digitalisierer (auch bekannt als Grafiktablett) im Wacom Bamboo A8-Format und beobachten das Kind.
Beachten Sie, dass mein sechsjähriger Proband zum ersten Mal in seinem Leben einen Laptop mit einem Grafikstift erhalten hat. Wir brauchten ungefähr zehn Minuten, um die Grundkenntnisse im Umgang mit dem Stift zu erlernen, und bereits in der zweiten Lektion benutzte das Kind das Tablet ziemlich sicher, unabhängig vom Brett gelöscht, zeichnete Gesichter, Blumen, unseren Hund und fing sogar an, in Epsilon verfügbare Knöpfe zu stechen und stellte gleichzeitig Fragen wie "Warum heben sie in der Schule ihre Hand?" Das Ergebnis ließ jedoch immer zu wünschen übrig. Tatsache ist, dass Designer und Künstler ein Fragment des Bildes maximieren, um ein Element zu zeichnen, das die Linien genau macht. Hier sollten wir die gesamte Tafel im Maßstab 1: 1 sehen. Hier und der Erwachsene wird nicht in die Linie fallen. Folgendes haben wir:
Endgültiges Urteil: Keine Handschrift kommt nicht in Frage. Und wenn wir unseren Kindern "Hand anlegen" wollen, müssen wir dies alleine erreichen, auf dem Papier wird die Schule dabei nicht helfen.
Ich muss sagen, dass das Kind alle meine Experimente mit Begeisterung gemacht hat und mir seitdem mit einem Schwanz gefolgt ist und mich gebeten hat, "die Rezepte einzuschalten". Bereits gut, die erworbene Fähigkeit wird ihm nur für ganz andere Zwecke nützlich sein.
Jedenfalls habe ich als Ergebnis von Experimenten tatsächlich einen MVP bekommen - fast ein Produkt mit minimaler Lebensfähigkeit Geeignet für Online-Lektionen mit Video- / Audiokonferenz, gemeinsam genutztem Bildschirm, interaktivem Whiteboard, einfachem Text-Chat und Hebetaste. Dies ist der Fall, wenn das Kind plötzlich kein Mikrofon mehr hat. Ja, dies geschieht insbesondere bei Kindern, die ihre Lektionen nicht gelernt haben.
Aber in diesem Fass Honig gibt es leider ein paar Teerlöffel.
Testen von WebRTC
Löffel Nummer 1. Da unsere Videokommunikation direkte Verbindungen zwischen Clients verwendet, besteht der erste Schritt darin, die Skalierbarkeit einer solchen Lösung zu testen. Für den Test nahm ich einen alten Laptop mit einem Dual-Core-i5-3230M an Bord und begann, Clients mit deaktivierten Webkameras damit zu verbinden, dh einen Eins-zu-Viele-Modus zu emulieren:
Wie Sie sehen, kann der experimentelle Laptop mehr oder weniger bequem an fünf Clients senden ( bei CPU-Auslastung innerhalb von 60%). Vorausgesetzt, die Auflösung des ausgehenden Videostreams wird auf 720p (640x480px) und die Bildrate auf 15 fps reduziert. Im Prinzip nicht so schlecht, aber wenn Sie eine Klasse mit mehreren Dutzend Schülern verbinden, müssen Sie das "vollständige Netz" zugunsten der Kaskadierung aufgeben, dh jeder der ersten fünf Clients überträgt den Stream auf die nächsten fünf und so weiter.
Löffel Nummer 2.Um eine direkte interaktive Verbindung (ICE) zwischen Clients herzustellen, müssen sie Firewalls und NATs umgehen. Zu diesem Zweck verwendet WebRTC einen STUN- Server , der Clients über externe Verbindungsparameter informiert. Es wird angenommen, dass dies in den meisten Fällen ausreichend ist. Aber ich hatte fast sofort "Glück":
Wie Sie sehen können, beschwert sich der Debugger über die Unmöglichkeit einer ICE-Verbindung und erfordert die Verbindung eines TURN-Servers, dh eines Relays. Und das ist schon teuer. Ein einfacher Signalisierungsserver ist unverzichtbar. Fazit - Sie müssen alle Streams durch den Medienserver leiten.
Medienserver
Zum Testen habe ich aiortc verwendet . Eine interessante Entwicklung, mit der Sie den Browser über WebRTC direkt mit dem Server verbinden können. Eine separate Signalisierung ist nicht erforderlich. Sie können den Datenkanal der Verbindung selbst verwenden. Dies funktioniert, alle meine Testpunkte sind ohne Probleme verbunden. Aber das Problem mit der Leistung. Ein einfaches Echo eines Video- / Audiostreams mit denselben 720p- und 15fps-Grenzwerten verschlang 50% meiner virtuellen CPU auf dem Test-VDS. Wenn die Last auf 100% erhöht wird, hat der Videostream keine Zeit zum Entladen auf Clients und beginnt, den Speicher zu verstopfen, was letztendlich zu einem Serverstopp führt. Offensichtlich ist der Python, den wir gerne für die E / A-Verarbeitung verwenden, nicht sehr CPU-gebunden. Wir müssen nach einer spezielleren Lösung suchen, zum Beispiel nach Janusoder Jitsy .
In jedem Fall erfordert eine Komplettlösung nach meinen Schätzungen dedizierte Server mit einer Rate von 1 Kern pro Raum (Klasse). Dies kostet bereits Geld und geht über einfache Tests hinaus. Daher werde ich an dieser Stelle die erste Phase meiner Forschung als abgeschlossen betrachten.
Schlussfolgerungen
1. Um es milde auszudrücken, es ist seltsam, Download- Anweisungen und Links zur Registrierung im Programm des ehemaligen potenziellen Feindes Nummer 1 (hier über Microsoft Teams) auf dem offiziellen Portal der Russischen Föderation zu sehen . Und dies ist in Zeiten von Sanktionen und Importsubstitution.
Nein, ich persönlich bin für die Freundschaft der Menschen und im Allgemeinen für alle Arten von Toleranz, aber sind es wirklich nur meine Haare, die von einer solchen "Integration" zu Berge stehen? Sind das nicht unsere Entwicklungen?
2. Integration von MES / NES in Schulen. Eigentlich sind die MES-Entwickler großartig, sie haben sogar die Integration mit Yandex.tutor gemacht. Was ist mit der Echtzeitbewertung während des Unterrichts? Wann wird es eine API geben? Oder ist mir etwas nicht bewusst?
3. Wenn Sie sich für eine Fern- oder Familienerziehung entscheiden, müssen Sie ehrlich zu sich selbst sein: Es wird nicht funktionieren, die Verantwortung für die Erziehung Ihres Kindes auf die Schule zu verlagern. Die gesamte Arbeit, Unterricht zu geben (im Fall von Familienerziehung), Disziplin und Selbstorganisation aufrechtzuerhalten (auf jeden Fall), liegt ganz bei den Eltern. Sie müssen sich dessen bewusst sein und Zeit für den Unterricht finden. In großen Familien sollte dies jedoch kein Problem sein.
4. Ich werde hier keine Links zu ausgewählten Online-Schulen einfügen, damit dies nicht als Werbung angesehen wird. Ich werde nur sagen, dass wir Privatschulen der mittleren Preisklasse ausgewählt haben. In jedem Fall hängt das Endergebnis vom Kind ab und wir erhalten es frühestens im September.
Oder ist es sinnvoll, die hier begonnene Entwicklung zu ihrem logischen Abschluss zu bringen und eine eigene Schule zu organisieren? Was denken Sie? Gibt es Gleichgesinnte mit Fachwissen und Erfahrung auf dem Gebiet der Bildung?
Nützliche Links:
Russische Elektronische Schule
Moskau Elektronische Schule
MES-Bibliothek für
Entwickler