MarByteBeep / StageLinq

NodeJS library implementation to access information through the Denon StageLinq protocol
GNU General Public License v3.0
25 stars 2 forks source link

Crash when trying to connect to X1800 mixer or SC5000 players #1

Closed kkirjala closed 2 years ago

kkirjala commented 2 years ago

My setup consists of: 2x Denon DJ Prime SC5000 player (SW version 2.1.1) 1x Denon DJ Prime X1800 mixer (SW version 1.6) * NOTE: the UDP broadcast message below says the mixer SW version is 1.00, but when looking in the mixer menu (Utility->System->Info->Version), it says 1.6 which is at the time of writing the latest SW version for X1800.

StageLinq library crashes when this kind of setup is run. Steps to reproduce:

As far as I could understand, the crashes are caused by two different issues, depending on whether the library first detects the mixer or either one of the players (Controller.ts class discover() function):

1) In case it first gets the UDP broadcast message from the mixer, the crash is caused by the Controller.connect() function throwing an exception (trying to connect to mixer’s port 50010 will give a E_CONNREFUSED, see my previous post). More specifically the tcp.connect() function: [02:21:03] [INFO] Found ‘DN-X1800Prime’ Controller at ‘192.168.1.100:50010’ with following software: { name: ‘JM08’, version: ‘1.00’ }

[02:21:05] [ERROR] Error: Failed to connect to ‘192.168.1.100:50010’ at /Users/kkirjala/Documents/StageLinq/dist/utils/tcp.js:12:15 at processTicksAndRejections (node:internal/process/task_queues:96:5) at async Object.connect (/Users/kkirjala/Documents/StageLinq/dist/utils/tcp.js:11:5) at async Controller.connect (/Users/kkirjala/Documents/StageLinq/dist/Controller.js:72:27) at async main (/Users/kkirjala/Documents/StageLinq/dist/main.js:29:5) at async /Users/kkirjala/Documents/StageLinq/dist/main.js:72:9

2) In case either one of the players is detected first, the library will connect (Controller.connect()) to the player and get a successful TCP connection, but the library will crash because “await this.requestAllServicePorts()” will timeout: [02:17:52] [INFO] Found ‘sc5000’ Controller at ‘192.168.1.226:44011’ with following software: { name: ‘JP07’, version: ‘2.1.1’ }

[02:17:52] [LOG] TCP connection to ‘192.168.1.226:44011’ local port: 64205

[02:17:57] [ERROR] Error: Failed to requestServices at Timeout._onTimeout (/Users/kkirjala/Documents/StageLinq/dist/Controller.js:234:24) at listOnTimeout (node:internal/timers:557:17) at processTimers (node:internal/timers:500:7)

MarByteBeep commented 2 years ago

Thanks for the report! You did verify that the Go code didn't have this particular problem, right?

kkirjala commented 2 years ago

Thanks for the report! You did verify that the Go code didn't have this particular problem, right?

