loukai-app 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +558 -0
- package/bin/loukai.js +32 -0
- package/package.json +243 -0
- package/src/main/appState.js +250 -0
- package/src/main/audioEngine.js +478 -0
- package/src/main/creator/conversionService.js +503 -0
- package/src/main/creator/downloadManager.js +1128 -0
- package/src/main/creator/ffmpegService.js +487 -0
- package/src/main/creator/installLogger.js +51 -0
- package/src/main/creator/keyDetection.js +212 -0
- package/src/main/creator/llmService.js +370 -0
- package/src/main/creator/lrclibService.js +340 -0
- package/src/main/creator/python/crepe_runner.py +189 -0
- package/src/main/creator/python/demucs_runner.py +158 -0
- package/src/main/creator/python/whisper_runner.py +172 -0
- package/src/main/creator/pythonRunner.js +268 -0
- package/src/main/creator/stemBuilder.js +491 -0
- package/src/main/creator/systemChecker.js +474 -0
- package/src/main/handlers/appHandlers.js +45 -0
- package/src/main/handlers/audioHandlers.js +33 -0
- package/src/main/handlers/autotuneHandlers.js +28 -0
- package/src/main/handlers/canvasHandlers.js +84 -0
- package/src/main/handlers/creatorHandlers.js +159 -0
- package/src/main/handlers/editorHandlers.js +98 -0
- package/src/main/handlers/effectsHandlers.js +100 -0
- package/src/main/handlers/fileHandlers.js +45 -0
- package/src/main/handlers/index.js +78 -0
- package/src/main/handlers/libraryHandlers.js +96 -0
- package/src/main/handlers/mixerHandlers.js +64 -0
- package/src/main/handlers/playerHandlers.js +39 -0
- package/src/main/handlers/preferencesHandlers.js +46 -0
- package/src/main/handlers/queueHandlers.js +81 -0
- package/src/main/handlers/rendererHandlers.js +63 -0
- package/src/main/handlers/settingsHandlers.js +42 -0
- package/src/main/handlers/webServerHandlers.js +105 -0
- package/src/main/main.js +2351 -0
- package/src/main/preload.js +252 -0
- package/src/main/settingsManager.js +139 -0
- package/src/main/statePersistence.js +193 -0
- package/src/main/utils/pathValidator.js +112 -0
- package/src/main/webServer.js +2535 -0
- package/src/native/autotune.js +417 -0
- package/src/renderer/adapters/ElectronBridge.js +677 -0
- package/src/renderer/canvas.html +80 -0
- package/src/renderer/components/App.jsx +303 -0
- package/src/renderer/components/AppRoot.jsx +37 -0
- package/src/renderer/components/AudioDeviceSettings.jsx +145 -0
- package/src/renderer/components/EffectsPanelWrapper.jsx +267 -0
- package/src/renderer/components/MixerTab.jsx +233 -0
- package/src/renderer/components/MixerTabWrapper.jsx +31 -0
- package/src/renderer/components/PortalSelect.jsx +239 -0
- package/src/renderer/components/QueueTab.jsx +116 -0
- package/src/renderer/components/RequestsListWrapper.jsx +78 -0
- package/src/renderer/components/ServerTab.jsx +472 -0
- package/src/renderer/components/SongInfoBarWrapper.jsx +77 -0
- package/src/renderer/components/StatusBar.jsx +92 -0
- package/src/renderer/components/TabNavigation.jsx +77 -0
- package/src/renderer/components/TransportControlsWrapper.jsx +69 -0
- package/src/renderer/components/creator/CreateTab.jsx +1236 -0
- package/src/renderer/dist/assets/kaiPlayer-CoMx__a_.js +2 -0
- package/src/renderer/dist/assets/kaiPlayer-CoMx__a_.js.map +1 -0
- package/src/renderer/dist/assets/microphoneEngine-BaCUhhQc.js +2 -0
- package/src/renderer/dist/assets/microphoneEngine-BaCUhhQc.js.map +1 -0
- package/src/renderer/dist/assets/player-DVrqp7N5.js +3 -0
- package/src/renderer/dist/assets/player-DVrqp7N5.js.map +1 -0
- package/src/renderer/dist/assets/songLoaders-BaTgGib4.js +2 -0
- package/src/renderer/dist/assets/songLoaders-BaTgGib4.js.map +1 -0
- package/src/renderer/dist/assets/webrtcManager-BhCHWceK.js +2 -0
- package/src/renderer/dist/assets/webrtcManager-BhCHWceK.js.map +1 -0
- package/src/renderer/dist/js/autoTuneWorklet.js +224 -0
- package/src/renderer/dist/js/micPitchDetectorWorklet.js +137 -0
- package/src/renderer/dist/js/musicAnalysisWorklet.js +216 -0
- package/src/renderer/dist/js/phaseVocoderWorklet.js +341 -0
- package/src/renderer/dist/js/soundtouch-worklet.js +1395 -0
- package/src/renderer/dist/renderer.css +1 -0
- package/src/renderer/dist/renderer.js +62 -0
- package/src/renderer/dist/renderer.js.map +1 -0
- package/src/renderer/dist/renderer.woff2 +0 -0
- package/src/renderer/hooks/useKeyboardShortcuts.js +154 -0
- package/src/renderer/index.html +24 -0
- package/src/renderer/index.html.backup +372 -0
- package/src/renderer/js/PlayerInterface.js +267 -0
- package/src/renderer/js/autoTuneWorklet.js +224 -0
- package/src/renderer/js/butterchurnVerify.js +46 -0
- package/src/renderer/js/canvas-app.js +114 -0
- package/src/renderer/js/cdgPlayer.js +685 -0
- package/src/renderer/js/kaiPlayer.js +1200 -0
- package/src/renderer/js/karaokeRenderer.js +3392 -0
- package/src/renderer/js/micPitchDetectorWorklet.js +137 -0
- package/src/renderer/js/microphoneEngine.js +656 -0
- package/src/renderer/js/musicAnalysisWorklet.js +216 -0
- package/src/renderer/js/phaseVocoderWorklet.js +341 -0
- package/src/renderer/js/player.js +232 -0
- package/src/renderer/js/referencePitchTracker.js +130 -0
- package/src/renderer/js/songLoaders.js +334 -0
- package/src/renderer/js/soundtouch-worklet.js +1395 -0
- package/src/renderer/js/webrtcManager.js +511 -0
- package/src/renderer/lib/butterchurn.min.js +6739 -0
- package/src/renderer/lib/butterchurnPresets.min.js +1 -0
- package/src/renderer/lib/cdgraphics-wrapper.js +16 -0
- package/src/renderer/lib/cdgraphics.js +299 -0
- package/src/renderer/public/js/autoTuneWorklet.js +224 -0
- package/src/renderer/public/js/micPitchDetectorWorklet.js +137 -0
- package/src/renderer/public/js/musicAnalysisWorklet.js +216 -0
- package/src/renderer/public/js/phaseVocoderWorklet.js +341 -0
- package/src/renderer/public/js/soundtouch-worklet.js +1395 -0
- package/src/renderer/react-entry.jsx +44 -0
- package/src/renderer/styles/tailwind.css +106 -0
- package/src/renderer/utils/qrCodeGenerator.js +98 -0
- package/src/renderer/vite.config.js +31 -0
- package/src/shared/adapters/BridgeInterface.js +195 -0
- package/src/shared/components/EffectsPanel.jsx +177 -0
- package/src/shared/components/LibraryPanel.jsx +701 -0
- package/src/shared/components/LineDetailCanvas.jsx +167 -0
- package/src/shared/components/LyricLine.jsx +505 -0
- package/src/shared/components/LyricRejection.jsx +84 -0
- package/src/shared/components/LyricSuggestion.jsx +80 -0
- package/src/shared/components/LyricsEditorCanvas.jsx +271 -0
- package/src/shared/components/MixerPanel.jsx +94 -0
- package/src/shared/components/PlayerControls.jsx +206 -0
- package/src/shared/components/PortalSelect.jsx +239 -0
- package/src/shared/components/QueueList.jsx +365 -0
- package/src/shared/components/QuickSearch.jsx +126 -0
- package/src/shared/components/RequestsList.jsx +121 -0
- package/src/shared/components/SongEditor.jsx +1362 -0
- package/src/shared/components/SongInfoBar.jsx +81 -0
- package/src/shared/components/ThemeToggle.jsx +106 -0
- package/src/shared/components/Toast.jsx +30 -0
- package/src/shared/components/VisualizationSettings.jsx +243 -0
- package/src/shared/constants.js +95 -0
- package/src/shared/context/BridgeContext.jsx +32 -0
- package/src/shared/contexts/AudioContext.jsx +37 -0
- package/src/shared/contexts/PlayerContext.jsx +66 -0
- package/src/shared/contexts/SettingsContext.jsx +50 -0
- package/src/shared/defaults.js +158 -0
- package/src/shared/formatUtils.js +59 -0
- package/src/shared/formatUtils.test.js +207 -0
- package/src/shared/hooks/useAppState.js +97 -0
- package/src/shared/hooks/useAudioEngine.js +264 -0
- package/src/shared/hooks/usePlayer.js +89 -0
- package/src/shared/hooks/useSettingsPersistence.js +74 -0
- package/src/shared/hooks/useWebRTC.js +118 -0
- package/src/shared/ipcContracts.js +299 -0
- package/src/shared/package.json +3 -0
- package/src/shared/services/creatorService.js +373 -0
- package/src/shared/services/creatorService.test.js +413 -0
- package/src/shared/services/editorService.js +213 -0
- package/src/shared/services/editorService.test.js +219 -0
- package/src/shared/services/effectsService.js +271 -0
- package/src/shared/services/effectsService.test.js +418 -0
- package/src/shared/services/libraryService.js +438 -0
- package/src/shared/services/libraryService.test.js +474 -0
- package/src/shared/services/mixerService.js +172 -0
- package/src/shared/services/mixerService.test.js +399 -0
- package/src/shared/services/playerService.js +221 -0
- package/src/shared/services/playerService.test.js +357 -0
- package/src/shared/services/preferencesService.js +219 -0
- package/src/shared/services/queueService.js +226 -0
- package/src/shared/services/queueService.test.js +430 -0
- package/src/shared/services/requestsService.js +155 -0
- package/src/shared/services/requestsService.test.js +362 -0
- package/src/shared/services/serverSettingsService.js +151 -0
- package/src/shared/services/settingsService.js +257 -0
- package/src/shared/services/settingsService.test.js +295 -0
- package/src/shared/state/StateManager.js +263 -0
- package/src/shared/utils/audio.js +42 -0
- package/src/shared/utils/format.js +32 -0
- package/src/shared/utils/lyricsUtils.js +162 -0
- package/src/test/setup.js +40 -0
- package/src/utils/cdgLoader.js +180 -0
- package/src/utils/m4aLoader.js +333 -0
- package/src/web/App.jsx +578 -0
- package/src/web/adapters/WebBridge.js +428 -0
- package/src/web/components/PlayerSettingsPanel.jsx +231 -0
- package/src/web/components/SongSearch.jsx +180 -0
- package/src/web/dist/assets/index-0H-RnRrV.js +51 -0
- package/src/web/dist/assets/index-0H-RnRrV.js.map +1 -0
- package/src/web/dist/assets/index-DYW2zB0u.css +1 -0
- package/src/web/dist/index.html +15 -0
- package/src/web/index.html +14 -0
- package/src/web/main.jsx +10 -0
- package/src/web/package-lock.json +1765 -0
- package/src/web/pages/SongRequestPage.jsx +619 -0
- package/src/web/styles/tailwind.css +68 -0
- package/src/web/vite.config.js +27 -0
- package/static/fonts/material-icons.woff2 +0 -0
- package/static/images/butterchurn-screenshots/Aderrasi - Potion of Spirits.png +0 -0
- package/static/images/butterchurn-screenshots/Aderrasi - Songflower _Moss Posy_.png +0 -0
- package/static/images/butterchurn-screenshots/Aderrasi - Storm of the Eye _Thunder_ - mash0000 - quasi pseudo meta concentrics.png +0 -0
- package/static/images/butterchurn-screenshots/Aderrasi _ Geiss - Airhandler _Kali Mix_ - Canvas Mix.png +0 -0
- package/static/images/butterchurn-screenshots/An AdamFX n Martin Infusion 2 flexi - Why The Sky Looks Diffrent Today - AdamFx n Martin Infusion - Tack Tile Disfunction B.png +0 -0
- package/static/images/butterchurn-screenshots/Cope - The Neverending Explosion of Red Liquid Fire.png +0 -0
- proton lights __Krash_s beat code_ _Phat_remix02b.png +0 -0
- package/static/images/butterchurn-screenshots/Eo_S_ _ Phat - cubetrace - v2.png +0 -0
- package/static/images/butterchurn-screenshots/Eo_S_ _ Zylot - skylight _Stained Glass Majesty mix_.png +0 -0
- package/static/images/butterchurn-screenshots/Flexi - alien fish pond.png +0 -0
- package/static/images/butterchurn-screenshots/Flexi - area 51.png +0 -0
- package/static/images/butterchurn-screenshots/Flexi - infused with the spiral.png +0 -0
- package/static/images/butterchurn-screenshots/Flexi - mindblob _shiny mix_.png +0 -0
- package/static/images/butterchurn-screenshots/Flexi - mindblob mix.png +0 -0
- package/static/images/butterchurn-screenshots/Flexi - predator-prey-spirals.png +0 -0
- package/static/images/butterchurn-screenshots/Flexi - smashing fractals _acid etching mix_.png +0 -0
- package/static/images/butterchurn-screenshots/Flexi - truly soft piece of software - this is generic texturing _Jelly_ .png +0 -0
- package/static/images/butterchurn-screenshots/Flexi _ Martin - astral projection.png +0 -0
- package/static/images/butterchurn-screenshots/Flexi _ Martin - cascading decay swing.png +0 -0
- package/static/images/butterchurn-screenshots/Flexi _ amandio c - piercing 05 - Kopie _2_ - Kopie.png +0 -0
- package/static/images/butterchurn-screenshots/Flexi _ stahlregen - jelly showoff parade.png +0 -0
- package/static/images/butterchurn-screenshots/Flexi_ fishbrain_ Geiss _ Martin - tokamak witchery.png +0 -0
- package/static/images/butterchurn-screenshots/Flexi_ martin _ geiss - dedicated to the sherwin maxawow.png +0 -0
- package/static/images/butterchurn-screenshots/Fumbling_Foo _ Flexi_ Martin_ Orb_ Unchained - Star Nova v7b.png +0 -0
- package/static/images/butterchurn-screenshots/Geiss - Cauldron - painterly 2 _saturation remix_.png +0 -0
- package/static/images/butterchurn-screenshots/Geiss - Reaction Diffusion 2.png +0 -0
- package/static/images/butterchurn-screenshots/Geiss - Spiral Artifact.png +0 -0
- package/static/images/butterchurn-screenshots/Geiss - Thumb Drum.png +0 -0
- package/static/images/butterchurn-screenshots/Geiss _ Flexi _ Martin - disconnected.png +0 -0
- package/static/images/butterchurn-screenshots/Geiss_ Flexi _ Stahlregen - Thumbdrum Tokamak _crossfiring aftermath jelly mashup_.png +0 -0
- package/static/images/butterchurn-screenshots/Goody - The Wild Vort.png +0 -0
- package/static/images/butterchurn-screenshots/Idiot - Star Of Annon.png +0 -0
- package/static/images/butterchurn-screenshots/Krash _ Illusion - Spiral Movement.png +0 -0
- package/static/images/butterchurn-screenshots/Martin - QBikal - Surface Turbulence IIb.png +0 -0
- package/static/images/butterchurn-screenshots/Martin - acid wiring.png +0 -0
- package/static/images/butterchurn-screenshots/Martin - charisma.png +0 -0
- package/static/images/butterchurn-screenshots/Martin - liquid arrows.png +0 -0
- package/static/images/butterchurn-screenshots/Milk Artist At our Best - FED - SlowFast Ft AdamFX n Martin - HD CosmoFX.png +0 -0
- package/static/images/butterchurn-screenshots/ORB - Waaa.png +0 -0
- package/static/images/butterchurn-screenshots/Phat_fiShbRaiN_Eo_S_Mandala_Chasers_remix.png +0 -0
- package/static/images/butterchurn-screenshots/Rovastar - Oozing Resistance.png +0 -0
- package/static/images/butterchurn-screenshots/Rovastar _ Loadus _ Geiss - FractalDrop _Triple Mix_.png +0 -0
- package/static/images/butterchurn-screenshots/TonyMilkdrop - Leonardo Da Vinci_s Balloon _Flexi - merry-go-round _ techstyle_.png +0 -0
- package/static/images/butterchurn-screenshots/TonyMilkdrop - Magellan_s Nebula _Flexi - you enter first _ multiverse_.png +0 -0
- package/static/images/butterchurn-screenshots/Unchained - Rewop.png +0 -0
- package/static/images/butterchurn-screenshots/Unchained - Unified Drag 2.png +0 -0
- package/static/images/butterchurn-screenshots/Unchained _ Rovastar - Wormhole Pillars _Hall of Shadows mix_.png +0 -0
- package/static/images/butterchurn-screenshots/Zylot - Paint Spill _Music Reactive Paint Mix_.png +0 -0
- package/static/images/butterchurn-screenshots/Zylot - Star Ornament.png +0 -0
- package/static/images/butterchurn-screenshots/Zylot - True Visionary _Final Mix_.png +0 -0
- package/static/images/butterchurn-screenshots/_Aderrasi - Wanderer in Curved Space - mash0000 - faclempt kibitzing meshuggana schmaltz _Geiss color mix_.png +0 -0
- package/static/images/butterchurn-screenshots/_Geiss - Artifact 01.png +0 -0
- package/static/images/butterchurn-screenshots/_Geiss - Desert Rose 2.png +0 -0
- package/static/images/butterchurn-screenshots/_Geiss - untitled.png +0 -0
- package/static/images/butterchurn-screenshots/_Mig_049.png +0 -0
- package/static/images/butterchurn-screenshots/_Mig_085.png +0 -0
- package/static/images/butterchurn-screenshots/_Rovastar _ Geiss - Hurricane Nightmare _Posterize Mix_.png +0 -0
- package/static/images/butterchurn-screenshots/___ Royal - Mashup _197_.png +0 -0
- package/static/images/butterchurn-screenshots/___ Royal - Mashup _220_.png +0 -0
- package/static/images/butterchurn-screenshots/___ Royal - Mashup _431_.png +0 -0
- package/static/images/butterchurn-screenshots/cope _ martin - mother-of-pearl.png +0 -0
- package/static/images/butterchurn-screenshots/fiShbRaiN _ Flexi - witchcraft 2_0.png +0 -0
- package/static/images/butterchurn-screenshots/flexi - bouncing balls _double mindblob neon mix_.png +0 -0
- package/static/images/butterchurn-screenshots/flexi - mom_ why the sky looks different today.png +0 -0
- package/static/images/butterchurn-screenshots/flexi - patternton_ district of media_ capitol of the united abstractions of fractopia.png +0 -0
- package/static/images/butterchurn-screenshots/flexi - swing out on the spiral.png +0 -0
- package/static/images/butterchurn-screenshots/flexi - what is the matrix.png +0 -0
- package/static/images/butterchurn-screenshots/flexi _ amandio c - organic _random mashup_.png +0 -0
- package/static/images/butterchurn-screenshots/flexi _ amandio c - organic12-3d-2_milk.png +0 -0
- package/static/images/butterchurn-screenshots/flexi _ fishbrain - neon mindblob grafitti.png +0 -0
- package/static/images/butterchurn-screenshots/flexi _ geiss - pogo cubes vs_ tokamak vs_ game of life _stahls jelly 4_5 finish_.png +0 -0
- package/static/images/butterchurn-screenshots/high-altitude basket unraveling - singh grooves nitrogen argon nz_.png +0 -0
- package/static/images/butterchurn-screenshots/martin - The Bridge of Khazad-Dum.png +0 -0
- package/static/images/butterchurn-screenshots/martin - angel flight.png +0 -0
- package/static/images/butterchurn-screenshots/martin - another kind of groove.png +0 -0
- package/static/images/butterchurn-screenshots/martin - bombyx mori.png +0 -0
- package/static/images/butterchurn-screenshots/martin - castle in the air.png +0 -0
- package/static/images/butterchurn-screenshots/martin - chain breaker.png +0 -0
- package/static/images/butterchurn-screenshots/martin - disco mix 4.png +0 -0
- package/static/images/butterchurn-screenshots/martin - extreme heat.png +0 -0
- package/static/images/butterchurn-screenshots/martin - frosty caves 2.png +0 -0
- package/static/images/butterchurn-screenshots/martin - fruit machine.png +0 -0
- package/static/images/butterchurn-screenshots/martin - ghost city.png +0 -0
- package/static/images/butterchurn-screenshots/martin - glass corridor.png +0 -0
- package/static/images/butterchurn-screenshots/martin - infinity _2010 update_.png +0 -0
- package/static/images/butterchurn-screenshots/martin - mandelbox explorer - high speed demo version.png +0 -0
- package/static/images/butterchurn-screenshots/martin - mucus cervix.png +0 -0
- package/static/images/butterchurn-screenshots/martin - reflections on black tiles.png +0 -0
- package/static/images/butterchurn-screenshots/martin - stormy sea _2010 update_.png +0 -0
- package/static/images/butterchurn-screenshots/martin - witchcraft reloaded.png +0 -0
- package/static/images/butterchurn-screenshots/martin _ flexi - diamond cutter _prismaticvortex_com_ - camille - i wish i wish i wish i was constrained.png +0 -0
- package/static/images/butterchurn-screenshots/martin _shadow harlequins shape code_ - fata morgana.png +0 -0
- package/static/images/butterchurn-screenshots/martin_ flexi_ fishbrain _ sto - enterstate _random mashup_.png +0 -0
- package/static/images/butterchurn-screenshots/sawtooth grin roam.png +0 -0
- package/static/images/butterchurn-screenshots/shifter - dark tides bdrv mix 2.png +0 -0
- package/static/images/butterchurn-screenshots/suksma - Rovastar - Sunflower Passion _Enlightment Mix__Phat_edit _ flexi und martin shaders - circumflex in character classes in regular expression.png +0 -0
- package/static/images/butterchurn-screenshots/suksma - heretical crosscut playpen.png +0 -0
- package/static/images/butterchurn-screenshots/suksma - uninitialized variabowl _hydroponic chronic_.png +0 -0
- package/static/images/butterchurn-screenshots/suksma - vector exp 1 - couldn_t not.png +0 -0
- package/static/images/butterchurn-screenshots/yin - 191 - Temporal singularities.png +0 -0
- package/static/images/logo-512.png +0 -0
- package/static/images/logo.png +0 -0
- package/static/loukai-logo.png +0 -0
- package/static/screenshot-generator.html +610 -0
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useAudioEngine - Audio engine initialization hook
|
|
3
|
+
*
|
|
4
|
+
* Initializes KAIPlayer and PlayerController
|
|
5
|
+
* Handles song loading events from main process
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { useEffect } from 'react';
|
|
9
|
+
import { useAudio } from '../contexts/AudioContext.jsx';
|
|
10
|
+
|
|
11
|
+
export function useAudioEngine() {
|
|
12
|
+
const { kaiPlayer, player, setKaiPlayer, setPlayer } = useAudio();
|
|
13
|
+
|
|
14
|
+
// Initialize audio engine
|
|
15
|
+
useEffect(() => {
|
|
16
|
+
let mounted = true;
|
|
17
|
+
|
|
18
|
+
async function initializeAudio() {
|
|
19
|
+
try {
|
|
20
|
+
// Dynamically import to avoid circular deps
|
|
21
|
+
const { KAIPlayer } = await import('../../renderer/js/kaiPlayer.js');
|
|
22
|
+
const { PlayerController } = await import('../../renderer/js/player.js');
|
|
23
|
+
|
|
24
|
+
const audioEngine = new KAIPlayer();
|
|
25
|
+
await audioEngine.initialize();
|
|
26
|
+
|
|
27
|
+
if (!mounted) return;
|
|
28
|
+
|
|
29
|
+
const playerController = new PlayerController(audioEngine);
|
|
30
|
+
|
|
31
|
+
setKaiPlayer(audioEngine);
|
|
32
|
+
setPlayer(playerController);
|
|
33
|
+
|
|
34
|
+
// Expose player globally for legacy code that needs direct access
|
|
35
|
+
window.app = window.app || {};
|
|
36
|
+
window.app.player = playerController;
|
|
37
|
+
|
|
38
|
+
console.log('✅ Audio engine initialized');
|
|
39
|
+
} catch (error) {
|
|
40
|
+
console.error('❌ Failed to initialize audio engine:', error);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (!kaiPlayer) {
|
|
45
|
+
initializeAudio();
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return () => {
|
|
49
|
+
mounted = false;
|
|
50
|
+
};
|
|
51
|
+
}, [kaiPlayer, setKaiPlayer, setPlayer]);
|
|
52
|
+
|
|
53
|
+
// Handle mixer changes from main process (web admin or other sources)
|
|
54
|
+
useEffect(() => {
|
|
55
|
+
if (!kaiPlayer || !window.kaiAPI?.mixer) return;
|
|
56
|
+
|
|
57
|
+
const handleSetMasterGain = (event, { bus, gainDb }) => {
|
|
58
|
+
console.log(`🎚️ Received mixer:setMasterGain from main: ${bus} = ${gainDb}dB`);
|
|
59
|
+
kaiPlayer.setMasterGain(bus, gainDb);
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const handleToggleMasterMute = (event, { bus, muted }) => {
|
|
63
|
+
// IMPORTANT: Despite the event name being "toggle", the event includes the explicit muted value
|
|
64
|
+
// Don't call toggleMasterMute() as that would toggle again - use setMasterMute()
|
|
65
|
+
console.log(`🎚️ Received mixer:toggleMasterMute from main: ${bus} = ${muted}`);
|
|
66
|
+
kaiPlayer.setMasterMute(bus, muted);
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const handleSetMasterMute = (event, { bus, muted }) => {
|
|
70
|
+
console.log(`🎚️ Received mixer:setMasterMute from main: ${bus} = ${muted}`);
|
|
71
|
+
kaiPlayer.setMasterMute(bus, muted);
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
window.kaiAPI.mixer.onSetMasterGain(handleSetMasterGain);
|
|
75
|
+
window.kaiAPI.mixer.onToggleMasterMute(handleToggleMasterMute);
|
|
76
|
+
window.kaiAPI.mixer.onSetMasterMute(handleSetMasterMute);
|
|
77
|
+
|
|
78
|
+
console.log('✅ Mixer IPC listeners registered');
|
|
79
|
+
|
|
80
|
+
// Note: Cleanup would require preload.js to expose removeListener methods
|
|
81
|
+
// These are long-lived listeners so cleanup is not critical
|
|
82
|
+
return () => {
|
|
83
|
+
console.log('🧹 Mixer IPC listeners cleanup');
|
|
84
|
+
};
|
|
85
|
+
}, [kaiPlayer]);
|
|
86
|
+
|
|
87
|
+
// Handle song loading events
|
|
88
|
+
useEffect(() => {
|
|
89
|
+
if (!player || !kaiPlayer || !window.kaiAPI?.song) return;
|
|
90
|
+
|
|
91
|
+
// Create mutable app state object (needed by songLoaders)
|
|
92
|
+
const appState = {
|
|
93
|
+
player,
|
|
94
|
+
kaiPlayer,
|
|
95
|
+
currentSong: null,
|
|
96
|
+
_pendingMetadata: null,
|
|
97
|
+
randomEffectTimeout: null,
|
|
98
|
+
handleSongEnded: async () => {
|
|
99
|
+
// Song ended - reset position to 0 and pause to show title screen
|
|
100
|
+
if (player && player.currentPlayer) {
|
|
101
|
+
await player.currentPlayer.seek(0);
|
|
102
|
+
await player.pause();
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Trigger next song via IPC
|
|
106
|
+
if (window.kaiAPI?.player) {
|
|
107
|
+
await window.kaiAPI.player.next();
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
updateStatus: (msg) => console.log('📊', msg),
|
|
111
|
+
updateEffectDisplay: () => {}, // TODO: implement if needed
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
const handleSongLoaded = async (event, metadata) => {
|
|
115
|
+
console.log('🎵 Song loading:', metadata?.title || 'Unknown');
|
|
116
|
+
appState._pendingMetadata = metadata;
|
|
117
|
+
|
|
118
|
+
// Stop current playback
|
|
119
|
+
if (kaiPlayer) {
|
|
120
|
+
await kaiPlayer.pause();
|
|
121
|
+
}
|
|
122
|
+
if (player) {
|
|
123
|
+
await player.pause();
|
|
124
|
+
// Also stop CDG renderer if it's playing
|
|
125
|
+
if (player.cdgPlayer && player.cdgPlayer.isPlaying) {
|
|
126
|
+
player.cdgPlayer.pause();
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Notify PlayerController to load song metadata (lyrics, etc.)
|
|
131
|
+
if (player && player.onSongLoaded) {
|
|
132
|
+
player.onSongLoaded(metadata);
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
const handleSongData = async (event, songData) => {
|
|
137
|
+
console.log('🎵 Song data received:', songData.format, songData.originalFilePath);
|
|
138
|
+
|
|
139
|
+
// Check if this is the same song
|
|
140
|
+
const isSameSong =
|
|
141
|
+
appState.currentSong && appState.currentSong.originalFilePath === songData.originalFilePath;
|
|
142
|
+
|
|
143
|
+
appState.currentSong = songData;
|
|
144
|
+
|
|
145
|
+
// Reset play state when loading a new song
|
|
146
|
+
if (!isSameSong) {
|
|
147
|
+
if (kaiPlayer) {
|
|
148
|
+
await kaiPlayer.pause();
|
|
149
|
+
}
|
|
150
|
+
if (player?.cdgPlayer?.isPlaying) {
|
|
151
|
+
player.cdgPlayer.pause();
|
|
152
|
+
}
|
|
153
|
+
if (player?.currentPlayer?.isPlaying) {
|
|
154
|
+
await player.currentPlayer.pause();
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Use pending metadata if available
|
|
159
|
+
const metadata = appState._pendingMetadata || songData.metadata || {};
|
|
160
|
+
|
|
161
|
+
// Detect format: CDG or KAI
|
|
162
|
+
const isCDG = songData.format === 'cdg';
|
|
163
|
+
|
|
164
|
+
try {
|
|
165
|
+
// Load song using songLoaders
|
|
166
|
+
const { loadCDGSong, loadKAISong } = await import('../../renderer/js/songLoaders.js');
|
|
167
|
+
|
|
168
|
+
if (isCDG) {
|
|
169
|
+
await loadCDGSong(appState, songData, metadata);
|
|
170
|
+
} else {
|
|
171
|
+
await loadKAISong(appState, songData, metadata);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
console.log('✅ Song loaded successfully');
|
|
175
|
+
} catch (error) {
|
|
176
|
+
console.error('❌ Failed to load song:', error);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// Clear pending metadata
|
|
180
|
+
appState._pendingMetadata = null;
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
window.kaiAPI.song.onLoaded(handleSongLoaded);
|
|
184
|
+
window.kaiAPI.song.onData(handleSongData);
|
|
185
|
+
|
|
186
|
+
// Handle playback control events from main process (web admin commands)
|
|
187
|
+
const handleTogglePlayback = async () => {
|
|
188
|
+
console.log('🌐 Remote play/pause command');
|
|
189
|
+
if (!player) return;
|
|
190
|
+
|
|
191
|
+
if (player.isPlaying) {
|
|
192
|
+
await player.pause();
|
|
193
|
+
} else {
|
|
194
|
+
await player.play();
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
const handleRestart = async () => {
|
|
199
|
+
console.log('🌐 Remote restart command');
|
|
200
|
+
if (!player || !player.currentPlayer) return;
|
|
201
|
+
|
|
202
|
+
// Seek to 0 based on format
|
|
203
|
+
if (player.currentFormat === 'kai' && kaiPlayer) {
|
|
204
|
+
await kaiPlayer.seek(0);
|
|
205
|
+
} else if (player.currentFormat === 'cdg' && player.cdgPlayer) {
|
|
206
|
+
await player.cdgPlayer.seek(0);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
if (!player.isPlaying) {
|
|
210
|
+
await player.play();
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
const handleSetPosition = async (event, positionSec) => {
|
|
215
|
+
console.log('🌐 Remote seek command:', positionSec);
|
|
216
|
+
if (!player || !player.currentPlayer) return;
|
|
217
|
+
|
|
218
|
+
// Seek based on format
|
|
219
|
+
if (player.currentFormat === 'kai' && kaiPlayer) {
|
|
220
|
+
await kaiPlayer.seek(positionSec);
|
|
221
|
+
} else if (player.currentFormat === 'cdg' && player.cdgPlayer) {
|
|
222
|
+
await player.cdgPlayer.seek(positionSec);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
if (player.currentPlayer.reportStateChange) {
|
|
226
|
+
player.currentPlayer.reportStateChange();
|
|
227
|
+
}
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
window.kaiAPI.player.onTogglePlayback(handleTogglePlayback);
|
|
231
|
+
window.kaiAPI.player.onRestart(handleRestart);
|
|
232
|
+
window.kaiAPI.player.onSetPosition(handleSetPosition);
|
|
233
|
+
|
|
234
|
+
// Handle settings changes (from local UI or remote web admin)
|
|
235
|
+
const handleWaveformSettings = (event, settings) => {
|
|
236
|
+
console.log('🎨 Waveform settings changed:', settings);
|
|
237
|
+
if (player && player.applyWaveformSettings) {
|
|
238
|
+
player.applyWaveformSettings(settings);
|
|
239
|
+
}
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
if (window.kaiAPI.events) {
|
|
243
|
+
window.kaiAPI.events.on('waveform:settingsChanged', handleWaveformSettings);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
return () => {
|
|
247
|
+
window.kaiAPI.song.removeSongListener(handleSongLoaded);
|
|
248
|
+
window.kaiAPI.song.removeDataListener?.(handleSongData);
|
|
249
|
+
window.kaiAPI.player.removeTogglePlaybackListener(handleTogglePlayback);
|
|
250
|
+
window.kaiAPI.player.removeRestartListener(handleRestart);
|
|
251
|
+
window.kaiAPI.player.removeSetPositionListener(handleSetPosition);
|
|
252
|
+
|
|
253
|
+
if (window.kaiAPI.events) {
|
|
254
|
+
window.kaiAPI.events.off?.('waveform:settingsChanged', handleWaveformSettings);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
if (appState.randomEffectTimeout) {
|
|
258
|
+
clearTimeout(appState.randomEffectTimeout);
|
|
259
|
+
}
|
|
260
|
+
};
|
|
261
|
+
}, [player, kaiPlayer]);
|
|
262
|
+
|
|
263
|
+
return { kaiPlayer, player };
|
|
264
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* usePlayer - Playback control hook
|
|
3
|
+
*
|
|
4
|
+
* Directly controls audio engine in renderer process
|
|
5
|
+
* Only uses IPC for next song (queue management in main process)
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { usePlayerState } from '../contexts/PlayerContext.jsx';
|
|
9
|
+
import { useAudio } from '../contexts/AudioContext.jsx';
|
|
10
|
+
|
|
11
|
+
export function usePlayer() {
|
|
12
|
+
const { currentSong, isPlaying } = usePlayerState();
|
|
13
|
+
const { kaiPlayer, player } = useAudio();
|
|
14
|
+
|
|
15
|
+
const togglePlayback = async () => {
|
|
16
|
+
if (!currentSong || !player || !player.currentPlayer) return;
|
|
17
|
+
|
|
18
|
+
if (isPlaying) {
|
|
19
|
+
await player.pause();
|
|
20
|
+
} else {
|
|
21
|
+
await player.play();
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const play = async () => {
|
|
26
|
+
if (!player || !player.currentPlayer || isPlaying) return;
|
|
27
|
+
await player.play();
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const pause = async () => {
|
|
31
|
+
if (!player || !player.currentPlayer || !isPlaying) return;
|
|
32
|
+
await player.pause();
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const seek = async (positionSec) => {
|
|
36
|
+
if (!player || !player.currentPlayer) return;
|
|
37
|
+
|
|
38
|
+
// For KAI format, use kaiPlayer.seek()
|
|
39
|
+
if (player.currentFormat === 'kai' && kaiPlayer) {
|
|
40
|
+
await kaiPlayer.seek(positionSec);
|
|
41
|
+
}
|
|
42
|
+
// For CDG format, seek is handled differently
|
|
43
|
+
else if (player.currentFormat === 'cdg' && player.cdgPlayer) {
|
|
44
|
+
await player.cdgPlayer.seek(positionSec);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Report state change
|
|
48
|
+
if (player.currentPlayer.reportStateChange) {
|
|
49
|
+
player.currentPlayer.reportStateChange();
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const restart = async () => {
|
|
54
|
+
if (!player || !player.currentPlayer) return;
|
|
55
|
+
|
|
56
|
+
// Seek to 0
|
|
57
|
+
if (player.currentFormat === 'kai' && kaiPlayer) {
|
|
58
|
+
await kaiPlayer.seek(0);
|
|
59
|
+
} else if (player.currentFormat === 'cdg' && player.cdgPlayer) {
|
|
60
|
+
await player.cdgPlayer.seek(0);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Start playing if not already
|
|
64
|
+
if (!isPlaying) {
|
|
65
|
+
await player.currentPlayer.play();
|
|
66
|
+
player.isPlaying = true;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Report state change
|
|
70
|
+
if (player.currentPlayer.reportStateChange) {
|
|
71
|
+
player.currentPlayer.reportStateChange();
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
const next = async () => {
|
|
76
|
+
// Next song requires queue management in main process
|
|
77
|
+
if (!window.kaiAPI?.player) return;
|
|
78
|
+
await window.kaiAPI.player.next();
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
return {
|
|
82
|
+
togglePlayback,
|
|
83
|
+
play,
|
|
84
|
+
pause,
|
|
85
|
+
seek,
|
|
86
|
+
restart,
|
|
87
|
+
next,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useSettingsPersistence - Settings load/save via IPC
|
|
3
|
+
*
|
|
4
|
+
* Loads settings from storage and saves changes
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { useEffect, useRef } from 'react';
|
|
8
|
+
import { useSettings } from '../contexts/SettingsContext.jsx';
|
|
9
|
+
|
|
10
|
+
export function useSettingsPersistence() {
|
|
11
|
+
const {
|
|
12
|
+
devicePreferences,
|
|
13
|
+
waveformPreferences,
|
|
14
|
+
autoTunePreferences,
|
|
15
|
+
setDevicePreferences,
|
|
16
|
+
setWaveformPreferences,
|
|
17
|
+
setAutoTunePreferences,
|
|
18
|
+
} = useSettings();
|
|
19
|
+
|
|
20
|
+
// Track whether initial load has completed to prevent saving hardcoded defaults
|
|
21
|
+
const isLoadedRef = useRef(false);
|
|
22
|
+
|
|
23
|
+
// Load settings on mount
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
async function loadSettings() {
|
|
26
|
+
if (!window.kaiAPI?.settings) return;
|
|
27
|
+
|
|
28
|
+
try {
|
|
29
|
+
const devices = await window.kaiAPI.settings.get('devicePreferences', null);
|
|
30
|
+
if (devices) setDevicePreferences(devices);
|
|
31
|
+
|
|
32
|
+
const waveform = await window.kaiAPI.settings.get('waveformPreferences', null);
|
|
33
|
+
if (waveform) setWaveformPreferences(waveform);
|
|
34
|
+
|
|
35
|
+
const autotune = await window.kaiAPI.settings.get('autoTunePreferences', null);
|
|
36
|
+
if (autotune) setAutoTunePreferences(autotune);
|
|
37
|
+
|
|
38
|
+
isLoadedRef.current = true; // Mark as loaded to enable saving
|
|
39
|
+
} catch (error) {
|
|
40
|
+
console.error('Failed to load settings:', error);
|
|
41
|
+
isLoadedRef.current = true; // Enable saving even on error
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
loadSettings();
|
|
46
|
+
}, [setDevicePreferences, setWaveformPreferences, setAutoTunePreferences]);
|
|
47
|
+
|
|
48
|
+
// Save device preferences when changed (only after initial load)
|
|
49
|
+
useEffect(() => {
|
|
50
|
+
if (!window.kaiAPI?.settings || !isLoadedRef.current) return;
|
|
51
|
+
window.kaiAPI.settings.set('devicePreferences', devicePreferences);
|
|
52
|
+
}, [devicePreferences]);
|
|
53
|
+
|
|
54
|
+
// Save waveform preferences when changed (only after initial load)
|
|
55
|
+
useEffect(() => {
|
|
56
|
+
if (!window.kaiAPI?.settings || !isLoadedRef.current) return;
|
|
57
|
+
window.kaiAPI.settings.set('waveformPreferences', waveformPreferences);
|
|
58
|
+
}, [waveformPreferences]);
|
|
59
|
+
|
|
60
|
+
// Save autotune preferences when changed (only after initial load)
|
|
61
|
+
useEffect(() => {
|
|
62
|
+
if (!window.kaiAPI?.settings || !isLoadedRef.current) return;
|
|
63
|
+
window.kaiAPI.settings.set('autoTunePreferences', autoTunePreferences);
|
|
64
|
+
}, [autoTunePreferences]);
|
|
65
|
+
|
|
66
|
+
return {
|
|
67
|
+
devicePreferences,
|
|
68
|
+
waveformPreferences,
|
|
69
|
+
autoTunePreferences,
|
|
70
|
+
setDevicePreferences,
|
|
71
|
+
setWaveformPreferences,
|
|
72
|
+
setAutoTunePreferences,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useWebRTC - WebRTC manager wrapper
|
|
3
|
+
*
|
|
4
|
+
* Wraps webrtcManager for streaming functionality
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { useEffect, useRef } from 'react';
|
|
8
|
+
|
|
9
|
+
export function useWebRTC() {
|
|
10
|
+
const webrtcManagerRef = useRef(null);
|
|
11
|
+
|
|
12
|
+
useEffect(() => {
|
|
13
|
+
async function loadWebRTC() {
|
|
14
|
+
try {
|
|
15
|
+
const module = await import('../../renderer/js/webrtcManager.js');
|
|
16
|
+
webrtcManagerRef.current = module.default;
|
|
17
|
+
console.log('✅ WebRTC manager loaded');
|
|
18
|
+
|
|
19
|
+
// Setup IPC handlers for WebRTC commands from main process
|
|
20
|
+
if (window.kaiAPI?.events) {
|
|
21
|
+
setupIPCHandlers(webrtcManagerRef.current);
|
|
22
|
+
}
|
|
23
|
+
} catch (error) {
|
|
24
|
+
console.error('❌ Failed to load WebRTC manager:', error);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
loadWebRTC();
|
|
29
|
+
}, []);
|
|
30
|
+
|
|
31
|
+
// Setup IPC handlers for WebRTC commands
|
|
32
|
+
function setupIPCHandlers(manager) {
|
|
33
|
+
if (!window.kaiAPI?.events) return;
|
|
34
|
+
|
|
35
|
+
// Setup sender
|
|
36
|
+
window.kaiAPI.events.on('webrtc:setupSender', async () => {
|
|
37
|
+
const result = await manager.setupSender();
|
|
38
|
+
if (window.kaiAPI?.renderer) {
|
|
39
|
+
window.kaiAPI.renderer.sendWebRTCResponse('setupSender', result);
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
// Create offer
|
|
44
|
+
window.kaiAPI.events.on('webrtc:createOffer', async () => {
|
|
45
|
+
const result = await manager.createOffer();
|
|
46
|
+
if (window.kaiAPI?.renderer) {
|
|
47
|
+
window.kaiAPI.renderer.sendWebRTCResponse('createOffer', result);
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
// Set answer
|
|
52
|
+
window.kaiAPI.events.on('webrtc:setAnswer', async (event, answer) => {
|
|
53
|
+
const result = await manager.setAnswer(answer);
|
|
54
|
+
if (window.kaiAPI?.renderer) {
|
|
55
|
+
window.kaiAPI.renderer.sendWebRTCResponse('setAnswer', result);
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
// Get sender status
|
|
60
|
+
window.kaiAPI.events.on('webrtc:getSenderStatus', () => {
|
|
61
|
+
const result = manager.getSenderStatus();
|
|
62
|
+
if (window.kaiAPI?.renderer) {
|
|
63
|
+
window.kaiAPI.renderer.sendWebRTCResponse('getSenderStatus', result);
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
// Add ICE candidate
|
|
68
|
+
window.kaiAPI.events.on('webrtc:addICECandidate', async (event, candidate) => {
|
|
69
|
+
await manager.addICECandidate(candidate);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
// Cleanup sender
|
|
73
|
+
window.kaiAPI.events.on('webrtc:cleanupSender', async () => {
|
|
74
|
+
await manager.cleanupSender();
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
console.log('✅ Main window WebRTC IPC handlers registered');
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const setupSender = async () => {
|
|
81
|
+
if (!webrtcManagerRef.current) return null;
|
|
82
|
+
return await webrtcManagerRef.current.setupSender();
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const createOffer = async () => {
|
|
86
|
+
if (!webrtcManagerRef.current) return null;
|
|
87
|
+
return await webrtcManagerRef.current.createOffer();
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
const setAnswer = async (answer) => {
|
|
91
|
+
if (!webrtcManagerRef.current) return null;
|
|
92
|
+
return await webrtcManagerRef.current.setAnswer(answer);
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
const getSenderStatus = () => {
|
|
96
|
+
if (!webrtcManagerRef.current) return null;
|
|
97
|
+
return webrtcManagerRef.current.getSenderStatus();
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
const addICECandidate = async (candidate) => {
|
|
101
|
+
if (!webrtcManagerRef.current) return;
|
|
102
|
+
await webrtcManagerRef.current.addICECandidate(candidate);
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
const cleanupSender = async () => {
|
|
106
|
+
if (!webrtcManagerRef.current) return;
|
|
107
|
+
await webrtcManagerRef.current.cleanupSender();
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
return {
|
|
111
|
+
setupSender,
|
|
112
|
+
createOffer,
|
|
113
|
+
setAnswer,
|
|
114
|
+
getSenderStatus,
|
|
115
|
+
addICECandidate,
|
|
116
|
+
cleanupSender,
|
|
117
|
+
};
|
|
118
|
+
}
|