Aller au contenu
Table des matières

Artemis-N3DS : Le streaming sur un client à deux écrans

Artemis-N3DS adapte Moonlight Embedded à la famille Nintendo 3DS. Le projet réunit découverte et jumelage de l’hôte, interface console, commandes et affichage vidéo. Le parcours matériel de la New 3DS demande une attention particulière.

Matériel et infographie Fork Docker
  • Mis à jour
  • C++ · 76.05%
  • GPL-3.0
Composants documentés
2Explorer les modules
Documents source
2Lire les instructions
Langages du dépôtC++ 76.05%6

Parts calculées à partir des octets GitHub Linguist.

C++76.05%
76.05%385 430 octets
C15.71%
15.71%79 616 octets
CMake4.36%
4.36%22 072 octets
Makefile2.84%
2.84%14 414 octets
Langage%Octets
C++76.05%385 430
C15.71%79 616
CMake4.36%22 072
Makefile2.84%14 414
Shell0.64%3 221
Dockerfile0.4%2 051

1. Aperçu

1.1. Pourquoi il existe

Défi d'ingénierie sous fortes contraintes : streaming 60 FPS sur architecture ARM11 double écran.

1.2. Cas d’usage

Accès distant et jeu PC sur matériel New 3DS.

2. Cas d’utilisation

Fork de Moonlight Embedded qui diffuse les jeux d’un PC Sunshine sur une New 3DS, avec une interface d’aide à l’écran du bas.

Diagramme de cas d’utilisation de Artemis-N3DS : Installer le CIA ou le 3DSX; Jumeler un hôte; Diffuser un jeu ou le bureau; Changer de mode tactile; Enregistrer les mesures en CSV; Compiler avec devkitProArtemis-N3DSInstaller le CIA ou le 3DSXJumeler un hôteDiffuser un jeu ou le bureauChanger de mode tactileEnregistrer les mesures en CSVCompiler avec devkitProJoueur sur 3DSDéveloppeur«système»PC hôte Sunshine
Acteurs à gauche (personnes) et à droite (systèmes externes) ; chaque ovale est un cas d’utilisation appuyé par les fichiers cités ci-dessous.
Installer le CIA ou le 3DSX
Joueur sur 3DS

dist/INSTALL.md explique comment installer artemis.cia depuis le menu HOME avec FBI, ou copier artemis.3dsx dans sd:/3ds/artemis/ pour le Homebrew Launcher ; un firmware modifié est requis.

Jumeler un hôte
Joueur sur 3DSPC hôte Sunshine

Le joueur ajoute un hôte par son IP locale (host_discovery.cpp peut aussi balayer le réseau) et choisit pair ; pair_host dans src/n3ds_main.cpp affiche un NIP à saisir dans Sunshine et garde un enregistrement de jumelage.

Diffuser un jeu ou le bureau
Joueur sur 3DSPC hôte Sunshine

La vidéo s’affiche à l’écran du haut avec le décodeur H.264 matériel de la New 3DS ; selon le README, les anciens modèles passent au décodage logiciel, avec moins d’images par seconde.

Changer de mode tactile
Joueur sur 3DSPC hôte Sunshine

Le menu SELECT de l’écran du bas passe d’un gestionnaire à l’autre dans src/input/touch/ : manette, souris, clavier, loupe et miroir, avec les affichages Fit, Fill, Stretch et le zoom.

Enregistrer les mesures en CSV
Joueur sur 3DS

Depuis l’onglet Session, la surcouche de performance affiche la télémétrie ; export_stream_benchmark_csv (src/stream_benchmark.cpp) écrit benchmark_<horodatage>.csv sur la carte SD.

Compiler avec devkitPro
Développeur

Le Dockerfile donne une image devkitPro ; make y produit artemis.3dsx, artemis.cia et artemis.elf. Une installation locale de devkitPro 3ds-dev avec bannertool et makerom fonctionne aussi.

2.1. Scénario : Jouer à un jeu PC sur New 3DS en Wi-Fi

  1. Copier artemis.cia sur la carte SD et l’installer dans FBI avec Install and delete CIA.
  2. Ouvrir Artemis, appuyer sur A pour ajouter un hôte et saisir l’adresse IP locale du PC.
  3. Choisir pair et taper dans la page PIN de Sunshine le NIP affiché sur la 3DS.
  4. Choisir stream puis une application ; la vidéo s’affiche à l’écran du haut.
  5. Appuyer sur SELECT pour passer en mode Souris ou Loupe, ou ouvrir la surcouche de performance et enregistrer un CSV.
  6. Quitter depuis l’onglet Session pour terminer la diffusion.

Fichiers consultésREADME.mddist/INSTALL.mddist/SD-DATA.mdsrc/n3ds_main.cppsrc/host_discovery.cppsrc/stream_benchmark.cppsrc/input/touch/stream_bottom_ui.cppDockerfile

3. Démarrage

Ces commandes viennent de la documentation du dépôt. Elles n’ont pas été exécutées pendant cette revue.

README.md · Local (devkitPro)
make
README.md · Docker (easiest)
docker build --network=host -t moonlight-n3ds .
docker run --rm -it -v .:/moonlight-N3DS -w /moonlight-N3DS moonlight-n3ds:latest
make

4. Références du dépôt

Extraits des guides du dépôt, dans leur langue d’origine. Les liens ouvrent la version du code consultée.