Yes. I ran the included cmd/stagelinq-discover command line app (https://github.com/djswolf/go-stagelinq/) and it was able to successfully discover one of the players, but not the mixer or the second player:

kkirjala@Kalle-Air stagelinq-discover % go run main.go 2021/12/30 02:58:10 Listening for devices for 5s 2021/12/30 02:58:10 192.168.1.100 "DN-X1800Prime" "JM08" "1.00" 2021/12/30 02:58:10 attempting to connect to this device… 2021/12/30 02:58:11 WARNING: dial tcp 192.168.1.100:50010: connect: connection refused 2021/12/30 02:58:11 192.168.1.101 "sc5000" "JP07" "2.1.1" 2021/12/30 02:58:11 attempting to connect to this device… 2021/12/30 02:58:11 requesting device data services… 2021/12/30 02:58:12 offers StateMap at port 33061 2021/12/30 02:58:12 /Engine/Deck1/Play = map[state:%!s(bool=false) type:%!s(float64=1)] 2021/12/30 02:58:12 /Engine/Deck1/PlayState = map[state:%!s(bool=false) type:%!s(float64=1)] 2021/12/30 02:58:12 /Engine/Deck1/Track/ArtistName = map[string:Anna & Miss Kittin type:%!s(float64=8)] 2021/12/30 02:58:12 /Engine/Deck1/Track/TrackNetworkPath = map[string:net://0f5a9001-ed85-413f-8cbf-f86806696271/(Unknown)streaming://TIDAL/Track/114449198 type:%!s(float64=8)] 2021/12/30 02:58:12 /Engine/Deck1/Track/SongLoaded = map[state:%!s(bool=true) type:%!s(float64=1)] 2021/12/30 02:58:12 /Engine/Deck1/Track/SongName = map[string:Forever Ravers type:%!s(float64=8)] 2021/12/30 02:58:12 /Engine/Deck1/Track/TrackData = map[state:%!s(bool=true) type:%!s(float64=3)] 2021/12/30 02:58:12 /Engine/Deck1/Track/TrackName = map[string:streaming://TIDAL/Track/114449198 type:%!s(float64=8)] 2021/12/30 02:58:12 /Engine/Deck2/Play = map[state:%!s(bool=false) type:%!s(float64=1)] 2021/12/30 02:58:12 /Engine/Deck2/PlayState = map[state:%!s(bool=false) type:%!s(float64=1)] 2021/12/30 02:58:12 /Engine/Deck2/Track/ArtistName = map[string: type:%!s(float64=8)] 2021/12/30 02:58:12 /Engine/Deck2/Track/TrackNetworkPath = map[string: type:%!s(float64=8)] 2021/12/30 02:58:12 /Engine/Deck2/Track/SongLoaded = map[state:%!s(bool=false) type:%!s(float64=1)] 2021/12/30 02:58:12 /Engine/Deck2/Track/SongName = map[string: type:%!s(float64=8)] 2021/12/30 02:58:12 /Engine/Deck2/Track/TrackData = map[state:%!s(bool=false) type:%!s(float64=3)] 2021/12/30 02:58:12 /Engine/Deck2/Track/TrackName = map[string: type:%!s(float64=8)] 2021/12/30 02:58:56 /Engine/Deck1/PlayState = map[state:%!s(bool=true) type:%!s(float64=1)] 2021/12/30 02:58:56 /Engine/Deck1/Play = map[state:%!s(bool=true) type:%!s(float64=1)] 2021/12/30 02:58:57 /Engine/Deck1/PlayState = map[state:%!s(bool=false) type:%!s(float64=1)] 2021/12/30 02:58:57 /Engine/Deck1/Play = map[state:%!s(bool=false) type:%!s(float64=1)]

I don't know if it's an issue with the sample app (stagelinq-discover) or something else, but the unbox app (https://github.com/erikrichardlarson/unbox) that, AFAIK uses the same Go library, is able to see both players and the mixer.

MarByteBeep commented 2 years ago

So the stand alone Go app seems to have the same problem? And can you try to narrow down the cause? Perhaps first try to connect 1 device (the player), start the NodeJS app and see if all works. Then 2 players, and check the behavior. Then just the mixer, and no player.

I'm trying to determine what device is causing the issues.

kkirjala commented 2 years ago

So the stand alone Go app seems to have the same problem?

Nope, the console demo app included with go-stagelinq works partially, it's able to detect and connect to 1 player.

Unbox v8.3 (https://github.com/erikrichardlarson/unbox/releases/tag/8.3) that uses the go-stagelinq library does work as it's able to figure out which track is currently playing (loaded into either player and the channel fader is up on the mixer).

And can you try to narrow down the cause? Perhaps first try to connect 1 device (the player), start the NodeJS app and see if all works. Then 2 players, and check the behavior. Then just the mixer, and no player.

I tried those combinations (only mixer powered up / only 1 player powered up / both players powered up, mixer is off) and I got the same result as mentioned in my earlier post, either the library not being able to connect to the mixer or failing to requestServices from a player.

kkirjala commented 2 years ago

Actually I managed to narrow down the issue with help of Wireshark.

It seems like when running on MacOS the library isn't able to successfully send out the UDP broadcast announcing itself (DISCOVERERHOWDY / MarByteBeep's StageLinq Handler testing) whereby the SC5000 player will immediately close the socket when the library tries to connect to it for fetching the list of available services.

I ran the same software on Windows 10 / NodeJS v16.13 and it was able to connect to a player and receive all the events (BPM change, track load, channel fader movement etc.).

It has something to do with the difference in how NodeJS handles UDP socket send on MacOS vs. Windows. The broadcastMessage() function used for sending out the broadcast doesn't throw an error or anything so by just looking at logs it looks like if the broadcasts get sent out but Wireshark tells a different story.

Another thing to note is that the library only was able to connect to 1 player at a time on Windows, but that's a different issue. I believe I'll have a look at the code and create a pull request once I have a fix for that.

kkirjala commented 2 years ago

Pull request with a fix created: https://github.com/MarByteBeep/StageLinq/pull/2

MarByteBeep commented 2 years ago

Thanks again. Merged fix into master

erikrichardlarson commented 2 years ago

Awesome work @kkirjala