GUI en russe, ou terminal VKS faites-le vous-même

Expérience dans le développement d'une interface graphique C ++ pour le système de vidéoconférence russe (VKS). La synthèse des technologies modernes et des exigences de certification. Le principal «rake» du développement et les moyens de les contourner. Qu'est-ce que l'interface graphique et le ballet russe ont en commun.

La première chose que voit l'utilisateur du système de visioconférence est l'interface. Et dans la plupart des cas, c'est par son apparence et sa fonctionnalité qu'ils jugent le système. Une interface incommode ou tentaculaire ne permettra pas d'évaluer les performances élevées du système ou les fonctionnalités étendues. Techniquement, un «beau» système doit être enveloppé dans une coque de travail attrayante et stable. Par conséquent, au début du développement du système VKS domestique, ce moment a été immédiatement pris en compte.

image

Qui sera l'utilisateur du système de vidéoconférence russe?


Depuis le printemps 2020, la réponse à la question de l'opportunité de développer un système VKS à part entière est devenue évidente. Les fonctionnaires, les entreprises commerciales, les hôpitaux et les écoles ont besoin de moyens de communication modernes avec un certain niveau de productivité et de sécurité. Vous pouvez parler dans Zoom, mais vaut-il la peine de l'utiliser pour de sérieuses négociations commerciales ou une réunion opérationnelle de managers?

Pour diverses tâches des entreprises russes, il est devenu nécessaire de créer un système de vidéoconférence national. De plus, un système composé non seulement d'un composant logiciel, mais également d'un matériel à part entière. Parmi les fournisseurs de renommée mondiale, au moins 5 entreprises proposent des systèmes de visioconférence multifonctionnels. Mais en Russie, le concept de substitution des importations commence progressivement à fonctionner. De plus, les problèmes de sécurité pour beaucoup sont devenus plus importants que le pays d'origine du produit, et le prix aux taux de change actuels n'est pas à la dernière place. Et la «beauté» de l'interface s'est avérée assez réaliste à développer à partir de zéro.

GUI au démarrage


Les principales exigences pour les interfaces modernes sont la rapidité de mise en œuvre, l'apparence à jour et la convivialité totale. Ainsi, la première tâche des développeurs de l'interface utilisateur graphique (GUI) a été une définition claire de la fonctionnalité logicielle pour la vidéoconférence.

Du point de vue de l'interface graphique, les exigences suivantes ont été formulées:

  • Passer des appels vidéo / audio sortants;
  • Accepter / rejeter les appels entrants;
  • Répondre automatiquement à un appel entrant à un intervalle de temps personnalisé;
  • Basculer entre deux appareils audio (casque / haut-parleur) pendant et en dehors de l'appel;
  • Allumez / éteignez le microphone et la caméra pendant et en dehors de l'appel;
  • Numérotation DTMF pendant un appel;
  • Réunion de conférence au terminal;
  • Gestion des caméras PTZ, sauvegarde des préréglages PTZ et de leur application;
  • La capacité de sortie vidéo sur plusieurs fenêtres différentes;
  • Contrôlez la souris, le clavier, la télécommande;
  • La possibilité de contrôler à distance le terminal depuis l'interface Web.

Cette liste de fonctions vous permet de résoudre le problème du développement d'une interface de différentes manières. De plus, le choix d'un type d'implémentation spécifique a été affecté par les limitations du type de langages de programmation (par exemple, Java n'était pas catégoriquement approprié pour des raisons de certification, CSS / HTML - selon la fonctionnalité), la spécialisation des développeurs et le calendrier. Collectivement, le choix a été fait en faveur de C ++ et de l'utilisation du framework Qt5, car, par exemple, la technologie QML plus moderne ne permet pas de rendre la vidéo en utilisant un contexte OpenGL arbitraire, et cela était nécessaire selon les ToR pour les terminaux VKS.

image

Rapide et efficace