Prérequis et premier essai

4.1. Requirements

README.md

  • New 3DS / New 3DS XL / New 2DS XL recommended (hardware H.264 decode)
  • Original 3DS / 2DS works with software decode only — expect lower FPS
  • PC running Sunshine (or compatible GameStream host) on the same network
  • CFW + FBI for CIA install
Lire les instructions complètes ↗

4.2. Install

README.md

Full FBI steps: dist/INSTALL.md. CIA (HOME Menu): copy dist/artemis.cia to the SD card → open FBI → Install and delete CIA. 3DSX: copy dist/artemis.3dsx to sd:/3ds/artemis/artemis.3dsx and launch from the Homebrew Launcher.
Lire les instructions complètes ↗
Configuration et utilisation

4.3. Configuration

README.md

Settings can be changed in-app or in: That path is legacy (kept so existing pairing and configs keep working). See dist/SD-DATA.md for the full SD layout (keys, paired hosts, diagnostics). Default settings are aimed at New 3DS.
Lire les instructions complètes ↗
Développement et contributions

4.4. Contribute

README.md

  1. Fork the repo
  2. Make your changes
  3. Open a pull request
Lire les instructions complètes ↗
Documentation source

2 documents lus parmi 2 candidats.

5. Fonctions et composants 2

Gestion de la session
n3ds_main.cpp réunit découverte, jumelage, profils et état de connexion. L’hôte et l’application sélectionnés déterminent la demande de streaming. Le cycle de vie graphique est suivi séparément de la configuration du flux.
Médias et interaction
L’audio, les commandes et la vidéo ont leurs modules dans src. Les capacités matérielles influencent les indications affichées. L’interface peut reprendre après un flux, tandis qu’une fermeture système explicite doit terminer l’application.

6. Architecture

Ouvrez un composant pour suivre ses connexions, ou explorez le diagramme complet.

Composants du système Contexte
Mermaid Diagramme interactif

Vue générale des composants et des échanges vérifiés dans le dépôt.

Vue statique de l’architecture de Artemis-N3DS
Aperçu statique. Le diagramme interactif le remplace après le chargement de Mermaid.
flowchart LR
node_user(("3DS user"))

subgraph group_host["Hosts and pairing"]
  node_discovery["Host discovery<br/>[host_discovery.cpp]"]
  node_pairing[("Pair records<br/>[pair_record.cpp]")]
  node_gamestream["GameStream client<br/>[client.c]"]
  node_xml["Protocol XML<br/>[xml.c]"]
end

subgraph group_session["Session coordination"]
  node_main["Application flow<br/>[n3ds_main.cpp]"]
  node_ui["Console menus<br/>[n3ds_ui.cpp]"]
  node_connection["Stream connection"]
  node_dispatcher["Message dispatcher<br/>[dispatcher.cpp]"]
end

subgraph group_stream["Stream pipeline"]
  node_presentation["Presentation state"]
  node_decoder["Video decoders"]
  node_mvd["Hardware decode<br/>[n3ds_video_mvd.cpp]"]
  node_software["Software decode"]
  node_renderer["Screen renderers"]
  node_graphics["Graphics lifecycle"]
  node_audio["Audio output<br/>[n3ds_audio.cpp]"]
end

subgraph group_interaction["Input and helpers"]
  node_input["Console input<br/>[n3ds_input.cpp]"]
  node_touch["Touch handlers<br/>[TouchHandler.hpp]"]
  node_menuhub["In-stream helper hub"]
  node_bottomui["Bottom-screen UI"]
end

subgraph group_state["Settings and telemetry"]
  node_config[("Configuration<br/>[config.cpp]")]
  node_appcache[("App list cache<br/>[app_list_cache.cpp]")]
  node_profiles["Stream profiles<br/>[stream_profile.cpp]"]
  node_telemetry[("Stream telemetry")]
  node_benchmark["Performance metrics"]
end

node_user -->|"uses"| node_main
node_gamestream -->|"parses responses"| node_xml
node_discovery -->|"uses records"| node_pairing
node_main -->|"shows menus"| node_ui
node_main -->|"starts session"| node_connection
node_main -->|"handles controls"| node_input
node_input -->|"posts events"| node_dispatcher
node_input -->|"owns handlers"| node_touch
node_main -->|"dispatches events"| node_dispatcher
node_user -->|"opens helpers"| node_menuhub
node_menuhub -->|"posts actions"| node_dispatcher
node_menuhub -.->|"draws interface"| node_bottomui
node_user -->|"chooses stream"| node_connection
node_connection -.->|"receives video"| node_decoder
node_decoder -.->|"hardware path"| node_mvd
node_decoder -.->|"software path"| node_software
node_decoder -->|"renders frames"| node_renderer
node_renderer -->|"uses layout state"| node_presentation
node_renderer -->|"uses graphics lifecycle"| node_graphics
node_connection -.->|"streams audio"| node_audio
node_user -->|"views or saves metrics"| node_telemetry
group_session --> group_host
group_session --> group_state
class node_discovery,node_pairing,node_gamestream,node_xml,node_user toneBlue
class node_main,node_ui,node_connection,node_dispatcher toneAmber
class node_presentation,node_decoder,node_mvd,node_software,node_renderer,node_graphics,node_audio toneMint
class node_input,node_touch,node_menuhub,node_bottomui toneRose
class node_config,node_appcache,node_profiles,node_telemetry,node_benchmark toneIndigo

Un client GameStream pour Nintendo 3DS. Les utilisateurs découvrent ou ajoutent un hôte compatible Sunshine, associent la console, choisissent une application et lancent la diffusion par les sous-systèmes de session, vidéo, rendu, entrées et écran inférieur.

Composants
25
Connexions
29
Liens appuyés par le code
23/29
Version texte du diagramme

Le diagramme regroupe les liens parallèles entre groupes : il en montre 23 sur 29. Liste complète :

  • 3DS user → Application flow (uses)
  • Application flow → Host discovery (finds hosts)
  • Application flow → Pair records (pairs host)
  • Application flow → GameStream client (manages host)
  • GameStream client → Protocol XML (parses responses)
  • Host discovery → Pair records (uses records)
  • Application flow → Console menus (shows menus)
  • Application flow → App list cache (lists apps)
  • Application flow → Stream connection (starts session)
  • Application flow → Configuration (loads settings)
  • Application flow → Stream profiles (selects profile)
  • Application flow → Console input (handles controls)
  • Console input → Message dispatcher (posts events)
  • Console input → Touch handlers (owns handlers)
  • Application flow → Message dispatcher (dispatches events)
  • 3DS user → In-stream helper hub (opens helpers)
  • In-stream helper hub → Message dispatcher (posts actions)
  • In-stream helper hub → Bottom-screen UI (draws interface)
  • 3DS user → Stream connection (chooses stream)
  • Stream connection → Video decoders (receives video)
  • Video decoders → Hardware decode (hardware path)
  • Video decoders → Software decode (software path)
  • Video decoders → Screen renderers (renders frames)
  • Screen renderers → Presentation state (uses layout state)
  • Screen renderers → Graphics lifecycle (uses graphics lifecycle)
  • Stream connection → Audio output (streams audio)
  • 3DS user → Stream telemetry (views or saves metrics)
  • 3DS user → Performance metrics (views performance)
  • Application flow → Stream telemetry (uses telemetry store)
Suivre un parcours dans le code

Suivez SelectedHost et le profil avant d’entrer dans le traitement des médias. Une fermeture système et un retour normal au menu sont deux transitions distinctes; un indicateur explicite évite de les confondre.

7. Dossier technique

Établi à partir du code au commit c5eb020 (104 fichiers). Chaque élément vient d’une correspondance de motif dans le code: ouvrez le fichier lié avant de vous y fier.

7.1. Couches et modules

Les dossiers sont classés par couche selon leur nom, de l’interface utilisateur jusqu’à l’accès aux données. Comme le classement repose sur les noms seulement, le diagramme ne dit rien des appels entre couches.

Mermaid Vue en couches
flowchart TB
  subgraph L_interface["Points d’entrée et API"]
    direction TB
    interface_0["src<br/>1 fichier"]
  end
  subgraph L_domain["Domaine et règles métier"]
    direction TB
    domain_0["input/touch<br/>2 fichiers"]
  end
  subgraph L_infrastructure["Données et infrastructure"]
    direction TB
    infrastructure_0["libgamestream<br/>2 fichiers"]
    infrastructure_1["src<br/>2 fichiers"]
    infrastructure_2["third_party/ilclient<br/>2 fichiers"]
  end
  subgraph L_core["Source principale"]
    direction TB
    core_0["src<br/>26 fichiers"]
    core_1["third_party/libuuid<br/>17 fichiers"]
    core_2["input/touch<br/>16 fichiers"]
    core_3["system<br/>12 fichiers"]
    core_more["+9"]
  end
  subgraph L_tests["Tests"]
    direction TB
    tests_0["tests<br/>1 fichier"]
  end
  subgraph L_hosting["Build, CI et hébergement"]
    direction TB
    hosting_0[".github<br/>7 fichiers"]
    hosting_1["(root)<br/>3 fichiers"]
    hosting_2["libgamestream<br/>1 fichier"]
  end
  L_interface ~~~ L_domain
  L_domain ~~~ L_infrastructure
  L_infrastructure ~~~ L_core
  L_core ~~~ L_tests
  L_core ~~~ L_hosting
Modules et couche principale
ModuleCoucheFichiersTypesExtensions
srcSource principale2922.hpp .cpp .c
input/touchSource principale1823.cpp .hpp
third_party/libuuidSource principale170.c .h
libgamestreamSource principale138.h .c
systemSource principale1210.hpp .cpp .c
video/rendererSource principale99.cpp .hpp
videoSource principale84.cpp .hpp .c
third_party/h264bitstreamSource principale60.h .c
3dsSource principale30.sh
third_party/ilclientDonnées et infrastructure30.c .h
audioSource principale20.h .cpp
inputSource principale21.cpp .hpp
third_party/libcecSource principale10.h

7.2. Modèle C4

Du contexte du système aux déclarations du code. Chaque niveau conserve les limites des sources disponibles.

UML 1 · Contexte du système
1 · Contexte du système

La vue C4 la plus large : qui utilise le projet et sur quels systèmes et stockages externes il s’appuie. Rendu avec uml-mcp.

Source PlantUML
@startuml
!include <C4/C4_Context>
LAYOUT_LEFT_RIGHT()
System(SYS, "Artemis-N3DS", "Artemis-N3DS adapte Moonlight Embedded à la famille Nintendo 3DS")
@enduml
UML 2 · Conteneurs
2 · Conteneurs