Le premier prototype d'interface graphique a été créé pour le softphone de Qt et a utilisé de nombreuses bibliothèques open source. Par exemple, pour le protocole SIP, des bibliothèques eXosip / oSIP ont été utilisées, ffmpeg pour l'encodage / décodage vidéo et audio et PortAudio pour travailler avec des périphériques audio. Ce softphone fonctionnait sous Linux, Windows, MacOS et était un démonstrateur de technologie, et non un véritable appareil.

Plus tard, un softphone abstrait a été transformé en un véritable projet de visiophone, et la première version du logiciel aurait dû être créée 2 mois après le début. Pour résoudre ce problème en si peu de temps, le logiciel du téléphone a été divisé en modules et réparti entre plusieurs groupes de développeurs en fonction des compétences. Une telle organisation du processus a permis de développer rapidement et efficacement le projet de visiophone.

Noyau et avant


Pour l'unification et la possibilité d'utiliser les développements GUI existants dans d'autres appareils à partir d'un projet existant, la base de code commune se trouve dans un module distinct - le backend GUI, ou le module de base GUI. Et les représentations directement, qui sont différentes pour différents appareils, sont implémentées dans des modules frontaux GUI distincts.

Cette architecture des modules GUI s'est avérée avantageuse et a conduit au résultat souhaité: le développement d'interfaces pour les nouveaux composants du système VKS lui-même est devenu relativement rapide et de haute qualité. Après tout, les interfaces des terminaux VKS n'avaient plus besoin d'être réécrites à partir de zéro.

Tourment et victoire


Sur le chemin de la création d'un logiciel, il y a naturellement des difficultés et des problèmes. La création d'une interface graphique pour la vidéoconférence n'a pas fait exception. Quel que soit le but spécifique du système, ils peuvent être répétés dans n'importe quelle commande. Les difficultés et les victoires sur la voie du développement sont intéressantes pour les collègues, et elles permettront peut-être de trouver des solutions efficaces sans notre «rake».

Une cohérence pour toujours


Historiquement, le tout premier problème intéressant qui s'est posé lors du développement de l'interface graphique pour différents types de terminaux VKS a été le problème de cohérence, c'est-à-dire l'état coordonné de tous les modules. Pendant le fonctionnement, l'interface graphique interagit avec plusieurs autres modules: un module d'interaction avec le matériel, un sous-système de gestion des appels, un module de traitement multimédia (MCU) et un sous-système d'interaction utilisateur.

image

Initialement, l'interface graphique fonctionnait avec tous ces modules comme indépendants, c'est-à-dire qu'elle pouvait envoyer des demandes à 2 modules différents en même temps. Cela s'est avéré faux et a parfois conduit à des problèmes, car ces modules eux-mêmes n'étaient pas indépendants et interagissaient activement les uns avec les autres. La solution au problème a été la création d'un programme de travail spécial, qui a assuré l'exécution strictement séquentielle des demandes dans tous les modules.

Il y avait deux difficultés à ajouter: premièrement, certaines (mais pas toutes) les demandes nécessitent une réponse, en prévision de laquelle le terminal est en fait dans un état incohérent, de sorte que d'autres demandes ne peuvent pas être effectuées. Cependant, le blocage de l'interface utilisateur en attendant les réponses est également indésirable. Deuxièmement, les réponses aux requêtes GUI des modules, ainsi que les requêtes des modules à l'interface graphique, viennent dans leurs propres threads, différents de l'interface graphique, mais l'interface graphique doit implémenter tous les changements d'état dans son thread (pour certaines actions, Qt l'exige, mais dans dans certains cas, cela évite des difficultés inutiles pour assurer la synchronisation des threads).

La solution a été trouvée et comprenait deux parties. Tout d'abord, toutes les demandes / réponses d'autres modules ont été redirigées vers le flux GUI en utilisant le mécanisme d'intervalle de signal Qt en conjonction avec QueuedConnection, c'est-à-dire en utilisant la boucle d'événement QApplication globale. Ensuite, pour assurer un traitement cohérent de toutes les demandes, un système Transitions a été développé avec sa propre file d'attente et son propre cycle de traitement (TransitionLoop).

Ainsi, lorsque l'utilisateur appuie sur un bouton d'action dans l'interface graphique (par exemple, le bouton d'appel), une transition correspondante est créée, qui est placée dans la file d'attente de transition. Après cela, un signal est généré pour le cycle de traitement de transition. TransitionLoop, lors de la réception d'un signal, cherche à voir s'il y a une transition en cours maintenant. Si tel est le cas, l'attente de la fin de la transition en cours se poursuit; sinon, la transition suivante est extraite de la file d'attente de transition et lancée. Lorsqu'une réponse est reçue d'un autre module TransitionLoop utilisant le même signal, la fin de la transition en cours est notifiée et TransitionLoop peut démarrer la transition suivante à partir de la file d'attente.