Un niveau plus près : les parties qui s’exécutent séparément dans le projet, leur langage principal et le chemin des appels entre elles. Rendu avec uml-mcp.

Source PlantUML
@startuml
!include <C4/C4_Container>
LAYOUT_LEFT_RIGHT()
System_Boundary(SYS, "Artemis-N3DS") {
  Container(APP, "Artemis-N3DS", "C++")
}
@enduml
UML 3 · Composants et couches
3 · Composants et couches

Modules regroupés par couche du code. Les limites indiquent l’organisation, sans affirmer une isolation à l’exécution ni des appels. Rendu avec uml-mcp.

Source PlantUML
@startuml
!include <C4/C4_Component>
LAYOUT_TOP_DOWN()
System_Boundary(SYS, "Artemis-N3DS") {
Boundary(L0, "Points d’entrée et API", "layer") {
Component(M0_0, "src", "C++", "1 fichiers")
}
Boundary(L1, "Domaine et règles métier", "layer") {
Component(M1_0, "input/touch", "C++", "2 fichiers")
}
Boundary(L2, "Données et infrastructure", "layer") {
Component(M2_0, "libgamestream", "C, C/C++", "2 fichiers")
Component(M2_1, "src", "C++", "2 fichiers")
Component(M2_2, "third_party/ilclient", "C, C/C++", "2 fichiers")
}
Boundary(L3, "Source principale", "layer") {
Component(M3_0, "src", "C++, C", "26 fichiers")
Component(M3_1, "third_party/libuuid", "C, C/C++", "17 fichiers")
Component(M3_2, "input/touch", "C++", "16 fichiers")
Component(M3_3, "system", "C++, C", "12 fichiers")
Component(M3_4, "libgamestream", "C/C++, C", "11 fichiers")
Component(M3_5, "video/renderer", "C++", "9 fichiers")
Component(M3_6, "video", "C++, C", "8 fichiers")
Component(M3_7, "third_party/h264bitstream", "C/C++, C", "6 fichiers")
Component(M3_more, "+5 modules", "", "")
}
Boundary(L4, "Tests", "layer") {
Component(M4_0, "tests", "C++", "1 fichiers")
}
Boundary(L5, "Build, CI et hébergement", "layer") {
Component(M5_0, ".github", ".md, .yml", "7 fichiers")
Component(M5_1, "(root)", ".txt, Dockerfile, Makefile", "3 fichiers")
Component(M5_2, "libgamestream", ".txt", "1 fichiers")
}
}
@enduml
UML 4 · Code
4 · Code

Déclarations, champs et méthodes sélectionnés, regroupés par fichier source. Aucun héritage ni appel n’est déduit. Rendu avec uml-mcp.

Source PlantUML
@startuml
skinparam backgroundColor transparent
skinparam shadowing false
skinparam roundCorner 10
skinparam defaultFontName Arial
skinparam defaultFontSize 13
skinparam ArrowColor #4e6070
skinparam ArrowFontColor #3d4f5f
skinparam titleFontSize 14
skinparam actorBorderColor #006a62
skinparam actorBackgroundColor #e9f3f4
skinparam usecaseBorderColor #006a62
skinparam usecaseBackgroundColor #e9f3f4
skinparam componentBorderColor #006a62
skinparam componentBackgroundColor #e9f3f4
skinparam interfaceBorderColor #006a62
skinparam interfaceBackgroundColor #ffffff
skinparam nodeBorderColor #4e6070
skinparam nodeBackgroundColor #f4f8fb
skinparam databaseBorderColor #006a62
skinparam databaseBackgroundColor #ffffff
skinparam cloudBorderColor #4e6070
skinparam cloudBackgroundColor #f0f5fa
skinparam artifactBorderColor #006a62
skinparam artifactBackgroundColor #ffffff
skinparam rectangleBorderColor #b0c2d3
skinparam activityBorderColor #006a62
skinparam activityBackgroundColor #e9f3f4
skinparam partitionBorderColor #b0c2d3
skinparam stereotypeCBackgroundColor #ffffff
top to bottom direction
hide empty members
package "Artemis-N3DS" {
package "src/video/renderer/N3dsRenderer.hpp" as F0 {
class "N3dsRendererBase" as T0_0 {
  draw_perf_counters()
  write_px_to_framebuffer_gpu()
  ensure_3d_enabled()
  ensure_3d_disabled()
  write24()
}
class "N3dsRendererDualScreenMagnify" as T0_1 {
  write_px_to_framebuffer()
  set_perf_decode_ticks()
  set_crop_region()
  accept()
}
class "N3dsRendererNormal" as T0_2 {
  write_px_to_framebuffer()
  set_perf_decode_ticks()
  set_bottom_screen()
}
class "N3dsRendererBottom" as T0_3 {
  write_px_to_framebuffer()
  write_px_to_framebuffer_raw()
}
class "N3dsRendererDualScreenMirror" as T0_4 {
  write_px_to_framebuffer()
  set_perf_decode_ticks()
}
}
package "src/input/touch/stream_bottom_ui.hpp" as F1 {
class "BottomCanvas" as T1_0 {
  ready()
  put()
  fill()
  clear()
  round_fill()
  glyph()
}
}
package "src/system/n3ds_connection.hpp" as F2 {
class "N3dsConnectionListener" as T2_0 {
  accept()
  create_instance()
  get_instance()
  destroy_instance()
  connection_terminated()
  connection_log_message()
}
}
package "src/input/n3ds_input.hpp" as F3 {
class "N3dsInput" as T3_0 {
  accept()
  n3dsinput_handle_event()
  force_touchscreen_menu()
  _add_gamepad()
  _remove_gamepad()
  _n3ds_to_li_buttons()
}
}
package "src/input/touch/TouchHandler.hpp" as F4 {
class "TouchHandlerBase" as T4_0 {
  handle_touch_down()
  handle_touch_up()
  handle_touch_hold()
  captures_gamepad_input()
  handle_navigation()
  _handle_touch_down()
}
class "KeyInfo" as T4_1 {
  min_x
  max_x
  min_y
  max_y
  key_px_size
  std
}
}
package "src/system/dispatcher.hpp" as F5 {
class "MessageDispatcher" as T5_0 {
  get_instance()
  subscribe()
  unsubscribe()
  post_immediate()
  post()
  dispatch_all()
}
}
package "src/stream_profile.hpp" as F6 {
class "StreamProfilePreset" as T6_0 {
  name
  width
  height
  fps
  bitrate_kbps
  presentation_mode
  _CONFIGURATION
  PCONFIGURATION
}
}
package "src/config.hpp" as F7 {
class "_CONFIGURATION" as T7_0 {
  stream
  app
  action
  address
  mapping
  platform
  audio_device
  config_file
}
}
package "libgamestream/client.h" as F8 {
class "_SERVER_DATA" as T8_0 {
  gpuType
  paired
  unsupported
  isNvidiaSoftware
  currentGame
  serverMajorVersion
  gsVersion
  modes
}
}
package "libgamestream/xml.c" as F9 {
class "xml_query" as T9_0 {
  memory
  size
  start
  data
  head
  tail
  current
}
class "xml_applist_query" as T9_1 {
  head
  tail
  current
  memory
  size
  field
}
}
package "libgamestream/xml.h" as F10 {
class "_APP_LIST" as T10_0 {
  name
  id
  next
  height
  width
  refresh
}
class "_DISPLAY_MODE" as T10_1 {
  height
  width
  refresh
  next
}
}
package "src/n3ds_ui.cpp" as F11 {
class "VisibleAction" as T11_0 {
  kind
  key
  std
  primary
}
class "AnalogNavState" as T11_1 {
  std
  value
}
}
package "src/input/touch/keycode_map.hpp" as F12 {
class "key_boundary" as T12_0 {
  max_x
  key_idx
  max_y
  std
}
}
package "src/input/touch/MenuTouchHandler.cpp" as F13 {
class "MenuTile" as T13_0 {
  label
  kind
  PresentationMode
}
}
package "src/input/touch/ShortcutsTouchHandler.cpp" as F14 {
class "ShortcutDef" as T14_0 {
  label
  key
  modifiers
}
}
package "libgamestream/mkcert.h" as F15 {
class "_CERT_KEY_PAIR" as T15_0 {
  x509
  pkey
  p12
}
}
}
@enduml

7.3. Flux de données

Les appels du diagramme GitDiagram, dans l’ordre où on les rencontre depuis les points d’entrée. GitDiagram produit ce graphe par IA; les chemins de fichiers cités ont été comparés à l’arbre du dépôt.

Mermaid Diagramme de séquence
sequenceDiagram
  autonumber
  participant P0 as 3DS user
  participant P1 as Application flow
  participant P2 as In-stream helper hub
  participant P3 as Stream connection
  participant P4 as Stream telemetry
  participant P5 as Performance metrics
  participant P6 as Host discovery
  participant P7 as Pair records
  participant P8 as GameStream client
  participant P9 as Console menus
  participant P10 as App list cache
  participant P11 as Configuration
  participant P12 as Stream profiles
  participant P13 as Console input
  participant P14 as Message dispatcher
  P0->>P1: uses
  P0->>P2: opens helpers
  P0->>P3: chooses stream
  P0->>P4: views or saves metrics
  P0->>P5: views performance
  P1->>P6: finds hosts
  P1->>P7: pairs host
  P1--)P8: manages host
  P1->>P9: shows menus
  P1->>P10: lists apps
  P1->>P3: starts session
  P1->>P11: loads settings
  P1->>P12: selects profile
  P1->>P13: handles controls
  P1->>P14: dispatches events
  P1->>P4: uses telemetry store
Étapes en texte (+5)
  1. 3DS user vers Application flow uses
  2. 3DS user vers In-stream helper hub opens helpers
  3. 3DS user vers Stream connection chooses stream
  4. 3DS user vers Stream telemetry views or saves metrics
  5. 3DS user vers Performance metrics views performance
  6. Application flow vers Host discovery finds hosts
  7. Application flow vers Pair records pairs host
  8. Application flow vers GameStream client manages host
  9. Application flow vers Console menus shows menus
  10. Application flow vers App list cache lists apps
  11. Application flow vers Stream connection starts session
  12. Application flow vers Configuration loads settings
  13. Application flow vers Stream profiles selects profile
  14. Application flow vers Console input handles controls
  15. Application flow vers Message dispatcher dispatches events
  16. Application flow vers Stream telemetry uses telemetry store
  17. In-stream helper hub vers Message dispatcher posts actions
  18. In-stream helper hub vers Bottom-screen UI draws interface
  19. Stream connection vers Video decoders receives video
  20. Stream connection vers Audio output streams audio
  21. Host discovery vers Pair records uses records
  22. GameStream client vers Protocol XML parses responses
  23. Console input vers Message dispatcher posts events
  24. Console input vers Touch handlers owns handlers