L'important ici est que tout le traitement de transition se fait dans un thread GUI. Ceci est assuré par l'utilisation du mécanisme d'intervalle de signal Qt dans la variante QueuedConnection, dans lequel un événement est généré pour chaque signal et placé dans le EventLoop principal de l'application.

Rendu OpenGL sur du matériel basse consommation


Une autre difficulté à laquelle nous avons dû faire face était le problème du rendu vidéo. Qt fournit pour le rendu OpenGL une classe QOpenGLWidget spéciale et des classes d'assistance associées, qui étaient à l'origine utilisées pour le rendu vidéo. Les données de rendu (images vidéo décodées) elles-mêmes sont fournies par le module de traitement multimédia (MCU), qui, entre autres, implémente le décodage matériel du flux vidéo (sur le GPU). Sur les processeurs de faible puissance, un "ralentissement" du rendu de la vidéo FullHD a été trouvé. La solution directe était de remplacer le processeur, mais cela nécessiterait un traitement sérieux des composants déjà finis du système de visioconférence et augmenterait le coût des appareils eux-mêmes. Par conséquent, l'ensemble du processus de rendu a été soigneusement analysé pour trouver de plus belles façons de résoudre le problème.

Avec le rendu OpenGL standard et le décodage matériel, les événements suivants se produisent: les données avec la vidéo encodée proviennent du réseau, elles sont stockées dans la RAM, puis ces données de la RAM sont transférées vers la mémoire vidéo sur le GPU, où elles sont décodées. Ensuite, les données décodées ayant un volume significativement plus grand que les données codées sont à nouveau transférées vers la RAM. Ensuite, un code de rendu entre en jeu, qui transfère ces données de la RAM au GPU directement pour le rendu. Ainsi, des quantités assez importantes de données sont pompées dans les deux sens via le bus mémoire, et le bus ne peut tout simplement pas le faire.

Dans les versions modernes d'OpenGL, il existe des extensions spéciales qui vous permettent de spécifier pour le rendu des données qui sont déjà dans la mémoire du GPU, et non des données dans la RAM principale, comme d'habitude. Ce mécanisme a exclu le mouvement des données des trames décodées matériellement du GPU vers la RAM, puis inversement. Ainsi, le problème du rendu sur les processeurs basse consommation a été presque résolu.

image

Un autre problème majeur était les contextes OpenGL pris en charge dans Qt. Ils ne vous permettent pas d'utiliser l'extension OpenGL nécessaire, c'est-à-dire que vous ne pouvez pas utiliser QOpenGLWidget avec cette option. La solution consistait à utiliser un QWidget classique, mais a désactivé le pipeline de rendu Qt. Une telle opportunité existe dans Qt. Cependant, une question s'est posée ici, car dans cette option, l'interface graphique est entièrement responsable de tout le rendu dans la zone de ce widget, Qt ne nous aide pas. Ceci est normal pour afficher la vidéo, mais pour utiliser des widgets au-dessus de la vidéo, les outils Qt standard ne peuvent pas être utilisés, car, par exemple, un menu contextuel supplémentaire doit être affiché au-dessus de la vidéo.