7.4. Interface privée

Ces noms sont internes selon les conventions du langage: tiret bas initial, private, static ou pub(crate).

Fonction static (locale au fichier)
59
Espace de noms anonyme
25

7.5. Services

Gestionnaire 10

Service 1

7.6. Entités et modèle de données 37

Mermaid Diagramme de classes des entités
classDiagram
  direction LR
  class E0["StreamProfilePreset"] {
    +char name
    +int width
    +int height
    +int fps
    +int bitrate_kbps
    +PresentationMode presentation_mode
  }
  class E1["_CONFIGURATION"] {
    +STREAM_CONFIGURATION stream
    +char app
    +char action
    +char address
    +char mapping
    +char platform
  }
  class E2["_SERVER_DATA"] {
    +char gpuType
    +bool paired
    +bool unsupported
    +bool isNvidiaSoftware
    +int currentGame
    +int serverMajorVersion
  }
  class E3["xml_query"] {
    +char memory
    +size_t size
    +int start
    +void data
    +PAPP_LIST head
    +PAPP_LIST tail
  }
  class E4["KeyInfo"] {
    +int min_x
    +int max_x
    +int min_y
    +int max_y
    +int key_px_size
    +:map std
  }
  class E5["_APP_LIST"] {
    +char name
    +int id
    +struct next
    +unsigned height
    +unsigned width
    +unsigned refresh
  }
  class E6["xml_applist_query"] {
    +PAPP_LIST head
    +PAPP_LIST tail
    +PAPP_LIST current
    +char memory
    +size_t size
    +enum field
  }
  class E7["VisibleAction"] {
    +ActionKind kind
    +char key
    +:vector std
    +bool primary
  }
  class E8["_DISPLAY_MODE"] {
    +unsigned height
    +unsigned width
    +unsigned refresh
    +struct next
  }
  class E9["key_boundary"] {
    +u16 max_x
    +int key_idx
    +u16 max_y
    +:vector std
  }
  E5 --> E8 : next

Une flèche relie un champ à l’entité que son type nomme.

EntitéNaturePremiers champs
StreamProfilePresetStructure de donnéesname, width, height, fps, bitrate_kbps, presentation_mode, _CONFIGURATION, PCONFIGURATION
_CONFIGURATIONStructure de donnéesstream, app, action, address, mapping, platform, audio_device, config_file
_SERVER_DATAStructure de donnéesgpuType, paired, unsupported, isNvidiaSoftware, currentGame, serverMajorVersion, gsVersion, modes
xml_queryStructure de donnéesmemory, size, start, data, head, tail, current
KeyInfoStructure de donnéesmin_x, max_x, min_y, max_y, key_px_size, std
_APP_LISTStructure de donnéesname, id, next, height, width, refresh
xml_applist_queryStructure de donnéeshead, tail, current, memory, size, field
VisibleActionStructure de donnéeskind, key, std, primary
Afficher 6 entités de plus
_DISPLAY_MODEStructure de donnéesheight, width, refresh, next
key_boundaryStructure de donnéesmax_x, key_idx, max_y, std
MenuTileStructure de donnéeslabel, kind, PresentationMode
ShortcutDefStructure de donnéeslabel, key, modifiers
_CERT_KEY_PAIRStructure de donnéesx509, pkey, p12
AnalogNavStateStructure de donnéesstd, value

7.7. Logique métier

Une fois écartés le code d’interface et les services et entités ci-dessus, ces classes ont le plus de méthodes.

N3dsRendererBase Source principale, 5 méthodes
draw_perf_counters, write_px_to_framebuffer_gpu, ensure_3d_enabled, ensure_3d_disabled, write24
BottomCanvas Source principale, 10 méthodes
ready, put, fill, clear, round_fill, glyph
N3dsConnectionListener Source principale, 10 méthodes
accept, create_instance, get_instance, destroy_instance, connection_terminated, connection_log_message
N3dsRendererDualScreenMagnify Source principale, 4 méthodes
write_px_to_framebuffer, set_perf_decode_ticks, set_crop_region, accept
N3dsInput Source principale, 9 méthodes
accept, n3dsinput_handle_event, force_touchscreen_menu, _add_gamepad, _remove_gamepad, _n3ds_to_li_buttons
N3dsRendererNormal Source principale, 3 méthodes
write_px_to_framebuffer, set_perf_decode_ticks, set_bottom_screen
N3dsRendererBottom Source principale, 2 méthodes
write_px_to_framebuffer, write_px_to_framebuffer_raw
N3dsRendererDualScreenMirror Source principale, 2 méthodes
write_px_to_framebuffer, set_perf_decode_ticks
TouchHandlerBase Source principale, 8 méthodes
handle_touch_down, handle_touch_up, handle_touch_hold, captures_gamepad_input, handle_navigation, _handle_touch_down
MessageDispatcher Source principale, 7 méthodes
get_instance, subscribe, unsubscribe, post_immediate, post, dispatch_all

7.8. Intégrations externes

Clients HTTP

libcurl

7.9. Stack et dépendances

C/C++ (CMake) CMakeLists.txt 8 à l’exécution

CMake ≥ 3.6

Ouvrir le manifeste

Native (Make) Makefile 21 à l’exécution

DEVKITARM

Ouvrir le manifeste

C/C++ (CMake) libgamestream/CMakeLists.txt 5 à l’exécution

Ouvrir le manifeste

Dépendances externes

13 paquets déclarés (13 à l’exécution, 0 pour le développement) dans CMakeLists.txt, Makefile, libgamestream/CMakeLists.txt.

Tableau des paquets 13
Dépendances externes
PaquetVersionUsageRôleRegistre
ALSA—exécution—C/C++ (CMake)
Opus—exécution—C/C++ (CMake)
Broadcom—exécution—C/C++ (CMake)
Freescale—exécution—C/C++ (CMake)
Amlogic—exécution—C/C++ (CMake)
Rockchip—exécution—C/C++ (CMake)
PkgConfig—exécution—C/C++ (CMake)
MMAL—exécution—C/C++ (CMake)
LibUUID—exécution—C/C++ (CMake)
Threads—exécution—C/C++ (CMake)
CURL—exécution—C/C++ (CMake)
OpenSSL—exécution—C/C++ (CMake)
EXPAT—exécution—C/C++ (CMake)

7.10. Pipeline CI/CD

2 workflows GitHub Actions, 3 tâches. Chaque boîte est une tâche ; les boîtes à double bord publient ou déploient, et les flèches suivent les dépendances needs.

Mermaid Déroulement du pipeline
flowchart LR
  subgraph wf0["CI"]
    direction LR
    wf0_foundation_tests["Foundation tests<br/>ubuntu-latest"]
    wf0_build_cia[["Build CIA and 3DSX<br/>ubuntu-latest"]]
  end
  subgraph wf1["Release"]
    direction LR
    wf1_release[["Build and publish release<br/>ubuntu-latest"]]
  end
  t0(["lancement manuel · push · demande de fusion"])
  t1(["lancement manuel · push"])
  d0[("Versions GitHub")]
  t0 --> wf0_foundation_tests
  wf0_foundation_tests --> wf0_build_cia
  t1 --> wf1_release
  wf1_release -.-> d0
Workflows, déclencheurs, tâches et cibles
WorkflowDéclencheursTâchesPublie vers
CI
.github/workflows/build-cia.yml
lancement manuel, push, demande de fusion
  • Foundation tests ubuntu-latest
    Checkout repository · Check whitespace errors · Build host smoke tests · Run host smoke tests
  • Build CIA and 3DSX ← foundation-tests ubuntu-latest
    Checkout repository · Verify submodules · Build toolchain image · Build Moonlight for 3DS · Verify release artifacts · Upload artifacts
—
Release
.github/workflows/release.yml
lancement manuel, push
  • Build and publish release ubuntu-latest
    Checkout repository · Run foundation tests · Build toolchain image · Build Moonlight for 3DS · Verify release artifacts · Publish GitHub release
Versions GitHub

7.11. Déploiement

Mermaid Schéma de déploiement
flowchart LR
  repo[("Dépôt GitHub")]
  ci[["GitHub Actions<br/>2 workflows"]]
  image["Image Docker<br/>FROM devkitpro/devkitarm:latest"]
  pub_GitHub_Releases[("Versions GitHub")]
  repo -->|"push ou demande de fusion"| ci
  ci -->|"docker build"| image
  ci -->|"publie"| pub_GitHub_Releases
UML Déploiement
Déploiement

Le nœud extérieur est l’endroit où le code s’exécute. Chaque image de base pointe vers ce qu’elle construit, les flèches pleines mènent aux bases de données et les pointillées aux services externes. Rendu avec uml-mcp.

Source PlantUML
@startuml
skinparam backgroundColor transparent
skinparam shadowing false
skinparam roundCorner 10
skinparam defaultFontName Arial
skinparam defaultFontSize 13
skinparam ArrowColor #4e6070
skinparam ArrowFontColor #3d4f5f
skinparam titleFontSize 14
skinparam actorBorderColor #006a62
skinparam actorBackgroundColor #e9f3f4
skinparam usecaseBorderColor #006a62
skinparam usecaseBackgroundColor #e9f3f4
skinparam componentBorderColor #006a62
skinparam componentBackgroundColor #e9f3f4
skinparam interfaceBorderColor #006a62
skinparam interfaceBackgroundColor #ffffff
skinparam nodeBorderColor #4e6070
skinparam nodeBackgroundColor #f4f8fb
skinparam databaseBorderColor #006a62
skinparam databaseBackgroundColor #ffffff
skinparam cloudBorderColor #4e6070
skinparam cloudBackgroundColor #f0f5fa
skinparam artifactBorderColor #006a62
skinparam artifactBackgroundColor #ffffff
skinparam rectangleBorderColor #b0c2d3
skinparam activityBorderColor #006a62
skinparam activityBackgroundColor #e9f3f4
skinparam partitionBorderColor #b0c2d3
skinparam stereotypeCBackgroundColor #ffffff
node "Image Docker" as H {
  artifact "Artemis-N3DS" as APP
}
artifact "FROM devkitpro/devkitarm:latest" as IMG0
IMG0 ..> APP : construit
cloud "Pile réseau console (libnx/li…" as E0
APP ..> E0
@enduml

Où il s’exécute

Publié vers

Images Docker de base

devkitpro/devkitarm:latest