Ce problème a été résolu comme suit: à partir du widget existant, son image est obtenue (QWidget a une méthode grab () pour cela), l'image résultante est convertie en texture OpenGL et cette dernière est rendue au-dessus de la vidéo à l'aide des outils OpenGL. En ajoutant l'environnement approprié, un mécanisme universel a été mis en œuvre qui peut être utilisé pour afficher tous les widgets standard au-dessus de la vidéo d'une manière non standard.

Kiosques et widgets


La tâche de gérer les affichages et de distribuer des fragments de l'interface utilisateur en mode «kiosque» n'a pas été facile. Le terminal VKS peut fonctionner en 2 modes - le mode fenêtre, c'est-à-dire comme toute autre application de fenêtre dans l'environnement de bureau du système d'exploitation, et le «mode kiosque» (c'est-à-dire que le système d'exploitation exécute une seule application avec une interface graphique - VKST - et qu'il n'y a pas d'environnement bureau).

En mode fenêtré, tout est relativement simple: la fenêtre est contrôlée par le gestionnaire de fenêtres de l'environnement de bureau, l'application crée une deuxième fenêtre si nécessaire, et l'utilisateur répartit les fenêtres sur les écrans selon ses besoins. Mais en mode «kiosque», tout est beaucoup plus compliqué, car le système n'a pas de gestionnaire de fenêtres et il ne peut y avoir qu'une seule fenêtre, et l'utilisateur n'a pas la possibilité de la déplacer. Par conséquent, la tâche de détecter automatiquement un événement, par exemple la connexion / déconnexion d'un écran, est apparue. Lorsque cet événement s'est produit, il était nécessaire de configurer automatiquement les affichages et de placer correctement des fragments de l'interface utilisateur dessus.

image

La réponse est venue de la bibliothèque système LINUX Xrandr OS, qui est chargée de travailler avec les écrans. Il y a très peu de documentation à ce sujet sur Internet, donc la mise en œuvre a été effectuée à l'aide d'exemples provenant d'Internet, y compris de Habr. De plus, il était nécessaire de trouver un algorithme pour distribuer les fragments d'interface entre les écrans, ainsi que d'intégrer deux fenêtres différentes en une seule. Ce dernier a été implémenté comme suit: ce sont des fenêtres en mode fenêtré, en mode «kiosque» sont des widgets à l'intérieur d'une grande fenêtre, qui s'étend sur 2 écrans (s'il y en a 2). Dans ce cas, il est nécessaire de configurer les positions des écrans afin qu'un espace virtuel continu soit créé (cela se fait à l'aide de la bibliothèque XRandr), puis de définir la géométrie des widgets internes à l'intérieur d'une seule fenêtre globale afinpour que tout le monde soit affiché.

Nous créons du russe


Toute la manière de créer le système de vidéoconférence russe a consisté et comprend de nombreuses étapes, et l'interface graphique n'est que la pointe de l'iceberg. Le plus visible et pas le plus difficile. Cependant, la complexité de la solution, la combinaison de logiciels et de composants matériels et logiciels, et le désir de créer un système techniquement et esthétiquement «beau» ont créé de nombreuses difficultés en cours de route. De nouvelles tâches ont donné naissance à des solutions non standard et ont aidé à créer un produit qui n'a pas honte d'être présenté non seulement en Russie mais aussi à l'étranger.

Les développements russes ont depuis longtemps prouvé leurs performances, et dans une belle coque et compétitivité. Nos hacks de vie seront utiles à toute personne sérieusement impliquée dans le développement d'interfaces graphiques, et nous espérons qu'ils aideront d'autres développeurs à accélérer et à simplifier le processus de création de shells modernes pour de nouveaux logiciels russes. Nous pensons que les décisions russes seront appréciées dans le monde au même titre que le ballet russe ou le caviar noir.

All Articles