7.12. Sécurité

Contrôles

7.13. Tests automatisés

Fichiers de test
1
Fichiers source
123
Tests unitaires
1

Aucun rapport chiffré de couverture dans les sources analysées.

Où sont les tests

tests 1

Rien trouvé pour: Interface publique, Base de données, Supervision.

8. Déploiement et exploitation

Les ports, le stockage et les relations de démarrage ci-dessous viennent de la configuration du dépôt. depends_on indique l’ordre de démarrage, pas la disponibilité du service.

9. Types et structure des fichiers

77 types déclarés, dont 12 dans l’aperçu des relations de base.

Diagramme des types
classDiagram
direction TB
class tc0387bd4c68b["SelectedHost"] {
  <<struct>>
}
class t72fa5c6e15be["RemoteApp"] {
  <<struct>>
}
class tf7c6d6aec7da["InputLoopContext"] {
  <<struct>>
}
class ta7f589e4be09["VideoDecoderBase"] {
  accept()
  _accept_touch_state_changed()
  _accept_keyboard_state_changed()
}
class tb2f58dc75feb["MockVideoDecoder"] {
}
class t391f53097446["SoftVideoDecoder"] {
  submit_decode_unit()
  _write_yuv_to_framebuffer()
}
class t4ad2ea8a811e["MvdDecoder"] {
  submit_decode_unit()
  _decode()
}
class t891d7e467987["_SERVER_DATA"] {
  <<struct>>
}
class ta59617f1a5fa["cb_ctx"] {
  <<struct>>
}
class tcb0c88684e67["_HTTP_DATA"] {
  <<struct>>
}
class taa2e3cf225d0["_CERT_KEY_PAIR"] {
  <<struct>>
}
class t91f7677e0266["xml_query"] {
  <<struct>>
}
class b34b203f09b57["ISubscriber"] {
  <<unresolved_base>>
}
b34b203f09b57 <|-- ta7f589e4be09
ta7f589e4be09 <|-- tb2f58dc75feb
ta7f589e4be09 <|-- t391f53097446
ta7f589e4be09 <|-- t4ad2ea8a811e

Les bases non résolues restent identifiées; les signatures complètes ne sont pas reconstruites.

10. Référence

101 / 101 fichiers admissibles lus (174 dans l’arbre); 0 trop volumineux, 0 échec de lecture et 6 diagnostic de syntaxe.

Ce que couvre l’analyse

Les dossiers connus de dépendances et de compilation, les fichiers d’identifiants et les binaires sont exclus. La collecte couvre les README, les manifestes reconnus et les fichiers source pris en charge.

Les statistiques Linguist couvrent l’ensemble du dépôt et peuvent inclure d’autres langages.

12. Fichiers à lire 3

13. Glossaire

Dépôt

Les fichiers source, la configuration et l’historique versionné d’un projet.

README

Le document d’entrée du dépôt, qui présente généralement son rôle et son installation.

Dépendance

Une bibliothèque, un outil ou un service nécessaire à la compilation ou à l’exécution d’un composant.

Session

Un état conservé entre plusieurs requêtes, souvent pour suivre un utilisateur connecté. L’authentification et les permissions restent des vérifications distinctes.

Conteneur

Un environnement de processus isolé créé à partir d’une image. Les données persistantes nécessitent un stockage hors de son système de fichiers temporaire.

Port publié

Un port de l’hôte associé au port d’un service dans un conteneur. Sa publication peut rendre le service accessible hors du réseau des conteneurs.

Interface en ligne de commande

Une interface textuelle où les commandes et arguments choisissent les opérations. Les codes de retour permettent aux scripts de détecter un succès ou un échec.

Compilation

Les étapes qui transforment les sources et dépendances en programme exécutable ou en livrable distribuable.

GPU

Un processeur conçu pour les calculs parallèles, dont le rendu graphique et de nombreuses opérations numériques.

Décodeur vidéo

Un composant qui reconstruit des images à partir d’un flux vidéo compressé. Le décodage et l’affichage sont des étapes distinctes.

Backend

Une implémentation derrière une interface commune. Selon le contexte, il peut s’agir d’un service côté serveur ou d’une implémentation graphique, d’entrée ou de stockage.

14. Références

  1. antoinebou12. (2026, 5 novembre). Artemis-N3DS. [Software repository] github.com.
  2. antoinebou12. (2026, 5 novembre). Artemis-N3DS: README. [Repository documentation] github.com.
  3. antoinebou12. (2026, 5 novembre). src/n3ds_main.cpp. [Source file] github.com.
  4. antoinebou12. (2026, 5 novembre). src/hardware_capabilities.cpp. [Source file] github.com.
  5. antoinebou12. (2026, 5 novembre). src/video/video.hpp. [Source file] github.com.
  6. Boucher, A. (2026, 2 septembre). Streaming portable et homebrew — Artemis-Switch, moonlight-N3DS, sm64coopdx-switch. [Project article] antoineboucher.info.
  7. Boucher, A. (2026, 2 septembre). moonlight-N3DS. [Project article] antoineboucher.info.
  8. Boucher, A. (2026, 23 octobre). Artemis-N3DS : Le streaming sur un client à deux écrans. [Project article] antoineboucher.info.

Les sources sans date de publication indiquent la date de leur dernière vérification, le 5 novembre 2026. Les liens des fichiers conservent la révision inspectée lorsqu’elle est disponible.