Compare commits

...

279 Commits

Author SHA1 Message Date
Seth Call 5a68b57a76 track utm_id 2026-02-04 21:53:36 -06:00
Seth Call 577bece75e Add threads to sources 2026-02-04 19:53:53 -06:00
Seth Call 3ee8577153 Fix Event 2026-01-28 20:03:52 -06:00
Seth Call 8aa5ba743e add array support for facebook ad source 2026-01-24 00:01:40 -06:00
Seth Call 3a4b900ebd Support more utm tracking 2026-01-23 23:31:34 -06:00
Seth Call bfbd266466 build this 2026-01-22 22:36:58 -06:00
Seth Call b6fc597f8b fix reporting 2026-01-22 22:18:11 -06:00
Seth Call 9761d8f44d removing rails loger junk 2026-01-19 13:23:33 -06:00
Seth Call 85d2b3fd53 Store / read UTM 2026-01-17 20:57:36 -06:00
Seth Call 0113408780 Add meta tracking to jam-ui 2026-01-16 07:56:26 -06:00
Seth Call a283c39a58 more logging for cAPI event 2026-01-15 08:01:59 -06:00
Seth Call f3d8c4763b Add beter logging 2026-01-15 07:52:05 -06:00
Seth Call e92e54fcd3 Missed some recurly/plan code for yearly 2026-01-14 22:12:58 -06:00
Seth Call 0fd37809c8 add all this stuff in 2026-01-14 21:04:58 -06:00
Nuwan caf3e2b2d5 Update "Zoom weekly office hours" link in Welcome to JamKazam email 2025-09-03 13:58:44 +05:30
Seth Call 6d2211cbb4 VRFS-5627 - VUs get busted when hovering over remote participants who change tracks/leave/change track settings 2025-08-03 11:51:12 -05:00
Seth Call f755e2b0a0 VRFS-5653 - fix Music/Chat slider 2025-08-02 11:04:46 -05:00
Seth Call 80010723ca Force build 2025-07-26 08:34:09 -05:00
Nuwan ef2497d0a4 remove audio delay from recording interface
remove audioDelay input and related code. also removed
the volume control which was on the same interface
2025-07-17 17:15:33 +05:30
Nuwan e6aad11685 remove unused video formats in recording window
remove .mkv, .ts, .flv, and .m3u8 options from the
video format list box, leaving only .mp4 and .mov options
2025-07-03 20:26:46 +05:30
Nuwan Chaturanga db2010e893 Merged in 5628-vu-meter_frequency (pull request #62)
Implement VU meter frequency preference

* Merged promised_based_api_interation into 5628-vu-meter_frequency

* Merge branch '5628-vu-meter_frequency' of bitbucket.org:jamkazam/jam-cloud into 5628-vu-meter_frequency

* force push

* wip

* wip VU meter update pref rendering

* fix for vu meter update

this fixes the previously broken vu meter update based on the user
selected update rate preference.

* Merge branch '5628-vu-meter_frequency' of bitbucket.org:jamkazam/jam-cloud into 5628-vu-meter_frequency


Approved-by: Seth Call
2025-06-20 10:48:47 +00:00
Seth Call 14dbef2be1 Force a build 2025-06-16 11:48:51 -05:00
Seth Call 915fa31f09 Indicate this comes from the 'modern' client 2025-06-15 14:23:50 -05:00
Seth Call c874158bd7 Fix diagnostic for GEAR_SELECTION 2025-06-15 14:22:30 -05:00
Nuwan 369dd10a02 Merge branch 'promised_based_api_interation' of bitbucket.org:jamkazam/jam-cloud into promised_based_api_interation 2025-06-15 04:02:58 +05:30
Nuwan 41fb6e7a2a force push 2025-06-15 04:02:17 +05:30
Seth Call 6e478d3411 Deactivate web/video setting for now 2025-06-15 04:02:17 +05:30
Nuwan 5ff7b049ce remove noisy log entry 2025-06-15 03:39:08 +05:30
Nuwan 82bc1c408b Implement VU meter frequency preference
render VU meter updates as per the user preference
2025-06-15 01:19:17 +05:30
Seth Call e82fea8d3d Deactivate web/video setting for now 2025-06-13 07:28:29 -05:00
Seth Call 324d34ff61 Recording seems to be working well enough atm. With new clients only 2025-06-08 22:24:37 -05:00
Seth Call e83805bd4a pause 2025-06-08 14:34:23 -05:00
Seth Call 02666d1680 Working on so far. at coffee shop pause 2025-06-08 14:34:10 -05:00
Seth Call d573904d05 pause before change to js 2025-06-07 12:15:08 -05:00
Seth Call cb24078c19 Merge branch 'promised_based_api_interation' of bitbucket.org:jamkazam/jam-cloud into promised_based_api_interation 2025-05-28 16:38:53 -05:00
Seth Call 4931908344 Update recording feature to show recording in progresso for late joiners. also update start recording button 2025-05-28 16:38:41 -05:00
Nuwan Chaturanga 2983b801f6 Merged in 5538-modal_dialog_to_remind_gear_setup (pull request #60)
5538 modal dialog to remind gear setup

* Setup Gear prompt

Display each time user runs app if Setup Gear step in PLG funnel not yet
completed


Approved-by: Seth Call
2025-05-23 13:01:45 +00:00
Nuwan 194c6156e0 chage references of beta.jamkazam to www.jamkazam 2025-05-21 12:17:06 +05:30
Nuwan 8ae89c1cbb debug custom URL handling in app 2025-04-30 17:40:21 +05:30
Nuwan a17c29216c 5551 2025-04-28 23:35:41 +05:30
Nuwan f88def1790 fixes related to recording state 2025-04-23 11:43:29 +05:30
Nuwan f666578872 add debug log to check recording video state 2025-04-21 15:19:57 +05:30
Nuwan 911a37bec5 fixing state issues of front end recording 2025-04-18 18:15:30 +05:30
Nuwan fdb392f723 wip 2025-04-17 00:35:54 +05:30
Nuwan ce5bb82fb5 wip 2025-04-16 23:47:24 +05:30
Nuwan 0f074b1e37 wip 2025-04-16 23:32:06 +05:30
Nuwan bbf4688830 wip 2025-04-16 23:25:49 +05:30
Nuwan e1b565847c wip 2025-04-16 19:31:34 +05:30
Nuwan c28508bcf7 recording state fix wip 2025-04-10 00:35:26 +05:30
Nuwan fd64e946bf FrontStopRecording api added 2025-04-04 04:46:21 +05:30
Nuwan 844633397f fixes for session recording with other participants 2025-04-04 03:19:00 +05:30
Nuwan ab34c37d80 changes to allow joining a seesion without stopping an onging recording 2025-04-02 18:50:37 +05:30
Nuwan 5d9a75deb3 wip chages in session recording 2025-03-31 13:22:57 +05:30
Nuwan c277fdce94 wip 2025-03-27 18:53:45 +05:30
Nuwan 76aefd6227 wip on leaving a session while recording 2025-03-17 15:51:59 +05:30
Nuwan eb9ad97ada validate custom URLs before processing 2025-02-08 18:34:53 +05:30
Nuwan c82a01361f customUrl validation 2025-02-06 22:11:01 +05:30
Nuwan e2828b0387 notify other participants on session leave
on leaving the session directly delete the participant record and
notify other clients ref: VRFS-5529
2025-02-05 01:04:11 +05:30
Nuwan 254ad61168 recording dialog update
add Audio Files options to select file storage options
add help help bubbles to audio files, audio delay and voice chat
2025-02-04 17:33:41 +05:30
Nuwan 532f29f3db changes to customUrl handling in client 2025-01-30 13:28:15 +05:30
Nuwan 9abaa539db fixes to app loading by custom URLs 2025-01-29 09:50:50 +05:30
Nuwan 0ed89f4e38 customUrl handling fixes 2025-01-28 17:18:58 +05:30
Nuwan 867b159c63 Merge branch 'promised_based_api_interation' of bitbucket.org:jamkazam/jam-cloud into promised_based_api_interation 2025-01-18 15:27:28 +05:30
Nuwan ccf3b3b5e7 force user to go to new jamtracks page (beta) once user clicks the JamTracks tile in client home page 2025-01-18 15:26:36 +05:30
Seth Call 767e1c7c83 Just how to test the start command 2024-12-14 14:32:12 -06:00
Seth Call fa068ad8be force build 2024-12-01 21:39:53 -06:00
Nuwan 1c47c70d35 custom url debug 2024-11-30 11:12:45 +05:30
Nuwan 80f0fa8bd9 add debug entries to check custom url 2024-11-23 20:00:26 +05:30
Nuwan ea3cecbfcf debug customUrl 2024-11-23 10:23:40 +05:30
Nuwan 9f59074b0e custom URL handling on onLoggedIn 2024-11-23 06:29:28 +05:30
Nuwan ba6c3c56dc joinSession custom URL: change parameter name 2024-11-22 22:59:07 +05:30
Nuwan e262c601b7 custom URL related adjestments 2024-11-17 00:10:20 +05:30
Nuwan f41c64acc8 comment duplicate code 2024-11-16 08:51:29 +05:30
Nuwan 8194e4c636 join session using custom url scheme 2024-11-15 22:18:58 +05:30
Nuwan 8dc3a56870 tweeks to session create from custom URL scheme 2024-11-15 18:06:41 +05:30
Nuwan 0bd3f9463d fixes for creating sessions by custom URL 2024-10-28 09:08:22 +05:30
Nuwan fd8f31e7d4 custom URL schema handling 2024-10-25 17:08:28 +05:30
Nuwan a5fce73848 wip - custom url handling 2024-10-25 08:29:13 +05:30
Nuwan 2b929c0d1e add debug log entries to identify possible errors when creating a session using custom URL 2024-10-23 23:54:13 +05:30
Nuwan 489f3a685d add debug log entries to identify possible errors when creating a session using custom URL 2024-10-23 23:42:48 +05:30
Nuwan cef7f1efbe custom URL schema for create a session
handles URL loaded as a custom URL format (jamkazam://)
which is meant to create a new session with the provided
parameters
2024-10-23 11:33:57 +05:30
Nuwan de115773ec add more logging to debug create session from custom URL 2024-10-18 08:34:35 +05:30
Nuwan 7f693b7e54 bug fixing in custom url app launching 2024-10-17 14:31:49 +05:30
Nuwan 12feacc908 add logging for debugging 2024-10-17 13:49:22 +05:30
Nuwan a718037dd3 customUrl handle - launch jk session screen when is invoked using custom URL 2024-10-17 00:12:22 +05:30
Nuwan c9528feabf assign session if as newSessionId to identify when the session is created 2024-10-16 13:52:56 +05:30
Nuwan 505d7c0496 invoking the client to create a session using custom URL 2024-10-16 12:49:56 +05:30
Nuwan 15583ce99d onLogginIn api handle for custom url wip 2024-10-16 12:49:56 +05:30
Nuwan 1280a3ca86 wip custom url handling 2024-10-16 12:49:56 +05:30
Seth Call 243a081aa9 Make the previously-slow query target feed query configurable. Default to on 2024-10-14 11:19:19 -05:00
Nuwan f71c0913b7 Merge branch 'promised_based_api_interation' of bitbucket.org:jamkazam/jam-cloud into promised_based_api_interation 2024-10-11 22:05:14 +05:30
Seth Call 1ae5437618 Fix recurly bug where updated 2x from a RJS token 'ruins' the account until the user re-deploys 2024-10-11 22:00:38 +05:30
Nuwan fb80a3a2c5 join session by custom url schema 2024-10-11 22:00:10 +05:30
Nuwan c9a3f7d1da Merge branch 'promised_based_api_interation' of bitbucket.org:jamkazam/jam-cloud into promised_based_api_interation 2024-10-11 08:54:15 +05:30
Nuwan 98273bae0d handle session invocation by custom URL schema 2024-10-11 08:50:10 +05:30
Seth Call a3e0666202 Fix recurly bug where updated 2x from a RJS token 'ruins' the account until the user re-deploys 2024-10-05 15:55:37 -05:00
Nuwan 317c0384e1 add await on SetScoreWorkTimingInterval 2024-09-26 08:29:49 +05:30
Nuwan 2546d3f550 change order of LaunchBroadcastSettings enum item in asyncJamClient 2024-09-25 22:22:23 +05:30
Nuwan 57e669cd22 session setting fix musician access drop down always disabled 2024-09-21 11:00:28 +05:30
Seth Call 1e50060087 Backport JAM_REASON_PRESENT into user model, to co-exist happily with develop servers 2024-09-17 22:27:27 -05:00
Nuwan 08fe7808a0 remove video gear link from account home page 2024-09-13 08:18:55 +05:30
Nuwan 7ea8a1e8fa Session broadcast button
add broadcast button which send a message to the client
2024-08-21 22:41:23 +05:30
Seth Call 279ba30506 Force build 2024-08-12 12:50:48 -05:00
Nuwan 2a64bbbfe8 fix js reference (this) error in waitForSessionPageEnterDone function 2024-04-11 17:03:28 +05:30
Nuwan 7617e4a4dd use jquery $.deferred in waitForSessionPageEnterDone
change the ES6 promise way of handling this method.
actually some of the code in this file expects $.deferred object
to be presented.
2024-04-11 14:54:48 +05:30
Nuwan 8bb0fa2809 fix not able to delete band 2024-03-09 16:34:21 +05:30
Nuwan 7c2ffe01ef fix band section listing musicians 2024-03-03 17:32:59 +05:30
Nuwan bcd819dfc3 fix recording window glitches
use RecordingStore instead of AppStore to track audioFormat changes.
this prevents session related state being altered unexpectedly.
2023-11-17 16:00:03 +05:30
Nuwan 8d4ed14fd6 sync recording audio format change with back end audio recording menu 2023-11-15 18:46:51 +05:30
Nuwan 03bb4190f1 sync audio recording format
on session startup fetch the audio format selected in the back end
and assign it in the front end audio recording window.
2023-11-14 17:37:19 +05:30
Nuwan 4a30d29c4b fix recording stop
this fix addresses the issue when stopping a recording in a subsequent
attemp to record
2023-10-17 18:09:12 +05:30
Nuwan b185a60656 change enum order of asyncJamClient 2023-10-12 23:08:19 +05:30
Nuwan 2b1309a3b0 change recording allowed video formats 2023-10-04 02:01:01 +05:30
Nuwan c116559d18 clean up comment 2023-10-04 01:17:09 +05:30
Nuwan 0617b1ba8d change in audio formats list for recording 2023-10-04 01:13:45 +05:30
Nuwan 001f59ba30 new session recording feature
for video recordings check if OBS has been installed on the
user's computer.
2023-10-03 19:17:26 +05:30
Nuwan 25586e06fc changes to allowed audio formats in new recording window 2023-10-03 01:16:09 +05:30
Nuwan 5618b08e79 call on start recording the new StartMediaRecording API 2023-09-30 10:07:08 +05:30
Nuwan e9ff7c5faa add IsOBSAvailable api in to asyncJamClient 2023-09-30 00:18:27 +05:30
Nuwan 6acf990b20 add StartMediaRecording api in to asyncJamClient 2023-09-30 00:08:09 +05:30
Nuwan da762dcd2c Merge branch 'promised_based_api_interation' of bitbucket.org:jamkazam/jam-cloud into promised_based_api_interation 2023-09-29 23:47:16 +05:30
Nuwan e1ff954709 guard session recording 2023-09-29 23:46:42 +05:30
Nuwan c9d7a560d0 debug jamtrack volume 2023-09-29 23:46:42 +05:30
Nuwan 8ef9530129 guard session recording 2023-09-22 16:18:02 +05:30
Nuwan 40282a82f3 debug jamtrack volume 2023-09-21 17:16:08 +05:30
Nuwan 4a2046aae6 handle new recording window events 2023-09-21 10:45:53 +05:30
Nuwan ad9f5dcef3 wip on new session recording window 2023-09-19 13:13:44 +05:30
Nuwan 2dceeb86c3 wip new recording window 2023-09-19 13:13:44 +05:30
Nuwan 5727780259 merge into promised_based_api_interation 2023-09-19 13:12:34 +05:30
Nuwan 2093c6da9e wip new recording window 2023-09-19 13:11:55 +05:30
Nuwan 2adf75eb7e wip new recording 2023-09-19 13:11:55 +05:30
Nuwan a01a10afab WIP recording settings form 2023-09-19 13:11:55 +05:30
Nuwan 3eac4cc4b1 WIP in new session recording window. UI is almost done. need to add functinality 2023-09-19 13:11:55 +05:30
Nuwan 25d651f450 add more volume data to SessionSetTrackVolumeData
id, _id and groupID added to the third parameter of this API call
2023-09-19 11:56:39 +05:30
Nuwan f835894620 add more context details to SessionSetTrackVolumeData
add  mediaType, isJamTrack, and isMetronome to trackVolumeObject parameter
of SessionSetTrackVolumeData api
2023-09-13 18:29:35 +05:30
Nuwan bf1291abf4 removing unused bits 2023-09-07 20:03:34 +05:30
Nuwan 55d3202c11 Merge branch 'promised_based_api_interation' of bitbucket.org:jamkazam/jam-cloud into promised_based_api_interation 2023-09-05 19:22:16 +05:30
Nuwan 61b58eddd1 prevent showing alert on audio instrument select
fix this bug due to previous introduction of alert which pops up
if midi instrument is selected without selecting midi interface and
vst plugin. The alert only applicable to the midi interface.
2023-09-05 19:19:16 +05:30
Seth Call fc9d69f5f9 Update to pass product from client back to ArtifactUpdate 2023-09-02 15:23:22 -05:00
Seth Call 21733110f4 skip all client updatse 2023-09-02 14:53:19 -05:00
Seth Call f9c3c33d6b Beta download page 2023-09-01 16:33:09 -05:00
Nuwan ccee1c6805 cleanup debug entries 2023-09-01 16:54:01 +05:30
Nuwan f92ae4dd8d debugging 2023-09-01 15:57:35 +05:30
Nuwan 9e2adc9ce0 fix artifact version upgrade 2023-09-01 13:51:16 +05:30
Nuwan c8be3b847f debug JamServer 2023-09-01 13:33:09 +05:30
Nuwan 6d2ef50a8d debug version upgrade 2023-09-01 10:20:46 +05:30
Nuwan 63ebf8259c changes related to client upgrade fixes 2023-09-01 00:45:44 +05:30
Nuwan ea5e32e14b fix recording window handling on conneted clients to the session 2023-08-31 22:22:30 +05:30
Nuwan 7936d8ac59 debug 2023-08-31 09:47:46 +05:30
Nuwan fff48bf399 client update debug logs 2023-08-31 09:36:25 +05:30
Nuwan d0966fe67a debug backing track on peer 2023-08-28 18:14:45 +05:30
Nuwan 4f1fd4880e fix inconsistency of volume gauge
this fixes the unpredictable behavior of volume level when changing the
volume gauge leveler.
2023-08-22 23:09:44 +05:30
Nuwan e3cb68dda8 Show instructions in midi track configuration popup 2023-08-21 16:45:12 +05:30
Nuwan d8d04dd33f Allow multiple recordings within session
change in recording flow. Now after stopping the recording we no longer ask
user to save or discard the recording, instead the app saves the recording to user's
computer and opens the file explorer to that folder.
therefore following scenario is no longer valid; hence skipping it.
2023-08-19 11:03:29 +05:30
Nuwan 701620089a async/await fix 2023-08-11 03:24:11 +05:30
Nuwan 126e08a90d fix for version upgrade alert 2023-08-05 18:07:27 +05:30
Nuwan 48b2316728 debug version upgrade 2023-08-05 17:19:11 +05:30
Nuwan 03e12da98a audio MIDI config alert
show an alert when midi interface or midi plugin is not selected
2023-08-05 00:39:24 +05:30
Nuwan c7822a14d0 more cleaning console logs 2023-08-02 09:15:09 +05:30
Nuwan 758e688db1 remove debug entries and cleanup 2023-08-02 08:57:59 +05:30
Nuwan 5e7d512a5e fix for midi instrument selection 2023-08-02 08:32:11 +05:30
Nuwan 6d4b775321 debugging 2023-07-28 15:52:36 +05:30
Nuwan 2f866e92a7 debugging 2023-07-28 15:19:59 +05:30
Nuwan fd929ab0dc remove debug lines 2023-07-28 12:29:59 +05:30
Nuwan 4fbe7fb8a3 debug websocket gateway handle login 2023-07-28 07:59:03 +05:30
Nuwan 7390355b3c provide detailed os name in jamserver to be consumed by websocket gateway router 2023-07-28 07:53:51 +05:30
Nuwan 9329e5d235 debug logs 2023-07-22 09:50:15 +05:30
Nuwan 5ca37d63c1 debug versioncheck api 2023-07-22 04:32:55 +05:30
Nuwan 20331c6d60 fix for version upgrade 2023-07-22 03:59:49 +05:30
Nuwan 60009208c0 fix for audio input port assignment
this fix addresses the invalid input port assignment issue
due to asynchronous nature of asyncjamClient method calls
2023-07-21 18:32:40 +05:30
Nuwan 81b3fecfd4 fix for client version upgrade 2023-07-20 04:11:44 +05:30
Nuwan e03389909e fix showing error alert on audio resync 2023-07-20 03:31:37 +05:30
Nuwan 483eb20c88 ArtifactsUpdate MacOSX-M 2023-07-12 10:39:57 +05:30
Nuwan e764047935 change in userAgent check to determine client type 2023-07-11 22:30:48 +05:30
Nuwan 287fad8443 Merge branch 'promised_based_api_interation' of bitbucket.org:jamkazam/jam-cloud into promised_based_api_interation 2023-07-07 18:54:10 +05:30
Nuwan eba15f255e remove alert on session recording stop 2023-07-07 18:53:19 +05:30
Nuwan 42ee0bcf26 WIP fixing midi configuration 2023-07-07 18:53:19 +05:30
Nuwan 5932cc3d67 WIP midi and audio channel config 2023-07-07 18:53:19 +05:30
Nuwan b6868a4fbb Merge branch 'promised_based_api_interation' of bitbucket.org:jamkazam/jam-cloud into promised_based_api_interation 2023-07-07 17:50:45 +05:30
Nuwan f1008baea8 remove alert on session recording stop 2023-07-07 17:50:12 +05:30
Nuwan 8e0e43359c WIP fixing midi configuration 2023-07-07 17:49:55 +05:30
Nuwan bc71730df4 remove alert on session recording stop 2023-07-06 10:05:21 +05:30
Nuwan 69addda196 fix Server Disconnect
add FakeJamClientProxy to wrap FakeJamClient. It accepts API calls and
sends back javascript promises.
2023-07-06 09:00:49 +05:30
Nuwan 917d8f1a8e WIP midi and audio channel config 2023-07-04 12:56:18 +05:30
Nuwan dd4f62cb07 fix js error 2023-06-14 16:55:13 +05:30
Nuwan 5d09d23809 suppress the preview recording window 2023-06-14 16:22:56 +05:30
Nuwan 01fda6b6f0 fix onSessionEnter 2023-06-02 06:48:56 +05:30
Nuwan d09baf05bb prevent session joining using web browser 2023-05-29 19:04:46 +05:30
Nuwan 03bb0f99fa fix start/stop recording dialog for session with video 2023-05-20 17:50:32 +05:30
Nuwan f4aebb44e2 fix start/stop recording dialog for session with video 2023-05-20 17:36:43 +05:30
Nuwan 7c306a13df remove debug message 2023-04-18 04:52:36 +05:30
Nuwan 6498485548 in session recording dialog box remove the video opts
with the newly invented webRTC based video recording system we can drop this options.
Only enable the video recording radio button if the backend has sent the relevant event.
2023-04-18 04:42:40 +05:30
Nuwan 0beb922db5 disable video gear setup link 2023-04-07 11:58:49 +05:30
Nuwan b8d8ca73fa sort user friend list in alphabetical order 2023-04-06 12:06:25 +05:30
Nuwan 8d816d69ed fix array iteration key/value in gear_util getChatInputs 2023-04-03 23:35:26 +05:30
Nuwan bb1c15205c fix GetDetailedOS 2023-03-18 20:09:09 +05:30
Nuwan 599e650d57 side bar search fixing
1) change the search results limit to 40
2) fix band search sql
2023-03-17 10:15:34 +05:30
Nuwan 76c56612cf fix showing build upgrade message on app startup 2023-03-16 12:26:29 +05:30
Nuwan 8d2e9d6663 fix async handler in updateSingleRecording 2023-03-14 20:26:45 +05:30
Nuwan 51f5f5ecf0 fix recording manager - not showing data 2023-03-14 13:38:55 +05:30
Nuwan dd0e24fa19 disable legacy video system 2023-02-24 23:23:10 +05:30
Nuwan aa3ac642da this includes fix for Resync button doesn't do anything 2023-02-24 17:23:19 +05:30
Nuwan 359ccfe431 fix async call order in configure audio
This error was appearing in audio gear configuration when clicking Next button in
select & test audio gear step. on this button click the program executed
an event listener on input channel check box click (programmatically) and
autoAssignToSingleInput inside the click event handler was invoked
an async call stack which was resolved before the next button click handler completed.
As a result a pop up was showing up saying "The application is no longer modifying a new profile".

This commits fixes this issue by explicitly preventing this event lister handler been executed
in this case.
2023-02-23 19:12:16 +05:30
Nuwan 4cef5acde8 new boolean parameter for TrackDeleteProfile to delete it from the Audio.ini file 2023-02-22 12:36:56 +05:30
Nuwan 172f3a654d new boolean parameter for TrackDeleteProfile to delete it from the Audio.ini file 2023-02-22 12:24:11 +05:30
Nuwan 972f9fadcc new boolean parameter for TrackDeleteProfile to delete it from the Audio.ini file 2023-02-22 11:28:37 +05:30
Nuwan 1fb6907df0 using Jquery .attr() for accessing data attributes. using .prop() here is erronious here 2023-02-22 00:16:42 +05:30
Nuwan 27d697149c fix js error when selecting framesize or sample rate settings in configure audio 2023-02-21 19:24:13 +05:30
Nuwan 60af5432ce fix frontend error when changing framesize in audio input/output configuration 2023-02-17 16:37:56 +05:30
Nuwan 19050d317b Fix configure voice chat
add missing async/await call to fetch chat inputs
2023-02-16 18:21:11 +05:30
Nuwan 80bf8119af show logs in asyncJamClient 2023-02-06 00:28:53 +05:30
Nuwan 3d26f241b4 turn off log messages in asyncJamClient 2023-02-04 03:48:19 +05:30
Nuwan b7f9ade2ea handle sendP2PMessage in asyncJamClient 2023-02-04 03:35:07 +05:30
Nuwan 4423a9c122 more async fixes related to audio interface configuration 2023-02-01 15:34:15 +05:30
Nuwan 6c56fe3af8 async calls in configure audio
adds async/await call for jamClient api calls
2023-01-31 17:58:16 +05:30
Nuwan 009ee6a6dd add GetDetailedOS in to async call array 2023-01-26 01:11:21 +05:30
Nuwan 20177f71dd Merge branch 'promised_based_api_interation' of bitbucket.org:jamkazam/jam-cloud into promised_based_api_interation 2023-01-26 00:48:27 +05:30
Seth Call 37533c9e18 Fix odd bug in jam_track_right for current_user, and send https redirectfor download link for jamtrack 2023-01-16 13:08:40 -05:00
Nuwan 2228b91285 Merge branch 'promised_based_api_interation' of bitbucket.org:jamkazam/jam-cloud into promised_based_api_interation 2023-01-13 11:12:09 +05:30
Seth Call dccc668d48 Fix special branch casing 2023-01-04 17:57:27 -06:00
Seth Call 16c5dbb218 Fix special branch casing 2023-01-04 17:20:21 -06:00
Nuwan 46f2fbb55f Merge branch 'promised_based_api_interation' of bitbucket.org:jamkazam/jam-cloud into promised_based_api_interation 2023-01-04 21:42:42 +05:30
Seth Call b3d4259b09 Try removing gemfile.lock 2023-01-04 08:44:02 -06:00
Seth Call d59b83bb42 wip 2023-01-04 08:43:13 -06:00
Seth Call 7dc640fb86 debugging build 2023-01-04 08:26:39 -06:00
Seth Call cbf348564d Try to fix build 2023-01-03 14:38:20 -06:00
Seth Call e9612cbc19 special case debians for this branch 2023-01-03 08:43:48 -06:00
Nuwan 5145bfeac1 add .ruby-version to .gitignore 2022-12-23 08:18:00 +05:30
Nuwan 3349c76076 Merge branch 'promised_based_api_interation' of bitbucket.org:jamkazam/jam-cloud into promised_based_api_interation 2022-12-16 13:51:08 +05:30
Murali Gowrisankaran bb9813ae26 Removed enumeration for open and close Url APIs 2022-12-16 02:37:30 +00:00
Nuwan bd1134b2bd Merge branch 'promised_based_api_interation' of bitbucket.org:jamkazam/jam-cloud into promised_based_api_interation 2022-12-13 12:09:37 +05:30
Murali Gowrisankaran cc4d1575c0 Added enumerated constants for window popup APIs 2022-12-13 06:07:29 +00:00
Nuwan 033d67639c fix js error 2022-12-07 19:44:45 +05:30
Nuwan d9b4a5b8d9 fix async call issue in bands search window 2022-12-03 02:21:47 +05:30
Nuwan 87762c5933 add bugsnag error reporting to asyncJamClient 2022-11-05 04:36:05 +05:30
Nuwan 9d787351fa fixes for recording related errors 2022-11-04 18:57:09 +05:30
Nuwan f392623049 wip session recording related fixes 2022-11-03 18:54:03 +05:30
Nuwan c207b76641 debug and fixing session recording wip 2022-11-02 04:15:22 +05:30
Nuwan 2c5708b28a fix syntax error - invalid comment 2022-10-29 00:04:50 +05:30
Nuwan 2370762c51 alperbatically order JKFrontendMethods method names in asyncJamClient 2022-10-28 22:18:29 +05:30
Nuwan 3be0e25bcb add jamClient.SessionSetTrackVolumeData
this new api method is used to send session track data
over web channel to qt c++ backend
2022-10-28 22:06:34 +05:30
Nuwan 768f3d976a convert anoter few jamClient. call to async format 2022-10-28 13:12:14 +05:30
Nuwan 5487e62f5a fixes for public session creation and joining 2022-10-12 19:39:09 +05:30
Nuwan 38baea686f fixes for the errors - public session
fix errors when creating group session
and when joining group session
2022-10-07 04:16:40 +05:30
Seth Call 8c472a90a8 Fix jamtracks for local dev 2022-09-12 17:04:48 -05:00
Nuwan 73a56b2cf6 fix session metronome related functions 2022-09-07 08:49:21 +05:30
Nuwan 6486761483 Merge branch 'promised_based_api_interation' of bitbucket.org:jamkazam/jam-cloud into promised_based_api_interation 2022-09-02 11:11:11 +05:30
Nuwan 7a7986e30a fixing audio config and session related issues 2022-09-02 11:10:51 +05:30
Seth Call 1f63aa77b4 Pass in client_id to backend websocket connection 2022-09-01 16:44:16 -05:00
Seth Call cbbfebddc9 make onMixersChanged async so that it can await internally 2022-08-17 21:57:54 -05:00
Nuwan 794d131a3e change context._.each( loops to classic for loops 2022-08-15 22:30:58 +05:30
Seth Call 98aa2adc42 Remove 2 context._.each statements combined with async 2022-08-14 17:00:38 -05:00
Nuwan 21af8446ca async call fixes for audio gear setup 2022-08-13 00:33:24 +05:30
Nuwan 8e7b9b278a fix session leave issues 2022-08-08 16:31:00 +05:30
Nuwan 1c1626df73 fix not showing Account screen content 2022-08-03 21:13:51 +05:30
Nuwan 07a00505b8 fix listing audio profiles 2022-08-03 19:08:32 +05:30
Nuwan 09e1d27c64 fix async realted errors and cleanup 2022-08-03 18:38:42 +05:30
Nuwan 11915454cb replacing context.jamClient.isNativeClient() with context.JK.isQWebEngine 2022-08-02 18:51:05 +05:30
Nuwan 8cc3a6753b Merge remote-tracking branch 'origin/promised_based_api_interation' into promised_based_api_interation 2022-08-02 13:56:23 +05:30
Nuwan c4a37daa73 adding async/await for fixing issues related to promised based pi calls 2022-08-02 09:43:01 +05:30
Seth Call 08b2de242e Create context.JK.isQWebEngine property instead of gon.isQWebEngine 2022-08-01 21:49:33 -05:00
Seth Call e19819e035 Fix step 2 of the FTUE Gear Wizard by setting some async's where needed.
Also added in gon.isQWebEngine to act as flag indicating this is the native client.
2022-08-01 21:37:35 -05:00
Nuwan b32621fe42 Merge branch 'promised_based_api_interation' of bitbucket.org:jamkazam/jam-cloud into promised_based_api_interation 2022-07-30 08:28:34 +05:30
Nuwan 795ab8bd13 fixing errors related to gear wizard 2022-07-30 08:27:59 +05:30
Murali Gowrisankaran 2adf33e689 Removed/commented out video related frontend API calls 2022-07-28 01:12:30 +00:00
Nuwan c3bcd3b470 fixing audio gear related async errors 2022-07-27 16:22:01 +05:30
Nuwan efbe685641 Merge branch 'promised_based_api_interation' of bitbucket.org:jamkazam/jam-cloud into promised_based_api_interation 2022-07-27 11:04:04 +05:30
Nuwan 9586e0547a fixing async errors 2022-07-27 11:03:20 +05:30
Murali Gowrisankaran ffddf28a25 Fixed enum for client ID 2022-07-27 01:31:14 +00:00
Murali Gowrisankaran 57fb3ea333 Revert "Fixed enum for client ID"
This reverts commit ad61bb00cb.
2022-07-27 01:26:43 +00:00
Murali Gowrisankaran ad61bb00cb Fixed enum for client ID 2022-07-27 01:24:47 +00:00
Nuwan f732e0dad6 fixing error due to async nature of api calls 2022-07-26 23:32:36 +05:30
Murali Gowrisankaran 21ce5c237d Added method for getClientID 2022-07-12 21:27:50 +00:00
Nuwan 4b281538b2 fix errors getting after async changes
this includes errors in websocket-gateway due to blank data been
passed from web frontend to websocket routes
2022-06-16 00:02:54 +05:30
Nuwan 69cc22106d fix js error in gear_utls after changing jamClient calls to async 2022-06-02 18:00:03 +05:30
Nuwan 99d20a9869 handle the response returned from ws server for unavailable methods 2022-04-20 16:36:23 +05:30
Nuwan 43caffb85e work continues on changing jamClient calls to asynchronous 2022-04-18 19:08:02 +05:30
Nuwan cd93211406 wip promised based jamClient 2022-04-13 03:02:44 +05:30
Nuwan f05287f45a convert jamClient.* calls as promises using async/await 2022-04-07 22:31:35 +05:30
234 changed files with 14672 additions and 41201 deletions

2
.gitignore vendored
View File

@ -11,3 +11,5 @@ working.png
ruby/.rails5-gems ruby/.rails5-gems
web/.rails5-gems web/.rails5-gems
websocket-gateway/.rails5-gems websocket-gateway/.rails5-gems
.pg_data/
.ruby-version

View File

@ -0,0 +1,181 @@
class Spacer
def self.spacer(val, row)
percentage = ((val * 100) / row.total.to_f).round(1).to_s
('%-5.5s' % percentage).gsub(' ', ' ') + '% - ' + val.to_s
end
end
=begin
select
count(id) as total,
count(first_downloaded_client_at) as downloaded,
count(first_ran_client_at) as ran_client,
count(first_certified_gear_at) as ftue,
count(first_music_session_at) as any_session,
count(first_real_music_session_at) as real_session,
count(first_good_music_session_at) as good_session,
count(first_invited_at) as invited,
count(first_friended_at) as friended,
count(first_subscribed_at) as subscribed
from users where users.created_at >= '2024-11-01' AND users.created_at < '2025-04-01'
select first_name, last_name, email
from users where users.created_at >= '2024-11-01' AND users.created_at < '2025-04-01'
AND first_music_session_at is NULL;
=end
ActiveAdmin.register_page "Jammers Subscription Cohorts" do
menu :parent => 'Reports'
content :title => "Jammers Subscription Cohorts" do
filter_type = params[:filter_type] || 'All'
filter_campaign = params[:filter_campaign]
filter_campaign_id = params[:filter_campaign_id]
filter_ad_set = params[:filter_ad_set]
filter_ad_name = params[:filter_ad_name]
campaigns = User.where("origin_utm_source ILIKE '%meta%'").distinct.pluck(:origin_utm_campaign).compact.sort
campaign_ids = User.where("origin_utm_source ILIKE '%meta%'").distinct.pluck(:origin_id).compact.sort
ad_sets = User.where("origin_utm_source ILIKE '%meta%'").distinct.pluck(:origin_term).compact.sort
ad_names = User.where("origin_utm_source ILIKE '%meta%'").distinct.pluck(:origin_content).compact.sort
div style: "margin-bottom: 20px; padding: 10px; background-color: #f4f4f4; border-radius: 4px;" do
form action: admin_jammers_subscription_cohorts_path, method: :get do
span "Source: ", style: "font-weight: bold; margin-right: 5px;"
select name: 'filter_type', onchange: 'this.form.submit()', style: "margin-right: 15px;" do
option "All", value: 'All', selected: filter_type == 'All'
option "Organic", value: 'Organic', selected: filter_type == 'Organic'
option "Advertising", value: 'Advertising', selected: filter_type == 'Advertising'
end
if filter_type == 'Advertising'
div style: "margin-top: 10px;" do
span "Campaign Name: ", style: "font-weight: bold; margin-right: 5px;"
select name: 'filter_campaign', onchange: 'this.form.submit()', style: "margin-right: 15px;" do
option "All", value: ''
option "Null", value: 'NULL', selected: filter_campaign == 'NULL'
campaigns.each do |c|
option c, value: c, selected: filter_campaign == c
end
end
span "Campaign ID: ", style: "font-weight: bold; margin-right: 5px;"
select name: 'filter_campaign_id', onchange: 'this.form.submit()', style: "margin-right: 15px;" do
option "All", value: ''
option "Null", value: 'NULL', selected: filter_campaign_id == 'NULL'
campaign_ids.each do |c|
option c, value: c, selected: filter_campaign_id == c
end
end
end
div style: "margin-top: 10px;" do
span "Ad Set: ", style: "font-weight: bold; margin-right: 5px;"
select name: 'filter_ad_set', onchange: 'this.form.submit()', style: "margin-right: 15px;" do
option "All", value: ''
option "Null", value: 'NULL', selected: filter_ad_set == 'NULL'
ad_sets.each do |c|
option c, value: c, selected: filter_ad_set == c
end
end
span "Ad Name: ", style: "font-weight: bold; margin-right: 5px;"
select name: 'filter_ad_name', onchange: 'this.form.submit()', style: "margin-right: 15px;" do
option "All", value: ''
option "Null", value: 'NULL', selected: filter_ad_name == 'NULL'
ad_names.each do |c|
option c, value: c, selected: filter_ad_name == c
end
end
end
end
noscript { input type: :submit, value: "Filter" }
end
end
h2 "Users Grouped By Month as Paying Subscribers"
query = User.select(%Q{date_trunc('month', users.created_at) as month,
count(id) as total,
count(first_downloaded_client_at) as downloaded,
count(first_ran_client_at) as ran_client,
count(first_certified_gear_at) as ftue,
count(first_music_session_at) as any_session,
count(first_real_music_session_at) as real_session,
count(first_good_music_session_at) as good_session,
count(first_invited_at) as invited,
count(first_friended_at) as friended,
count(first_subscribed_at) as subscribed,
count(first_played_jamtrack_at) as played_jamtrack
})
.joins(%Q{LEFT JOIN LATERAL (
SELECT
j.created_at
FROM
jam_track_rights as j
WHERE
j.user_id = users.id
ORDER BY
j.created_at
LIMIT 1 -- Select only that single row
) j ON TRUE })
if filter_type == 'Organic'
query = query.where("users.origin_utm_source = 'organic'")
elsif filter_type == 'Advertising'
query = query.where("users.origin_utm_source ILIKE '%meta%'")
if filter_campaign.present?
if filter_campaign == 'NULL'
query = query.where("users.origin_utm_campaign IS NULL")
else
query = query.where("users.origin_utm_campaign = ?", filter_campaign)
end
end
if filter_campaign_id.present?
if filter_campaign_id == 'NULL'
query = query.where("users.origin_id IS NULL")
else
query = query.where("users.origin_id = ?", filter_campaign_id)
end
end
if filter_ad_set.present?
if filter_ad_set == 'NULL'
query = query.where("users.origin_term IS NULL")
else
query = query.where("users.origin_term = ?", filter_ad_set)
end
end
if filter_ad_name.present?
if filter_ad_name == 'NULL'
query = query.where("users.origin_content IS NULL")
else
query = query.where("users.origin_content = ?", filter_ad_name)
end
end
end
table_for query.group("date_trunc('month', users.created_at)")
.where("j.created_at IS NULL OR (j.created_at - users.created_at) >= INTERVAL '2 hours'")
.order("date_trunc('month', users.created_at) DESC") do |row|
column "Month", Proc.new { |user| user.month.strftime('%B %Y') }
column "Total", :total
column "Subscribed", Proc.new { |user| raw(Spacer.spacer(user.subscribed, user)) }
column "Downloaded", Proc.new { |user| raw(Spacer.spacer(user.downloaded, user)) }
column "Ran Client", Proc.new { |user| raw(Spacer.spacer(user.ran_client, user)) }
column "FTUE", Proc.new { |user| raw(Spacer.spacer(user.ftue, user)) }
column "Any Session", Proc.new { |user| raw(Spacer.spacer(user.any_session, user)) }
column "2+ Session", Proc.new { |user| raw(Spacer.spacer(user.real_session, user)) }
column "Good Session", Proc.new { |user| raw(Spacer.spacer(user.good_session, user)) }
column "Invited", Proc.new { |user| raw(Spacer.spacer(user.invited, user)) }
column "Friended", Proc.new { |user| raw(Spacer.spacer(user.friended, user)) }
column "Played JT", Proc.new { |user| raw(Spacer.spacer(user.played_jamtrack, user)) }
end
end
end

View File

@ -131,7 +131,7 @@ module JamAdmin
config.email_smtp_starttls_auto = true config.email_smtp_starttls_auto = true
config.verify_email_enabled = false config.verify_email_enabled = false
config.musician_count = '200,000+' config.musician_count = '300,000+'
config.facebook_app_id = ENV['FACEBOOK_APP_ID'] || '468555793186398' config.facebook_app_id = ENV['FACEBOOK_APP_ID'] || '468555793186398'
config.facebook_app_secret = ENV['FACEBOOK_APP_SECRET'] || '546a5b253972f3e2e8b36d9a3dd5a06e' config.facebook_app_secret = ENV['FACEBOOK_APP_SECRET'] || '546a5b253972f3e2e8b36d9a3dd5a06e'

View File

@ -1,5 +0,0 @@
<atlassian-ide-plugin>
<project-configuration id="1">
<servers id="2" />
</project-configuration>
</atlassian-ide-plugin>

2
build
View File

@ -61,7 +61,7 @@ if [ ! -z "$PACKAGE" ]; then
GEM_SERVER=http://localhost:9000/gems GEM_SERVER=http://localhost:9000/gems
# if still going, then push all debs up # if still going, then push all debs up
if [[ "$GIT_BRANCH" == *develop* || "$GIT_BRANCH" == *master* || "$GIT_BRANCH" == *release* || "$GIT_BRANCH" == *feature* || "$GIT_BRANCH" == *hotfix* ]]; then if [[ "$GIT_BRANCH" == *develop* || "$GIT_BRANCH" == *master* || "$GIT_BRANCH" == *release* || "$GIT_BRANCH" == *feature* || "$GIT_BRANCH" == *hotfix* || "$GIT_BRANCH" == *promised_based_api_interation* ]]; then
echo "" echo ""
echo "PUSHING WEB" echo "PUSHING WEB"

View File

@ -1,4 +1,4 @@
HOST=beta.jamkazam.com HOST=www.jamkazam.com
PORT=4000 PORT=4000
REACT_APP_ORIGIN=jamkazam.com REACT_APP_ORIGIN=jamkazam.com
REACT_APP_LEGACY_BASE_URL=https://www.jamkazam.com REACT_APP_LEGACY_BASE_URL=https://www.jamkazam.com

View File

@ -0,0 +1,161 @@
import React, { useRef, useState, useEffect } from 'react';
import { Form, FormGroup, Input, Label, Card, CardBody, Button, Row, Col } from 'reactstrap';
import FalconCardHeader from '../common/FalconCardHeader';
import JKTooltip from '../common/JKTooltip';
import { useTranslation } from 'react-i18next';
import { useAuth } from '../../context/UserAuth';
import JKFriendsAutoComplete from '../people/JKFriendsAutoComplete';
import JKSessionInviteesChips from '../people/JKSessionInviteesChips';
import { getFriends } from '../../helpers/rest';
const JKNewMusicSession = () => {
const { currentUser } = useAuth();
const { t } = useTranslation();
const [friends, setFriends] = useState([]);
const [isFriendsFetched, setIsFriendsFetched] = useState(false)
const [description, setDescription] = useState("")
const [invitees, setInvitees] = useState([]);
const [privacy, setPrivacy] = useState("1");
useEffect(() => {
fetchFriends();
}, []);
useEffect(() => {
if(isFriendsFetched){
populateFormDataFromLocalStorage()
}
}, [isFriendsFetched])
const fetchFriends = () => {
getFriends(currentUser.id)
.then(resp => {
if (resp.ok) {
return resp.json();
}
})
.then(data => {
console.log('friends = ', data)
setFriends(data);
setIsFriendsFetched(true);
});
}
const populateFormDataFromLocalStorage = () => {
try {
const formData = localStorage.getItem('formData');
if(formData){
const formDataItems = JSON.parse(formData);
setDescription(formDataItems['description']);
setPrivacy(formDataItems['privacy']);
const inviteeIds = formDataItems['inviteeIds'];
const invitees = friends.filter(f => inviteeIds.includes(f.id));
updateSessionInvitations(invitees);
}
} catch (error) {
console.error('localStorage is not available', error)
}
}
const handleSubmit = event => {
event.preventDefault();
const formData = new FormData(event.target);
const payload = {
privacy: formData.get('privacy'),
description: formData.get('description'),
inviteeIds: invitees.map(i => i.id)
};
console.log(payload); //TODO: handle payload
try {
//store this payload in localstorage.
localStorage.setItem('formData', JSON.stringify(payload))
} catch (error) {
console.error("localStorage is not available", error);
}
//if JamKazam application is not upload on the local computer
//Show a modal dialog for the user
//TODO: need a new backend api to start the session with the formdata
};
const handleOnSelect = submittedItems => {
updateSessionInvitations(submittedItems)
};
const updateSessionInvitations = (submittedInvitees) => {
const updatedInvitees = Array.from(new Set([...invitees, ...submittedInvitees]));
setInvitees(updatedInvitees);
const friendIds = submittedInvitees.map(si => si.id)
const updatedFriends = friends.filter(f => !friendIds.includes(f.id));
setFriends(updatedFriends);
}
const removeInvitee = invitee => {
const updatedInvitees = invitees.filter(i => i.id !== invitee.id);
setInvitees(updatedInvitees);
const updatedFriends = [...friends, invitee];
setFriends(updatedFriends);
};
return (
<div>
<Card>
<FalconCardHeader title={t('new.page_title', { ns: 'sessions' })} titleClass="font-weight-bold" />
<CardBody className="pt-0">
<Row>
<Col>
<Form onSubmit={handleSubmit}>
<FormGroup className="mb-3">
<Label>
{t('new.privacy', { ns: 'sessions' })}{' '}
<JKTooltip title={t('new.privacy_help', { ns: 'sessions' })} />
</Label>
<Input type="select" aria-label="Session Privacy" name="privacy" value={privacy} onChange={(e) => setPrivacy(e.target.value)} data-testid="session-privacy">
<option value="1">{t('new.privacy_opt_public', { ns: 'sessions' })}</option>
<option value="2">{t('new.privacy_opt_private_invite', { ns: 'sessions' })}</option>
<option value="3">{t('new.privacy_opt_private_approve', { ns: 'sessions' })}</option>
</Input>
</FormGroup>
<FormGroup className="mb-3">
<Label>
{t('new.invitations', { ns: 'sessions' })}{' '}
<JKTooltip title={t('new.invitations_help', { ns: 'sessions' })} />
</Label>
<JKFriendsAutoComplete friends={friends} onSelect={handleOnSelect} />
{ invitees.length > 0 &&
<JKSessionInviteesChips invitees={invitees} removeInvitee={removeInvitee} />
}
</FormGroup>
<FormGroup className="mb-3">
<Label>
{t('new.description', { ns: 'sessions' })}{' '}
<JKTooltip title={t('new.description_help', { ns: 'sessions' })} />
</Label>
<Input
value={description}
onChange={(e) => setDescription(e.target.value)}
name="description"
type="textarea"
data-testid="session-description"
placeholder={t('new.description_placeholder', { ns: 'sessions' })}
/>
</FormGroup>
<FormGroup className="mb-3">
<Button color="primary" data-testid="btn-create-session">{t('new.create_session', { ns: 'sessions' })}</Button>
</FormGroup>
</Form>
</Col>
<Col />
</Row>
</CardBody>
</Card>
</div>
);
};
export default JKNewMusicSession;

View File

@ -0,0 +1,98 @@
/**
* meta_tracking.js
* A standalone module to capture and persist Meta attribution signals (fbclid, _fbp) in cookies.
*
* Logic adapted from web/app/assets/javascripts/meta_tracking.js for React environment.
* - Checks URL for `fbclid` and sets `_fbc` cookie.
* - Checks for `_fbp` cookie; if missing, generates and sets it.
*/
const MetaTracking = {
init: function () {
const location = window.location;
this.handleFbc(location.search);
this.handleUtm(location.search);
this.handleFbp();
},
// 1. Parsing and storing _fbc (Click ID)
handleFbc: function (searchParams) {
const fbclid = this.getQueryParam('fbclid', searchParams);
if (fbclid) {
const version = 'fb';
const subdomainIndex = 1; // 1 = example.com
const creationTime = new Date().getTime(); // Unix timestamp in ms
// Format: fb.1.timestamp.id
const fbcValue = `${version}.${subdomainIndex}.${creationTime}.${fbclid}`;
this.setCookie('_fbc', fbcValue, 90);
}
},
handleUtm: function (searchParams) {
if (!searchParams) return;
const query = searchParams.substring(1);
const vars = query.split('&');
vars.forEach(v => {
const pair = v.split('=');
if (pair.length === 2) {
const key = decodeURIComponent(pair[0]);
const value = decodeURIComponent(pair[1]);
if (key.indexOf('utm_') === 0) {
this.setCookie(key, value, 90);
}
}
});
},
// 2. Handling _fbp (Browser ID)
handleFbp: function () {
if (!this.getCookie('_fbp')) {
const version = 'fb';
const subdomainIndex = 1;
const creationTime = new Date().getTime();
const randomInt = Math.floor(Math.random() * 10000000000); // 10-digit random number
// Format: fb.1.timestamp.randomDigits
const fbpValue = `${version}.${subdomainIndex}.${creationTime}.${randomInt}`;
this.setCookie('_fbp', fbpValue, 90);
}
},
// Helper: Get query param by name
getQueryParam: function (name, search) {
name = name.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]');
const regex = new RegExp('[\\?&]' + name + '=([^&#]*)');
const results = regex.exec(search);
return results === null ? '' : decodeURIComponent(results[1].replace(/\+/g, ' '));
},
// Helper: Set cookie
setCookie: function (name, value, days) {
let expires = "";
if (days) {
const date = new Date();
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
expires = "; expires=" + date.toUTCString();
}
// Ensure path is root and domain is included if needed (defaults to current host)
document.cookie = name + "=" + (value || "") + expires + "; path=/";
},
// Helper: Get cookie
getCookie: function (name) {
const nameEQ = name + "=";
const ca = document.cookie.split(';');
for (let i = 0; i < ca.length; i++) {
let c = ca[i];
while (c.charAt(0) === ' ') c = c.substring(1, c.length);
if (c.indexOf(nameEQ) === 0) return c.substring(nameEQ.length, c.length);
}
return null;
}
};
export default MetaTracking;

View File

@ -1,4 +1,4 @@
import React, {useEffect} from 'react'; import React, { useEffect } from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'; import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import { toast, ToastContainer } from 'react-toastify'; import { toast, ToastContainer } from 'react-toastify';
import { CloseButton, Fade } from '../components/common/Toast'; import { CloseButton, Fade } from '../components/common/Toast';
@ -8,11 +8,13 @@ import ErrorLayout from './ErrorLayout';
import BuildMeta from "./JKBuildMeta"; import BuildMeta from "./JKBuildMeta";
import loadable from '@loadable/component'; import loadable from '@loadable/component';
import MetaTracking from "../helpers/MetaTracking";
const AuthBasicLayout = loadable(() => import('./JKAuthBasicLayout')); const AuthBasicLayout = loadable(() => import('./JKAuthBasicLayout'));
const Layout = () => { const Layout = () => {
useEffect(() => { useEffect(() => {
AuthBasicLayout.preload(); AuthBasicLayout.preload();
MetaTracking.init();
}, []); }, []);
return ( return (

View File

@ -210,8 +210,8 @@ end
def jk_select(text, select) def jk_select(text, select)
# the approach here is to find the hidden select element, and work way back up to the elements that need to be interacted with # the approach here is to find the hidden select element, and work way back up to the elements that need to be interacted with
find(select, :visible => false).find(:xpath, 'ancestor::div[contains(@class, "dropdown easydropdown")]').trigger(:click) find(select, :visible => false).find(:xpath, 'ancestor::div[contains(@class, "dropdown easydropdown")]').click()
find(select, :visible => false).find(:xpath, 'ancestor::div[contains(@class, "dropdown-wrapper") and contains(@class, "easydropdown-wrapper") and contains(@class, "open")]').find('li', text: text).trigger(:click) find(select, :visible => false).find(:xpath, 'ancestor::div[contains(@class, "dropdown-wrapper") and contains(@class, "easydropdown-wrapper") and contains(@class, "open")]').find('span', text: text).click()
# works, but is 'cheating' because of visible = false # works, but is 'cheating' because of visible = false
#select(genre, :from => 'genres', :visible => false) #select(genre, :from => 'genres', :visible => false)

View File

@ -13,4 +13,4 @@ RUBY VERSION
ruby 2.4.1p111 ruby 2.4.1p111
BUNDLED WITH BUNDLED WITH
1.17.3 2.3.17

View File

@ -8,6 +8,8 @@ RUBY_OUT=$TARGET/ruby
command -v "bundle" || { echo >&2 "bundle is required but not installed. Skipping ruby protocol buffers."; exit 0; } command -v "bundle" || { echo >&2 "bundle is required but not installed. Skipping ruby protocol buffers."; exit 0; }
# creates a bin folder with 'rprotoc' command inside # creates a bin folder with 'rprotoc' command inside
#echo "skipping creation of binstubs as it breaks bin/ruby-protoc invocation below"
rm Gemfile.lock
bundle install --binstubs bundle install --binstubs
# die on error at this point # die on error at this point

View File

@ -184,7 +184,7 @@ CREATE FUNCTION public.discard_scores(keep integer) RETURNS void
CREATE FUNCTION public.generate_scores_dataset() RETURNS void CREATE FUNCTION public.generate_scores_dataset() RETURNS void
LANGUAGE plpgsql STRICT LANGUAGE plpgsql STRICT
AS $$ BEGIN delete from GeoIPLocations; insert into GeoIPLocations (locId, countryCode, region, city, postalCode, latitude, longitude, metroCode, areaCode) values (17192,'US','TX','Austin','78749',30.2076,-97.8587,635,'512'), (667,'US','TX','Dallas','75207',32.7825,-96.8207,623,'214'), (30350,'US','TX','Houston','77001',29.7633,-95.3633,618,'713'), (31423,'US','CO','Denver','80201',39.7392,-104.9847,751,'303'), (1807,'US','TX','San Antonio','78201',29.4713,-98.5353,641,'210'), (23565,'US','FL','Miami','33101',25.7743,-80.1937,528,'305'), (11704,'US','FL','Tampa','33601',27.9475,-82.4584,539,'813'), (26424,'US','MA','Boston','02101',42.3584,-71.0598,506,'617'), (5059,'US','ME','Portland','04101',43.6589,-70.2615,500,'207'), (2739,'US','OR','Portland','97201',45.5073,-122.6932,820,'503'), (1539,'US','WA','Seattle','98101',47.6103,-122.3341,819,'206'), (2720,'US','CA','Mountain View','94040',37.3845,-122.0881,807,'650'), (154078,'US','AR','Mountain View','72560',35.8732,-92.0717,693,'870'), (3964,'US','CA','Barstow','92311',34.9701,-116.9929,803,'760'), (14447,'US','OK','Tulsa','74101',36.154,-95.9928,671,'918'), (162129,'US','TN','Memphis','37501',35.1693,-89.9904,640,'713'); delete from GeoIPBlocks; insert into GeoIPBlocks (beginIp, endIp, locId) values (x'00000000'::bigint,x'0FFFFFFF'::bigint,17192), (x'10000000'::bigint,x'1FFFFFFF'::bigint,667), (x'20000000'::bigint,x'2FFFFFFF'::bigint,30350), (x'30000000'::bigint,x'3FFFFFFF'::bigint,31423), (x'40000000'::bigint,x'4FFFFFFF'::bigint,1807), (x'50000000'::bigint,x'5FFFFFFF'::bigint,23565), (x'60000000'::bigint,x'6FFFFFFF'::bigint,11704), (x'70000000'::bigint,x'7FFFFFFF'::bigint,26424), (x'80000000'::bigint,x'8FFFFFFF'::bigint,5059), (x'90000000'::bigint,x'9FFFFFFF'::bigint,2739), (x'A0000000'::bigint,x'AFFFFFFF'::bigint,1539), (x'B0000000'::bigint,x'BFFFFFFF'::bigint,2720), (x'C0000000'::bigint,x'CFFFFFFF'::bigint,154078), (x'D0000000'::bigint,x'DFFFFFFF'::bigint,3964), (x'E0000000'::bigint,x'EFFFFFFF'::bigint,14447), (x'F0000000'::bigint,x'FFFEFFFF'::bigint,162129); delete from GeoIPISP; insert into GeoIPISP values (x'00000000'::bigint,x'0FFFFFFF'::bigint,'Intergalactic Boogie'), (x'10000000'::bigint,x'1FFFFFFF'::bigint,'Powerful Pipes'), (x'20000000'::bigint,x'2FFFFFFF'::bigint,'Powerful Pipes'), (x'30000000'::bigint,x'3FFFFFFF'::bigint,'Intergalactic Boogie'), (x'40000000'::bigint,x'4FFFFFFF'::bigint,'Tangled Webs'), (x'50000000'::bigint,x'5FFFFFFF'::bigint,'Tangled Webs'), (x'60000000'::bigint,x'6FFFFFFF'::bigint,'Powerful Pipes'), (x'70000000'::bigint,x'7FFFFFFF'::bigint,'Intergalactic Boogie'), (x'80000000'::bigint,x'8FFFFFFF'::bigint,'Greasy Lightning'), (x'90000000'::bigint,x'9FFFFFFF'::bigint,'Powerful Pipes'), (x'A0000000'::bigint,x'AFFFFFFF'::bigint,'Intergalactic Boogie'), (x'B0000000'::bigint,x'BFFFFFFF'::bigint,'Tangled Webs'), (x'C0000000'::bigint,x'CFFFFFFF'::bigint,'Greasy Lightning'), (x'D0000000'::bigint,x'DFFFFFFF'::bigint,'Tangled Webs'), (x'E0000000'::bigint,x'EFFFFFFF'::bigint,'Intergalactic Boogie'), (x'F0000000'::bigint,x'FFFEFFFF'::bigint,'Powerful Pipes'); DELETE FROM jamcompany; ALTER SEQUENCE jamcompany_coid_seq RESTART WITH 1; INSERT INTO jamcompany (company) SELECT DISTINCT company FROM geoipisp ORDER BY company; DELETE FROM jamisp; INSERT INTO jamisp (beginip, endip, coid) SELECT x.beginip, x.endip, y.coid FROM geoipisp x, jamcompany y WHERE x.company = y.company; IF EXISTS( SELECT * FROM information_schema.tables WHERE table_schema = 'public' AND table_name = 'cities') THEN DELETE FROM cities; INSERT INTO cities (city, region, countrycode) select distinct city, region, countrycode from geoiplocations where length(city) > 0 and length(countrycode) > 0; DELETE FROM regions; INSERT INTO regions (region, regionname, countrycode) select distinct region, region, countrycode from cities; DELETE FROM countries; INSERT INTO countries (countrycode, countryname) select distinct countrycode, countrycode from regions; END IF; RETURN; END; $$; AS $$ BEGIN delete from GeoIPLocations; insert into GeoIPLocations (locId, countryCode, region, city, postalCode, latitude, longitude, metroCode, areaCode) values (17192,'US','TX','Austin','78749',30.2076,-97.8587,635,'512'), (667,'US','TX','Dallas','75207',32.7825,-96.8207,623,'214'), (30350,'US','TX','Houston','77001',29.7633,-95.3633,618,'713'), (31423,'US','CO','Denver','80201',39.7392,-104.9847,751,'303'), (1807,'US','TX','San Antonio','78201',29.4713,-98.5353,641,'210'), (23565,'US','FL','Miami','33101',25.7743,-80.1937,528,'305'), (11704,'US','FL','Tampa','33601',27.9475,-82.4584,539,'813'), (26424,'US','MA','Boston','02101',42.3584,-71.0598,506,'617'), (5059,'US','ME','Portland','04101',43.6589,-70.2615,500,'207'), (2739,'US','OR','Portland','97201',45.5073,-122.6932,820,'503'), (1539,'US','WA','Seattle','98101',47.6103,-122.3341,819,'206'), (2720,'US','CA','Mountain View','94040',37.3845,-122.0881,807,'650'), (154078,'US','AR','Mountain View','72560',35.8732,-92.0717,693,'870'), (3964,'US','CA','Barstow','92311',34.9701,-116.9929,803,'760'), (14447,'US','OK','Tulsa','74101',36.154,-95.9928,671,'918'), (162129,'US','TN','Memphis','37501',35.1693,-89.9904,640,'713'); delete from GeoIPBlocks; insert into GeoIPBlocks (beginIp, endIp, locId) values (x'00000000'::bigint,x'0FFFFFFF'::bigint,17192), (x'10000000'::bigint,x'1FFFFFFF'::bigint,667), (x'20000000'::bigint,x'2FFFFFFF'::bigint,30350), (x'30000000'::bigint,x'3FFFFFFF'::bigint,31423), (x'40000000'::bigint,x'4FFFFFFF'::bigint,1807), (x'50000000'::bigint,x'5FFFFFFF'::bigint,23565), (x'60000000'::bigint,x'6FFFFFFF'::bigint,11704), (x'70000000'::bigint,x'7FFFFFFF'::bigint,26424), (x'80000000'::bigint,x'8FFFFFFF'::bigint,5059), (x'90000000'::bigint,x'9FFFFFFF'::bigint,2739), (x'A0000000'::bigint,x'AFFFFFFF'::bigint,1539), (x'B0000000'::bigint,x'BFFFFFFF'::bigint,2720), (x'C0000000'::bigint,x'CFFFFFFF'::bigint,154078), (x'D0000000'::bigint,x'DFFFFFFF'::bigint,3964), (x'E0000000'::bigint,x'EFFFFFFF'::bigint,14447), (x'F0000000'::bigint,x'FFFEFFFF'::bigint,162129); delete from GeoIPISP; insert into GeoIPISP values (x'00000000'::bigint,x'0FFFFFFF'::bigint,'Intergalactic Boogie'), (x'10000000'::bigint,x'1FFFFFFF'::bigint,'Powerful Pipes'), (x'20000000'::bigint,x'2FFFFFFF'::bigint,'Powerful Pipes'), (x'30000000'::bigint,x'3FFFFFFF'::bigint,'Intergalactic Boogie'), (x'40000000'::bigint,x'4FFFFFFF'::bigint,'Tangled Webs'), (x'50000000'::bigint,x'5FFFFFFF'::bigint,'Tangled Webs'), (x'60000000'::bigint,x'6FFFFFFF'::bigint,'Powerful Pipes'), (x'70000000'::bigint,x'7FFFFFFF'::bigint,'Intergalactic Boogie'), (x'80000000'::bigint,x'8FFFFFFF'::bigint,'Greasy Lightning'), (x'90000000'::bigint,x'9FFFFFFF'::bigint,'Powerful Pipes'), (x'A0000000'::bigint,x'AFFFFFFF'::bigint,'Intergalactic Boogie'), (x'B0000000'::bigint,x'BFFFFFFF'::bigint,'Tangled Webs'), (x'C0000000'::bigint,x'CFFFFFFF'::bigint,'Greasy Lightning'), (x'D0000000'::bigint,x'DFFFFFFF'::bigint,'Tangled Webs'), (x'E0000000'::bigint,x'EFFFFFFF'::bigint,'Intergalactic Boogie'), (x'F0000000'::bigint,x'FFFEFFFF'::bigint,'Powerful Pipes'); DELETE FROM jamcompany; ALTER SEQUENCE jamcompany_coid_seq RESTART WITH 1; INSERT INTO jamcompany (company) SELECT DISTINCT company FROM geoipisp ORDER BY company; DELETE FROM jamisp; INSERT INTO jamisp (beginip, endip, coid) SELECT x.beginip, x.endip, y.coid FROM geoipisp x, jamcompany y WHERE x.company = y.company; IF EXISTS( SELECT * FROM information_schema.tables WHERE table_schema = 'public' AND table_name = 'cities') THEN DELETE FROM cities; INSERT INTO cities (city, region, countrycode) select distinct city, region, countrycode from geoiplocations where length(city) > 0 and length(countrycode) > 0; DELETE FROM regions; INSERT INTO regions (region, regionname, countrycode) select distinct region, region, countrycode from cities; DELETE FROM countries; INSERT INTO countries (countrycode, countryname) select distinct countrycode, countrycode from regions; update countries set countryname='United States' where countrycode='US'; END IF; RETURN; END; $$;
-- --
@ -10279,7 +10279,7 @@ SELECT pg_catalog.setval('public.connections_client_id_int_seq', 1, false);
-- Data for Name: countries; Type: TABLE DATA; Schema: public; Owner: postgres -- Data for Name: countries; Type: TABLE DATA; Schema: public; Owner: postgres
-- --
INSERT INTO public.countries VALUES ('US', NULL); INSERT INTO public.countries VALUES ('US', 'United States');
-- --
@ -11019,17 +11019,17 @@ SELECT pg_catalog.setval('public.partner_key_sequence', 10000, false);
-- Data for Name: regions; Type: TABLE DATA; Schema: public; Owner: postgres -- Data for Name: regions; Type: TABLE DATA; Schema: public; Owner: postgres
-- --
INSERT INTO public.regions VALUES ('TN', NULL, 'US'); INSERT INTO public.regions VALUES ('TN', 'Tennessee', 'US');
INSERT INTO public.regions VALUES ('ME', NULL, 'US'); INSERT INTO public.regions VALUES ('ME', 'Maine', 'US');
INSERT INTO public.regions VALUES ('MA', NULL, 'US'); INSERT INTO public.regions VALUES ('MA', 'Massachusetts', 'US');
INSERT INTO public.regions VALUES ('TX', NULL, 'US'); INSERT INTO public.regions VALUES ('TX', 'Texas', 'US');
INSERT INTO public.regions VALUES ('OK', NULL, 'US'); INSERT INTO public.regions VALUES ('OK', 'Oklahoma', 'US');
INSERT INTO public.regions VALUES ('WA', NULL, 'US'); INSERT INTO public.regions VALUES ('WA', 'Washington', 'US');
INSERT INTO public.regions VALUES ('CO', NULL, 'US'); INSERT INTO public.regions VALUES ('CO', 'Colorado', 'US');
INSERT INTO public.regions VALUES ('CA', NULL, 'US'); INSERT INTO public.regions VALUES ('CA', 'California', 'US');
INSERT INTO public.regions VALUES ('AR', NULL, 'US'); INSERT INTO public.regions VALUES ('AR', 'Arkansas', 'US');
INSERT INTO public.regions VALUES ('FL', NULL, 'US'); INSERT INTO public.regions VALUES ('FL', 'Florida', 'US');
INSERT INTO public.regions VALUES ('OR', NULL, 'US'); INSERT INTO public.regions VALUES ('OR', 'Oregon', 'US');
-- --

View File

@ -0,0 +1,31 @@
class AddExtendedUtmToUsers < ActiveRecord::Migration[5.0]
def up
execute <<-SQL
ALTER TABLE users ADD COLUMN origin_id character varying;
ALTER TABLE users ADD COLUMN origin_term character varying;
ALTER TABLE users ADD COLUMN origin_content character varying;
CREATE INDEX index_users_on_origin_id ON users (origin_id);
CREATE INDEX index_users_on_origin_term ON users (origin_term);
CREATE INDEX index_users_on_origin_content ON users (origin_content);
CREATE INDEX index_users_on_origin_utm_source ON users (origin_utm_source);
CREATE INDEX index_users_on_origin_utm_medium ON users (origin_utm_medium);
SQL
end
def down
execute <<-SQL
DROP INDEX IF EXISTS index_users_on_origin_utm_medium;
DROP INDEX IF EXISTS index_users_on_origin_utm_source;
DROP INDEX IF EXISTS index_users_on_origin_content;
DROP INDEX IF EXISTS index_users_on_origin_term;
DROP INDEX IF EXISTS index_users_on_origin_id;
ALTER TABLE users DROP COLUMN IF EXISTS origin_content;
ALTER TABLE users DROP COLUMN IF EXISTS origin_term;
ALTER TABLE users DROP COLUMN IF EXISTS origin_id;
SQL
end
end

View File

@ -55,6 +55,7 @@ require "jam_ruby/lib/em_helper"
require "jam_ruby/lib/nav" require "jam_ruby/lib/nav"
require "jam_ruby/lib/html_sanitize" require "jam_ruby/lib/html_sanitize"
require "jam_ruby/lib/guitar_center" require "jam_ruby/lib/guitar_center"
require "jam_ruby/lib/capi_transmitter"
require "jam_ruby/subscription_definitions" require "jam_ruby/subscription_definitions"
require "jam_ruby/resque/resque_jam_error" require "jam_ruby/resque/resque_jam_error"
require "jam_ruby/resque/resque_hooks" require "jam_ruby/resque/resque_hooks"

View File

@ -478,6 +478,7 @@ SQL
end end
if tracks_changed if tracks_changed
music_session.active_music_session.tick_track_changes
Notification.send_tracks_changed(music_session.active_music_session) Notification.send_tracks_changed(music_session.active_music_session)
end end
@ -529,6 +530,7 @@ SQL
end end
if send_tracks_changed if send_tracks_changed
music_session.active_music_session.tick_track_changes
Notification.send_tracks_changed(music_session.active_music_session) Notification.send_tracks_changed(music_session.active_music_session)
end end
end end

View File

@ -32,5 +32,4 @@ INSERT INTO regions (region, countrycode) SELECT DISTINCT region, countrycode FR
DELETE FROM countries; DELETE FROM countries;
INSERT INTO countries (countrycode) SELECT DISTINCT countrycode FROM regions; INSERT INTO countries (countrycode) SELECT DISTINCT countrycode FROM regions;
VACUUM ANALYSE; VACUUM ANALYSE;

View File

@ -1875,9 +1875,9 @@ module JamRuby
mp3_48000 = File.join(tmp_dir, File.basename(basename, ".wav") + "-48000.mp3") mp3_48000 = File.join(tmp_dir, File.basename(basename, ".wav") + "-48000.mp3")
aac_48000 = File.join(tmp_dir, File.basename(basename, ".wav") + "-48000.aac") aac_48000 = File.join(tmp_dir, File.basename(basename, ".wav") + "-48000.aac")
`ffmpeg -i "#{wav_file}" -ar 48000 -ab 192k "#{mp3_48000}"` `#{APP_CONFIG.ffmpeg_path} -i "#{wav_file}" -ar 48000 -ab 192k "#{mp3_48000}"`
`ffmpeg -i "#{wav_file}" -c:a libfdk_aac -b:a 192k "#{aac_48000}"` `#{APP_CONFIG.ffmpeg_path} -i "#{wav_file}" -c:a libfdk_aac -b:a 192k "#{aac_48000}"`
# upload the new ogg files to s3 # upload the new ogg files to s3
@@log.debug("uploading mp3 48000 to #{mp3_48000_s3_path}") @@log.debug("uploading mp3 48000 to #{mp3_48000_s3_path}")
@ -1971,9 +1971,9 @@ module JamRuby
mp3_48000 = File.join(tmp_dir, File.basename(basename, ".wav") + "-48000.mp3") mp3_48000 = File.join(tmp_dir, File.basename(basename, ".wav") + "-48000.mp3")
aac_48000 = File.join(tmp_dir, File.basename(basename, ".wav") + "-48000.aac") aac_48000 = File.join(tmp_dir, File.basename(basename, ".wav") + "-48000.aac")
`ffmpeg -i "#{wav_file}" -ar 48000 -ab 192k "#{mp3_48000}"` `#{APP_CONFIG.ffmpeg_path} -i "#{wav_file}" -ar 48000 -ab 192k "#{mp3_48000}"`
`ffmpeg -i "#{wav_file}" -c:a libfdk_aac -b:a 192k "#{aac_48000}"` `#{APP_CONFIG.ffmpeg_path} -i "#{wav_file}" -c:a libfdk_aac -b:a 192k "#{aac_48000}"`
# upload the new ogg files to s3 # upload the new ogg files to s3
@@log.debug("uploading mp3 48000 to #{mp3_48000_s3_path}") @@log.debug("uploading mp3 48000 to #{mp3_48000_s3_path}")
@ -2710,7 +2710,7 @@ module JamRuby
click_wav = File.join(tmp_dir, 'Click.wav') click_wav = File.join(tmp_dir, 'Click.wav')
song_storage_manager.download(base_dir + '/Click.mp3', click_mp3) song_storage_manager.download(base_dir + '/Click.mp3', click_mp3)
`ffmpeg -i "#{click_mp3}" "#{click_wav}"` `#{APP_CONFIG.ffmpeg_path} -i "#{click_mp3}" "#{click_wav}"`
song_storage_manager.upload(base_dir + '/Click.wav', click_wav) song_storage_manager.upload(base_dir + '/Click.wav', click_wav)
importer.finish("success", nil) importer.finish("success", nil)
@ -3136,6 +3136,10 @@ module JamRuby
count = 0 count = 0
iterate_song_storage do |metadata, metalocation| iterate_song_storage do |metadata, metalocation|
if metadata[:original_artist] != "AC DC"
@@log.info("skipping #{metadata[:original_artist]}")
next
end
next if metadata.nil? && (is_tency_storage? || is_paris_storage?) next if metadata.nil? && (is_tency_storage? || is_paris_storage?)
importer = synchronize_from_meta(metalocation, options) importer = synchronize_from_meta(metalocation, options)

View File

@ -56,7 +56,7 @@ module JamRuby
part = jam_track_track.track_type == 'Click' ? 'ClickTrack' : jam_track_track.part part = jam_track_track.track_type == 'Click' ? 'ClickTrack' : jam_track_track.part
jam_file_opts << " -i #{Shellwords.escape("#{track_filename}+#{part}")}" jam_file_opts << " -i #{Shellwords.escape("#{track_filename}+#{part}")}"
end end
#puts "LS + " + `ls -la '#{tmp_dir}'` # puts "LS + " + `ls -la '#{tmp_dir}'`
sku=jam_track.id sku=jam_track.id
title=jam_track.name title=jam_track.name
@ -68,7 +68,7 @@ module JamRuby
step = bump_step(jam_track_right, step) step = bump_step(jam_track_right, step)
# From http://stackoverflow.com/questions/690151/getting-output-of-system-calls-in-ruby/5970819#5970819: # From http://stackoverflow.com/questions/690151/getting-output-of-system-calls-in-ruby/5970819#5970819:
cli = "python #{py_file} -D -k #{sku} -p #{Shellwords.escape(tmp_dir)}/pkey.pem -s #{Shellwords.escape(tmp_dir)}/skey.pem #{jam_file_opts} -o #{Shellwords.escape(output_jkz)} -t #{Shellwords.escape(title)} -V #{Shellwords.escape(version)}" cli = "python2 #{py_file} -D -k #{sku} -p #{Shellwords.escape(tmp_dir)}/pkey.pem -s #{Shellwords.escape(tmp_dir)}/skey.pem #{jam_file_opts} -o #{Shellwords.escape(output_jkz)} -t #{Shellwords.escape(title)} -V #{Shellwords.escape(version)}"
Open3.popen3(cli) do |stdin, stdout, stderr, wait_thr| Open3.popen3(cli) do |stdin, stdout, stderr, wait_thr|
pid = wait_thr.pid pid = wait_thr.pid
exit_status = wait_thr.value exit_status = wait_thr.value

View File

@ -34,7 +34,7 @@ module JamRuby
@@log.info "Executing python source in #{py_file}, outputting to #{output_json})" @@log.info "Executing python source in #{py_file}, outputting to #{output_json})"
# From http://stackoverflow.com/questions/690151/getting-output-of-system-calls-in-ruby/5970819#5970819: # From http://stackoverflow.com/questions/690151/getting-output-of-system-calls-in-ruby/5970819#5970819:
cli = "python #{py_file} -i '#{input_text}' -o '#{output_json}'" cli = "python2 #{py_file} -i '#{input_text}' -o '#{output_json}'"
Open3.popen3(cli) do |stdin, stdout, stderr, wait_thr| Open3.popen3(cli) do |stdin, stdout, stderr, wait_thr|
pid = wait_thr.pid pid = wait_thr.pid
exit_status = wait_thr.value exit_status = wait_thr.value

View File

@ -0,0 +1,81 @@
require 'net/http'
require 'uri'
require 'json'
class CapiTransmitter
def self.send_event(event_name, user, custom_data = {}, event_source_url = nil)
begin
pixel_id = APP_CONFIG.facebook_pixel_id
access_token = APP_CONFIG.facebook_access_token
if pixel_id.blank? || access_token.blank?
puts("CapiTransmitter: Missing Facebook Pixel ID or Access Token. Skipping event #{event_name}.")
return
end
# Construct the User Data object
user_data = {
# client_ip_address: user.current_sign_in_ip,
# client_user_agent: user.user_agent # Note: User model might not have user_agent stored directly, might need to pass it or rely on what's available
}
if !user.facebook_click_id.present? ||
!APP_CONFIG.facebook_ad_source.include?(user.origin_utm_source)
return
end
# Enhance user data with hashed PII if available
# Facebook requires SHA256 hashing for PII
# For now, we rely on click_id and browser_id as primary keys if available
user_data[:fbc] = user.facebook_click_id if user.facebook_click_id.present?
user_data[:fbp] = user.facebook_browser_id if user.facebook_browser_id.present?
# If we have email/phone, we should hash them. But for now, let's stick to the IDs.
# Ideally we should hash email if we have it.
if user.email.present?
user_data[:em] = Digest::SHA256.hexdigest(user.email.downcase)
end
payload = {
data: [
{
event_name: event_name,
event_time: Time.now.to_i,
action_source: "website",
user_data: user_data,
custom_data: custom_data,
event_source_url: event_source_url
}
]
}
url = URI.parse("https://graph.facebook.com/v19.0/#{pixel_id}/events?access_token=#{access_token}")
http = Net::HTTP.new(url.host, url.port)
if APP_CONFIG.facebook_conversion_api_tls == false
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
else
http.use_ssl = true
end
request = Net::HTTP::Post.new(url.request_uri)
request['Content-Type'] = 'application/json'
request.body = payload.to_json
response = http.request(request)
if response.code.to_i >= 400
puts("CapiTransmitter Error: #{response.code} - #{response.body}")
else
puts("CapiTransmitter Success: #{event_name} sent for User #{user.id}")
end
rescue => e
puts("CapiTransmitter Exception: #{e.message}")
puts(e.backtrace.join("\n"))
end
end
end

View File

@ -863,6 +863,10 @@ module JamRuby
self.save!(:validate => false) self.save!(:validate => false)
end end
def in_session?(user)
self.users.exists?(user.id)
end
def connected_participant_count def connected_participant_count
Connection.where(:music_session_id => self.id, Connection.where(:music_session_id => self.id,
:aasm_state => Connection::CONNECT_STATE.to_s, :aasm_state => Connection::CONNECT_STATE.to_s,

View File

@ -3,8 +3,17 @@ module JamRuby
DEFAULT_ENVIRONMENT = 'public' DEFAULT_ENVIRONMENT = 'public'
CLIENT_PREFIX = 'JamClient' CLIENT_PREFIX = 'JamClient'
CLIENT_PREFIX_MODERN = 'JamClientModern'
PRODUCTS = ["#{CLIENT_PREFIX}/Win32", "#{CLIENT_PREFIX}/MacOSX", "#{CLIENT_PREFIX}/JamBlaster", "#{CLIENT_PREFIX}/JamBlasterClient"] PRODUCTS = [
"#{CLIENT_PREFIX}/Win32",
"#{CLIENT_PREFIX}/MacOSX",
"#{CLIENT_PREFIX}/JamBlaster",
"#{CLIENT_PREFIX}/JamBlasterClient",
"#{CLIENT_PREFIX_MODERN}/Win32",
"#{CLIENT_PREFIX_MODERN}/MacOSX-Intel",
"#{CLIENT_PREFIX_MODERN}/MacOSX-M"
]
self.primary_key = 'id' self.primary_key = 'id'
attr_accessible :version, :uri, :sha1, :environment, :product, as: :admin attr_accessible :version, :uri, :sha1, :environment, :product, as: :admin
@ -34,8 +43,8 @@ module JamRuby
Notification.send_client_update(product, version, determine_url, size) Notification.send_client_update(product, version, determine_url, size)
end end
def self.find_client_by_os(os, environment=DEFAULT_ENVIRONMENT) def self.find_client_by_os(product, os, environment=DEFAULT_ENVIRONMENT)
ArtifactUpdate.find_by_product_and_environment("#{CLIENT_PREFIX}/#{os}", environment) ArtifactUpdate.find_by_product_and_environment("#{product}/#{os}", environment)
end end
def determine_url def determine_url

View File

@ -23,8 +23,11 @@ module JamRuby
validate :validate_photo_info validate :validate_photo_info
validate :require_at_least_one_genre, :unless => :skip_genre_validation validate :require_at_least_one_genre, :unless => :skip_genre_validation
validate :limit_max_genres validate :limit_max_genres
validates_numericality_of :hourly_rate, greater_than:0, less_than:100000, :if => :paid_gigs #validates_numericality_of :hourly_rate, greater_than:0, less_than:100000, :if => :paid_gigs, allow_blank: true
validates_numericality_of :gig_minimum, greater_than:0, less_than:200000, :if => :paid_gigs validates :hourly_rate, numericality: { greater_than:0, less_than:100000 }, :if => :paid_gigs
#validates_numericality_of :gig_minimum, greater_than:0, less_than:200000, :if => :paid_gigs, allow_blank: true
validates :gig_minimum, numericality: { greater_than:0, less_than:200000 }, :if => :paid_gigs
before_save :check_lat_lng before_save :check_lat_lng
before_save :check_website_url before_save :check_website_url

View File

@ -145,9 +145,10 @@ module JamRuby
end end
end end
if music_session.is_recording? #removing this check to allow users to join recording sessions
errors.add(:music_session, ValidationMessages::CANT_JOIN_RECORDING_SESSION) # if music_session.is_recording?
end # errors.add(:music_session, ValidationMessages::CANT_JOIN_RECORDING_SESSION)
# end
# same logic as Search.scope_schools_together_sessions # same logic as Search.scope_schools_together_sessions
if !self.user.is_platform_instructor if !self.user.is_platform_instructor

View File

@ -31,9 +31,12 @@ module JamRuby
target_user = params[:user] target_user = params[:user]
target_band = params[:band] target_band = params[:band]
# TODO: SPEED UP QUERY. CURRENTLY TAKES FOR EVER. # TODO: SPEED UP QUERY. CURRENTLY TAKES FOR EVER.
if target_user or target_band if Rails.application.config.targeted_feed_disabled
return { query: [], next_page: nil} if target_user or target_band
return { query: [], next_page: nil}
end
end end
#query = Feed.includes([:recording]).includes([:music_session]).limit(limit) #query = Feed.includes([:recording]).includes([:music_session]).limit(limit)

View File

@ -60,7 +60,7 @@ module JamRuby
end end
def verify_download_count def verify_download_count
if (self.download_count < 0 || self.download_count > MAX_JAM_TRACK_DOWNLOADS) && !@current_user.admin if (self.download_count < 0 || self.download_count > MAX_JAM_TRACK_DOWNLOADS) && !self.user.admin
errors.add(:download_count, "must be less than or equal to #{MAX_JAM_TRACK_DOWNLOADS}") errors.add(:download_count, "must be less than or equal to #{MAX_JAM_TRACK_DOWNLOADS}")
end end
end end

View File

@ -33,7 +33,7 @@ module JamRuby
dependent: :destroy dependent: :destroy
validate :not_already_recording, :on => :create validate :not_already_recording, :on => :create
validate :not_still_finalizing_previous, :on => :create #validate :not_still_finalizing_previous, :on => :create
validate :not_playback_recording, :on => :create validate :not_playback_recording, :on => :create
validate :already_stopped_recording validate :already_stopped_recording
validate :only_one_mix validate :only_one_mix
@ -75,6 +75,10 @@ module JamRuby
has_stream_mix has_stream_mix
end end
def can_stop?(user)
# only allow the starting-user to create (ideally, perhaps, only the client that did it)
user == owner
end
# this should be a has-one relationship. until this, this is easiest way to get from recording > mix # this should be a has-one relationship. until this, this is easiest way to get from recording > mix
def mix def mix
self.mixes[0] if self.mixes.length > 0 self.mixes[0] if self.mixes.length > 0
@ -214,7 +218,7 @@ module JamRuby
def has_access?(user) def has_access?(user)
return false if user.nil? return false if user.nil?
users.exists?(user.id) || attached_with_lesson(user) #|| plays.where("player_id=?", user).count != 0 users.exists?(user.id) || attached_with_lesson(user) || (music_session && music_session.in_session?(user))
end end
def attached_with_lesson(user) def attached_with_lesson(user)

View File

@ -75,7 +75,7 @@ module JamRuby
rel = case params[SEARCH_TEXT_TYPE_ID].to_s rel = case params[SEARCH_TEXT_TYPE_ID].to_s
when 'bands' when 'bands'
@search_type = :bands @search_type = :bands
Band.where(nil) Band.where(nil).joins(:users)
when 'fans' when 'fans'
@search_type = :fans @search_type = :fans
User.fans.not_deleted User.fans.not_deleted
@ -83,8 +83,13 @@ module JamRuby
@search_type = :musicians @search_type = :musicians
User.musicians.not_deleted User.musicians.not_deleted
end end
if @search_type == :bands
@results = rel.where("(bands.name_tsv @@ to_tsquery('jamenglish', ?))", tsquery)
else
@results = rel.where("(users.name_tsv @@ to_tsquery('jamenglish', ?))", tsquery)
end
@results = @results.limit(40)
@results = rel.where("(name_tsv @@ to_tsquery('jamenglish', ?))", tsquery).limit(10)
@results = Search.scope_schools_together(@results, user) @results = Search.scope_schools_together(@results, user)
end end

View File

@ -21,6 +21,7 @@ module JamRuby
JAM_REASON_JOIN = 'j' JAM_REASON_JOIN = 'j'
JAM_REASON_IMPORT = 'i' JAM_REASON_IMPORT = 'i'
JAM_REASON_LOGIN = 'l' JAM_REASON_LOGIN = 'l'
JAM_REASON_PRESENT = 'p'
# MOD KEYS # MOD KEYS
MOD_GEAR = "gear" MOD_GEAR = "gear"
@ -72,7 +73,7 @@ module JamRuby
after_save :update_teacher_pct after_save :update_teacher_pct
attr_accessible :first_name, :last_name, :email, :city, :password, :password_confirmation, :state, :country, :birth_date, :subscribe_email, :terms_of_service, :original_fpfile, :cropped_fpfile, :cropped_large_fpfile, :cropped_s3_path, :cropped_large_s3_path, :photo_url, :large_photo_url, :crop_selection, :used_current_month, :used_month_play_time attr_accessible :first_name, :last_name, :email, :city, :password, :password_confirmation, :state, :country, :birth_date, :subscribe_email, :terms_of_service, :original_fpfile, :cropped_fpfile, :cropped_large_fpfile, :cropped_s3_path, :cropped_large_s3_path, :photo_url, :large_photo_url, :crop_selection, :used_current_month, :used_month_play_time, :facebook_click_id, :facebook_browser_id
# updating_password corresponds to a lost_password # updating_password corresponds to a lost_password
attr_accessor :test_drive_packaging, :validate_instruments, :updating_password, :updating_email, :updated_email, :update_email_confirmation_url, :administratively_created, :current_password, :setting_password, :confirm_current_password, :updating_avatar, :updating_progression_field, :mods_json, :expecting_gift_card, :purchase_required, :user_type attr_accessor :test_drive_packaging, :validate_instruments, :updating_password, :updating_email, :updated_email, :update_email_confirmation_url, :administratively_created, :current_password, :setting_password, :confirm_current_password, :updating_avatar, :updating_progression_field, :mods_json, :expecting_gift_card, :purchase_required, :user_type
@ -281,7 +282,7 @@ module JamRuby
validates :is_onboarder, :inclusion => {:in => [true, false, nil]} validates :is_onboarder, :inclusion => {:in => [true, false, nil]}
#validates :mods, json: true #validates :mods, json: true
validates_numericality_of :last_jam_audio_latency, greater_than: MINIMUM_AUDIO_LATENCY, less_than: MAXIMUM_AUDIO_LATENCY, :allow_nil => true validates_numericality_of :last_jam_audio_latency, greater_than: MINIMUM_AUDIO_LATENCY, less_than: MAXIMUM_AUDIO_LATENCY, :allow_nil => true
validates :last_jam_updated_reason, :inclusion => {:in => [nil, JAM_REASON_REGISTRATION, JAM_REASON_NETWORK_TEST, JAM_REASON_FTUE, JAM_REASON_JOIN, JAM_REASON_IMPORT, JAM_REASON_LOGIN]} validates :last_jam_updated_reason, :inclusion => {:in => [nil, JAM_REASON_REGISTRATION, JAM_REASON_NETWORK_TEST, JAM_REASON_FTUE, JAM_REASON_JOIN, JAM_REASON_IMPORT, JAM_REASON_LOGIN, JAM_REASON_PRESENT]}
# stored in cents # stored in cents
validates_numericality_of :paid_sessions_hourly_rate, greater_than: 0, less_than: 200000, :if => :paid_sessions validates_numericality_of :paid_sessions_hourly_rate, greater_than: 0, less_than: 200000, :if => :paid_sessions
@ -494,6 +495,23 @@ module JamRuby
@updating_progression_field = true @updating_progression_field = true
if self[field_name].nil? if self[field_name].nil?
self[field_name] = time self[field_name] = time
# CAPI Hooks
begin
case field_name.to_s
when 'first_ran_client_at'
# StartTrial: When user opens the app (progression field updated usually via API)
CapiTransmitter.send_event('StartTrial', self, { value: '0.00', currency: 'USD', predicted_ltv: '0.00' })
when 'first_certified_gear_at'
# AddToCart: When user completes gear setup
CapiTransmitter.send_event('AddToCart', self)
end
rescue => e
# Fail silently but log, don't break progression update
@@log.error("CAPI error in update_progression_field: #{field_name} #{e.message}")
puts("CAPI error in update_progression_field: #{field_name} #{e.message}")
end
self.save self.save
end end
end end
@ -1501,6 +1519,8 @@ module JamRuby
license_end = options[:license_end] license_end = options[:license_end]
import_source = options[:import_source] import_source = options[:import_source]
desired_plan_code = options[:desired_plan_code] desired_plan_code = options[:desired_plan_code]
facebook_click_id = options[:facebook_click_id]
facebook_browser_id = options[:facebook_browser_id]
if desired_plan_code == '' if desired_plan_code == ''
desired_plan_code = nil desired_plan_code = nil
@ -1567,11 +1587,17 @@ module JamRuby
user.origin_utm_source = origin["utm_source"] user.origin_utm_source = origin["utm_source"]
user.origin_utm_medium = origin["utm_medium"] user.origin_utm_medium = origin["utm_medium"]
user.origin_utm_campaign = origin["utm_campaign"] user.origin_utm_campaign = origin["utm_campaign"]
user.origin_id = origin["utm_id"]
user.origin_term = origin["utm_term"]
user.origin_content = origin["utm_content"]
user.origin_referrer = origin["referrer"] user.origin_referrer = origin["referrer"]
else else
user.origin_utm_source = 'organic' user.origin_utm_source = 'organic'
user.origin_utm_medium = 'organic' user.origin_utm_medium = 'organic'
user.origin_utm_campaign = nil user.origin_utm_campaign = nil
user.origin_id = nil
user.origin_term = nil
user.origin_content = nil
user.origin_referrer = nil user.origin_referrer = nil
end end
@ -1656,6 +1682,9 @@ module JamRuby
end end
end end
user.facebook_click_id = facebook_click_id
user.facebook_browser_id = facebook_browser_id
unless fb_signup.nil? unless fb_signup.nil?
user.update_fb_authorization(fb_signup) user.update_fb_authorization(fb_signup)
@ -1718,6 +1747,16 @@ module JamRuby
user.save user.save
# CAPI: CompleteRegistration
# Fire only if we have attribution data (click_id) indicating they came from FB
if user.persisted? && user.facebook_click_id.present?
begin
CapiTransmitter.send_event('CompleteRegistration', user)
rescue => e
@@log.error("CAPI CompleteRegistration error: #{e.message}")
end
end
# now that the user is saved, let's # now that the user is saved, let's
if invited_user && invited_user.autofriend && !invited_user.sender.nil? if invited_user && invited_user.autofriend && !invited_user.sender.nil?
# hookup this user with the sender # hookup this user with the sender

View File

@ -336,6 +336,33 @@ module JamRuby
end end
end end
def report_meta_capi(current_user, plan_code)
# CAPI Hook: Subscribe
begin
monthly_cost = case plan_code
when JamRuby::SubscriptionDefinitions::JAM_SILVER, JamRuby::SubscriptionDefinitions::JAM_SILVER_YEARLY
5.00
when JamRuby::SubscriptionDefinitions::JAM_GOLD, JamRuby::SubscriptionDefinitions::JAM_GOLD_YEARLY
10.00
when JamRuby::SubscriptionDefinitions::JAM_PLATINUM, JamRuby::SubscriptionDefinitions::JAM_PLATINUM_YEARLY
20.00
else
0.00
end
ltv = monthly_cost * 12
begin
puts "Sending CAPI Subscribe event #{current_user.email}, #{monthly_cost}, #{ltv}"
CapiTransmitter.send_event('Subscribe', current_user, { value: monthly_cost.to_s, currency: 'USD', predicted_ltv: ltv.to_s })
rescue => e
puts "Error sending CAPI Subscribe event #{current_user.email}, #{e.message}"
end
rescue => e
puts "Error sending CAPI Subscribe event #{current_user.email}, #{e.message}"
end
end
def get_highest_plan(subscription) def get_highest_plan(subscription)
SubscriptionDefinitions.higher_plan(subscription.plan.plan_code, get_pending_plan_code(subscription)) SubscriptionDefinitions.higher_plan(subscription.plan.plan_code, get_pending_plan_code(subscription))
end end
@ -364,6 +391,8 @@ module JamRuby
end end
current_user.reset_playtime current_user.reset_playtime
current_user.save(validate: false) current_user.save(validate: false)
report_meta_capi(current_user, plan_code)
rescue => e rescue => e
puts "Could not create subscription for user #{current_user.email}. #{e}" puts "Could not create subscription for user #{current_user.email}. #{e}"
return false, subscription, account return false, subscription, account
@ -704,7 +733,8 @@ module JamRuby
end end
if !recurly_token.nil? if !recurly_token.nil?
update_billing_info_from_token(current_user, account, recurly_token) puts "#{current_user.id} skipping double-update of billing of #{recurly_token} due to 2024 Oct Recurly Bug"
# update_billing_info_from_token(current_user, account, recurly_token)
end end
account account
end end

View File

@ -533,7 +533,11 @@ describe Recording do
@user.first_recording_at.should_not be_nil @user.first_recording_at.should_not be_nil
end end
describe "chance for everyone to keep or discard" do #NOTE: change in recording flow. Now after stopping the recording we no longer ask
#user to save or discard the recording, instead the app saves the recording to user's
#computer and opens the file explorer to that folder.
#therefore following scenario is no longer valid; hence skipping it.
xdescribe "chance for everyone to keep or discard" do
before(:each) do before(:each) do
@user2 = FactoryGirl.create(:user) @user2 = FactoryGirl.create(:user)
@connection2 = FactoryGirl.create(:connection, :user => @user2, :music_session => @music_session) @connection2 = FactoryGirl.create(:connection, :user => @user2, :music_session => @music_session)

View File

@ -82,6 +82,10 @@ def app_config
false false
end end
def targeted_feed_disabled
false
end
def audiomixer_path def audiomixer_path
# you can specify full path to audiomixer with AUDIOMIXER_PATH env variable... # you can specify full path to audiomixer with AUDIOMIXER_PATH env variable...
# or we check for audiomixer path in the user's workspace # or we check for audiomixer path in the user's workspace

View File

@ -554,6 +554,8 @@ GEM
rabl (0.13.1) rabl (0.13.1)
activesupport (>= 2.3.14) activesupport (>= 2.3.14)
rack (1.6.13) rack (1.6.13)
rack-cors (1.0.6)
rack (>= 1.6.0)
rack-oauth2 (1.12.0) rack-oauth2 (1.12.0)
activesupport activesupport
attr_required attr_required
@ -873,6 +875,7 @@ DEPENDENCIES
puma puma
quiet_assets quiet_assets
rabl (= 0.13.1) rabl (= 0.13.1)
rack-cors (~> 1.0, >= 1.0.6)
rack-test rack-test
rails (= 4.2.8) rails (= 4.2.8)
rails-assets-bluebird! rails-assets-bluebird!

View File

@ -1,7 +1,34 @@
Jasmine Javascript Unit Tests Jasmine Javascript Unit Tests
============================= =============================
Open browser to localhost:3000/teaspoon Open browser to localhost:3000/teaspoon
Test
##Custom URL Scheme handling
URLs starting as jamkazam:// are considered custom urls that can be used to open up / bring up the JK client program
and load a screen or call an internal function.
Let's say a user clicks or submits a from which in turns call a custom URL.
For example in the new react web interface, when a session is created using the form in https://www.jamkazam.com/sessions/new let's say it calls following custom URL
jamkazam://https//www.jamkazam.com/client#/createSession/custom~yes%7Cprivacy~2%7Cdescription~Testing%20session%20creation%20from%20beta%20website%7CinviteeIds~062deeba-b917-46e2-bfa3-e829405ca602
In the JK client this url is passed to the front end by the back end either by
1) onLoggedIn - This function is been called when the client is loaded (after user login). Used to handled the CustomUrl if the app is not already up and running
2) asyncJamClient 3012 event - If the app is up and running this event is fired with the CustomUrl
In either case the CustomUrl is stored in the localStorage and handled by the respective function being called.
Currently we have two customUrls
1) Session create by custom URL - call it using shell by
open "jamkazam://www.jamkazam.com/client#/createSession/custom~yes%7Cprivacy~2%7Cdescription~Testing%20session%20creation%20from%20beta%20website%7CinviteeIds~062deeba-b917-46e2-bfa3-e829405ca602"
2) Join to an existing session
open "jamkazam://www.jamkazam.com/client#/joinSession/custom~yes%7CsessionId~3190c211-f741-47d1-9171-05cf8df020d0"
Tets

View File

@ -27,8 +27,6 @@
"error" : 1 "error" : 1
} }
var logCache = [];
if ('undefined' === typeof(context.console)) { if ('undefined' === typeof(context.console)) {
context.console = {}; context.console = {};
$.each(console_methods, function(index, value) { $.each(console_methods, function(index, value) {
@ -62,11 +60,6 @@
logAsString.push("unable to parse node: " + e.toString()); logAsString.push("unable to parse node: " + e.toString());
} }
} }
logCache.push([method].concat(logAsString));
if(logCache.length > 50) {
// keep the cache size 50 or lower
logCache.shift();
}
if (original.apply){ if (original.apply){
// Do this for normal browsers // Do this for normal browsers
@ -92,7 +85,6 @@
takeOverConsole(); takeOverConsole();
context.JK.logger = context.console; context.JK.logger = context.console;
context.JK.logger.logCache = logCache;
})(window, jQuery); })(window, jQuery);

File diff suppressed because it is too large Load Diff

View File

@ -45,22 +45,24 @@
var invalidProfiles = prettyPrintAudioProfiles(context.JK.getBadConfigMap()); var invalidProfiles = prettyPrintAudioProfiles(context.JK.getBadConfigMap());
var sessionSummary = summarizeSession(userDetail); var sessionSummary = summarizeSession(userDetail);
if(gon.global.video_available && gon.global.video_available!="none" ) { // if(gon.global.video_available && gon.global.video_available!="none" ) {
var webcamName; // var webcamName;
var webcam = null; // var webcam = null;
if (context.jamClient.FTUECurrentSelectedVideoDevice) { // //if (context.jamClient.FTUECurrentSelectedVideoDevice) {
webcam = context.jamClient.FTUECurrentSelectedVideoDevice() // webcam = await context.jamClient.FTUECurrentSelectedVideoDevice()
} // //}
if (webcam == null || typeof(webcam) == "undefined" || Object.keys(webcam).length == 0) { // if (webcam == null || typeof(webcam) == "undefined" || Object.keys(webcam).length == 0) {
webcamName = "None Configured" // webcamName = "None Configured"
} else { // } else {
webcamName = _.values(webcam)[0] // webcamName = _.values(webcam)[0]
} // }
} // }
else { // else {
webcamName = 'video unavailable' // webcamName = 'video unavailable'
} // }
var webcamName = 'video available in session';
var $template = $(context._.template($('#template-account-main').html(), { var $template = $(context._.template($('#template-account-main').html(), {
email: userDetail.email, email: userDetail.email,

View File

@ -56,29 +56,31 @@
$root.find('a[data-purpose=reload-audio]').addClass('disabled') $root.find('a[data-purpose=reload-audio]').addClass('disabled')
$root.find('.rescanning-notice').show(); $root.find('.rescanning-notice').show();
}, },
function(canceled) { async function(canceled) {
$root.find('a[data-purpose=reload-audio]').removeClass('disabled') $root.find('a[data-purpose=reload-audio]').removeClass('disabled')
$root.find('.rescanning-notice').hide(); $root.find('.rescanning-notice').hide();
if(!canceled) { if(!canceled) {
var result = context.jamClient.ReloadAudioSystem(false, true, true); var result = await context.jamClient.ReloadAudioSystem(false, true, true);
} }
populateAccountAudio(); populateAccountAudio();
}); });
} }
function onUsbDeviceConnected() { async function onUsbDeviceConnected() {
if(showingGearWizard) { return; } // gear wizard also handles these events; unpredictable if both are rebuilding port audio if(showingGearWizard) { return; } // gear wizard also handles these events; unpredictable if both are rebuilding port audio
if(!context.jamClient.IsFrontendVisible()) {return;} // don't handle USB events when minimized var isFrontendVisible = await context.jamClient.IsFrontendVisible();
if(!isFrontendVisible) {return;} // don't handle USB events when minimized
logger.debug("USB device connected"); logger.debug("USB device connected");
scheduleRescanSystem(5000); scheduleRescanSystem(5000);
} }
function onUsbDeviceDisconnected() { async function onUsbDeviceDisconnected() {
if(showingGearWizard) { return; } // gear wizard also handles these events; unpredictable if both are rebuilding port audio if(showingGearWizard) { return; } // gear wizard also handles these events; unpredictable if both are rebuilding port audio
if(!context.jamClient.IsFrontendVisible()) {return;} // don't handle USB events when minimized var isFrontendVisible = await context.jamClient.IsFrontendVisible();
if(!isFrontendVisible) {return;} // don't handle USB events when minimized
logger.debug("USB device disconnected"); logger.debug("USB device disconnected");
@ -100,8 +102,8 @@
} }
} }
function populateAccountAudio() { async function populateAccountAudio() {
var profiles = gearUtils.getProfiles(); var profiles = await gearUtils.getProfiles();
context._.each(profiles, function(profile) { context._.each(profiles, function(profile) {
profile.active_text = profile.current ? '(active)' : ''; profile.active_text = profile.current ? '(active)' : '';
@ -111,14 +113,17 @@
// then you will have 'FTUE' (incomplete) profiles. This is the only time // then you will have 'FTUE' (incomplete) profiles. This is the only time
var cleansedProfiles = []; var cleansedProfiles = [];
context._.each(profiles, function(profile) { //context._.each(profiles, async function(profile) {
for (const profile of profiles) {
if(profile.id.indexOf('FTUE') == 0) { if(profile.id.indexOf('FTUE') == 0) {
context.jamClient.TrackDeleteProfile(profile.id); await context.jamClient.TrackDeleteProfile(profile.id);
} }
else { else {
cleansedProfiles.push(profile) cleansedProfiles.push(profile)
} }
}); }
//});
var template = context._.template($('#template-account-audio').html(), {is_admin: context.JK.currentUserAdmin, profiles: cleansedProfiles}, {variable: 'data'}); var template = context._.template($('#template-account-audio').html(), {is_admin: context.JK.currentUserAdmin, profiles: cleansedProfiles}, {variable: 'data'});
@ -134,19 +139,18 @@
function resetForm() { function resetForm() {
} }
function handleDeleteAudioProfile(audioProfileId) { async function handleDeleteAudioProfile(audioProfileId) {
logger.debug("deleting audio profile: " + audioProfileId); console.log("deleting audio profile: " + audioProfileId);
await context.jamClient.TrackDeleteProfile(audioProfileId, true);
context.jamClient.TrackDeleteProfile(audioProfileId);
// redraw after deletion of profile // redraw after deletion of profile
populateAccountAudio(); await populateAccountAudio();
} }
function handleLoopbackAudioProfile(audioProfileId) { async function handleLoopbackAudioProfile(audioProfileId) {
if(audioProfileId != context.jamClient.FTUEGetMusicProfileName()) { if(audioProfileId != await context.jamClient.FTUEGetMusicProfileName()) {
var result = context.jamClient.FTUELoadAudioConfiguration(audioProfileId); var result = await context.jamClient.FTUELoadAudioConfiguration(audioProfileId);
if(!result) { if(!result) {
logger.error("unable to activate audio configuration: " + audioProfileId); logger.error("unable to activate audio configuration: " + audioProfileId);
@ -154,14 +158,14 @@
} }
else { else {
// redraw after activation of profile // redraw after activation of profile
populateAccountAudio(); await populateAccountAudio();
} }
} }
app.layout.showDialog('loopback-wizard'); app.layout.showDialog('loopback-wizard');
} }
function handleConfigureAudioProfile(audioProfileId) { async function handleConfigureAudioProfile(audioProfileId) {
if(!gearUtils.canBeConfigured(audioProfileId)) { if(!gearUtils.canBeConfigured(audioProfileId)) {
@ -170,9 +174,9 @@
} }
if(audioProfileId == gearUtils.GearUtil) if(audioProfileId == gearUtils.GearUtil)
if(audioProfileId != context.jamClient.FTUEGetMusicProfileName()) { if(audioProfileId != await context.jamClient.FTUEGetMusicProfileName()) {
logger.debug("activating " + audioProfileId); logger.debug("activating " + audioProfileId);
var result = context.jamClient.FTUELoadAudioConfiguration(audioProfileId); var result = await context.jamClient.FTUELoadAudioConfiguration(audioProfileId);
if(!result) { if(!result) {
logger.error("unable to activate audio configuration: " + audioProfileId); logger.error("unable to activate audio configuration: " + audioProfileId);
@ -181,7 +185,7 @@
} }
// FTUELoadAudioConfiguration eventually sets this, but apparently asynchronously // FTUELoadAudioConfiguration eventually sets this, but apparently asynchronously
result = context.jamClient.SetLastUsedProfileName(audioProfileId); result = await context.jamClient.SetLastUsedProfileName(audioProfileId);
if(!result) { if(!result) {
logger.error("unable to activate audio configuration after loading it: " + audioProfileId); logger.error("unable to activate audio configuration after loading it: " + audioProfileId);
@ -190,22 +194,25 @@
} }
// redraw after activation of profile // redraw after activation of profile
populateAccountAudio(); await populateAccountAudio();
} }
app.layout.showDialog('configure-tracks') app.layout.showDialog('configure-tracks')
.one(EVENTS.DIALOG_CLOSED, populateAccountAudio) .one(EVENTS.DIALOG_CLOSED, async function(){
await populateAccountAudio()
})
} }
function handleActivateAudioProfile(audioProfileId) { async function handleActivateAudioProfile(audioProfileId) {
logger.debug("activating audio profile: " + audioProfileId); logger.debug("activating audio profile: " + audioProfileId);
if(audioProfileId == context.jamClient.LastUsedProfileName()) { if(audioProfileId == await context.jamClient.LastUsedProfileName()) {
context.JK.Banner.showAlert("This profile is already active."); context.JK.Banner.showAlert("This profile is already active.");
return; return;
} }
var result = context.jamClient.SetLastUsedProfileName(audioProfileId); var result = await context.jamClient.SetLastUsedProfileName(audioProfileId);
if(!result) { if(!result) {
logger.error("unable to activate audio configuration: " + audioProfileId); logger.error("unable to activate audio configuration: " + audioProfileId);
@ -213,48 +220,52 @@
} }
// redraw after activation of profile // redraw after activation of profile
populateAccountAudio(); await populateAccountAudio();
} }
function handleStartAudioQualification() { async function handleStartAudioQualification() {
app.afterFtue = function() { app.afterFtue = async function() {
showingGearWizard = false; showingGearWizard = false;
if(populateAccountAudio().length == 1) { if(await populateAccountAudio().length == 1) {
app.layout.showDialog('join-test-session'); app.layout.showDialog('join-test-session');
} }
}; };
app.cancelFtue = function() { showingGearWizard = false; populateAccountAudio() }; app.cancelFtue = async function() { showingGearWizard = false; await populateAccountAudio() };
showingGearWizard = true; showingGearWizard = true;
app.layout.startNewFtue() app.layout.startNewFtue()
} }
function reloadAudio() { async function reloadAudio() {
// false = don't start audio, true = reload last audio configuration, false = don't re-init tracks // false = don't start audio, true = reload last audio configuration, false = don't re-init tracks
context.jamClient.ReloadAudioSystem(false, true, false); await context.jamClient.ReloadAudioSystem(false, true, false);
populateAccountAudio(); await populateAccountAudio();
} }
function registerFtueSuccess() { function registerFtueSuccess() {
$('div[layout-id=ftue]').on("ftue_success", ftueSuccessHandler); $('div[layout-id=ftue]').on("ftue_success", async function(){
await ftueSuccessHandler()
});
} }
function unregisterFtueSuccess() { function unregisterFtueSuccess() {
$('div[layout-id=ftue]').off("ftue_success", ftueSuccessHandler); $('div[layout-id=ftue]').off("ftue_success", async function(){
await ftueSuccessHandler();
});
} }
function ftueSuccessHandler() { async function ftueSuccessHandler() {
populateAccountAudio(); await populateAccountAudio();
} }
// events for main screen // events for main screen
function events() { function events() {
// wire up main panel clicks // wire up main panel clicks
$root = $('#account-audio-content-scroller'); $root = $('#account-audio-content-scroller');
$root.on('click', 'a[data-purpose=delete-audio-profile]', function (evt) { $root.on('click', 'a[data-purpose=delete-audio-profile]', async function (evt) {
evt.stopPropagation(); evt.stopPropagation();
handleDeleteAudioProfile($(this).attr('data-id')); await handleDeleteAudioProfile($(this).attr('data-id'));
return false; return false;
}); });
@ -286,13 +297,13 @@
return false; return false;
}); });
$root.on('click', 'a[data-purpose=configure-audio-profile]', function (evt) { $root.on('click', 'a[data-purpose=configure-audio-profile]', async function (evt) {
evt.stopPropagation(); evt.stopPropagation();
var $btn = $(this); var $btn = $(this);
var status = $btn.closest('tr').attr('data-status'); var status = $btn.closest('tr').attr('data-status');
if(status == "good") { if(status == "good") {
cancelRescan(); cancelRescan();
handleConfigureAudioProfile($btn.attr('data-id')); await handleConfigureAudioProfile($btn.attr('data-id'));
} }
else { else {
context.JK.Banner.showAlert("Unable to configure this profile. Please verify that the devices associated are connected."); context.JK.Banner.showAlert("Unable to configure this profile. Please verify that the devices associated are connected.");
@ -301,10 +312,10 @@
}); });
$root.on('click', 'a[data-purpose=add-profile]', function (evt) { $root.on('click', 'a[data-purpose=add-profile]', async function (evt) {
evt.stopPropagation(); evt.stopPropagation();
cancelRescan(); cancelRescan();
handleStartAudioQualification(); await handleStartAudioQualification();
return false; return false;
}); });

View File

@ -57,49 +57,101 @@ context.JK.AccountJamTracks = class AccountJamTracks
@createSession(jamRow.data(), false, jamRow.data('jamTrack')) @createSession(jamRow.data(), false, jamRow.data('jamTrack'))
return false; return false;
createSession:(sessionData, solo, jamTrack) => # createSession:(sessionData, solo, jamTrack) =>
tracks = context.JK.TrackHelpers.getUserTracks(context.jamClient) # tracks = context.JK.TrackHelpers.getUserTracks(context.jamClient)
if (context.JK.guardAgainstBrowser(@app)) # if (context.JK.guardAgainstBrowser(@app))
data = {} # data = {}
data.client_id = @app.clientId # data.client_id = @app.clientId
#data.description = $('#description').val() # #data.description = $('#description').val()
data.description = "Jam Track Session" # data.description = "Jam Track Session"
data.as_musician = true # data.as_musician = true
data.legal_terms = true # data.legal_terms = true
data.intellectual_property = true # data.intellectual_property = true
data.approval_required = false # data.approval_required = false
data.musician_access = !solo # data.musician_access = !solo
data.fan_access = false # data.fan_access = false
data.fan_chat = false # data.fan_chat = false
data.genre = $.map(sessionData.jamTrack.genres, (genre) -> genre.id) # data.genre = $.map(sessionData.jamTrack.genres, (genre) -> genre.id)
data.genres = $.map(sessionData.jamTrack.genres, (genre)-> genre.id) # data.genres = $.map(sessionData.jamTrack.genres, (genre)-> genre.id)
# data.genres = context.JK.GenreSelectorHelper.getSelectedGenres('#create-session-genre') # # data.genres = context.JK.GenreSelectorHelper.getSelectedGenres('#create-session-genre')
# data.musician_access = if $('#musician-access option:selected').val() == 'true' then true else false # # data.musician_access = if $('#musician-access option:selected').val() == 'true' then true else false
# data.approval_required = if $('input[name=\'musician-access-option\']:checked').val() == 'true' then true else false # # data.approval_required = if $('input[name=\'musician-access-option\']:checked').val() == 'true' then true else false
# data.fan_access = if $('#fan-access option:selected').val() == 'true' then true else false # # data.fan_access = if $('#fan-access option:selected').val() == 'true' then true else false
# data.fan_chat = if $('input[name=\'fan-chat-option\']:checked').val() == 'true' then true else false # # data.fan_chat = if $('input[name=\'fan-chat-option\']:checked').val() == 'true' then true else false
# if $('#band-list option:selected').val() != '' # # if $('#band-list option:selected').val() != ''
# data.band = $('#band-list option:selected').val() # # data.band = $('#band-list option:selected').val()
data.audio_latency = context.jamClient.FTUEGetExpectedLatency().latency # data.audio_latency = context.jamClient.FTUEGetExpectedLatency().latency
data.tracks = tracks # data.tracks = tracks
rest.legacyCreateSession(data).done((response) => # rest.legacyCreateSession(data).done((response) =>
newSessionId = response.id # newSessionId = response.id
@sessionUtils.setAutoOpenJamTrack(jamTrack) # so that the session screen will pick this up # @sessionUtils.setAutoOpenJamTrack(jamTrack) # so that the session screen will pick this up
context.location = '/client#/session/' + newSessionId # context.location = '/client#/session/' + newSessionId
# Re-loading the session settings will cause the form to reset with the right stuff in it. # # Re-loading the session settings will cause the form to reset with the right stuff in it.
# This is an extra xhr call, but it keeps things to a single codepath # # This is an extra xhr call, but it keeps things to a single codepath
#loadSessionSettings() # #loadSessionSettings()
context.JK.GA.trackSessionCount data.musician_access, data.fan_access, 0 # context.JK.GA.trackSessionCount data.musician_access, data.fan_access, 0
context.JK.GA.trackSessionMusicians context.JK.GA.SessionCreationTypes.create # context.JK.GA.trackSessionMusicians context.JK.GA.SessionCreationTypes.create
).fail (jqXHR) => # ).fail (jqXHR) =>
handled = false # handled = false
if jqXHR.status = 422 # if jqXHR.status = 422
response = JSON.parse(jqXHR.responseText) # response = JSON.parse(jqXHR.responseText)
if response['errors'] and response['errors']['tracks'] and response['errors']['tracks'][0] == 'Please select at least one track' # if response['errors'] and response['errors']['tracks'] and response['errors']['tracks'][0] == 'Please select at least one track'
@app.notifyAlert 'No Inputs Configured', $('<span>You will need to reconfigure your audio device.</span>') # @app.notifyAlert 'No Inputs Configured', $('<span>You will need to reconfigure your audio device.</span>')
handled = true # handled = true
if !handled # if !handled
@app.notifyServerError jqXHR, 'Unable to Create Session' # @app.notifyServerError jqXHR, 'Unable to Create Session'
createSession: `async function(sessionData, solo, jamTrack){
const tracks = await context.JK.TrackHelpers.getUserTracks(context.jamClient);
if (context.JK.guardAgainstBrowser(this.app)) {
const data = {};
data.client_id = this.app.clientId;
//data.description = $('#description').val()
data.description = "Jam Track Session";
data.as_musician = true;
data.legal_terms = true;
data.intellectual_property = true;
data.approval_required = false;
data.musician_access = !solo;
data.fan_access = false;
data.fan_chat = false;
data.genre = $.map(sessionData.jamTrack.genres, genre => genre.id);
data.genres = $.map(sessionData.jamTrack.genres, genre => genre.id);
// data.genres = context.JK.GenreSelectorHelper.getSelectedGenres('#create-session-genre')
// data.musician_access = if $('#musician-access option:selected').val() == 'true' then true else false
// data.approval_required = if $('input[name=\'musician-access-option\']:checked').val() == 'true' then true else false
// data.fan_access = if $('#fan-access option:selected').val() == 'true' then true else false
// data.fan_chat = if $('input[name=\'fan-chat-option\']:checked').val() == 'true' then true else false
// if $('#band-list option:selected').val() != ''
// data.band = $('#band-list option:selected').val()
let expectedLatency = await context.jamClient.FTUEGetExpectedLatency()
data.audio_latency = expectedLatency.latency;
data.tracks = tracks;
return rest.legacyCreateSession(data).done(response => {
const newSessionId = response.id;
this.sessionUtils.setAutoOpenJamTrack(jamTrack); // so that the session screen will pick this up
context.location = '/client#/session/' + newSessionId;
// Re-loading the session settings will cause the form to reset with the right stuff in it.
// This is an extra xhr call, but it keeps things to a single codepath
//loadSessionSettings()
context.JK.GA.trackSessionCount(data.musician_access, data.fan_access, 0);
return context.JK.GA.trackSessionMusicians(context.JK.GA.SessionCreationTypes.create);
}).fail(jqXHR => {
let handled = false;
if (jqXHR.status = 422) {
const response = JSON.parse(jqXHR.responseText);
if (response['errors'] && response['errors']['tracks'] && (response['errors']['tracks'][0] === 'Please select at least one track')) {
this.app.notifyAlert('No Inputs Configured', $('<span>You will need to reconfigure your audio device.</span>'));
handled = true;
}
}
if (!handled) {
return this.app.notifyServerError(jqXHR, 'Unable to Create Session');
}
});
}
}`

View File

@ -74,22 +74,22 @@
track2AudioInputChannels = _loadList(ASSIGNMENT.TRACK2, true, false); track2AudioInputChannels = _loadList(ASSIGNMENT.TRACK2, true, false);
} }
function _loadList(assignment, input, chat) { async function _loadList(assignment, input, chat) {
var list = []; var list = [];
// get data needed for listboxes // get data needed for listboxes
var channels = context.jamClient.TrackGetChannels(); var channels = await context.jamClient.TrackGetChannels();
var musicDevices = context.jamClient.TrackGetMusicDeviceNames(input); var musicDevices = await context.jamClient.TrackGetMusicDeviceNames(input);
// SEE loadList function in TrackAssignGui.cpp of client code // SEE loadList function in TrackAssignGui.cpp of client code
$.each(channels, function(index, val) { $.each(channels, async function(index, val) {
if (input !== val.input) { if (input !== val.input) {
return; return;
} }
var currAssignment = context.jamClient.TrackGetAssignment(val.id, val.input); var currAssignment = await context.jamClient.TrackGetAssignment(val.id, val.input);
if (assignment !== currAssignment) { if (assignment !== currAssignment) {
return; return;
} }
@ -97,9 +97,9 @@
logger.debug("channel id=" + val.id + ", channel input=" + val.input + ", channel assignment=" + currAssignment + logger.debug("channel id=" + val.id + ", channel input=" + val.input + ", channel assignment=" + currAssignment +
", channel name=" + val.name + ", channel type=" + val.device_type + ", chat=" + val.chat); ", channel name=" + val.name + ", channel type=" + val.device_type + ", chat=" + val.chat);
var os = context.jamClient.GetOSAsString(); var os = await context.jamClient.GetOSAsString();
if (os === context.JK.OS.WIN32) { if (os === context.JK.OS.WIN32) {
if (chat && ($.inArray(val.device_id, musicDevices) > -1 || context.jamClient.TrackIsMusicDeviceType(val.device_type))) { if (chat && ($.inArray(val.device_id, musicDevices) > -1 || await context.jamClient.TrackIsMusicDeviceType(val.device_type))) {
return; return;
} }
} }
@ -137,13 +137,13 @@
app.layout.closeDialog('add-track'); app.layout.closeDialog('add-track');
} }
function saveTrack() { async function saveTrack() {
// TRACK 2 INPUTS // TRACK 2 INPUTS
var trackId = null; var trackId = null;
$("#add-track2-input > option").each(function() { $("#add-track2-input > option").each(async function() {
logger.debug("Saving track 2 input = " + this.value); logger.debug("Saving track 2 input = " + this.value);
trackId = this.value; trackId = this.value;
context.jamClient.TrackSetAssignment(this.value, true, ASSIGNMENT.TRACK2); await context.jamClient.TrackSetAssignment(this.value, true, ASSIGNMENT.TRACK2);
}); });
// TRACK 2 INSTRUMENT // TRACK 2 INSTRUMENT
@ -151,13 +151,13 @@
var instrumentText = $('#add-track2-instrument > option:selected').text().toLowerCase(); var instrumentText = $('#add-track2-instrument > option:selected').text().toLowerCase();
logger.debug("Saving track 2 instrument = " + instrumentVal); logger.debug("Saving track 2 instrument = " + instrumentVal);
context.jamClient.TrackSetInstrument(ASSIGNMENT.TRACK2, instrumentVal); await context.jamClient.TrackSetInstrument(ASSIGNMENT.TRACK2, instrumentVal);
// UPDATE SERVER // UPDATE SERVER
logger.debug("Adding track with instrument " + instrumentText); logger.debug("Adding track with instrument " + instrumentText);
var data = {}; var data = {};
context.jamClient.TrackSaveAssignments(); await context.jamClient.TrackSaveAssignments();
/** /**
setTimeout(function() { setTimeout(function() {

View File

@ -0,0 +1,716 @@
(function (context, $) {
"use strict";
context.JK = context.JK || {};
class Deferred {
constructor(request_id) {
var self = this;
this.request_id = request_id;
this.promise = new Promise(function (resolve, reject) {
self.reject = reject;
self.resolve = resolve;
});
}
}
context.JK.AsyncJamClient = function (app) {
const self = this;
const logger = context.JK.logger;
let deferredQueue = [];
let jkfrontendchannel = null;
let enumAppCounter = 1000;
let request_id = 1;
const JKFrontendMethods = Object.freeze({
UnknownJKAppMessage: enumAppCounter++,
AbortRecording: enumAppCounter++,
addUserBackingTracksToJamkazamAsset: enumAppCounter++,
applySubscriptionPolicy: enumAppCounter++,
BringVideoWindowToFront: enumAppCounter++,
browseForUserBackingTracksCandidate: enumAppCounter++,
cancelVideoUpload: enumAppCounter++,
clientID: enumAppCounter++,
ClientJoinedSession: enumAppCounter++,
ClientLeftSession: enumAppCounter++,
ClientUpdateStartDownload: enumAppCounter++,
ClientUpdateStartUpdate: enumAppCounter++,
ClientUpdateVersion: enumAppCounter++,
ClosePreviewRecording: enumAppCounter++,
CloseRecording: enumAppCounter++,
deleteVideo: enumAppCounter++,
DownloadFileStatus: enumAppCounter++,
endPairing: enumAppCounter++,
FTUEAudioResync: enumAppCounter++,
FTUECancel: enumAppCounter++,
FTUEChatFrameSize: enumAppCounter++,
FTUEClearChannelAssignments: enumAppCounter++,
FTUEClearChatInput: enumAppCounter++,
FTUECreateUpdatePlayBackProfile: enumAppCounter++,
FTUECurrentSelectedVideoDevice: enumAppCounter++,
FTUEGetAllAudioConfigurations: enumAppCounter++,
FTUEGetAllConfigurationList: enumAppCounter++,
FTUEGetAudioConfigurationsMissingDevice: enumAppCounter++,
FTUEGetAudioDevices: enumAppCounter++,
FTUEGetAutoSelectVideoLayout: enumAppCounter++,
FTUEGetAvailableEncodeVideoResolutions: enumAppCounter++,
FTUEGetAvailableVideoLayoutGroupStyles: enumAppCounter++,
FTUEGetBadConfigurationMissingDev: enumAppCounter++,
FTUEGetCaptureResolution: enumAppCounter++,
FTUEGetChannels: enumAppCounter++,
FTUEGetChatInputs: enumAppCounter++,
FTUEGetChatInputVolume: enumAppCounter++,
FTUEGetChatLatency: enumAppCounter++,
FTUEGetConfigurationDevice: enumAppCounter++,
FTUEGetConfigurationDevs: enumAppCounter++,
FTUEGetCurrentCaptureResolution: enumAppCounter++,
FTUEGetCurrentVideoCaptureDeviceCapability: enumAppCounter++,
FTUEGetDefaultAudioConfigurations: enumAppCounter++,
FTUEGetDevices: enumAppCounter++,
FTUEGetExpectedLatency: enumAppCounter++,
FTUEGetFrameSize: enumAppCounter++,
FTUEGetGoodAudioConfigurations: enumAppCounter++,
FTUEGetGoodConfigurationList: enumAppCounter++,
FTUEgetInputDeviceSampleRate: enumAppCounter++,
FTUEGetInputLatency: enumAppCounter++,
FTUEGetInputMusicDevice: enumAppCounter++,
FTUEGetInputVolume: enumAppCounter++,
FTUEGetIoPerfData: enumAppCounter++,
FTUEGetMapUserCntPreferredVideoLayoutGroupStyle: enumAppCounter++,
FTUEGetMusicInputs: enumAppCounter++,
FTUEGetMusicOutputs: enumAppCounter++,
FTUEGetMusicProfileName: enumAppCounter++,
FTUEgetOutputDeviceSampleRate: enumAppCounter++,
FTUEGetOutputLatency: enumAppCounter++,
FTUEGetOutputMusicDevice: enumAppCounter++,
FTUEGetOutputVolume: enumAppCounter++,
FTUEGetPreferredChatSampleRate: enumAppCounter++,
FTUEGetPreferredMixerSampleRate: enumAppCounter++,
FTUEGetPreferredOutputSampleRate: enumAppCounter++,
FTUEGetSendFrameRates: enumAppCounter++,
FTUEGetStatus: enumAppCounter++,
FTUEGetUserCountPreferredVideoLayoutGroupStyle: enumAppCounter++,
FTUEGetVideoCaptureDeviceCapabilities: enumAppCounter++,
FTUEGetVideoCaptureDeviceNames: enumAppCounter++,
FTUEGetVideoShareEnable: enumAppCounter++,
FTUEGetVolumeRanges: enumAppCounter++,
FTUEHasControlPanel: enumAppCounter++,
FTUEInit: enumAppCounter++,
FTUEIsMusicDeviceWDM: enumAppCounter++,
FTUELoadAudioConfiguration: enumAppCounter++,
FTUEOpenControlPanel: enumAppCounter++,
FTUEPageEnter: enumAppCounter++,
FTUEPageLeave: enumAppCounter++,
FTUERefreshDevices: enumAppCounter++,
FTUERegisterLatencyCallback: enumAppCounter++,
FTUERegisterVUCallbacks: enumAppCounter++,
FTUESave: enumAppCounter++,
FTUESelectVideoCaptureDevice: enumAppCounter++,
FTUESetAutoSelectVideoLayout: enumAppCounter++,
FTUESetCaptureResolution: enumAppCounter++,
FTUESetChatInput: enumAppCounter++,
FTUESetChatInputVolume: enumAppCounter++,
FTUESetChatLatency: enumAppCounter++,
FTUESetFrameSize: enumAppCounter++,
FTUESetInputLatency: enumAppCounter++,
FTUESetInputMusicDevice: enumAppCounter++,
FTUESetInputVolume: enumAppCounter++,
FTUESetLatencySamples: enumAppCounter++,
FTUESetMusicDevice: enumAppCounter++,
FTUESetMusicInput: enumAppCounter++,
FTUESetMusicInput2: enumAppCounter++,
FTUESetMusicOutput: enumAppCounter++,
FTUESetMusicProfileName: enumAppCounter++,
FTUESetOutputLatency: enumAppCounter++,
FTUESetOutputMusicDevice: enumAppCounter++,
FTUESetOutputVolume: enumAppCounter++,
FTUESetPreferredChatSampleRate: enumAppCounter++,
FTUESetPreferredMixerSampleRate: enumAppCounter++,
FTUESetPreferredOutputSampleRate: enumAppCounter++,
FTUESetPreferredVideoLayoutGroupStyle: enumAppCounter++,
FTUESetSendFrameRates: enumAppCounter++,
FTUESetStatus: enumAppCounter++,
FTUESetUserCountPreferredVideoLayoutGroupStyle: enumAppCounter++,
FTUESetVideoEncodeResolution: enumAppCounter++,
FTUESetVideoShareEnable: enumAppCounter++,
FTUEStartIoPerfTest: enumAppCounter++,
FTUEStartLatency: enumAppCounter++,
FTUEUnsetMusicInput2: enumAppCounter++,
get48vAndLineInstState: enumAppCounter++,
getABLoopState: enumAppCounter++,
getAllClientsStateMap: enumAppCounter++,
getAllClientsStateStr: enumAppCounter++,
GetASIODevices: enumAppCounter++,
GetAutoStart: enumAppCounter++,
getAvailableMetronomeClickNames: enumAppCounter++,
getBackingTrackList: enumAppCounter++,
getClientParentChildRole: enumAppCounter++,
getConnectionDetail: enumAppCounter++,
GetCurrentVideoFrameRate: enumAppCounter++,
GetCurrentVideoResolution: enumAppCounter++,
GetDetailedOS: enumAppCounter++,
GetFTUE: enumAppCounter++,
GetJamTrackSettings: enumAppCounter++,
GetJamTrackTimeline: enumAppCounter++,
getJBAutoPair: enumAppCounter++,
getJbNetworkState: enumAppCounter++,
getJbPortBindState: enumAppCounter++,
getJbPreampState: enumAppCounter++,
getJbStaticPortFlag: enumAppCounter++,
getJbStaticPortValue: enumAppCounter++,
getJbTrackState: enumAppCounter++,
getJbUsbState: enumAppCounter++,
GetLastLatencyTestTimes: enumAppCounter++,
getLatencyServerState: enumAppCounter++,
getLocalClients: enumAppCounter++,
GetLocalRecordingState: enumAppCounter++,
getLogLevel: enumAppCounter++,
getMetronomeCricketTestState: enumAppCounter++,
GetMixerIDs: enumAppCounter++,
GetMixerMode: enumAppCounter++,
GetMixerVolume: enumAppCounter++,
getMyChildren: enumAppCounter++,
getMyNetworkState: enumAppCounter++,
getMyParentState: enumAppCounter++,
GetNetworkTestScore: enumAppCounter++,
getOpenVideoSources: enumAppCounter++,
getOperatingMode: enumAppCounter++,
GetOS: enumAppCounter++,
GetOSAsString: enumAppCounter++,
getParentClientId: enumAppCounter++,
getPeerState: enumAppCounter++,
GetRecordingManagerState: enumAppCounter++,
GetSampleRate: enumAppCounter++,
GetScoreWorkTimingInterval: enumAppCounter++,
getSessionSetCompressorState: enumAppCounter++,
GetStaticPort: enumAppCounter++,
GetUseStaticPort: enumAppCounter++,
GetVideoNetworkTestScore: enumAppCounter++,
hasBonjour: enumAppCounter++,
hasVstAssignment: enumAppCounter++,
hasVstHost: enumAppCounter++,
hasWebrtc: enumAppCounter++,
InitiateScoringSession: enumAppCounter++,
InvalidateJamTrack: enumAppCounter++,
IsAppInWritableVolume: enumAppCounter++,
IsAudioStarted: enumAppCounter++,
IsFrontendVisible: enumAppCounter++,
isJamBlaster: enumAppCounter++,
isLatencyTestBlocked: enumAppCounter++,
IsMyNetworkWireless: enumAppCounter++,
IsNativeClient: enumAppCounter++,
IsSessionLiveBroadCastRunning: enumAppCounter++,
isSessionTrackPaused: enumAppCounter++,
isSessionTrackPlaying: enumAppCounter++,
isSessVideoRecording: enumAppCounter++,
isSessVideoShared: enumAppCounter++,
isSessYouTubeVideoBroadcasting: enumAppCounter++,
isVideoRecordingAllowed: enumAppCounter++,
isVideoWindowOpen: enumAppCounter++,
IsVstLoaded: enumAppCounter++,
isWebCamOpen: enumAppCounter++,
jamBlasterSerialNo: enumAppCounter++,
JamTrackDownload: enumAppCounter++,
JamTrackGetImage: enumAppCounter++,
JamTrackGetTrackDetail: enumAppCounter++,
JamTrackGetTracks: enumAppCounter++,
JamTrackIsPlayable: enumAppCounter++,
JamTrackIsPlaying: enumAppCounter++,
JamTrackKeysRequest: enumAppCounter++,
JamTrackLoadJmep: enumAppCounter++,
JamTrackPlay: enumAppCounter++,
JamTrackStopPlay: enumAppCounter++,
JoinSession: enumAppCounter++,
LastUsedProfileName: enumAppCounter++,
LeaveSession: enumAppCounter++,
LeaveSessionAndMinimize: enumAppCounter++,
log: enumAppCounter++,
NetworkTest: enumAppCounter++,
NetworkTestResult: enumAppCounter++,
OnDownloadAvailable: enumAppCounter++,
OnLoggedIn: enumAppCounter++,
OnLoggedInUserName: enumAppCounter++,
OnLoggedOut: enumAppCounter++,
OnTrySyncCommand: enumAppCounter++,
openBackingTrackFile: enumAppCounter++,
OpenBackingTracksDirectory: enumAppCounter++,
OpenRecording: enumAppCounter++,
OpenSystemBrowser: enumAppCounter++,
openVideo: enumAppCounter++,
P2PMessageReceived: enumAppCounter++,
ParticipantJoined: enumAppCounter++,
ParticipantLeft: enumAppCounter++,
pauseVideoUpload: enumAppCounter++,
PerformQuit: enumAppCounter++,
PostTaskBarMessage: enumAppCounter++,
PreviewRecording: enumAppCounter++,
rebootJamBlaster: enumAppCounter++,
RegisterGenericCallBack: enumAppCounter++,
registerMasterClippingCallback: enumAppCounter++,
RegisterMixerInterfaceModeChangeCallback: enumAppCounter++,
RegisterMuteChangeCallBack: enumAppCounter++,
RegisterQuitCallback: enumAppCounter++,
RegisterRecordingCallbacks: enumAppCounter++,
RegisterRecordingManagerCallbacks: enumAppCounter++,
RegisterSessionJoinLeaveRequestCallBack: enumAppCounter++,
RegisterVolChangeCallBack: enumAppCounter++,
ReloadAudioSystem: enumAppCounter++,
removeBackingTrackFiles: enumAppCounter++,
ResetPageCounters: enumAppCounter++,
RestartApplication: enumAppCounter++,
restartParentClient: enumAppCounter++,
resumeVideoUpload: enumAppCounter++,
SaveSettings: enumAppCounter++,
SaveToClipboard: enumAppCounter++,
SendP2PMessage: enumAppCounter++,
SessGetInsetPosition: enumAppCounter++,
SessGetListOfPeersSharingVideo: enumAppCounter++,
SessGetPeersVideoPosition: enumAppCounter++,
SessGetVideoDisplayLayoutGroup: enumAppCounter++,
SessGetVideoReceiveEnable: enumAppCounter++,
SessGetVideoRecordings: enumAppCounter++,
SessionAddPlayTrack: enumAppCounter++,
SessionAddTrack: enumAppCounter++,
SessionAudioResync: enumAppCounter++,
SessionCloseBackingTrackFile: enumAppCounter++,
SessionCloseMetronome: enumAppCounter++,
SessionCurrentPlaybackMode: enumAppCounter++,
SessionCurrrentJamTrackPlayPosMs: enumAppCounter++,
SessionCurrrentPlayPosMs: enumAppCounter++,
SessionFirstGet: enumAppCounter++,
SessionFirstSet: enumAppCounter++,
SessionGetAllControlState: enumAppCounter++,
SessionGetControlState: enumAppCounter++,
SessionGetDeviceLatency: enumAppCounter++,
SessionGetIDs: enumAppCounter++,
SessionGetJamTracksPlayDurationMs: enumAppCounter++,
SessionGetMacHash: enumAppCounter++,
SessionGetMasterLocalMix: enumAppCounter++,
SessionGetTracksPlayDurationMs: enumAppCounter++,
SessionJamTrackSeekMs: enumAppCounter++,
SessionLiveBroadcastStart: enumAppCounter++,
SessionLiveBroadcastStop: enumAppCounter++,
SessionOpenBackingTrackFile: enumAppCounter++,
SessionOpenMetronome: enumAppCounter++,
SessionPageEnter: enumAppCounter++,
SessionPageLeave: enumAppCounter++,
SessionPausePlay: enumAppCounter++,
SessionRegisterCallback: enumAppCounter++,
SessionRemoveAllPlayTracks: enumAppCounter++,
SessionRemovePlayTrack: enumAppCounter++,
SessionRemoveTrack: enumAppCounter++,
SessionRequestUserControlUpdate: enumAppCounter++,
SessionSetAlertCallback: enumAppCounter++,
SessionSetAlertPeriod: enumAppCounter++,
SessionSetConnectionStatusRefreshRate: enumAppCounter++,
SessionSetControlState: enumAppCounter++,
SessionSetMasterLocalMix: enumAppCounter++,
SessionSetMetronome: enumAppCounter++,
SessionSetRecordingFilename: enumAppCounter++,
SessionSetRecordingFolder: enumAppCounter++,
SessionSetTrackVolumeData: enumAppCounter++,
SessionSetUserData: enumAppCounter++,
SessionSetUserName: enumAppCounter++,
SessionShowMetronomeGui: enumAppCounter++,
SessionStartPlay: enumAppCounter++,
SessionStopPlay: enumAppCounter++,
SessionTrackSeekMs: enumAppCounter++,
SessionTracksSeek: enumAppCounter++,
SessPlayVideoRecording: enumAppCounter++,
SessRotatePeerVideoPositions: enumAppCounter++,
SessSelectVideoDisplayLayoutGroup: enumAppCounter++,
SessSetInsetPosition: enumAppCounter++,
SessSetInsetSize: enumAppCounter++,
SessSetPeersVideoPosition: enumAppCounter++,
SessSetVideoReceiveEnable: enumAppCounter++,
SessStartVideoRecordAndReturnFileName: enumAppCounter++,
SessStartVideoSharing: enumAppCounter++,
SessStartWebcamVideoRecordAndReturnFileName: enumAppCounter++,
SessStartYouTubeVideoBroadcast: enumAppCounter++,
SessStopVideoRecord: enumAppCounter++,
SessStopVideoSharing: enumAppCounter++,
SessStopYouTubeVideoBroadcast: enumAppCounter++,
SessSubscribePeerVideo: enumAppCounter++,
SessUnsubscribePeerVideo: enumAppCounter++,
set48vAndLineInstState: enumAppCounter++,
setABLoopState: enumAppCounter++,
SetAutoStart: enumAppCounter++,
setBackingTrackOpenCallback: enumAppCounter++,
SetFakeRecordingImpl: enumAppCounter++,
SetFTUE: enumAppCounter++,
setJBAutoPair: enumAppCounter++,
setJBName: enumAppCounter++,
setJbNetworkState: enumAppCounter++,
setJbPortBindState: enumAppCounter++,
setJbPreampState: enumAppCounter++,
setJbStaticPortFlag: enumAppCounter++,
setJbStaticPortValue: enumAppCounter++,
setJbTrackState: enumAppCounter++,
setJbUsbState: enumAppCounter++,
setJmepMetronomeVolume: enumAppCounter++,
SetLastUsedProfileName: enumAppCounter++,
SetLatencyTestBlocked: enumAppCounter++,
setMetronomeCricketTestState: enumAppCounter++,
setMetronomeOpenCallback: enumAppCounter++,
SetMixerMode: enumAppCounter++,
SetNetworkTestScore: enumAppCounter++,
SetRecordingFilename: enumAppCounter++,
SetRecordingFolder: enumAppCounter++,
SetScoreWorkTimingInterval: enumAppCounter++,
setSessionMixerCategoryPlayoutState: enumAppCounter++,
setSessionSetCompressorState: enumAppCounter++,
SetStaticPort: enumAppCounter++,
SetUseStaticPort: enumAppCounter++,
SetVideoNetworkTestScore: enumAppCounter++,
SetVURefreshRate: enumAppCounter++,
ShowSelectBackingTrackDialog: enumAppCounter++,
ShowSelectVSTScanDialog: enumAppCounter++,
ShutdownApplication: enumAppCounter++,
StartLiveStreaming: enumAppCounter++,
startPairing: enumAppCounter++,
StartRecording: enumAppCounter++,
StopAudio: enumAppCounter++,
StopLiveStreaming: enumAppCounter++,
StopNetworkTest: enumAppCounter++,
StopRecording: enumAppCounter++,
TestLatency: enumAppCounter++,
TestNetworkPktBwRate: enumAppCounter++,
testVideoRender: enumAppCounter++,
TrackDeleteProfile: enumAppCounter++,
TrackGetAssignment: enumAppCounter++,
TrackGetChannels: enumAppCounter++,
TrackGetChatEnable: enumAppCounter++,
TrackGetChatUsesMusic: enumAppCounter++,
TrackGetCount: enumAppCounter++,
TrackGetDevices: enumAppCounter++,
TrackGetInstrument: enumAppCounter++,
TrackGetMusicDeviceID: enumAppCounter++,
TrackGetMusicDeviceNames: enumAppCounter++,
TrackHasControlPanel: enumAppCounter++,
TrackIsMusicDeviceType: enumAppCounter++,
TrackLoadAssignments: enumAppCounter++,
TrackLoadAudioProfile: enumAppCounter++,
TrackOpenControlPanel: enumAppCounter++,
TrackRefreshDevices: enumAppCounter++,
TrackSaveAssignments: enumAppCounter++,
TrackSetAssignment: enumAppCounter++,
TrackSetChatEnable: enumAppCounter++,
TrackSetChatInput: enumAppCounter++,
TrackSetChatUsesMusic: enumAppCounter++,
TrackSetCount: enumAppCounter++,
TrackSetInstrument: enumAppCounter++,
TrackSetMusicDevice: enumAppCounter++,
UpdateMixer: enumAppCounter++,
UpdateSessionInfo: enumAppCounter++,
uploadVideo: enumAppCounter++,
UserAttention: enumAppCounter++,
VideoDecision: enumAppCounter++,
VSTAddSearchPath: enumAppCounter++,
VSTClearAll: enumAppCounter++,
VSTListSearchPaths: enumAppCounter++,
VSTListTrackAssignments: enumAppCounter++,
VSTListVsts: enumAppCounter++,
VSTLoad: enumAppCounter++,
VSTRemoveSearchPath: enumAppCounter++,
VSTScan: enumAppCounter++,
VSTSetTrackAssignment: enumAppCounter++,
VSTShowHideGui: enumAppCounter++,
VST_EnableMidiForTrack: enumAppCounter++,
VST_GetMidiDeviceList: enumAppCounter++,
VST_ScanForMidiDevices: enumAppCounter++,
IsOBSAvailable: enumAppCounter++,
StartMediaRecording: enumAppCounter++,
LaunchBroadcastSettings: enumAppCounter++,
SetRecordingOptionStartedByPeer: enumAppCounter++,
GetRecordingOptionStartedByPeer: enumAppCounter++,
SetAudioRecordingPreference: enumAppCounter++,
GetAudioRecordingPreference: enumAppCounter++,
PeerStopRecording: enumAppCounter++,
FrontStopRecording: enumAppCounter++,
GetCurrentRecordingId: enumAppCounter++,
});
function setupWebSocketConnection() {
const baseUrl = "ws://localhost:3060";
logger.log(
"[asyncJamClient] connecting to WebSocket server at " + baseUrl + "."
);
const socket = new WebSocket(baseUrl);
socket.onclose = function (event) {
logger.error("[asyncJamClient] QWebChannel websocket closed");
if (event.code != 1000) {
// Error code 1000 means that the connection was closed normally.
// Try to reconnect.
if (!navigator.onLine) {
//alert("You are offline. Please connect to the Internet and try again.");
}
}
};
socket.onerror = function (error) {
logger.error("[asyncJamClient] QWebChannel websocket error: " + error);
};
socket.onopen = function () {
logger.log(
"[asyncJamClient] WebSocket connected, setting up QWebChannel."
);
const skipLogMethods = [
'getConnectionDetail'
]
const displayLogMethod = [
]
new QWebChannel(socket, function (channel) {
jkfrontendchannel = channel.objects.jkfrontendchannel;
if (jkfrontendchannel) {
window.isWebChannelReady = true;
let deferred;
try {
jkfrontendchannel.sendText.connect(function (message) {
// logger.log(
// "[asyncJamClient] Message received via QWebChannel: " +
// message
// );
//handle Method Not Implemented"
if (
typeof resp === "object" &&
resp[0] === "Method Not Implemented"
) {
//throw new Error("Method Not Implemented");
deferred.resolve(null); //return null value
} else {
let msg = JSON.parse(message);
let req_id = msg.request_id; //frontend originated request
let response = msg.response;
let evt_id = msg.event_id; //backend originated async event
let methodName = msg.method_name;
deferred = deferredQueue.find((d) => {
return d.request_id === req_id;
});
if (deferred) {
if(skipLogMethods.length > 0 && skipLogMethods.includes(methodName)){
}else{
if(displayLogMethod.includes(methodName)){
logger.log(
"[asyncJamClient] Message received via QWebChannel: " +
msg
);
}
}
deferred.resolve(response);
//remove this deferred object from queue
deferredQueue = deferredQueue.filter(
(d) => d.request_id !== deferred.request_id
);
} else if (evt_id) {
let method = Object.keys(response)[0]
// logger.log("[asyncJamClient] event received:", evt_id.toString(), Object.keys(response)[0])
// if(evt_id.toString() === '3012'){
// alert(evt_id.toString())
// }
switch (evt_id.toString()) {
case '3006': //execute_script
if(!response['execute_script'].match('HandleBridgeCallback2')){
//logger.log(`[asyncJamClient] 3006 execute_script: ${response['execute_script']}`);
}
try {
eval(response['execute_script']);
} catch (error) {
logger.log(`[asyncJamClient] error: execute_script: ${response['execute_script']}`);
logger.log(error);
}
break;
case '3007': //message
//logger.log(`[asyncJamClient] 3007 message: ${response['message']}`);
try {
const msg = response['message'];
const clientId = response['targetClientID'];
context.JK.JamServer.sendP2PMessage(clientId, msg)
} catch (error) {
logger.log(`[asyncJamClient] error: sendP2PMessage: ${response['message']}`);
logger.log(error);
}
break;
case '3010': //JKVideoSession
logger.log(`[asyncJamClient] 3010 JKVideoSession: ${response['JKVideoSession']['connect']}`);
const vidConnect = response['JKVideoSession']['connect'];
context.ExternalVideoActions.setVideoEnabled(vidConnect);
context.JK.videoIsOngoing = vidConnect;
break;
case '3011': //AudioFormatChangeEvent
logger.log(`[asyncJamClient] 3011 AudioFormatChangeEvent: ${response['AudioFormat']}`);
const audioFormat = response['AudioFormat']
context.RecordingActions.audioRecordingFormatChanged(`.${audioFormat}`)
break;
case '3012': //customUrl
const customUrl = response['CustomUrl']
//if localStorage is available and has customUrl key, remove it
if(localStorage){
if(localStorage.getItem('customUrl')){
localStorage.removeItem('customUrl')
}
//now set the customUrl which received from backend
if(customUrl){
const httpUrl = window.location.protocol + '//' + customUrl;
const customUrlHandler = new JK.CustomUrlHandler();
if(customUrlHandler.isValidUrl(httpUrl)){
localStorage.setItem('customUrl', httpUrl);
if(context.JK.currentUserId){
window.location.href = httpUrl;
}
}else{
logger.log(`[asyncJamClient] invalid customUrl: ${httpUrl}`);
}
}
}
break;
default:
break;
}
}
}
});
//TODO: handle method does not exist
} catch (e) {
logger.log(
"[asyncJamClient] Error when receving message via QWebChannel"
);
if (deferred) {
deferred.reject(e.message);
deferred = null;
}
Bugsnag.notify(e, function(event){
event.severity = 'info'
event.context = 'asyncJamClient'
event.setUser(gon.user_id, gon.user_email, gon.user_name)
});
}
}
});
};
}
function waitForOpenConnection(){
return new Promise((resolve, reject) => {
const maxNumberOfAttempts = 10
const intervalTime = 200 //ms
let currentAttempt = 0
const interval = setInterval(() => {
if (currentAttempt > maxNumberOfAttempts - 1) {
clearInterval(interval)
reject(new Error('Maximum number of attempts exceeded'))
} else if (jkfrontendchannel) {
clearInterval(interval)
resolve()
}
currentAttempt++
}, intervalTime)
})
}
async function sendWhenReady(prop, args){
if (jkfrontendchannel) {
return sendMessage(prop, args)
}else{
try {
await waitForOpenConnection()
return sendMessage(prop, args)
} catch (err) { console.error(err) }
}
}
function sendMessage(prop, args){
let appMessage = new Object();
appMessage.request_id = ++request_id;
appMessage.arguments = Array.from(args) || [];
let method = JKFrontendMethods[prop];
appMessage.method = method;
let deferred = new Deferred(appMessage.request_id);
const skipLogMethods = [
]
const displayLogMethod = [
// 'SessionSetTrackVolumeData'
]
if(skipLogMethods.length > 0 && skipLogMethods.includes(prop)){
}else{
if(displayLogMethod.includes(prop)){
logger.log(
"[asyncJamClient] diverting to backend:",
prop,
appMessage
);
}
}
if (jkfrontendchannel) {
try {
jkfrontendchannel.receiveText(JSON.stringify(appMessage));
deferredQueue.push(deferred);
return deferred.promise;
} catch (e) {
logger.error(
"[asyncJamClient] Native app not connected",
e.message
);
deferred.reject('Native app not connected')
return deferred.promise;
}
} else {
logger.info(
"[asyncJamClient] jkfrontendchannel is not ready yet"
);
deferred.reject('frontendchannel is not ready yet')
return deferred.promise;
}
}
function setupAsyncProxy() {
let proxy;
const handler = {
get(target, prop, receiver) {
//const origMethod = target[prop];
//console.log('[asyncJamClient] get:', target, prop);
return function (...args) {
// let result = origMethod.apply(this, args);
// console.log(prop + JSON.stringify(args)+ ' -> ' + JSON.stringify(result));
// return result;
return sendWhenReady(prop, arguments)
};
},
};
proxy = new Proxy(self, handler);
logger.log(
"[asyncJamClient] Connected to WebChannel, ready to send/receive messages!"
);
return proxy;
}
setupWebSocketConnection();
return setupAsyncProxy();
};
})(window, jQuery);

View File

@ -23,8 +23,8 @@
context.location = "/client#"; // leaveSession will be called in beforeHide below context.location = "/client#"; // leaveSession will be called in beforeHide below
} }
function onStunEvent() { async function onStunEvent() {
var testResults = context.jamClient.NetworkTestResult(); var testResults = await context.jamClient.NetworkTestResult();
$.each(testResults, function (index, val) { $.each(testResults, function (index, val) {
if (val.bStunFailed) { if (val.bStunFailed) {
@ -49,8 +49,7 @@
} }
function alertCallback(type, text) { async function alertCallback(type, text) {
function timeCallback() { function timeCallback() {
var start = new Date(); var start = new Date();
setTimeout(function() { setTimeout(function() {
@ -64,6 +63,7 @@
timeCallback(); timeCallback();
logger.debug("alert callback", type, text); logger.debug("alert callback", type, text);
console.log("alert callback", type, text);
var alertData = $.extend({}, ALERT_TYPES[type]); var alertData = $.extend({}, ALERT_TYPES[type]);
@ -129,7 +129,7 @@
else if(type === ALERT_NAMES.RECORD_PLAYBACK_STATE) { else if(type === ALERT_NAMES.RECORD_PLAYBACK_STATE) {
//if(context.JK.CurrentSessionModel) //if(context.JK.CurrentSessionModel)
// context.JK.CurrentSessionModel.onPlaybackStateChange(type, text); // context.JK.CurrentSessionModel.onPlaybackStateChange(type, text);
context.MediaPlaybackActions.playbackStateChange(text); await context.MediaPlaybackActions.playbackStateChange(text);
} }
else if(type === ALERT_NAMES.VIDEO_WINDOW_OPENED) { else if(type === ALERT_NAMES.VIDEO_WINDOW_OPENED) {
context.VideoActions.videoWindowOpened() context.VideoActions.videoWindowOpened()
@ -150,8 +150,8 @@
} }
} }
function initialize() { async function initialize() {
context.jamClient.SessionSetAlertCallback("JK.AlertCallback"); await context.jamClient.SessionSetAlertCallback("JK.AlertCallback");
} }
this.initialize = initialize; this.initialize = initialize;

View File

@ -153,7 +153,7 @@
// refreshes the currently active tab // refreshes the currently active tab
function renderActive() { function renderActive() {
//console.log("_DEBUG_ renderActive isAdmin: " + isAdmin + " isMember: " + isMember);
if (isMember) { if (isMember) {
$("#btn-follow-band").hide(); $("#btn-follow-band").hide();
$("#btn-edit-band-profile").show(); $("#btn-edit-band-profile").show();
@ -549,6 +549,7 @@
error: app.ajaxError error: app.ajaxError
}) })
.done(function(response) { .done(function(response) {
//console.log("_DEBUG_ determineMembership response: " + JSON.stringify(response));
isAdmin = isMember = false; isAdmin = isMember = false;
$.each(response, function(index, val) { $.each(response, function(index, val) {
if (val.id === context.JK.currentUserId) { if (val.id === context.JK.currentUserId) {

View File

@ -197,7 +197,7 @@
} }
function renderErrors(errors) { function renderErrors(errors) {
logger.debug("Band setup errors: ", errors) console.log("Band setup errors: ", errors)
var name = context.JK.format_errors("name", errors); var name = context.JK.format_errors("name", errors);
var country = context.JK.format_errors("country", errors); var country = context.JK.format_errors("country", errors);
var state = context.JK.format_errors("state", errors); var state = context.JK.format_errors("state", errors);
@ -205,6 +205,8 @@
var biography = context.JK.format_errors("biography", errors); var biography = context.JK.format_errors("biography", errors);
var website = context.JK.format_errors("website", errors); var website = context.JK.format_errors("website", errors);
var genres = context.JK.format_errors("genres", errors); var genres = context.JK.format_errors("genres", errors);
var hourly_rate = context.JK.format_errors("hourly_rate", errors);
var gig_minimum = context.JK.format_errors("gig_minimum", errors);
if(name) $("#band-name").closest('div.field').addClass('error').end().after(name); if(name) $("#band-name").closest('div.field').addClass('error').end().after(name);
if(country) $("#band-country").closest('div.field').addClass('error').end().after(country); if(country) $("#band-country").closest('div.field').addClass('error').end().after(country);
@ -213,6 +215,8 @@
if(biography) $("#band-biography").closest('div.field').addClass('error').end().after(biography); if(biography) $("#band-biography").closest('div.field').addClass('error').end().after(biography);
if(website) $("#band-website").closest('div.field').addClass('error').end().after(website); if(website) $("#band-website").closest('div.field').addClass('error').end().after(website);
if(genres) $("#band-genres").closest('div.field').addClass('error').end().after(genres); if(genres) $("#band-genres").closest('div.field').addClass('error').end().after(genres);
if(hourly_rate) $("#hourly-rate").closest('div.field').addClass('error').end().after(hourly_rate);
if(gig_minimum) $("#gig-minimum").closest('div.field').addClass('error').end().after(gig_minimum);
} }
function buildBand() { function buildBand() {
@ -402,6 +406,7 @@
function loadBandDetails() { function loadBandDetails() {
rest.getBand(bandId).done(function (band) { rest.getBand(bandId).done(function (band) {
console.log("Band details: ", band)
$("#band-name").val(band.name); $("#band-name").val(band.name);
$("#band-website").val(band.website); $("#band-website").val(band.website);
$("#band-biography").val(band.biography); $("#band-biography").val(band.biography);
@ -411,21 +416,27 @@
concertCount.val(band.concert_count) concertCount.val(band.concert_count)
if (band.add_new_members){ if (band.add_new_members){
$("#new-member-no").iCheck('check').attr('checked', 'checked')
} else {
$("#new-member-yes").iCheck('check').attr('checked', 'checked') $("#new-member-yes").iCheck('check').attr('checked', 'checked')
$("#new-member-no").iCheck('uncheck').removeAttr('checked')
} else {
$("#new-member-no").iCheck('check').attr('checked', 'checked')
$("#new-member-yes").iCheck('uncheck').removeAttr('checked')
} }
if (band.paid_gigs) { if (band.paid_gigs) {
$("#paid-gigs-no").iCheck('check').attr('checked', 'checked')
} else {
$("#paid-gigs-yes").iCheck('check').attr('checked', 'checked') $("#paid-gigs-yes").iCheck('check').attr('checked', 'checked')
$("#paid-gigs-no").iCheck('uncheck').removeAttr('checked')
} else {
$("#paid-gigs-no").iCheck('check').attr('checked', 'checked')
$("#paid-gigs-yes").iCheck('uncheck').removeAttr('checked')
} }
if (band.free_gigs) { if (band.free_gigs) {
$("#free-gigs-no").iCheck('check').attr('checked', 'checked')
} else {
$("#free-gigs-yes").iCheck('check').attr('checked', 'checked') $("#free-gigs-yes").iCheck('check').attr('checked', 'checked')
$("#free-gigs-no").iCheck('uncheck').removeAttr('checked')
} else {
$("#free-gigs-no").iCheck('check').attr('checked', 'checked')
$("#free-gigs-yes").iCheck('uncheck').removeAttr('checked')
} }
$('#touring-option').val(band.touring_option ? 'yes' : 'no') $('#touring-option').val(band.touring_option ? 'yes' : 'no')

View File

@ -149,7 +149,7 @@
} }
// called from sidebar when messages come in // called from sidebar when messages come in
function chatMessageReceived(payload) { async function chatMessageReceived(payload) {
if (fullyInitialized) { if (fullyInitialized) {
if (isChatPanelVisible()) { if (isChatPanelVisible()) {
@ -157,7 +157,7 @@
else { else {
highlightCount(); highlightCount();
incrementChatCount(); incrementChatCount();
context.jamClient.UserAttention(true); await context.jamClient.UserAttention(true);
} }
} }
} }

View File

@ -18,7 +18,7 @@
function cancelUpdate(e) { function cancelUpdate(e) {
if ((e.ctrlKey || e.metaKey) && e.keyCode == 78) { if ((e.ctrlKey || e.metaKey) && e.keyCode == 78) {
logger.debug("update canceled!"); console.log("update canceled!");
app.layout.closeDialog('client-update'); app.layout.closeDialog('client-update');
app.clientUpdating = false; app.clientUpdating = false;
} }
@ -82,7 +82,7 @@
/***************************************/ /***************************************/
function clientUpdateDownloadProgress(bytesReceived, bytesTotal, downloadSpeedMegSec, timeRemaining) { function clientUpdateDownloadProgress(bytesReceived, bytesTotal, downloadSpeedMegSec, timeRemaining) {
// this fires way too many times to leave in. uncomment if debugging update feature // this fires way too many times to leave in. uncomment if debugging update feature
//logger.debug("bytesReceived: " + bytesReceived, ", bytesTotal: " + bytesTotal, ", downloadSpeed: " + downloadSpeedMegSec, ", timeRemaining: " + timeRemaining + ", updateSize: " + updateSize); //console.log("bytesReceived: " + bytesReceived, ", bytesTotal: " + bytesTotal, ", downloadSpeed: " + downloadSpeedMegSec, ", timeRemaining: " + timeRemaining + ", updateSize: " + updateSize);
bytesReceived = Number(bytesReceived) bytesReceived = Number(bytesReceived)
bytesTotal = Number(bytesTotal) bytesTotal = Number(bytesTotal)
@ -93,7 +93,7 @@
} }
function clientUpdateDownloadSuccess(updateLocation) { function clientUpdateDownloadSuccess(updateLocation) {
logger.debug("client update downloaded successfully to: " + updateLocation); console.log("client update downloaded successfully to: " + updateLocation);
updateClientUpdateDialog("update-proceeding"); updateClientUpdateDialog("update-proceeding");
@ -112,12 +112,12 @@
} }
function clientUpdateLaunchSuccess(userTimeToRead) { async function clientUpdateLaunchSuccess(userTimeToRead) {
if(userTimeToRead === undefined) { if(userTimeToRead === undefined) {
userTimeToRead = 1000; // older clients didn't pass this in, and exit very quickly userTimeToRead = 1000; // older clients didn't pass this in, and exit very quickly
} }
logger.debug("client update launching in: " + userTimeToRead); console.log("client update launching in: " + userTimeToRead);
// set timer to update countdown // set timer to update countdown
var rounded = Math.round(userTimeToRead / 1000); var rounded = Math.round(userTimeToRead / 1000);
@ -135,7 +135,7 @@
} }
}, rounded * 1000); }, rounded * 1000);
updateClientUpdateDialog("update-restarting", {countdown: rounded, os: context.JK.GetOSAsString()}); updateClientUpdateDialog("update-restarting", {countdown: rounded, os: await context.JK.GetOSAsString()});
} }
function clientUpdateLaunchFailure(errorMsg) { function clientUpdateLaunchFailure(errorMsg) {
@ -145,7 +145,7 @@
} }
function clientUpdateLaunchStatuses(statuses) { function clientUpdateLaunchStatuses(statuses) {
logger.debug("client update launch statuses"); console.log("client update launch statuses");
if (statuses) { if (statuses) {
for (var i = 0; i < statuses.length; i++) { for (var i = 0; i < statuses.length; i++) {
@ -155,7 +155,7 @@
} }
function clientUpdateLaunchStatusChange(done, status) { function clientUpdateLaunchStatusChange(done, status) {
logger.debug("client update launch status change. starting=" + done + ", status=" + status); console.log("client update launch status change. starting=" + done + ", status=" + status);
if (!done) { if (!done) {
var $ellipses = $('<span class="ellipses">.</span>'); var $ellipses = $('<span class="ellipses">.</span>');
@ -201,19 +201,24 @@
} }
} }
function runCheck(product, version, uri, size, currentVersion) { async function runCheck(product, version, uri, size, currentVersion) {
if (app.clientUpdating) { if (app.clientUpdating) {
logger.debug("client is already updating; skipping") console.log("client is already updating; skipping")
return return
} }
if(currentVersion === undefined) { console.log("runCheck: product , version", product, version)
currentVersion = context.jamClient.ClientUpdateVersion(); // check kill switch before all other logic
if (!gon.check_for_client_updates) {
console.log("runCheck: skipping client update because the server is telling us not to")
return;
}
if(currentVersion === undefined) {
currentVersion = await context.jamClient.ClientUpdateVersion() //.then(function(currentVersion){
if (!forceShow && (currentVersion == null || currentVersion.indexOf("Compiled")) > -1) { if (!forceShow && (currentVersion == null || currentVersion.indexOf("Compiled")) > -1) {
// this is a developer build; it doesn't make much sense to do an packaged update, so skip // this is a developer build; it doesn't make much sense to do an packaged update, so skip
logger.debug("skipping client update check because this is a development build ('" + currentVersion + "')") console.log("skipping client update check because this is a development build ('" + currentVersion + "')")
return; return;
} }
@ -221,9 +226,10 @@
if (currentVersion.indexOf('"') == 0 && currentVersion.lastIndexOf('"') == currentVersion.length - 1) { if (currentVersion.indexOf('"') == 0 && currentVersion.lastIndexOf('"') == currentVersion.length - 1) {
currentVersion = currentVersion.substring(1, currentVersion.length - 1); currentVersion = currentVersion.substring(1, currentVersion.length - 1);
} }
//});
} }
logger.debug("our client version: " + currentVersion + ", server client version: " + version); //console.log("_DEBUG_ our client version: " + currentVersion + ", server client version: " + version);
// test url in lieu of having a configured server with a client-update available // test url in lieu of having a configured server with a client-update available
@ -233,7 +239,7 @@
updateSize = size; updateSize = size;
if(context.SessionStore.inSession()) { if(context.SessionStore.inSession()) {
logger.debug("deferring client update because in session") console.log("deferring client update because in session")
return; return;
} }
@ -254,23 +260,23 @@
} }
// check if updated is needed // check if updated is needed
function check() { async function check() {
var os = await context.jamClient.GetDetailedOS();
var os = context.JK.GetOSAsString();
//os = 'Win32' //os = 'Win32'
// check kill switch before all other logic // check kill switch before all other logic
if (!gon.check_for_client_updates) { if (!gon.check_for_client_updates) {
logger.debug("skipping client update because the server is telling us not to") console.log("skipping client update because the server is telling us not to")
return; return;
} }
var product = "JamClient" //var product = "JamClient"
var currentVersion = context.jamClient.ClientUpdateVersion(); var product = "JamClientModern"
var currentVersion = await context.jamClient.ClientUpdateVersion();
if (!forceShow && (currentVersion == null || currentVersion.indexOf("Compiled")) > -1) { if (!forceShow && (currentVersion == null || currentVersion.indexOf("Compiled")) > -1) {
// this is a developer build; it doesn't make much sense to do an packaged update, so skip // this is a developer build; it doesn't make much sense to do an packaged update, so skip
logger.debug("skipping client update check because this is a development build ('" + currentVersion + "')") console.log("skipping client update check because this is a development build ('" + currentVersion + "')")
return; return;
} }
@ -283,7 +289,9 @@
type: "GET", type: "GET",
url: "/api/versioncheck?product=" + product + "&os=" + os, url: "/api/versioncheck?product=" + product + "&os=" + os,
success: function (response) { success: function (response) {
runCheck(product, response.version, response.uri, response.size, currentVersion); if(!jQuery.isEmptyObject(response)){
runCheck(product, response.version, response.uri, response.size, currentVersion);
}
}, },
error: function (jqXHR, textStatus, errorThrown) { error: function (jqXHR, textStatus, errorThrown) {
logger.error("Unable to do a client update check against /api/versioncheck"); logger.error("Unable to do a client update check against /api/versioncheck");
@ -291,21 +299,61 @@
}); });
} }
function startDownload(url) { async function isUpdateAvailable(){
logger.debug("starting client updater download from: " + url); //this should check if the current version is less than the server version
//if so, return true
//otherwise return false
var os = await context.jamClient.GetDetailedOS();
//os = 'Win32'
var product = "JamClientModern"
var currentVersion = await context.jamClient.ClientUpdateVersion();
if (!forceShow && (currentVersion == null || currentVersion.indexOf("Compiled")) > -1) {
// this is a developer build; it doesn't make much sense to do an packaged update, so skip
console.log("skipping client update check because this is a development build ('" + currentVersion + "')")
return false;
}
// # strange client oddity: remove quotes, if found, from start and finish of version.
if (currentVersion.indexOf('"') == 0 && currentVersion.lastIndexOf('"') == currentVersion.length - 1) {
currentVersion = currentVersion.substring(1, currentVersion.length - 1);
}
return new Promise((resolve, reject) => {
$.ajax({
type: "GET",
url: "/api/versioncheck?product=" + product + "&os=" + os,
success: function (response) {
if(!jQuery.isEmptyObject(response)){
// runCheck(product, response.version, response.uri, response.size, currentVersion);
var result = shouldUpdate(currentVersion, response.version);
resolve(result);
} else {
resolve(false);
}
},
error: function (jqXHR, textStatus, errorThrown) {
logger.error("Unable to do a client update check against /api/versioncheck");
resolve(false);
}
});
});
}
async function startDownload(url) {
console.log("starting client updater download from: " + url);
updateClientUpdateDialog("update-downloading") updateClientUpdateDialog("update-downloading")
context.jamClient.ClientUpdateStartDownload(url, await context.jamClient.ClientUpdateStartDownload(url,
"JK.ClientUpdate.DownloadProgressCallback", "JK.ClientUpdate.DownloadProgressCallback",
"JK.ClientUpdate.DownloadSuccessCallback", "JK.ClientUpdate.DownloadSuccessCallback",
"JK.ClientUpdate.DownloadFailureCallback"); "JK.ClientUpdate.DownloadFailureCallback");
} }
function startUpdate(updaterFilePath) { async function startUpdate(updaterFilePath) {
logger.debug("starting client update from: " + updaterFilePath) console.log("starting client update from: " + updaterFilePath)
context.jamClient.ClientUpdateStartUpdate(updaterFilePath, await context.jamClient.ClientUpdateStartUpdate(updaterFilePath,
"JK.ClientUpdate.LaunchUpdateSuccessCallback", "JK.ClientUpdate.LaunchUpdateSuccessCallback",
"JK.ClientUpdate.LaunchUpdateFailureCallback", "JK.ClientUpdate.LaunchUpdateFailureCallback",
"JK.ClientUpdate.LaunchUpdateStatusesCallback", "JK.ClientUpdate.LaunchUpdateStatusesCallback",
@ -336,6 +384,7 @@
this.initialize = initialize; this.initialize = initialize;
this.check = check; this.check = check;
this.runCheck = runCheck; this.runCheck = runCheck;
this.isUpdateAvailable = isUpdateAvailable;
} }
return this; return this;

View File

@ -11,16 +11,30 @@ context.JK.ClientInit = class ClientInit
@ALERT_NAMES = context.JK.ALERT_NAMES; @ALERT_NAMES = context.JK.ALERT_NAMES;
@lastCheckedBroadcast = null @lastCheckedBroadcast = null
init: () => # init: () =>
if context.gon.isNativeClient # if context.gon.isNativeClient
this.nativeClientInit() # this.nativeClientInit()
context.JK.onBackendEvent(@ALERT_NAMES.WINDOW_OPEN_FOREGROUND_MODE, 'client_init', @watchBroadcast); # context.JK.onBackendEvent(@ALERT_NAMES.WINDOW_OPEN_FOREGROUND_MODE, 'client_init', @watchBroadcast);
this.watchBroadcast() # this.watchBroadcast()
if context.jamClient.RegisterSessionJoinLeaveRequestCallBack? # if context.jamClient.RegisterSessionJoinLeaveRequestCallBack?
context.jamClient.RegisterSessionJoinLeaveRequestCallBack("SessionStore.handleJoinLeaveRequestCallback") # context.jamClient.RegisterSessionJoinLeaveRequestCallBack("SessionStore.handleJoinLeaveRequestCallback")
init: `async function(){
if (context.gon.isNativeClient) {
await this.nativeClientInit();
}
context.JK.onBackendEvent(this.ALERT_NAMES.WINDOW_OPEN_FOREGROUND_MODE, 'client_init', this.watchBroadcast);
this.watchBroadcast();
//if (await context.jamClient.RegisterSessionJoinLeaveRequestCallBack != null) {
await context.jamClient.RegisterSessionJoinLeaveRequestCallBack("SessionStore.handleJoinLeaveRequestCallback");
//}
}`
checkBroadcast: () => checkBroadcast: () =>
promise = window.BroadcastActions.load.trigger() promise = window.BroadcastActions.load.trigger()
@ -38,9 +52,15 @@ context.JK.ClientInit = class ClientInit
setTimeout(@checkBroadcast, 3000) setTimeout(@checkBroadcast, 3000)
nativeClientInit: () => # nativeClientInit: () =>
@gearUtils.bootstrapDefaultPlaybackProfile(); # @gearUtils.bootstrapDefaultPlaybackProfile();
context.VideoActions.checkPromptConfigureVideo() # context.VideoActions.checkPromptConfigureVideo()
nativeClientInit: `async function(){
await this.gearUtils.bootstrapDefaultPlaybackProfile();
return context.VideoActions.checkPromptConfigureVideo();
}`

View File

@ -146,8 +146,8 @@
}); });
$('#btn-driver-settings').unbind("click"); $('#btn-driver-settings').unbind("click");
$('#btn-driver-settings').click(function () { $('#btn-driver-settings').click(async function () {
context.jamClient.TrackOpenControlPanel(); await context.jamClient.TrackOpenControlPanel();
}); });
$('#btn-cancel-new-audio').unbind("click"); $('#btn-cancel-new-audio').unbind("click");
@ -156,10 +156,14 @@
$('#btn-error-ok').click(context.JK.showOverlay); $('#btn-error-ok').click(context.JK.showOverlay);
$('#btn-save-settings').unbind("click"); $('#btn-save-settings').unbind("click");
$('#btn-save-settings').click(saveSettings); $('#btn-save-settings').click(async function(){
await saveSettings()
});
$('#btn-cancel-settings').unbind("click"); $('#btn-cancel-settings').unbind("click");
$('#btn-cancel-settings').click(cancelSettings); $('#btn-cancel-settings').click(async function(){
await cancelSettings()
});
} }
function _handleTrackInputAdd($selectedMusicInputs, selector) { function _handleTrackInputAdd($selectedMusicInputs, selector) {
@ -262,14 +266,14 @@
return chatOtherUnassignedListCopy.length > 0 || chatOtherAssignedListCopy.length > 0; return chatOtherUnassignedListCopy.length > 0 || chatOtherAssignedListCopy.length > 0;
} }
function audioDriverChanged() { async function audioDriverChanged() {
context.jamClient.TrackSetMusicDevice($('#audio-drivers').val()); await context.jamClient.TrackSetMusicDevice($('#audio-drivers').val());
logger.debug("Called TrackSetMusicDevice with " + $('#audio-drivers').val()); logger.debug("Called TrackSetMusicDevice with " + $('#audio-drivers').val());
context.jamClient.TrackLoadAssignments(); await context.jamClient.TrackLoadAssignments();
initDialogData(); await initDialogData();
// refresh dialog // refresh dialog
showVoiceChatPanel(true); showVoiceChatPanel(true);
@ -319,8 +323,8 @@
}); });
} }
function configureDriverSettingsButton() { async function configureDriverSettingsButton() {
if (context.jamClient.TrackHasControlPanel()) { if (await context.jamClient.TrackHasControlPanel()) {
$('#btn-driver-settings').show(); $('#btn-driver-settings').show();
} }
else { else {
@ -328,7 +332,7 @@
} }
} }
function showMusicAudioPanel(refreshLists) { async function showMusicAudioPanel(refreshLists) {
_setInstructions('audio'); _setInstructions('audio');
_activateTab('audio'); _activateTab('audio');
@ -336,11 +340,11 @@
$('#audio-drivers').empty(); $('#audio-drivers').empty();
// determine correct music device to preselect // determine correct music device to preselect
var deviceId = context.jamClient.TrackGetMusicDeviceID(); var deviceId = await context.jamClient.TrackGetMusicDeviceID();
logger.debug("deviceId = " + deviceId); logger.debug("deviceId = " + deviceId);
// load Audio Driver dropdown // load Audio Driver dropdown
devices = context.jamClient.TrackGetDevices(); devices = await context.jamClient.TrackGetDevices();
logger.debug("Called TrackGetDevices with response " + JSON.stringify(devices)); logger.debug("Called TrackGetDevices with response " + JSON.stringify(devices));
var keys = Object.keys(devices); var keys = Object.keys(devices);
@ -362,7 +366,7 @@
context.JK.dropdown($('#audio-drivers')); context.JK.dropdown($('#audio-drivers'));
if (deviceId === '') { if (deviceId === '') {
context.jamClient.TrackSetMusicDevice($('#audio-drivers').val()); await context.jamClient.TrackSetMusicDevice($('#audio-drivers').val());
} }
configureDriverSettingsButton(); configureDriverSettingsButton();
@ -384,7 +388,7 @@
context.JK.loadOptions($('#template-option').html(), $('#track1-input'), track1AudioInputChannels, "id", "name", -1); context.JK.loadOptions($('#template-option').html(), $('#track1-input'), track1AudioInputChannels, "id", "name", -1);
// load Track 1 Instrument // load Track 1 Instrument
var current_instrument = context.jamClient.TrackGetInstrument(ASSIGNMENT.TRACK1); var current_instrument = await context.jamClient.TrackGetInstrument(ASSIGNMENT.TRACK1);
// if no instrument is stored on the backend, the user is opening this dialog for the first time after FTUE; // if no instrument is stored on the backend, the user is opening this dialog for the first time after FTUE;
// initialize to the user's first instrument // initialize to the user's first instrument
@ -401,7 +405,7 @@
context.JK.loadOptions($('#template-option').html(), $('#track2-input'), track2AudioInputChannels, "id", "name", -1); context.JK.loadOptions($('#template-option').html(), $('#track2-input'), track2AudioInputChannels, "id", "name", -1);
// load Track 2 Instrument // load Track 2 Instrument
current_instrument = context.jamClient.TrackGetInstrument(ASSIGNMENT.TRACK2); current_instrument = await context.jamClient.TrackGetInstrument(ASSIGNMENT.TRACK2);
context.JK.loadOptions($('#template-option').html(), $('#track2-instrument'), instrument_array, "id", "description", current_instrument); context.JK.loadOptions($('#template-option').html(), $('#track2-instrument'), instrument_array, "id", "description", current_instrument);
// load Unused Outputs // load Unused Outputs
@ -455,56 +459,56 @@
} }
} }
function initDialogData() { async function initDialogData() {
_initMusicTabData(); await _initMusicTabData();
_initVoiceChatTabData(); await _initVoiceChatTabData();
} }
function _initMusicTabData() { async function _initMusicTabData() {
inputUnassignedList = _loadList(ASSIGNMENT.UNASSIGNED, true, false); inputUnassignedList = await _loadList(ASSIGNMENT.UNASSIGNED, true, false);
//logger.debug("inputUnassignedList=" + JSON.stringify(inputUnassignedList)); //logger.debug("inputUnassignedList=" + JSON.stringify(inputUnassignedList));
track1AudioInputChannels = _loadList(ASSIGNMENT.TRACK1, true, false); track1AudioInputChannels = await _loadList(ASSIGNMENT.TRACK1, true, false);
//logger.debug("track1AudioInputChannels=" + JSON.stringify(track1AudioInputChannels)); //logger.debug("track1AudioInputChannels=" + JSON.stringify(track1AudioInputChannels));
track2AudioInputChannels = _loadList(ASSIGNMENT.TRACK2, true, false); track2AudioInputChannels = await _loadList(ASSIGNMENT.TRACK2, true, false);
//logger.debug("track2AudioInputChannels=" + JSON.stringify(track2AudioInputChannels)); //logger.debug("track2AudioInputChannels=" + JSON.stringify(track2AudioInputChannels));
outputUnassignedList = _loadList(ASSIGNMENT.UNASSIGNED, false, false); outputUnassignedList = await _loadList(ASSIGNMENT.UNASSIGNED, false, false);
outputAssignedList = _loadList(ASSIGNMENT.OUTPUT, false, false); outputAssignedList = await _loadList(ASSIGNMENT.OUTPUT, false, false);
} }
function _initVoiceChatTabData() { async function _initVoiceChatTabData() {
chatUnassignedList = _loadList(ASSIGNMENT.UNASSIGNED, true, false); chatUnassignedList = await _loadList(ASSIGNMENT.UNASSIGNED, true, false);
//logger.debug("chatUnassignedList=" + JSON.stringify(chatUnassignedList)); //logger.debug("chatUnassignedList=" + JSON.stringify(chatUnassignedList));
chatAssignedList = _loadList(ASSIGNMENT.CHAT, true, false); chatAssignedList = await _loadList(ASSIGNMENT.CHAT, true, false);
//logger.debug("chatAssignedList=" + JSON.stringify(chatAssignedList)); //logger.debug("chatAssignedList=" + JSON.stringify(chatAssignedList));
chatOtherUnassignedList = _loadList(ASSIGNMENT.UNASSIGNED, true, true); chatOtherUnassignedList = await _loadList(ASSIGNMENT.UNASSIGNED, true, true);
//logger.debug("chatOtherUnassignedList=" + JSON.stringify(chatOtherUnassignedList)); //logger.debug("chatOtherUnassignedList=" + JSON.stringify(chatOtherUnassignedList));
chatOtherAssignedList = _loadList(ASSIGNMENT.CHAT, true, true); chatOtherAssignedList = await _loadList(ASSIGNMENT.CHAT, true, true);
//logger.debug("chatOtherAssignedList=" + JSON.stringify(chatOtherAssignedList)); //logger.debug("chatOtherAssignedList=" + JSON.stringify(chatOtherAssignedList));
} }
// TODO: copied in addTrack.js - refactor to common place // TODO: copied in addTrack.js - refactor to common place
function _loadList(assignment, input, chat) { async function _loadList(assignment, input, chat) {
var list = []; var list = [];
// get data needed for listboxes // get data needed for listboxes
var channels = context.jamClient.TrackGetChannels(); var channels = await context.jamClient.TrackGetChannels();
var musicDevices = context.jamClient.TrackGetMusicDeviceNames(input); var musicDevices = await context.jamClient.TrackGetMusicDeviceNames(input);
// SEE loadList function in TrackAssignGui.cpp of client code // SEE loadList function in TrackAssignGui.cpp of client code
$.each(channels, function (index, val) { $.each(channels, async function (index, val) {
if (input !== val.input) { if (input !== val.input) {
return; return;
} }
var currAssignment = context.jamClient.TrackGetAssignment(val.id, val.input); var currAssignment = await context.jamClient.TrackGetAssignment(val.id, val.input);
if (assignment !== currAssignment) { if (assignment !== currAssignment) {
return; return;
} }
@ -512,14 +516,15 @@
// logger.debug("channel id=" + val.id + ", channel input=" + val.input + ", channel assignment=" + currAssignment + // logger.debug("channel id=" + val.id + ", channel input=" + val.input + ", channel assignment=" + currAssignment +
// ", channel name=" + val.name + ", channel type=" + val.device_type + ", chat=" + val.chat); // ", channel name=" + val.name + ", channel type=" + val.device_type + ", chat=" + val.chat);
var os = context.jamClient.GetOSAsString(); var os = await context.jamClient.GetOSAsString();
if (os === context.JK.OS.WIN32) { if (os === context.JK.OS.WIN32) {
if (chat && ($.inArray(val.device_id, musicDevices) > -1 || context.jamClient.TrackIsMusicDeviceType(val.device_type))) { if (chat && ($.inArray(val.device_id, musicDevices) > -1 || await context.jamClient.TrackIsMusicDeviceType(val.device_type))) {
return; return;
} }
} }
else { else {
if (chat && ($.inArray(val.device_id, musicDevices) > -1 || !context.jamClient.TrackIsMusicDeviceType(val.device_type))) { var trackIsType = await context.jamClient.TrackIsMusicDeviceType(val.device_type)
if (chat && ($.inArray(val.device_id, musicDevices) > -1 || !trackIsType)) {
return; return;
} }
} }
@ -538,7 +543,7 @@
return list; return list;
} }
function saveSettings() { async function saveSettings() {
if (!context.JK.verifyNotRecordingForTrackChange(app)) { if (!context.JK.verifyNotRecordingForTrackChange(app)) {
return; return;
} }
@ -551,29 +556,29 @@
return; return;
} }
saveAudioSettings(); await saveAudioSettings();
saveVoiceChatSettings(); await saveVoiceChatSettings();
context.jamClient.TrackSaveAssignments(); await context.jamClient.TrackSaveAssignments();
originalDeviceId = $('#audio-drivers').val(); originalDeviceId = $('#audio-drivers').val();
app.layout.closeDialog('configure-audio'); app.layout.closeDialog('configure-audio');
} }
function saveAudioSettings() { async function saveAudioSettings() {
context.jamClient.TrackSetMusicDevice($('#audio-drivers').val()); await context.jamClient.TrackSetMusicDevice($('#audio-drivers').val());
// UNASSIGNED INPUTS // UNASSIGNED INPUTS
$('#audio-inputs-unused > option').each(function () { $('#audio-inputs-unused > option').each(async function () {
logger.debug("Marking " + this.value + " as unassigned input."); logger.debug("Marking " + this.value + " as unassigned input.");
context.jamClient.TrackSetAssignment(this.value, true, ASSIGNMENT.UNASSIGNED); await context.jamClient.TrackSetAssignment(this.value, true, ASSIGNMENT.UNASSIGNED);
}); });
// TRACK 1 INPUTS // TRACK 1 INPUTS
$('#track1-input > option').each(function () { $('#track1-input > option').each(async function () {
logger.debug("Saving track 1 input = " + this.value); logger.debug("Saving track 1 input = " + this.value);
context.jamClient.TrackSetAssignment(this.value, true, ASSIGNMENT.TRACK1); await context.jamClient.TrackSetAssignment(this.value, true, ASSIGNMENT.TRACK1);
}); });
// TRACK 1 INSTRUMENT // TRACK 1 INSTRUMENT
@ -581,15 +586,15 @@
var instrumentText = $('#track1-instrument > option:selected').text().toLowerCase(); var instrumentText = $('#track1-instrument > option:selected').text().toLowerCase();
logger.debug("Saving track 1 instrument = " + instrumentVal); logger.debug("Saving track 1 instrument = " + instrumentVal);
context.jamClient.TrackSetInstrument(ASSIGNMENT.TRACK1, instrumentVal); await context.jamClient.TrackSetInstrument(ASSIGNMENT.TRACK1, instrumentVal);
// TRACK 2 INPUTS // TRACK 2 INPUTS
var track2Selected = false; var track2Selected = false;
$('#track2-input > option').each(function () { $('#track2-input > option').each(async function () {
track2Selected = true; track2Selected = true;
logger.debug("Saving track 2 input = " + this.value); logger.debug("Saving track 2 input = " + this.value);
context.jamClient.TrackSetAssignment(this.value, true, ASSIGNMENT.TRACK2); await context.jamClient.TrackSetAssignment(this.value, true, ASSIGNMENT.TRACK2);
}); });
if (track2Selected) { if (track2Selected) {
@ -598,66 +603,66 @@
instrumentText = $('#track2-instrument > option:selected').text().toLowerCase(); instrumentText = $('#track2-instrument > option:selected').text().toLowerCase();
logger.debug("Saving track 2 instrument = " + instrumentVal); logger.debug("Saving track 2 instrument = " + instrumentVal);
context.jamClient.TrackSetInstrument(ASSIGNMENT.TRACK2, instrumentVal); await context.jamClient.TrackSetInstrument(ASSIGNMENT.TRACK2, instrumentVal);
} }
else { else {
// track 2 was removed // track 2 was removed
if (myTrackCount === 2) { if (myTrackCount === 2) {
logger.debug("Deleting track " + myTracks[1].trackId); logger.debug("Deleting track " + myTracks[1].trackId);
context.jamClient.TrackSetCount(1); await context.jamClient.TrackSetCount(1);
//sessionModel.deleteTrack(sessionId, myTracks[1].trackId); //sessionModel.deleteTrack(sessionId, myTracks[1].trackId);
} }
} }
// UNASSIGNED OUTPUTS // UNASSIGNED OUTPUTS
$('#audio-output-unused > option').each(function () { $('#audio-output-unused > option').each(async function () {
logger.debug("Marking " + this.value + " as unassigned output."); logger.debug("Marking " + this.value + " as unassigned output.");
context.jamClient.TrackSetAssignment(this.value, false, ASSIGNMENT.UNASSIGNED); await context.jamClient.TrackSetAssignment(this.value, false, ASSIGNMENT.UNASSIGNED);
}); });
// OUTPUT // OUTPUT
$('#audio-output-selection > option').each(function () { $('#audio-output-selection > option').each(async function () {
logger.debug("Saving session audio output = " + this.value); logger.debug("Saving session audio output = " + this.value);
context.jamClient.TrackSetAssignment(this.value, false, ASSIGNMENT.OUTPUT); await context.jamClient.TrackSetAssignment(this.value, false, ASSIGNMENT.OUTPUT);
}); });
} }
function saveVoiceChatSettings() { async function saveVoiceChatSettings() {
var voiceChatType = isChatInputSpecified(); var voiceChatType = isChatInputSpecified();
originalVoiceChat = voiceChatType; originalVoiceChat = voiceChatType;
logger.debug("Calling TrackSetChatEnable with value = " + voiceChatType); logger.debug("Calling TrackSetChatEnable with value = " + voiceChatType);
context.jamClient.TrackSetChatEnable(voiceChatType == VOICE_CHAT.CHAT ? true : false); await context.jamClient.TrackSetChatEnable(voiceChatType == VOICE_CHAT.CHAT ? true : false);
if (voiceChatType == VOICE_CHAT.CHAT) { if (voiceChatType == VOICE_CHAT.CHAT) {
// UNASSIGNED VOICE CHAT // UNASSIGNED VOICE CHAT
$('#voice-inputs-unused > option').each(function () { $('#voice-inputs-unused > option').each(async function () {
logger.debug("Marking " + this.value + " as unassigned voice input."); logger.debug("Marking " + this.value + " as unassigned voice input.");
context.jamClient.TrackSetAssignment(this.value, true, ASSIGNMENT.UNASSIGNED); await context.jamClient.TrackSetAssignment(this.value, true, ASSIGNMENT.UNASSIGNED);
}); });
// VOICE CHAT INPUT // VOICE CHAT INPUT
$("#voice-inputs-selection > option").each(function () { $("#voice-inputs-selection > option").each(async function () {
logger.debug("Saving chat input = " + this.value); logger.debug("Saving chat input = " + this.value);
context.jamClient.TrackSetAssignment(this.value, true, ASSIGNMENT.CHAT); await context.jamClient.TrackSetAssignment(this.value, true, ASSIGNMENT.CHAT);
}); });
} }
// make sure any previously assigned chat devices are marked as unassigned // make sure any previously assigned chat devices are marked as unassigned
else if (voiceChatType == VOICE_CHAT.NO_CHAT) { else if (voiceChatType == VOICE_CHAT.NO_CHAT) {
// chat devices that were assigned // chat devices that were assigned
$.each(chatOtherAssignedList, function (index, val) { $.each(chatOtherAssignedList, async function (index, val) {
logger.debug("Marking " + val.id + " as unassigned voice input."); logger.debug("Marking " + val.id + " as unassigned voice input.");
context.jamClient.TrackSetAssignment(val.id, true, ASSIGNMENT.UNASSIGNED); await context.jamClient.TrackSetAssignment(val.id, true, ASSIGNMENT.UNASSIGNED);
}); });
} }
} }
function cancelSettings() { async function cancelSettings() {
logger.debug("Cancel settings"); logger.debug("Cancel settings");
// reset to original device ID // reset to original device ID
context.jamClient.TrackSetMusicDevice(originalDeviceId); await context.jamClient.TrackSetMusicDevice(originalDeviceId);
$('#voice-chat-type').val(originalVoiceChat); $('#voice-chat-type').val(originalVoiceChat);
@ -759,10 +764,10 @@
return isValid; return isValid;
} }
function _setInstructions(type) { async function _setInstructions(type) {
var $instructions = $('#instructions', 'div[layout-id="configure-audio"]'); var $instructions = $('#instructions', 'div[layout-id="configure-audio"]');
if (type === 'audio') { if (type === 'audio') {
var os = context.jamClient.GetOSAsString(); var os = await context.jamClient.GetOSAsString();
$instructions.html(configure_audio_instructions[os]); $instructions.html(configure_audio_instructions[os]);
} }
else if (type === 'voice') { else if (type === 'voice') {
@ -774,18 +779,18 @@
return $('#voice-inputs-selection option').size() > 0 ? VOICE_CHAT.CHAT : VOICE_CHAT.NO_CHAT; return $('#voice-inputs-selection option').size() > 0 ? VOICE_CHAT.CHAT : VOICE_CHAT.NO_CHAT;
} }
function _init() { async function _init() {
// load instrument array for populating listboxes, using client_id in instrument_map as ID // load instrument array for populating listboxes, using client_id in instrument_map as ID
instrument_array = context.JK.listInstruments(); instrument_array = context.JK.listInstruments();
originalVoiceChat = context.jamClient.TrackGetChatEnable() ? VOICE_CHAT.CHAT : VOICE_CHAT.NO_CHAT; originalVoiceChat = await context.jamClient.TrackGetChatEnable() ? VOICE_CHAT.CHAT : VOICE_CHAT.NO_CHAT;
$('#voice-chat-type').val(originalVoiceChat); $('#voice-chat-type').val(originalVoiceChat);
originalDeviceId = context.jamClient.TrackGetMusicDeviceID(); originalDeviceId = await context.jamClient.TrackGetMusicDeviceID();
context.jamClient.TrackLoadAssignments(); await context.jamClient.TrackLoadAssignments();
initDialogData(); await initDialogData();
var $option1 = $('#voice-chat-type > option[value="1"]'); var $option1 = $('#voice-chat-type > option[value="1"]');

View File

@ -155,8 +155,8 @@
// inputChannelFilter is an optional argument that is used by the Gear Wizard. // inputChannelFilter is an optional argument that is used by the Gear Wizard.
// basically, if an input channel isn't in there, it's not going to be displayed // basically, if an input channel isn't in there, it's not going to be displayed
function loadChannels(forceInputsToUnassign, inputChannelFilter) { async function loadChannels(forceInputsToUnassign, inputChannelFilter) {
var musicPorts = jamClient.FTUEGetChannels(); var musicPorts = await jamClient.FTUEGetChannels();
$unassignedInputsHolder.empty(); $unassignedInputsHolder.empty();
$unassignedOutputsHolder.empty(); $unassignedOutputsHolder.empty();
@ -370,33 +370,44 @@
return true; return true;
} }
function save(state) { async function save(state) {
context._.each(state.unassignedChannels, function(unassignedChannelId) { //context._.each(state.unassignedChannels, async function(unassignedChannelId) {
context.jamClient.TrackSetAssignment(unassignedChannelId, true, ASSIGNMENT.UNASSIGNED); for(const unassignedChannelId of state.unassignedChannels){
}); await context.jamClient.TrackSetAssignment(unassignedChannelId, true, ASSIGNMENT.UNASSIGNED);
}
//});
// save input/tracks // save input/tracks
context._.each(state.tracks, function(track, index) { //context._.each(state.tracks, async function(track, index) {
for(let index = 0; index < state.tracks.length; index++) {
var track = state.tracks[index];
var trackNumber = index + 1; var trackNumber = index + 1;
context._.each(track.channels, function(channelId) { //context._.each(track.channels, async function(channelId) {
context.jamClient.TrackSetAssignment(channelId, true, trackNumber); for(const channelId of track.channels){
await context.jamClient.TrackSetAssignment(channelId, true, trackNumber);
}); }
//});
logger.debug("context.jamClient.TrackSetInstrument(trackNumber, track.instrument_id)", trackNumber, track.instrument_id); logger.debug("context.jamClient.TrackSetInstrument(trackNumber, track.instrument_id)", trackNumber, track.instrument_id);
context.jamClient.TrackSetInstrument(trackNumber, context.JK.instrument_id_to_instrument[track.instrument_id].client_id); await context.jamClient.TrackSetInstrument(trackNumber, context.JK.instrument_id_to_instrument[track.instrument_id].client_id);
}); }
//});
// save outputs // save outputs
context._.each(state.outputs, function(output, index) { //context._.each(state.outputs, function(output, index) {
context._.each(output.channels, function(channelId) { for(let index = 0; index < state.outputs.length; index ++) {
context.jamClient.TrackSetAssignment(channelId, true, ASSIGNMENT.OUTPUT); let output = state.outputs[index];
}); //context._.each(output.channels, async function(channelId) {
}); for (const channelId of output.channels) {
await context.jamClient.TrackSetAssignment(channelId, true, ASSIGNMENT.OUTPUT);
}
//});
}
//});
var result = context.jamClient.TrackSaveAssignments();
var result = await context.jamClient.TrackSaveAssignments();
if(!result || result.length == 0) { if(!result || result.length == 0) {
// success // success
@ -408,20 +419,25 @@
} }
} }
function loadTrackInstruments(forceInputsToUnassign) { async function loadTrackInstruments(forceInputsToUnassign) {
var $trackInstruments = $instrumentsHolder.find('.track-instrument'); var $trackInstruments = $instrumentsHolder.find('.track-instrument');
context._.each($trackInstruments, function(trackInstrument) { //context._.each($trackInstruments, async function(trackInstrument) {
for(let i = 0; i < $trackInstruments.length; i++) {
var trackInstrument = $trackInstruments[i];
var $trackInstrument = $(trackInstrument); var $trackInstrument = $(trackInstrument);
var trackIndex = parseInt($trackInstrument.attr('data-num')) + 1; var trackIndex = parseInt($trackInstrument.attr('data-num')) + 1;
var clientInstrument = context.jamClient.TrackGetInstrument(trackIndex); var clientInstrument = await context.jamClient.TrackGetInstrument(trackIndex);
var instrument = context.JK.client_to_server_instrument_map[clientInstrument]; var instrument = context.JK.client_to_server_instrument_map[clientInstrument];
$trackInstrument.instrumentSelectorSet(instrument ? instrument.server_id : instrument); $trackInstrument.instrumentSelectorSet(instrument ? instrument.server_id : instrument);
}); }
//});
} }
function trySave() { function trySave() {
@ -440,9 +456,9 @@
return saved; return saved;
} }
function reset(forceInputsToUnassign, inputChannelFilter) { async function reset(forceInputsToUnassign, inputChannelFilter) {
loadChannels(forceInputsToUnassign, inputChannelFilter); loadChannels(forceInputsToUnassign, inputChannelFilter);
loadTrackInstruments(forceInputsToUnassign); await loadTrackInstruments(forceInputsToUnassign);
} }
function unassignOutputChannel($channel) { function unassignOutputChannel($channel) {

View File

@ -26,8 +26,8 @@
// inputChannelFilter is an optional argument that is used by the Gear Wizard. // inputChannelFilter is an optional argument that is used by the Gear Wizard.
// basically, if an input channel isn't in there, it's not going to be displayed // basically, if an input channel isn't in there, it's not going to be displayed
function loadChannels(forceInputsToUnassign, inputChannelFilter) { async function loadChannels(forceInputsToUnassign, inputChannelFilter) {
var musicPorts = jamClient.FTUEGetChannels(); var musicPorts = await jamClient.FTUEGetChannels();
$unassignedInputsHolder.empty(); $unassignedInputsHolder.empty();
$unassignedOutputsHolder.empty(); $unassignedOutputsHolder.empty();
@ -177,33 +177,45 @@
return true; return true;
} }
function save(state) { async function save(state) {
context._.each(state.unassignedChannels, function(unassignedChannelId) { //context._.each(state.unassignedChannels, async function(unassignedChannelId) {
context.jamClient.TrackSetAssignment(unassignedChannelId, true, ASSIGNMENT.UNASSIGNED); for (const unassignedChannelId of state.unassignedChannels) {
}); await context.jamClient.TrackSetAssignment(unassignedChannelId, true, ASSIGNMENT.UNASSIGNED);
}
//});
// save input/tracks // save input/tracks
context._.each(state.tracks, function(track, index) { //context._.each(state.tracks, async function(track, index) {
for (let index = 0; index < state.tracks; index++) {
var track = state.tracks[index];
var trackNumber = index + 1; var trackNumber = index + 1;
context._.each(track.channels, function(channelId) { //context._.each(track.channels, async function(channelId) {
context.jamClient.TrackSetAssignment(channelId, true, trackNumber); for (const channelId of track.channels) {
await context.jamClient.TrackSetAssignment(channelId, true, trackNumber);
}); }
//});
logger.debug("context.jamClient.TrackSetInstrument(trackNumber, track.instrument_id)", trackNumber, track.instrument_id); logger.debug("context.jamClient.TrackSetInstrument(trackNumber, track.instrument_id)", trackNumber, track.instrument_id);
context.jamClient.TrackSetInstrument(trackNumber, context.JK.instrument_id_to_instrument[track.instrument_id].client_id); await context.jamClient.TrackSetInstrument(trackNumber, context.JK.instrument_id_to_instrument[track.instrument_id].client_id);
}); }
//});
// save outputs // save outputs
context._.each(state.outputs, function(output, index) { //context._.each(state.outputs, async function(output, index) {
context._.each(output.channels, function(channelId) { for(let index = 0; index < state.outputs.length; index++) {
context.jamClient.TrackSetAssignment(channelId, true, ASSIGNMENT.OUTPUT); let output = state.outputs[index];
}); //context._.each(output.channels, async function(channelId) {
}); for(const channelId of output.channels) {
await context.jamClient.TrackSetAssignment(channelId, true, ASSIGNMENT.OUTPUT);
}
//});
}
//});
var result = context.jamClient.TrackSaveAssignments(); var result = await context.jamClient.TrackSaveAssignments();
if(!result || result.length == 0) { if(!result || result.length == 0) {
// success // success
@ -215,20 +227,26 @@
} }
} }
function loadTrackInstruments(forceInputsToUnassign) { async function loadTrackInstruments(forceInputsToUnassign) {
var $trackInstruments = $instrumentsHolder.find('.track-instrument'); var $trackInstruments = $instrumentsHolder.find('.track-instrument');
context._.each($trackInstruments, function(trackInstrument) { //context._.each($trackInstruments, async function(trackInstrument) {
for(var i = 0; i < $trackInstruments.length; i++){
var trackInstrument = $trackInstruments[i];
var $trackInstrument = $(trackInstrument); var $trackInstrument = $(trackInstrument);
var trackIndex = parseInt($trackInstrument.attr('data-num')) + 1; var trackIndex = parseInt($trackInstrument.attr('data-num')) + 1;
var clientInstrument = context.jamClient.TrackGetInstrument(trackIndex); var clientInstrument = await context.jamClient.TrackGetInstrument(trackIndex);
var instrument = context.JK.client_to_server_instrument_map[clientInstrument]; var instrument = context.JK.client_to_server_instrument_map[clientInstrument];
$trackInstrument.instrumentSelectorSet(instrument ? instrument.server_id : instrument); $trackInstrument.instrumentSelectorSet(instrument ? instrument.server_id : instrument);
}); }
//});
} }
function trySave() { function trySave() {
@ -247,9 +265,9 @@
return saved; return saved;
} }
function reset(forceInputsToUnassign, inputChannelFilter) { async function reset(forceInputsToUnassign, inputChannelFilter) {
loadChannels(forceInputsToUnassign, inputChannelFilter); loadChannels(forceInputsToUnassign, inputChannelFilter);
loadTrackInstruments(forceInputsToUnassign); await loadTrackInstruments(forceInputsToUnassign);
} }
function unassignOutputChannel($channel) { function unassignOutputChannel($channel) {

View File

@ -116,7 +116,7 @@
return isValid; return isValid;
} }
function submitForm(evt) { async function submitForm(evt) {
evt.preventDefault(); evt.preventDefault();
if(!gon.isNativeClient) { if(!gon.isNativeClient) {
@ -136,7 +136,7 @@
} }
// if for some reason there are 0 tracks, show FTUE // if for some reason there are 0 tracks, show FTUE
var tracks = context.JK.TrackHelpers.getUserTracks(context.jamClient); var tracks = await context.JK.TrackHelpers.getUserTracks(context.jamClient);
if(tracks.length == 0) { if(tracks.length == 0) {
logger.error("we should never have 0 tracks and have gotten this far. Launch FTUE is the best we can do right now") logger.error("we should never have 0 tracks and have gotten this far. Launch FTUE is the best we can do right now")
// If user hasn't completed FTUE - do so now. // If user hasn't completed FTUE - do so now.
@ -172,7 +172,7 @@
if ($('#band-list option:selected').val() !== '') { if ($('#band-list option:selected').val() !== '') {
data.band = $('#band-list option:selected').val(); data.band = $('#band-list option:selected').val();
} }
data.audio_latency = context.jamClient.FTUEGetExpectedLatency().latency; data.audio_latency = await context.jamClient.FTUEGetExpectedLatency().latency;
// 1. If no previous session data, a single stereo track with the // 1. If no previous session data, a single stereo track with the
// top instrument in the user's profile. // top instrument in the user's profile.

View File

@ -0,0 +1,139 @@
(function (context, $) {
"use strict";
context.JK = context.JK || {};
context.JK.CustomUrlHandler = function () {
var hashchangeEvent;
var loadEvent;
function handleCustomUrlScheme(customUrl) {
var maxAttempts = 10;
//TODO: show a notification while waiting for the screen to load
//extract the hash from the custom URL passed in
var url = new URL(customUrl);
var hash = url.hash;
if (hash) { // if the hash contains the custom yes flag
var screenLoadInterval = setInterval(() => {
//handle create session. #/createSession is a valid hash. switch to the createSession screen and handle creating a session from the custom URL
if (hash.includes("#/createSession/")) { // if the hash contains the createSession flag
if(context.SessionStore && context.SessionStore.inSession()){
// clearInterval(screenLoadInterval);
// return;
}else{
console.log("attempting to create session", maxAttempts);
if (JK.createScheduledSessionScreen && JK.CreateScheduledSessionDataIsLoaded) { // if the createScheduledSessionScreen is loaded
JK.createScheduledSessionScreen.createSessionByCustomUrlScheme(hash); // this will create a session
clearInterval(screenLoadInterval);
} else {
console.log("attempting to create session. ", maxAttempts);
maxAttempts--;
if (maxAttempts <= 0) {
clearInterval(screenLoadInterval);
}
}
}
}
//handle join session. there is no joinSession screen. JK.SessionUtils is a helper class that handles joining a session
if (hash.includes("#/joinSession/")) { // if the hash contains the joinSession flag
if (JK.SessionUtils) { // if the SessionUtils is loaded
JK.SessionUtils.joinSessionFromCustomUrlScheme(hash);
clearInterval(screenLoadInterval);
} else {
console.log("attempting to join session", maxAttempts);
maxAttempts--;
if (maxAttempts <= 0) {
clearInterval(screenLoadInterval);
}
}
}
}, 1000); // check every second
}
}
function isValidUrl(customUrl) {
if (!customUrl) {
return false;
}
try {
var url = new URL(customUrl);
var hash = url.hash;
//if the customUrl is valid, return true
if (hash.includes("#/createSession/") || hash.includes("#/joinSession/")) {
return true;
}
}catch (e) {
return false;
}
return false
}
function getCustomUrl() {
//get customUrl from local storage
if (localStorage && localStorage.getItem("customUrl")) {
try{
return decodeURIComponent(localStorage.getItem("customUrl"));
}
catch(e){
console.error("error decoding customUrl", e);
return null;
}
}
return null;
}
function handle() {
//clear the event listeners
if (hashchangeEvent) {
window.removeEventListener('hashchange', hashchangeEvent);
}
if (loadEvent) {
window.removeEventListener('load', loadEvent);
}
// check periodically if localStorage has customUrl available for 10 seconds
//if available call handleCustomUrlScheme and clear the interval and localStorage customUrl
var attempts = 5;
var customUrlInterval = setInterval(() => {
const customUrl = getCustomUrl();
if(customUrl && isValidUrl(customUrl)){
handleCustomUrlScheme(customUrl);
localStorage.removeItem("customUrl");
clearInterval(customUrlInterval);
}
if (attempts < 0) {
localStorage.removeItem("customUrl");
clearInterval(customUrlInterval);
}
attempts--;
}, 1000);
}
function initialize() {
hashchangeEvent = window.addEventListener('hashchange', function () {
handle();
});
loadEvent = window.addEventListener('load', (event) => {
handle();
});
}
return {
initialize: initialize,
isValidUrl: isValidUrl,
};
};
})(window, jQuery);

View File

@ -51,22 +51,22 @@
gearUtils.updateDefaultBuffers(selectedDeviceInfo, frameBuffers) gearUtils.updateDefaultBuffers(selectedDeviceInfo, frameBuffers)
} }
function onFramesizeChanged() { async function onFramesizeChanged() {
//context.JK.prodBubble($resyncBtn, 'push-resync-when-done', {}, {positions:['top']}); //context.JK.prodBubble($resyncBtn, 'push-resync-when-done', {}, {positions:['top']});
updateDefaultBuffers(); updateDefaultBuffers();
context.jamClient.FTUESetFrameSize(frameBuffers.selectedFramesize()); await context.jamClient.FTUESetFrameSize(frameBuffers.selectedFramesize());
invalidateScore(); invalidateScore();
} }
function onBufferInChanged() { async function onBufferInChanged() {
//context.JK.prodBubble($resyncBtn, 'push-resync-when-done', {}, {positions:['top']}); //context.JK.prodBubble($resyncBtn, 'push-resync-when-done', {}, {positions:['top']});
context.jamClient.FTUESetInputLatency(frameBuffers.selectedBufferIn()); await context.jamClient.FTUESetInputLatency(frameBuffers.selectedBufferIn());
invalidateScore(); invalidateScore();
} }
function onBufferOutChanged() { async function onBufferOutChanged() {
//context.JK.prodBubble($resyncBtn, 'push-resync-when-done', {}, {positions:['top']}); //context.JK.prodBubble($resyncBtn, 'push-resync-when-done', {}, {positions:['top']});
context.jamClient.FTUESetOutputLatency(frameBuffers.selectedBufferOut()); await context.jamClient.FTUESetOutputLatency(frameBuffers.selectedBufferOut());
invalidateScore(); invalidateScore();
} }
@ -110,12 +110,13 @@
} }
} }
function beforeShow() { async function beforeShow() {
selectedDeviceInfo = gearUtils.selectedDeviceInfo(context.jamClient.FTUEGetInputMusicDevice(), context.jamClient.FTUEGetOutputMusicDevice()); let [p1, p2] = await Promise.all([context.jamClient.FTUEGetInputMusicDevice(), context.jamClient.FTUEGetOutputMusicDevice()])
deviceInformation = gearUtils.loadDeviceInfo(); selectedDeviceInfo = await gearUtils.selectedDeviceInfo(p1, p1);
startingFramesize = context.jamClient.FTUEGetFrameSize(); deviceInformation = await gearUtils.loadDeviceInfo();
startingBufferIn = context.jamClient.FTUEGetInputLatency(); startingFramesize = await context.jamClient.FTUEGetFrameSize();
startingBufferOut = context.jamClient.FTUEGetOutputLatency(); startingBufferIn = await context.jamClient.FTUEGetInputLatency();
startingBufferOut = await context.jamClient.FTUEGetOutputLatency();
var startingSpeed = translateFrameSizeToSpeed(startingFramesize) var startingSpeed = translateFrameSizeToSpeed(startingFramesize)
logger.debug("speed upon entry: " + startingSpeed) logger.debug("speed upon entry: " + startingSpeed)
$speedOptions.filter('[value=' + startingSpeed + ']').iCheck('check') $speedOptions.filter('[value=' + startingSpeed + ']').iCheck('check')
@ -219,7 +220,7 @@
} }
function initialize() { async function initialize() {
var dialogBindings = { var dialogBindings = {
'beforeShow': beforeShow, 'beforeShow': beforeShow,
'beforeHide': beforeHide, 'beforeHide': beforeHide,
@ -238,7 +239,7 @@
$fairLabel = $dialog.find('label[for="adjust-gear-speed-fair"]') $fairLabel = $dialog.find('label[for="adjust-gear-speed-fair"]')
$fastLabel = $dialog.find('label[for="adjust-gear-speed-fast"]') $fastLabel = $dialog.find('label[for="adjust-gear-speed-fast"]')
operatingSystem = context.JK.GetOSAsString(); operatingSystem = await context.JK.GetOSAsString();
$frameBuffers = $dialog.find('.frame-and-buffers'); $frameBuffers = $dialog.find('.frame-and-buffers');
frameBuffers.initialize($frameBuffers); frameBuffers.initialize($frameBuffers);

View File

@ -120,15 +120,17 @@
}) })
} }
function onUsbDeviceConnected() { async function onUsbDeviceConnected() {
if(!context.jamClient.IsFrontendVisible()) {return;} // don't handle USB events when minimized var isFrontendVisible = await context.jamClient.IsFrontendVisible()
if(!isFrontendVisible) {return;} // don't handle USB events when minimized
logger.debug("USB device connected"); logger.debug("USB device connected");
scheduleRescanSystem(3000); scheduleRescanSystem(3000);
} }
function onUsbDeviceDisconnected() { async function onUsbDeviceDisconnected() {
if(!context.jamClient.IsFrontendVisible()) {return;} // don't handle USB events when minimized var isFrontendVisible = await context.jamClient.IsFrontendVisible()
if(!isFrontendVisible) {return;} // don't handle USB events when minimized
logger.debug("USB device disconnected"); logger.debug("USB device disconnected");
scheduleRescanSystem(3000); scheduleRescanSystem(3000);
@ -149,8 +151,8 @@
context.JK.Banner.showYesNo({ context.JK.Banner.showYesNo({
title: "Confirm Restart", title: "Confirm Restart",
html: "Are you sure you want to restart JamKazam?", html: "Are you sure you want to restart JamKazam?",
yes: function() { yes: async function() {
context.jamClient.RestartApplication(); await context.jamClient.RestartApplication();
}, },
no : function() { no : function() {
context.JK.Banner.hide(); context.JK.Banner.hide();

View File

@ -50,31 +50,31 @@
context.JK.checkbox($autoStartInput); context.JK.checkbox($autoStartInput);
context.JK.checkbox($useStaticPortInput); context.JK.checkbox($useStaticPortInput);
$btnSave.click(function() { $btnSave.click(async function() {
if (!validate()) { if (!validate()) {
return false; return false;
} }
var autostart = $autoStartField.find('.icheckbox_minimal').is('.checked'); var autostart = $autoStartField.find('.icheckbox_minimal').is('.checked');
context.jamClient.SetAutoStart(autostart); await context.jamClient.SetAutoStart(autostart);
var useStaticPort = $useStaticPortField.find('.icheckbox_minimal').is('.checked'); var useStaticPort = $useStaticPortField.find('.icheckbox_minimal').is('.checked');
context.jamClient.SetUseStaticPort(useStaticPort); await context.jamClient.SetUseStaticPort(useStaticPort);
var staticPort = new Number($staticPortInput.val()); var staticPort = new Number($staticPortInput.val());
context.jamClient.SetStaticPort(staticPort); await context.jamClient.SetStaticPort(staticPort);
app.layout.closeDialog('client-preferences-dialog') app.layout.closeDialog('client-preferences-dialog')
context.jamClient.SaveSettings(); await context.jamClient.SaveSettings();
logger.debug("New Client Settings", {autostart: autostart, useStaticPort: useStaticPort, staticPort: staticPort}) logger.debug("New Client Settings", {autostart: autostart, useStaticPort: useStaticPort, staticPort: staticPort})
if ((beforeValues.useStaticPort != useStaticPort) || (beforeValues.staticPort != staticPort)) { if ((beforeValues.useStaticPort != useStaticPort) || (beforeValues.staticPort != staticPort)) {
context.JK.Banner.showYesNo({ context.JK.Banner.showYesNo({
title: "Please Restart", title: "Please Restart",
html: "The changes you made won't take effect until you restart JamKazam. Restart now?", html: "The changes you made won't take effect until you restart JamKazam. Restart now?",
yes: function() { yes: async function() {
context.jamClient.RestartApplication(); await context.jamClient.RestartApplication();
}, },
no : function() { no : function() {
context.JK.Banner.hide(); context.JK.Banner.hide();
@ -85,14 +85,14 @@
}) })
} }
function beforeShow() { async function beforeShow() {
var autostart = context.jamClient.GetAutoStart(); var autostart = await context.jamClient.GetAutoStart();
autostart ? $autoStartInput.iCheck('check') : $autoStartInput.iCheck('uncheck'); autostart ? $autoStartInput.iCheck('check') : $autoStartInput.iCheck('uncheck');
var useStaticPort = context.jamClient.GetUseStaticPort(); var useStaticPort = await context.jamClient.GetUseStaticPort();
useStaticPort ? $useStaticPortInput.iCheck('check') : $useStaticPortInput.iCheck('uncheck'); useStaticPort ? $useStaticPortInput.iCheck('check') : $useStaticPortInput.iCheck('uncheck');
var staticPort = context.jamClient.GetStaticPort(); var staticPort = await context.jamClient.GetStaticPort();
$staticPortInput.val(staticPort); $staticPortInput.val(staticPort);

View File

@ -33,9 +33,9 @@
rest.getSessionHistory(sessionId) rest.getSessionHistory(sessionId)
.done(function(response) { .done(function(response) {
if (response && response.comments) { if (response && response.comments) {
$.each(response.comments, function(index, val) { $.each(response.comments, async function(index, val) {
renderComment(val.comment, val.creator.id, val.creator.name, renderComment(val.comment, val.creator.id, val.creator.name,
context.JK.resolveAvatarUrl(val.creator.photo_url), $.timeago(val.created_at), val.creator.musician, true); await context.JK.resolveAvatarUrl(val.creator.photo_url), $.timeago(val.created_at), val.creator.musician, true);
}); });
context.JK.bindHoverEvents($content); context.JK.bindHoverEvents($content);
context.JK.bindProfileClickEvents($content, ['comment-dialog']); context.JK.bindProfileClickEvents($content, ['comment-dialog']);
@ -49,9 +49,9 @@
rest.getClaimedRecording(claimedRecordingId) rest.getClaimedRecording(claimedRecordingId)
.done(function(response) { .done(function(response) {
if (response.recording && response.recording.comments) { if (response.recording && response.recording.comments) {
$.each(response.recording.comments, function(index, val) { $.each(response.recording.comments, async function(index, val) {
renderComment(val.comment, val.creator.id, val.creator.name, renderComment(val.comment, val.creator.id, val.creator.name,
context.JK.resolveAvatarUrl(val.creator.photo_url), $.timeago(val.created_at), val.creator.musician, true); await context.JK.resolveAvatarUrl(val.creator.photo_url), $.timeago(val.created_at), val.creator.musician, true);
}); });
context.JK.bindHoverEvents($content); context.JK.bindHoverEvents($content);

View File

@ -158,7 +158,7 @@
//context.JK.dropdown($certifiedAudioProfile); //context.JK.dropdown($certifiedAudioProfile);
} }
function deviceChanged() { async function deviceChanged() {
var profile = $certifiedAudioProfile.val(); var profile = $certifiedAudioProfile.val();
if(currentProfile == profile) { if(currentProfile == profile) {
@ -166,7 +166,7 @@
} }
logger.debug("activating audio profile: " + profile); logger.debug("activating audio profile: " + profile);
var result = context.jamClient.FTUELoadAudioConfiguration(profile); var result = await context.jamClient.FTUELoadAudioConfiguration(profile);
if(!result) { if(!result) {
logger.error("unable to activate audio configuration: " + profile + ", " + JSON.stringify(result)); logger.error("unable to activate audio configuration: " + profile + ", " + JSON.stringify(result));
@ -176,7 +176,7 @@
} }
// FTUELoadAudioConfiguration eventually sets this, but apparently asynchronously // FTUELoadAudioConfiguration eventually sets this, but apparently asynchronously
result = context.jamClient.SetLastUsedProfileName(profile); result = await context.jamClient.SetLastUsedProfileName(profile);
if(!result) { if(!result) {
logger.error("unable to activate audio configuration after loading it: " + profile); logger.error("unable to activate audio configuration after loading it: " + profile);
@ -189,20 +189,20 @@
window.ConfigureTracksActions.reset(false); window.ConfigureTracksActions.reset(false);
} }
function beforeShow() { async function beforeShow() {
profiles = gearUtils.getProfiles(); profiles = await gearUtils.getProfiles();
renderCertifiedGearDropdown(); renderCertifiedGearDropdown();
showMusicAudioPanel(); showMusicAudioPanel();
currentProfile = context.jamClient.LastUsedProfileName(); currentProfile = await context.jamClient.LastUsedProfileName();
if(currentProfile != $certifiedAudioProfile.val()) { if(currentProfile != $certifiedAudioProfile.val()) {
logger.error("the currently active profile (" + currentProfile + ") is not the same as the Certified Audio Gear dropdown (" + $certifiedAudioProfile.val() + ")"); logger.error("the currently active profile (" + currentProfile + ") is not the same as the Certified Audio Gear dropdown (" + $certifiedAudioProfile.val() + ")");
context.JK.alertSupportedNeeded("Unable to determine the current profile."); context.JK.alertSupportedNeeded("Unable to determine the current profile.");
} }
var result = context.jamClient.FTUELoadAudioConfiguration(currentProfile); var result = await context.jamClient.FTUELoadAudioConfiguration(currentProfile);
if(!result) { if(!result) {
logger.error("unable to activate audio configuration: " + currentProfile + ", " + JSON.stringify(result)); logger.error("unable to activate audio configuration: " + currentProfile + ", " + JSON.stringify(result));
@ -221,12 +221,12 @@
voiceChatHelper.beforeShow(); voiceChatHelper.beforeShow();
} }
function delayEnableVst() { async function delayEnableVst() {
if (enableVstTimeout) { if (enableVstTimeout) {
clearTimeout(enableVstTimeout) clearTimeout(enableVstTimeout)
} }
var isVstLoaded = context.jamClient.IsVstLoaded() var isVstLoaded = await context.jamClient.IsVstLoaded()
var hasVstAssignment = context.jamClient.hasVstAssignment() var hasVstAssignment = await context.jamClient.hasVstAssignment()
if (hasVstAssignment && !isVstLoaded) { if (hasVstAssignment && !isVstLoaded) {
enableVstTimeout = setTimeout(function() { enableVst() }, 1000) enableVstTimeout = setTimeout(function() { enableVst() }, 1000)

View File

@ -20,7 +20,7 @@
var template = $('#template-friend-selection').html(); var template = $('#template-friend-selection').html();
var friends = rest.getFriends({ id: context.JK.currentUserId }) var friends = rest.getFriends({ id: context.JK.currentUserId })
.done(function(friends) { .done(function(friends) {
$.each(friends, function(index, val) { $.each(friends, async function(index, val) {
var id = val.id; var id = val.id;
var isSelected = selectedIds[id]; var isSelected = selectedIds[id];
@ -28,7 +28,7 @@
userId: id, userId: id,
css_class: isSelected ? 'selected' : '', css_class: isSelected ? 'selected' : '',
userName: val.name, userName: val.name,
avatar_url: context.JK.resolveAvatarUrl(val.photo_url), avatar_url: await context.JK.resolveAvatarUrl(val.photo_url),
status: "", status: "",
status_img_url: "", status_img_url: "",
check_mark_display: isSelected ? "block" : "none", check_mark_display: isSelected ? "block" : "none",

View File

@ -24,13 +24,13 @@
function registerEvents() { function registerEvents() {
$setupGearBtn.click(function() { $setupGearBtn.click(async function() {
if (gon.isNativeClient) { if (gon.isNativeClient) {
app.layout.closeDialog('getting-started'); app.layout.closeDialog('getting-started');
// if no profiles, show FTUE in-line, if any, redirect to audio profile line // if no profiles, show FTUE in-line, if any, redirect to audio profile line
var profiles = context.jamClient.FTUEGetAllAudioConfigurations(); var profiles = await context.jamClient.FTUEGetAllAudioConfigurations();
if(profiles && profile.length > 0) { if(profiles && profile.length > 0) {
window.location = '/client#/account/audio' window.location = '/client#/account/audio'

View File

@ -28,7 +28,8 @@
resetPagination(); resetPagination();
showing = true; showing = true;
getRecordings(0) getRecordings(0)
.done(function(data, textStatus, jqXHR) { .then(function(resp) {
const [claimedRecordings, textStatus, jqXHR] = resp;
// initialize pagination // initialize pagination
var $paginator = context.JK.Paginator.create(parseInt(jqXHR.getResponseHeader('total-entries')), perPage, 0, onPageSelected) var $paginator = context.JK.Paginator.create(parseInt(jqXHR.getResponseHeader('total-entries')), perPage, 0, onPageSelected)
$('#local-recordings-dialog .paginator-holder').append($paginator); $('#local-recordings-dialog .paginator-holder').append($paginator);
@ -45,15 +46,15 @@
} }
function getRecordings(page) { function getRecordings(page) {
return rest.getClaimedRecordings({page:page + 1, per_page:10}) const promise = rest.getClaimedRecordingsPromise({page:page + 1, per_page:10})
.done(function(claimedRecordings) { promise.then(async function(resp) {
const [claimedRecordings, textStatus, jqXHR] = resp;
emptyList(); emptyList();
var $tbody = tbody(); const $tbody = tbody();
var recordings = $.map(claimedRecordings, function(val, i) { return val.recording; }); const recordings = $.map(claimedRecordings, function(val, i) { return val.recording; });
var localResults = context.jamClient.GetLocalRecordingState({recordings: recordings}); const localResults = await context.jamClient.GetLocalRecordingState({recordings: recordings});
if(localResults['error']) { if(localResults['error']) {
app.notify({ app.notify({
@ -69,7 +70,7 @@
$.each(claimedRecordings, function(index, claimedRecording) { $.each(claimedRecordings, function(index, claimedRecording) {
var options = { const options = {
recordingId: claimedRecording.recording.id, recordingId: claimedRecording.recording.id,
//date: context.JK.formatDate(claimedRecording.recording.created_at), //date: context.JK.formatDate(claimedRecording.recording.created_at),
//time: context.JK.formatTime(claimedRecording.recording.created_at), //time: context.JK.formatTime(claimedRecording.recording.created_at),
@ -79,15 +80,18 @@
duration: context.JK.prettyPrintSeconds(claimedRecording.recording.duration) duration: context.JK.prettyPrintSeconds(claimedRecording.recording.duration)
}; };
var tr = $(context._.template($('#template-claimed-recording-row').html(), options, { variable: 'data' })); const tr = $(context._.template($('#template-claimed-recording-row').html(), options, { variable: 'data' }));
tr.data('server-model', claimedRecording); tr.data('server-model', claimedRecording);
$tbody.append(tr); $tbody.append(tr);
}); });
}) })
.fail(function(jqXHR, textStatus, errorMessage) { .catch(function(error) {
const [jqXHR, textStatus, errorMessage] = error;
app.ajaxError(jqXHR, textStatus, errorMessage); app.ajaxError(jqXHR, textStatus, errorMessage);
}); });
return promise;
} }
function registerStaticEvents() { function registerStaticEvents() {
@ -123,13 +127,13 @@
// tell the server we are about to start a recording // tell the server we are about to start a recording
rest.startPlayClaimedRecording({id: context.SessionStore.id(), claimed_recording_id: claimedRecording.id}) rest.startPlayClaimedRecording({id: context.SessionStore.id(), claimed_recording_id: claimedRecording.id})
.done(function(response) { .then(async function(response) {
// update session info // update session info
context.SessionActions.updateSession.trigger(response); context.SessionActions.updateSession.trigger(response);
var recordingId = $(this).attr('data-recording-id'); var recordingId = $(this).attr('data-recording-id');
var openRecordingResult = context.jamClient.OpenRecording(claimedRecording.recording); var openRecordingResult = await context.jamClient.OpenRecording(claimedRecording.recording);
logger.debug("OpenRecording response: %o", openRecordingResult); logger.debug("OpenRecording response: %o", openRecordingResult);
@ -153,14 +157,15 @@
app.layout.closeDialog('localRecordings'); app.layout.closeDialog('localRecordings');
$(this).triggerHandler('openedSession', {}); $(this).triggerHandler('openedSession', {});
} }
openingRecording = false;
}) })
.fail(function(jqXHR) { .catch(function(jqXHR) {
app.notifyServerError(jqXHR, "Unable to Open Recording For Playback"); app.notifyServerError(jqXHR, "Unable to Open Recording For Playback");
openingRecording = false;
})
.always(function() {
openingRecording = false;
}) })
// .finally(function() {
// openingRecording = false;
// })
} }

View File

@ -46,9 +46,9 @@
return getBackingTracks(targetPage); return getBackingTracks(targetPage);
} }
function getBackingTracks(page) { async function getBackingTracks(page) {
var result = context.jamClient.getBackingTrackList(); var result = await context.jamClient.getBackingTrackList();
var backingTracks = result.backing_tracks; var backingTracks = result.backing_tracks;
if (!backingTracks || backingTracks.length == 0) { if (!backingTracks || backingTracks.length == 0) {
@ -86,8 +86,8 @@
// tell the server we are about to open a backing track: // tell the server we are about to open a backing track:
rest.openBackingTrack({id: context.SessionStore.id(), backing_track_path: backingTrack.name}) rest.openBackingTrack({id: context.SessionStore.id(), backing_track_path: backingTrack.name})
.done(function(response) { .done(async function(response) {
var result = context.jamClient.SessionOpenBackingTrackFile(backingTrack.name, false); var result = await context.jamClient.SessionOpenBackingTrackFile(backingTrack.name, false);
// TODO: Possibly actually check the result. Investigate // TODO: Possibly actually check the result. Investigate
// what real client returns: // what real client returns:
@ -112,9 +112,9 @@
context.JK.helpBubble($whatAreBackingTracks, 'no help yet for this topic', {}, {positions:['bottom'], offsetParent: $dialog}) context.JK.helpBubble($whatAreBackingTracks, 'no help yet for this topic', {}, {positions:['bottom'], offsetParent: $dialog})
$whatAreBackingTracks.on('click', false) // no help yet $whatAreBackingTracks.on('click', false) // no help yet
$displayAudioFileFolder.on('click', function(e) { $displayAudioFileFolder.on('click', async function(e) {
e.stopPropagation(); e.stopPropagation();
context.jamClient.OpenBackingTracksDirectory(); await context.jamClient.OpenBackingTracksDirectory();
}) })
} }

View File

@ -96,11 +96,11 @@
} }
function afterShow() { async function afterShow() {
$dialog.data('result', null) $dialog.data('result', null)
showing = true; showing = true;
sampleRate = context.jamClient.GetSampleRate() sampleRate = await context.jamClient.GetSampleRate()
sampleRateForFilename = sampleRate == 48 ? '48' : '44'; sampleRateForFilename = sampleRate == 48 ? '48' : '44';
doSearch(); doSearch();
} }
@ -134,14 +134,14 @@
emptyList(); emptyList();
$.each(purchasedJamTracks.jamtracks, function(index, jamTrack) { $.each(purchasedJamTracks.jamtracks, async function(index, jamTrack) {
var options = {} var options = {}
options.jamTrackState = null; options.jamTrackState = null;
options.jamTrackId = jamTrack.id; options.jamTrackId = jamTrack.id;
options.name = jamTrack.name; options.name = jamTrack.name;
options.artist = jamTrack.original_artist; options.artist = jamTrack.original_artist;
var detail = context.jamClient.JamTrackGetTrackDetail(jamTrack.id + '-' + sampleRateForFilename) || {} var detail = await context.jamClient.JamTrackGetTrackDetail(jamTrack.id + '-' + sampleRateForFilename) || {}
options.downloaded = detail.key_state == 'ready' ? 'Yes' : 'No' options.downloaded = detail.key_state == 'ready' ? 'Yes' : 'No'
var $tr = $(context._.template($templateOpenJamTrackRow.html(), options, { variable: 'data' })); var $tr = $(context._.template($templateOpenJamTrackRow.html(), options, { variable: 'data' }));

View File

@ -81,7 +81,7 @@
} }
return false; return false;
}); });
$('#btn-rate-session-send', $scopeSelector).click(function(evt) { $('#btn-rate-session-send', $scopeSelector).click(async function(evt) {
var rr = getRating(), cc = getComment(); var rr = getRating(), cc = getComment();
if (0 == rr && 0 == cc.length) { if (0 == rr && 0 == cc.length) {
closeDialog(); closeDialog();
@ -93,10 +93,10 @@
} }
var url = "/api/participant_histories/"+clientId+"/rating"; var url = "/api/participant_histories/"+clientId+"/rating";
// get backend details too // get backend details too
if(context.jamClient.getAllClientsStateMap) { //if(context.jamClient.getAllClientsStateMap) {
var backendDetails = context.jamClient.getAllClientsStateMap() var backendDetails = await context.jamClient.getAllClientsStateMap()
console.log("got backend details", backendDetails) console.log("got backend details", backendDetails)
} //}
$.ajax({ $.ajax({
type: "POST", type: "POST",

View File

@ -36,7 +36,7 @@
removeGoogleLoginErrors() removeGoogleLoginErrors()
} }
function beforeShow() { async function beforeShow() {
$dialog.data('result', null); $dialog.data('result', null);
if (recording == null) { if (recording == null) {
alert("recording data should not be null"); alert("recording data should not be null");
@ -46,7 +46,7 @@
resetForm(); resetForm();
if(context.jamClient.getClientParentChildRole() == CLIENT_ROLE.CHILD) { if(await context.jamClient.getClientParentChildRole() == CLIENT_ROLE.CHILD) {
logger.debug("child client; launching preview after xfer"); logger.debug("child client; launching preview after xfer");
$('#recording-finished-dialog span.nowait').addClass('hidden') $('#recording-finished-dialog span.nowait').addClass('hidden')
@ -61,14 +61,14 @@
$('#recording-finished-dialog span.nowait').removeClass('hidden') $('#recording-finished-dialog span.nowait').removeClass('hidden')
$('#recording-finished-dialog .preview-area').css('visibility', 'visible') $('#recording-finished-dialog .preview-area').css('visibility', 'visible')
$('#recording-finished-dialog form').css('visibility', 'visible') $('#recording-finished-dialog form').css('visibility', 'visible')
launchPreview(); await launchPreview();
} }
} }
function waitForMixTransfer() { function waitForMixTransfer() {
timeout = setTimeout(function() { timeout = setTimeout(async function() {
console.log("checking for file transfer", window.RecordingStore.mixTransferred) console.log("checking for file transfer", window.RecordingStore.mixTransferred)
if(window.RecordingStore.mixTransferred) { if(window.RecordingStore.mixTransferred) {
@ -77,7 +77,7 @@
$('#recording-finished-dialog .preview-area').css('visibility', 'visible') $('#recording-finished-dialog .preview-area').css('visibility', 'visible')
$('#recording-finished-dialog form').css('visibility', 'visible') $('#recording-finished-dialog form').css('visibility', 'visible')
timeout = null timeout = null
launchPreview() await launchPreview()
} }
else { else {
waitForMixTransfer(); waitForMixTransfer();
@ -86,7 +86,7 @@
}, 1000) }, 1000)
} }
function launchPreview() { async function launchPreview() {
var parentSelector = '#recording-finished-dialog div.genre-selector'; var parentSelector = '#recording-finished-dialog div.genre-selector';
context.JK.GenreSelectorHelper.render(parentSelector); context.JK.GenreSelectorHelper.render(parentSelector);
@ -97,7 +97,7 @@
context.JK.GenreSelectorHelper.setSelectedGenres(parentSelector, [genreDescription]); context.JK.GenreSelectorHelper.setSelectedGenres(parentSelector, [genreDescription]);
} }
var localResults = context.jamClient.GetLocalRecordingState({recordings: [recording]}); var localResults = await context.jamClient.GetLocalRecordingState({recordings: [recording]});
if (localResults['error']) { if (localResults['error']) {
logger.error("unable to open recording due to error: %o", localResults); logger.error("unable to open recording due to error: %o", localResults);
@ -128,7 +128,7 @@
else { else {
// load recording // load recording
var openRecordingResult = context.jamClient.PreviewRecording(recording); var openRecordingResult = await context.jamClient.PreviewRecording(recording);
logger.debug("OpenRecording response: %o", openRecordingResult); logger.debug("OpenRecording response: %o", openRecordingResult);
@ -161,7 +161,7 @@
} }
} }
} }
function afterHide() { async function afterHide() {
if(timeout) { if(timeout) {
clearTimeout(timeout) clearTimeout(timeout)
timeout = null timeout = null
@ -177,12 +177,12 @@
logger.debug("VideoDecision rid:" + recording.id + ", name=" + name + ", keepResult=" + keepResult + ", saveToDisk=" + saveToDisk); logger.debug("VideoDecision rid:" + recording.id + ", name=" + name + ", keepResult=" + keepResult + ", saveToDisk=" + saveToDisk);
context.jamClient.VideoDecision(recording.id, name, keepResult && saveToDisk) await context.jamClient.VideoDecision(recording.id, name, keepResult && saveToDisk)
} }
recording = null; recording = null;
playbackControls.stopMonitor(); playbackControls.stopMonitor();
context.jamClient.ClosePreviewRecording(); await context.jamClient.ClosePreviewRecording();
} }
function onCancel() { function onCancel() {
@ -337,24 +337,24 @@
} }
} }
function onPause() { async function onPause() {
logger.debug("calling jamClient.SessionPausePlay"); logger.debug("calling jamClient.SessionPausePlay");
context.jamClient.SessionPausePlay(); await context.jamClient.SessionPausePlay();
} }
function onStop() { async function onStop() {
logger.debug("calling jamClient.SessionStopPlay"); logger.debug("calling jamClient.SessionStopPlay");
context.jamClient.SessionStopPlay(); await context.jamClient.SessionStopPlay();
} }
function onPlay(e, data) { async function onPlay(e, data) {
logger.debug("calling jamClient.SessionStartPlay"); logger.debug("calling jamClient.SessionStartPlay");
context.jamClient.SessionStartPlay(data.playbackMode); await context.jamClient.SessionStartPlay(data.playbackMode);
} }
function onChangePlayPosition(e, data) { async function onChangePlayPosition(e, data) {
logger.debug("calling jamClient.SessionTrackSeekMs(" + data.positionMs + ")"); logger.debug("calling jamClient.SessionTrackSeekMs(" + data.positionMs + ")");
context.jamClient.SessionTrackSeekMs(data.positionMs); await context.jamClient.SessionTrackSeekMs(data.positionMs);
} }
function registerStaticEvents() { function registerStaticEvents() {

View File

@ -23,14 +23,23 @@ context.JK.SessionMasterMixDialog = class SessionMasterMixDialog
@app.bindDialog(@dialogId, dialogBindings) @app.bindDialog(@dialogId, dialogBindings)
@content = @dialog.find(".dialog-inner") @content = @dialog.find(".dialog-inner")
beforeShow:() => # beforeShow:() =>
@logger.debug("session-master-mix-dlg: beforeShow") # @logger.debug("session-master-mix-dlg: beforeShow")
context.jamClient.SetMixerMode(MIX_MODES.MASTER) # context.jamClient.SetMixerMode(MIX_MODES.MASTER)
beforeShow: `async function(){
this.logger.debug("session-master-mix-dlg: beforeShow");
await context.jamClient.SetMixerMode(MIX_MODES.MASTER);
}`
afterShow:() => afterShow:() =>
@logger.debug("session-master-mix-dlg: afterShow") @logger.debug("session-master-mix-dlg: afterShow")
afterHide:() => # afterHide:() =>
context.jamClient.SetMixerMode(MIX_MODES.PERSONAL) # context.jamClient.SetMixerMode(MIX_MODES.PERSONAL)
afterHide: `async function(){
await context.jamClient.SetMixerMode(MIX_MODES.PERSONAL);
}`

View File

@ -15,9 +15,9 @@
var rest = new JK.Rest(); var rest = new JK.Rest();
var sessionId; var sessionId;
function beforeShow(data) { async function beforeShow(data) {
var canPlayWithOthers = gearUtils.canPlayWithOthers(); var canPlayWithOthers = await gearUtils.canPlayWithOthers();
context.JK.GenreSelectorHelper.render('#session-settings-genre'); context.JK.GenreSelectorHelper.render('#session-settings-genre');
$dialog = $('[layout-id="session-settings"]'); $dialog = $('[layout-id="session-settings"]');

View File

@ -452,7 +452,7 @@
registerEvents(false); registerEvents(false);
} }
function initialize(_facebookHelper) { async function initialize(_facebookHelper) {
facebookHelper = _facebookHelper; facebookHelper = _facebookHelper;
var dialogBindings = { var dialogBindings = {
@ -467,9 +467,9 @@
facebookHelper.deferredLoginStatus().done(function(response) { handleFbStateChange(response); }); facebookHelper.deferredLoginStatus().done(function(response) { handleFbStateChange(response); });
if(context.jamClient.IsNativeClient()) { if(context.JK.isQWebEngine) {
$("#btn-share-copy").unbind('click').click(function() { $("#btn-share-copy").unbind('click').click(async function() {
context.jamClient.SaveToClipboard($("#link-contents").text()); await context.jamClient.SaveToClipboard($("#link-contents").text());
return false; return false;
}) })
} }

View File

@ -15,20 +15,20 @@
logger.debug("'CANCEL SHUTDOWN' selected") logger.debug("'CANCEL SHUTDOWN' selected")
context.JK.Banner.hide(); context.JK.Banner.hide();
}}, }},
{name: 'SHUT DOWN', click: function() { {name: 'SHUT DOWN', click: async function() {
logger.debug("'COMPLETELY SHUT DOWN THE APP' selected") logger.debug("'COMPLETELY SHUT DOWN THE APP' selected")
context.jamClient.ShutdownApplication() await context.jamClient.ShutdownApplication()
}}, }},
], ],
html: $('#template-shutdown-prompt').html()}); html: $('#template-shutdown-prompt').html()});
} }
function initialize() { async function initialize() {
// guard against old clients // guard against old clients
if(context.jamClient.RegisterQuitCallback) { //if(context.jamClient.RegisterQuitCallback) {
context.jamClient.RegisterQuitCallback("window.JK.ShutdownDialogCallback"); await context.jamClient.RegisterQuitCallback("window.JK.ShutdownDialogCallback");
} //}
} }
function quitCallback(options) { function quitCallback(options) {

View File

@ -30,7 +30,7 @@ context.JK.SoundCloudPlayerDialog = class SoundCloudPlayerDialog
@player.attr("src", "") @player.attr("src", "")
# the Windows client does not play back correctly # the Windows client does not play back correctly
if context.jamClient.IsNativeClient() if context.JK.isQWebEngine
context.JK.popExternalLink(@url) context.JK.popExternalLink(@url)
return false return false
else else

View File

@ -262,7 +262,7 @@
} }
// called from sidebar when messages come in // called from sidebar when messages come in
function messageReceived(payload) { async function messageReceived(payload) {
if(showing && otherId == payload.sender_id) { if(showing && otherId == payload.sender_id) {
if(fullyInitialized) { if(fullyInitialized) {
renderMessage(payload.msg, payload.sender_id, payload.sender_name, payload.created_at, true); renderMessage(payload.msg, payload.sender_id, payload.sender_name, payload.created_at, true);
@ -278,7 +278,7 @@
app.notify({ app.notify({
"title": "Message from " + payload.sender_name, "title": "Message from " + payload.sender_name,
"text": payload.msg, "text": payload.msg,
"icon_url": context.JK.resolveAvatarUrl(payload.photo_url) "icon_url": await context.JK.resolveAvatarUrl(payload.photo_url)
}, [{ }, [{
id: "btn-reply", id: "btn-reply",
text: "REPLY", text: "REPLY",

View File

@ -9,9 +9,10 @@
var rest = context.JK.Rest(); var rest = context.JK.Rest();
var dialogId = '#video-dialog'; var dialogId = '#video-dialog';
function videoClick(e) { async function videoClick(e) {
var $self = $(this); var $self = $(this);
if (!context.jamClient || !context.jamClient.IsNativeClient()) { var isNativeClient = context.JK.isQWebEngine;
if (!isNativeClient) {
$('#video-dialog-header').html($self.data('video-header') || $self.attr('data-video-header')); $('#video-dialog-header').html($self.data('video-header') || $self.attr('data-video-header'));
$('#video-dialog-iframe').attr('src', $self.data('video-url') || $self.attr('data-video-url')); $('#video-dialog-iframe').attr('src', $self.data('video-url') || $self.attr('data-video-url'));
@ -22,7 +23,7 @@
} }
else { else {
var videoUrl = $.param.querystring(window.location.href, 'showVideo=' + encodeURIComponent($self.data('video-url'))); var videoUrl = $.param.querystring(window.location.href, 'showVideo=' + encodeURIComponent($self.data('video-url')));
context.jamClient.OpenSystemBrowser(videoUrl); await context.jamClient.OpenSystemBrowser(videoUrl);
} }
} }

View File

@ -148,7 +148,8 @@ context.JK.DownloadJamTrack = class DownloadJamTrack
@stateHolder.children().remove() @stateHolder.children().remove()
@stateHolder.append(context._.template(@state.template.html(), @jamTrack, { variable: 'data' })) @stateHolder.append(context._.template(@state.template.html(), @jamTrack, { variable: 'data' }))
@stateHolder.find('.' + @size).removeClass('hidden') @stateHolder.find('.' + @size).removeClass('hidden')
@state.show() # force this
@state.show.call(this)
# report a stat now that we've reached the end of this widget's journey # report a stat now that we've reached the end of this widget's journey
trackProgress: () => trackProgress: () =>
@ -184,38 +185,65 @@ context.JK.DownloadJamTrack = class DownloadJamTrack
@tracked = true @tracked = true
showPackaging: () => showPackaging: () =>
@logger.debug("showing #{@state.name}") console.log("showing #{@state.name}")
this.expectTransition() this.expectTransition()
showDownloading: () => # showDownloading: () =>
@logger.debug("showing #{@state.name}") # console.log("showing #{@state.name}")
# while downloading, we don't run the transition timer, because the download API is guaranteed to call success, or failure, eventually # # while downloading, we don't run the transition timer, because the download API is guaranteed to call success, or failure, eventually
context.jamClient.JamTrackDownload(@jamTrack.id, null, context.JK.currentUserId, # context.jamClient.JamTrackDownload(@jamTrack.id, null, context.JK.currentUserId,
# this.makeDownloadProgressCallback(),
# this.makeDownloadSuccessCallback(),
# this.makeDownloadFailureCallback())
showDownloading: `async function(){
console.log('showing '+this.state.name);
// while downloading, we do not run the transition timer, because the download API is guaranteed to call success, or failure, eventually
await context.jamClient.JamTrackDownload(this.jamTrack.id, null, context.JK.currentUserId,
this.makeDownloadProgressCallback(), this.makeDownloadProgressCallback(),
this.makeDownloadSuccessCallback(), this.makeDownloadSuccessCallback(),
this.makeDownloadFailureCallback()) this.makeDownloadFailureCallback());
}`
showKeying: () => # showKeying: () =>
@logger.debug("showing #{@state.name}") # console.log("showing #{@state.name}")
context.jamClient.JamTrackKeysRequest() # context.jamClient.JamTrackKeysRequest()
this.waitForState() # this.waitForState()
showKeying: `async function(){
this.logger.debug('showing '+this.state.name);
await context.jamClient.JamTrackKeysRequest();
this.waitForState();
}`
showQuiet: () => showQuiet: () =>
@logger.debug("showing #{@state.name}") console.log("showing #{@state.name}")
showInitial: () => # showInitial: () =>
@logger.debug("showing #{@state.name}") # console.log("showing #{@state.name}")
@sampleRate = context.jamClient.GetSampleRate() # @sampleRate = context.jamClient.GetSampleRate()
@fingerprint = context.jamClient.SessionGetMacHash() # @fingerprint = context.jamClient.SessionGetMacHash()
logger.debug("fingerprint: ", @fingerprint) # logger.debug("fingerprint: ", @fingerprint)
@sampleRateForFilename = if @sampleRate == 48 then '48' else '44' # @sampleRateForFilename = if @sampleRate == 48 then '48' else '44'
@attempts = @attempts + 1 # @attempts = @attempts + 1
this.expectTransition() # this.expectTransition()
context.JK.SubscriptionUtils.subscribe('jam_track_right', @jamTrack.jam_track_right_id).on(context.JK.EVENTS.SUBSCRIBE_NOTIFICATION, this.onJamTrackRightEvent) # context.JK.SubscriptionUtils.subscribe('jam_track_right', @jamTrack.jam_track_right_id).on(context.JK.EVENTS.SUBSCRIBE_NOTIFICATION, this.onJamTrackRightEvent)
this.checkState() # this.checkState()
showInitial: `async function() {
console.log('showing '+ this.state.name);
this.sampleRate = await context.jamClient.GetSampleRate();
this.fingerprint = await context.jamClient.SessionGetMacHash();
console.log("fingerprint: ", this.fingerprint);
this.sampleRateForFilename = this.sampleRate === 48 ? '48' : '44';
this.attempts = this.attempts + 1;
this.expectTransition();
context.JK.SubscriptionUtils.subscribe('jam_track_right', this.jamTrack.jam_track_right_id).on(context.JK.EVENTS.SUBSCRIBE_NOTIFICATION, this.onJamTrackRightEvent);
this.checkState();
}`
showError: () => showError: () =>
@logger.debug("showing #{@state.name}") console.log("showing #{@state.name}")
context.JK.SubscriptionUtils.unsubscribe('jam_track_right', @jamTrack.jam_track_right_id) context.JK.SubscriptionUtils.unsubscribe('jam_track_right', @jamTrack.jam_track_right_id)
if @size == 'large' if @size == 'large'
@ -233,17 +261,17 @@ context.JK.DownloadJamTrack = class DownloadJamTrack
@stateHolder.find('.retry').text(retryMsg) @stateHolder.find('.retry').text(retryMsg)
showSynchronized: () => showSynchronized: () =>
@logger.debug("showing #{@state.name}") console.log("showing #{@state.name}")
context.JK.SubscriptionUtils.unsubscribe('jam_track_right', @jamTrack.jam_track_right_id) context.JK.SubscriptionUtils.unsubscribe('jam_track_right', @jamTrack.jam_track_right_id)
showNoClient: () => showNoClient: () =>
@logger.debug("showing #{@state.name}") console.log("showing #{@state.name}")
downloadCheck: () => downloadCheck: () =>
@logger.debug "downloadCheck" console.log "downloadCheck"
retry: () => retry: () =>
@logger.debug "user initiated retry" console.log "user initiated retry"
@path = [] @path = []
@path.push('retry') @path.push('retry')
this.clear() this.clear()
@ -263,7 +291,7 @@ context.JK.DownloadJamTrack = class DownloadJamTrack
# if not, then let's see if we have timed out # if not, then let's see if we have timed out
if @state.timer? if @state.timer?
if (new Date()).getTime() - @state.stateStartTime.getTime() > @state.max_time if (new Date()).getTime() - @state.stateStartTime.getTime() > @state.max_time
@logger.debug("The current step (#{@state.name}) took too long") console.log("The current step (#{@state.name}) took too long")
if @state == @states.keying if @state == @states.keying
# specific message # specific message
@ -327,19 +355,19 @@ context.JK.DownloadJamTrack = class DownloadJamTrack
return return
if newState == @state if newState == @state
@logger.debug("DownloadJamTrack: ignoring state change #{@state.name}") console.log("DownloadJamTrack: ignoring state change #{@state.name}")
return return
if @state? if @state?
@logger.debug("DownloadJamTrack: state change: #{@state.name} => #{newState.name}") console.log("DownloadJamTrack: state change: #{@state.name} => #{newState.name}")
# make sure there is no timer running on the old state # make sure there is no timer running on the old state
this.clearTransitionTimer() this.clearTransitionTimer()
this.clearStateTimer() this.clearStateTimer()
this.abortEnqueue() this.abortEnqueue()
@logger.debug("aborting getJamTrack right on state change") console.log("aborting getJamTrack right on state change")
this.abortGetJamTrackRight() this.abortGetJamTrackRight()
else else
@logger.debug("DownloadJamTrack: initial state: #{newState.name}") console.log("DownloadJamTrack: initial state: #{newState.name}")
@state = newState @state = newState
@ -353,38 +381,76 @@ context.JK.DownloadJamTrack = class DownloadJamTrack
$(this).triggerHandler(@EVENTS.JAMTRACK_DOWNLOADER_STATE_CHANGED, {state: @state}) $(this).triggerHandler(@EVENTS.JAMTRACK_DOWNLOADER_STATE_CHANGED, {state: @state})
checkState: () => # checkState: () =>
# check for the success state against the local state of the client... if it's playable, then we should be OK # # check for the success state against the local state of the client... if it's playable, then we should be OK
fqId = "#{@jamTrack.id}-#{@sampleRateForFilename}" # fqId = "#{@jamTrack.id}-#{@sampleRateForFilename}"
@trackDetail = context.jamClient.JamTrackGetTrackDetail (fqId) # @trackDetail = context.jamClient.JamTrackGetTrackDetail (fqId)
@logger.debug("DownloadJamTrack: JamTrackGetTrackDetail(#{fqId}).key_state: " + @trackDetail.key_state, @trackDetail) # console.log("DownloadJamTrack: JamTrackGetTrackDetail(#{fqId}).key_state: " + @trackDetail.key_state, @trackDetail)
# first check if the version is not the same; if so, invalidate. # # first check if the version is not the same; if so, invalidate.
if @trackDetail.version? # if @trackDetail.version?
if @jamTrack.version != @trackDetail.version # if @jamTrack.version != @trackDetail.version
@logger.info("DownloadJamTrack: JamTrack on disk is different version (stored: #{@trackDetail.version}, server: #{@jamTrack.version}. Invalidating") # @logger.info("DownloadJamTrack: JamTrack on disk is different version (stored: #{@trackDetail.version}, server: #{@jamTrack.version}. Invalidating")
context.jamClient.InvalidateJamTrack("#{@jamTrack.id}-#{@sampleRateForFilename}") # context.jamClient.InvalidateJamTrack("#{@jamTrack.id}-#{@sampleRateForFilename}")
@trackDetail = context.jamClient.JamTrackGetTrackDetail ("#{@jamTrack.id}-#{@sampleRateForFilename}") # @trackDetail = context.jamClient.JamTrackGetTrackDetail ("#{@jamTrack.id}-#{@sampleRateForFilename}")
if @trackDetail.version? # if @trackDetail.version?
@logger.error("after invalidating package, the version is still wrong!", @trackDetail) # @logger.error("after invalidating package, the version is still wrong!", @trackDetail)
throw "after invalidating package, the version is still wrong! #{@trackDetail.version}" # throw "after invalidating package, the version is still wrong! #{@trackDetail.version}"
switch @trackDetail.key_state # switch @trackDetail.key_state
when 'pending' # when 'pending'
this.transition(@states.keying) # this.transition(@states.keying)
when 'not authorized' # when 'not authorized'
# TODO: if not authorized, do we need to re-initiate a keying attempt? # # TODO: if not authorized, do we need to re-initiate a keying attempt?
this.transition(@states.keying) # this.transition(@states.keying)
when 'ready' # when 'ready'
this.transition(@states.synchronized) # this.transition(@states.synchronized)
when 'unknown' # when 'unknown'
@ajaxGetJamTrackRightAborted = false # @ajaxGetJamTrackRightAborted = false
@rest.getJamTrackRight({id: @jamTrack.id}) # @rest.getJamTrackRight({id: @jamTrack.id})
# .done(this.processJamTrackRight)
# .fail(this.processJamTrackRightFail)
checkState: `async function() {
// check for the success state against the local state of the client... if its playable, then we should be OK
const fqId = this.jamTrack.id+'-'+this.sampleRateForFilename;
this.trackDetail = await context.jamClient.JamTrackGetTrackDetail((fqId));
this.logger.debug('DownloadJamTrack: JamTrackGetTrackDetail('+fqId+').key_state: ' + this.trackDetail.key_state, this.trackDetail);
//first check if the version is not the same; if so, invalidate.
if (this.trackDetail.version != null) {
if (this.jamTrack.version !== this.trackDetail.version) {
this.logger.info('DownloadJamTrack: JamTrack on disk is different version (stored: '+this.trackDetail.version+', server: '+this.jamTrack.version+'. Invalidating');
await context.jamClient.InvalidateJamTrack(this.jamTrack.id+'-'+this.sampleRateForFilename);
this.trackDetail = await context.jamClient.JamTrackGetTrackDetail((this.jamTrack.id+'-'+this.sampleRateForFilename));
if (this.trackDetail.version != null) {
this.logger.error("after invalidating package, the version is still wrong!", this.trackDetail);
throw 'after invalidating package, the version is still wrong! ' + this.trackDetail.version;
}
}
}
switch (this.trackDetail.key_state) {
case 'pending':
return this.transition(this.states.keying);
case 'not authorized':
// TODO: if not authorized, do we need to re-initiate a keying attempt?
return this.transition(this.states.keying);
case 'ready':
return this.transition(this.states.synchronized);
case 'unknown':
this.ajaxGetJamTrackRightAborted = false;
return this.rest.getJamTrackRight({id: this.jamTrack.id})
.done(this.processJamTrackRight) .done(this.processJamTrackRight)
.fail(this.processJamTrackRightFail) .fail(this.processJamTrackRightFail);
}
}`
# update progress indicator for packaging step # update progress indicator for packaging step
updateSteps: () => updateSteps: () =>
@ -402,7 +468,7 @@ context.JK.DownloadJamTrack = class DownloadJamTrack
@updateSteps() @updateSteps()
@logger.debug("DownloadJamTrack: processSigningState: " + signingState) console.log("DownloadJamTrack: processSigningState: " + signingState)
switch signingState switch signingState
when 'QUIET' when 'QUIET'
@ -459,23 +525,23 @@ context.JK.DownloadJamTrack = class DownloadJamTrack
processJamTrackRight: (myJamTrack) => processJamTrackRight: (myJamTrack) =>
@logger.debug("processJamTrackRight", myJamTrack) console.log("processJamTrackRight", myJamTrack)
unless @ajaxGetJamTrackRightAborted unless @ajaxGetJamTrackRightAborted
this.processSigningState(myJamTrack) this.processSigningState(myJamTrack)
else else
@logger.debug("DownloadJamTrack: ignoring processJamTrackRight response") console.log("DownloadJamTrack: ignoring processJamTrackRight response")
processJamTrackRightFail: () => processJamTrackRightFail: () =>
unless @ajaxGetJamTrackRightAborted? unless @ajaxGetJamTrackRightAborted?
this.transitionError("status-check-error", "Unable to check with the server on the status of your JamTrack.") this.transitionError("status-check-error", "Unable to check with the server on the status of your JamTrack.")
else else
@logger.debug("DownloadJamTrack: ignoring processJamTrackRightFail response") console.log("DownloadJamTrack: ignoring processJamTrackRightFail response")
processEnqueueJamTrack: (enqueueResponse) => processEnqueueJamTrack: (enqueueResponse) =>
unless @ajaxEnqueueAborted unless @ajaxEnqueueAborted
this.expectTransition() # the act of enqueuing should send down events to the client. we wait... this.expectTransition() # the act of enqueuing should send down events to the client. we wait...
else else
@logger.debug("DownloadJamTrack: ignoring processEnqueueJamTrack response") console.log("DownloadJamTrack: ignoring processEnqueueJamTrack response")
displayUIForGuard:(response) => displayUIForGuard:(response) =>
display = switch response.message display = switch response.message
@ -496,10 +562,10 @@ context.JK.DownloadJamTrack = class DownloadJamTrack
else else
this.transitionError("enqueue-error", "Unable to ask the server to build your JamTrack.") this.transitionError("enqueue-error", "Unable to ask the server to build your JamTrack.")
else else
@logger.debug("DownloadJamTrack: ignoring processEnqueueJamTrackFail response") console.log("DownloadJamTrack: ignoring processEnqueueJamTrackFail response")
onJamTrackRightEvent: (e, data) => onJamTrackRightEvent: (e, data) =>
@logger.debug("DownloadJamTrack: subscription notification received: type:" + data.type, data) console.log("DownloadJamTrack: subscription notification received: type:" + data.type, data)
this.expectTransition() this.expectTransition()
this.processSigningState(data.body) this.processSigningState(data.body)
@ -513,7 +579,7 @@ context.JK.DownloadJamTrack = class DownloadJamTrack
@root.find('.state-downloading .progress').text(progress) @root.find('.state-downloading .progress').text(progress)
downloadProgressCallback: (bytesReceived, bytesTotal) => downloadProgressCallback: (bytesReceived, bytesTotal) =>
@logger.debug("download #{bytesReceived}/#{bytesTotal}") console.log("download #{bytesReceived}/#{bytesTotal}")
@bytesReceived = Number(bytesReceived) @bytesReceived = Number(bytesReceived)
@bytesTotal = Number(bytesTotal) @bytesTotal = Number(bytesTotal)
@ -524,7 +590,7 @@ context.JK.DownloadJamTrack = class DownloadJamTrack
downloadSuccessCallback: (updateLocation) => downloadSuccessCallback: (updateLocation) =>
# is the package loadable yet? # is the package loadable yet?
@logger.debug("DownloadJamTrack: download complete - on to keying") console.log("DownloadJamTrack: download complete - on to keying")
this.transition(@states.keying) this.transition(@states.keying)
downloadFailureCallback: (errorMsg) => downloadFailureCallback: (errorMsg) =>

View File

@ -2,8 +2,11 @@
// !!!! Keep white space after last require !!!! // !!!! Keep white space after last require !!!!
// //
//= require fakeJamClient //= require fakeJamClient
//= require fakeJamClientProxy
//= require fakeJamClientMessages //= require fakeJamClientMessages
//= require fakeJamClientRecordings //= require fakeJamClientRecordings
//= require qwebchannel.js
//= require asyncJamClient
//= require backend_alerts //= require backend_alerts
//= require stun //= require stun
//= require influxdb-latest //= require influxdb-latest
@ -28,9 +31,8 @@
$(window).on('pagehide', setNavigationStart) $(window).on('pagehide', setNavigationStart)
} }
$(document).on('JAMKAZAM_CONSTRUCTED', function(e, data) { $(document).on('JAMKAZAM_CONSTRUCTED', function(e, data) {
console.log('JAMKAZAM_CONSTRUCTED event called');
var app = data.app; var app = data.app;
if(!app) throw "app not found"; if(!app) throw "app not found";
@ -52,7 +54,8 @@
$.cookie("browser.timezone", window.jstz.determine().name(), { expires: 365, path: '/' }); $.cookie("browser.timezone", window.jstz.determine().name(), { expires: 365, path: '/' });
} }
$(document).on('JAMKAZAM_READY', function() { $(document).on('JAMKAZAM_READY', async function() {
console.log('JAMKAZAM_READY event called');
// this event is fired when context.app is initialized // this event is fired when context.app is initialized
var app = context.JK.app; var app = context.JK.app;
@ -61,9 +64,9 @@
initializeDialogs(app); initializeDialogs(app);
checkAudioStopped(); await checkAudioStopped();
checkMacOSXInstalledCorrectly(); await checkMacOSXInstalledCorrectly();
watchPreferencesEvent(app); watchPreferencesEvent(app);
@ -90,13 +93,14 @@
}); });
} }
function checkMacOSXInstalledCorrectly() { async function checkMacOSXInstalledCorrectly() {
var os = context.jamClient.GetOSAsString(); var os = await context.jamClient.GetOSAsString();
// check if method exists at all for migration purposes // check if method exists at all for migration purposes
if(context.jamClient.IsAppInWritableVolume && os == "MacOSX" && !context.jamClient.IsAppInWritableVolume()) { var isAppInWritableVolume = await context.jamClient.IsAppInWritableVolume()
if(os == "MacOSX" && !isAppInWritableVolume) {
context.JK.Banner.showAlert( context.JK.Banner.showAlert(
{ title: "Drag JamKazam to the Applications Folder!", { title: "Drag JamKazam to the Applications Folder!",
buttons: [{name: 'SHUTDOWN APPLICATION', click: function() {context.jamClient.ShutdownApplication()}} ], buttons: [{name: 'SHUTDOWN APPLICATION', click: async function() { await context.jamClient.ShutdownApplication()}} ],
html: $('#template-app-in-read-only-volume').html()}); html: $('#template-app-in-read-only-volume').html()});
return; return;
} }
@ -164,36 +168,36 @@
} }
// wait 10 seconds // wait 10 seconds
function checkAudioStopped() { async function checkAudioStopped() {
if(context.jamClient.ResetPageCounters) { //if(context.jamClient.ResetPageCounters) {
// upgrade concern // upgrade concern
context.jamClient.ResetPageCounters(); await context.jamClient.ResetPageCounters();
context.JK.AudioStopTimeout = setTimeout(function() { context.JK.AudioStopTimeout = setTimeout(async function() {
if(context.jamClient.IsAudioStarted()) { if(await context.jamClient.IsAudioStarted()) {
logger.debug("checkAudioStopped: stopping audio ...") logger.debug("checkAudioStopped: stopping audio ...")
context.jamClient.StopAudio(); await context.jamClient.StopAudio();
} }
}, 10000); }, 10000);
} //}
} }
function updateScoringIntervals() { async function updateScoringIntervals() {
if(context.jamClient.SetLatencyTestBlocked) { if(await context.jamClient.SetLatencyTestBlocked) {
// make sure latency testing is still going on, in case a refresh occurred during network test // make sure latency testing is still going on, in case a refresh occurred during network test
context.jamClient.SetLatencyTestBlocked(false) await context.jamClient.SetLatencyTestBlocked(false)
} }
// set scoring intervals // set scoring intervals
if(context.jamClient.SetScoreWorkTimingInterval){ if(await context.jamClient.SetScoreWorkTimingInterval){
var success = context.jamClient.SetScoreWorkTimingInterval( var success = await context.jamClient.SetScoreWorkTimingInterval(
{ {
interval: gon.global.scoring_get_work_interval, interval: gon.global.scoring_get_work_interval,
backoff: gon.global.scoring_get_work_backoff_interval backoff: gon.global.scoring_get_work_backoff_interval
}) })
if(!success) logger.warning("unable to set scoring intervals") //if(!success) logger.warning("unable to set scoring intervals")
} }
} }
@ -213,6 +217,7 @@
} }
function initializeStun(app) { function initializeStun(app) {
stun = new context.JK.Stun(app); stun = new context.JK.Stun(app);
context.JK.StunInstance = stun; context.JK.StunInstance = stun;
stun.initialize(); stun.initialize();
@ -226,12 +231,12 @@
window.location.reload(); window.location.reload();
}); });
JK.JamServer.registerMessageCallback(JK.MessageType.RESTART_APPLICATION, function(header, payload) { JK.JamServer.registerMessageCallback(JK.MessageType.RESTART_APPLICATION, async function(header, payload) {
context.jamClient.RestartApplication(); await context.jamClient.RestartApplication();
}); });
JK.JamServer.registerMessageCallback(JK.MessageType.STOP_APPLICATION, function(header, payload) { JK.JamServer.registerMessageCallback(JK.MessageType.STOP_APPLICATION, async function(header, payload) {
context.jamClient.ShutdownApplication(); await context.jamClient.ShutdownApplication();
}); });
} }

View File

@ -529,6 +529,10 @@
dbg('LeaveSession:' + JSON.stringify(map)); dbg('LeaveSession:' + JSON.stringify(map));
} }
function LaunchBroadcastSettings() {
dbg('LaunchBroadcastSettings');
}
// this is not a real bridge method; purely used by the fake jam client // this is not a real bridge method; purely used by the fake jam client
function RegisterP2PMessageCallbacks(callbacks) { function RegisterP2PMessageCallbacks(callbacks) {
p2pCallbacks = callbacks; p2pCallbacks = callbacks;
@ -923,6 +927,7 @@
} }
function SessionSetAlertCallback(callback) { function SessionSetAlertCallback(callback) {
//console('running.....')
alertCallbackName = callback; alertCallbackName = callback;
// simulate a backend alert // simulate a backend alert
@ -1529,6 +1534,12 @@
return {} return {}
} }
function RegisterSessionJoinLeaveRequestCallBack(){}
function RegisterGenericCallBack(){}
function GetDetailedOS(){}
// Javascript Bridge seems to camel-case // Javascript Bridge seems to camel-case
// Set the instance functions: // Set the instance functions:
this.AbortRecording = AbortRecording; this.AbortRecording = AbortRecording;
@ -1540,6 +1551,7 @@
this.JoinSession = JoinSession; this.JoinSession = JoinSession;
this.LatencyUpdated = LatencyUpdated; this.LatencyUpdated = LatencyUpdated;
this.LeaveSession = LeaveSession; this.LeaveSession = LeaveSession;
this.LaunchBroadcastSettings = LaunchBroadcastSettings;
this.P2PMessageReceived = P2PMessageReceived; this.P2PMessageReceived = P2PMessageReceived;
this.ParticipantJoined = ParticipantJoined; this.ParticipantJoined = ParticipantJoined;
this.ParticipantLeft = ParticipantLeft; this.ParticipantLeft = ParticipantLeft;
@ -1575,6 +1587,8 @@
this.GetStaticPort = GetStaticPort; this.GetStaticPort = GetStaticPort;
this.SetStaticPort = SetStaticPort; this.SetStaticPort = SetStaticPort;
this.connected = true; this.connected = true;
this.RegisterGenericCallBack = RegisterGenericCallBack;
this.GetDetailedOS = GetDetailedOS;
// FTUE (round 3) // FTUE (round 3)
this.FTUESetInputMusicDevice = FTUESetInputMusicDevice; this.FTUESetInputMusicDevice = FTUESetInputMusicDevice;
@ -1664,6 +1678,7 @@
this.SessionPageEnter = SessionPageEnter; this.SessionPageEnter = SessionPageEnter;
this.SessionPageLeave = SessionPageLeave; this.SessionPageLeave = SessionPageLeave;
this.SetMixerMode = SetMixerMode; this.SetMixerMode = SetMixerMode;
this.RegisterSessionJoinLeaveRequestCallBack = RegisterSessionJoinLeaveRequestCallBack;
this.SetVURefreshRate = SetVURefreshRate; this.SetVURefreshRate = SetVURefreshRate;
this.SessionGetMasterLocalMix = SessionGetMasterLocalMix; this.SessionGetMasterLocalMix = SessionGetMasterLocalMix;
@ -1811,6 +1826,8 @@
this.listTrackAssignments = listTrackAssignments; this.listTrackAssignments = listTrackAssignments;
this.applySubscriptionPolicy = applySubscriptionPolicy; this.applySubscriptionPolicy = applySubscriptionPolicy;
this.clientID = "devtester"; this.clientID = "devtester";
this.NetworkTestResult = NetworkTestResult;
}; };
})(window, jQuery); })(window, jQuery);

View File

@ -0,0 +1,35 @@
(function(context,$) {
"use strict";
context.JK = context.JK || {};
context.JK.FakeJamClientProxy = function(app, p2pMessageFactory) {
const handler = {
get: (target, prop, receiver) => {
return function (...args) {
return new Promise((resolve, reject) => {
try {
//console.log('[fakeJamClient]', prop)
if(target[prop]){
const result = target[prop].apply(target, args);
resolve(result);
}else{
console.error('[fakeJamClient] error: No such method in FakeJamClient', prop);
reject(`No such method in FakeJamClient: ${prop}`);
}
} catch (error) {
console.error('[fakeJamClient] error:', prop, error);
reject(error);
}
});
}
}
}
const fakeJamClient = new JK.FakeJamClient(app, p2pMessageFactory);
return new Proxy(fakeJamClient, handler);
}
})(window, jQuery);

View File

@ -46,19 +46,19 @@
'ftue-audio-output-fader': jamClient.FTUEGetOutputVolume 'ftue-audio-output-fader': jamClient.FTUEGetOutputVolume
}; };
function latencyTimeoutCheck() { async function latencyTimeoutCheck() {
if (context.JK.FtueWizard.latencyTimeout) { if (context.JK.FtueWizard.latencyTimeout) {
jamClient.FTUERegisterLatencyCallback(''); await jamClient.FTUERegisterLatencyCallback('');
context.JK.app.setWizardStep("5"); context.JK.app.setWizardStep("5");
} }
} }
function afterHide(data) { async function afterHide(data) {
// Unsubscribe from FTUE VU callbacks. // Unsubscribe from FTUE VU callbacks.
jamClient.FTUERegisterVUCallbacks('', '', ''); await jamClient.FTUERegisterVUCallbacks('', '', '');
if (!successfulFtue && app.cancelFtue) { if (!successfulFtue && app.cancelFtue) {
app.cancelFtue(); await app.cancelFtue();
app.afterFtue = null; app.afterFtue = null;
app.cancelFtue = null; app.cancelFtue = null;
} }
@ -150,12 +150,12 @@
} }
function settingsInit() { async function settingsInit() {
jamClient.FTUEInit(); await jamClient.FTUEInit();
//setLevels(0); //setLevels(0);
resetFtueLatencyView(); resetFtueLatencyView();
setSaveButtonState($('#btn-ftue-2-save'), false); setSaveButtonState($('#btn-ftue-2-save'), false);
if (jamClient.GetOSAsString() !== "Win32") { if (await jamClient.GetOSAsString() !== "Win32") {
$('#btn-ftue-2-asio-control-panel').hide(); $('#btn-ftue-2-asio-control-panel').hide();
} }
renderDisableTest(); renderDisableTest();
@ -176,18 +176,19 @@
$('[layout-wizard="ftue"] [layout-wizard-step="2"] .settings-controls select[data-device="voice-chat-output"]').val(""); $('[layout-wizard="ftue"] [layout-wizard-step="2"] .settings-controls select[data-device="voice-chat-output"]').val("");
} }
function setLevels(db) { async function setLevels(db) {
if (db < -80 || db > 20) { if (db < -80 || db > 20) {
throw ("BUG! ftue.js:setLevels db arg must be between -80 and 20"); throw ("BUG! ftue.js:setLevels db arg must be between -80 and 20");
} }
var trackIds = jamClient.SessionGetIDs(); var trackIds = await jamClient.SessionGetIDs();
var controlStates = jamClient.SessionGetControlState(trackIds); var controlStates = await jamClient.SessionGetControlState(trackIds);
$.each(controlStates, function (index, value) { $.each(controlStates, async function (index, value) {
context.JK.Mixer.fillTrackVolume(value, false); context.JK.Mixer.fillTrackVolume(value, false);
// Default input/output to 0 DB // Default input/output to 0 DB
context.trackVolumeObject.volL = db; context.trackVolumeObject.volL = db;
context.trackVolumeObject.volR = db; context.trackVolumeObject.volR = db;
jamClient.SessionSetControlState(trackIds[index]); //await jamClient.SessionSetControlState(trackIds[index]);
await context.jamClient.SessionSetTrackVolumeData(trackIds[index], null, context.trackVolumeObject)
}); });
$.each(context._.keys(faderMap), function (index, faderId) { $.each(context._.keys(faderMap), function (index, faderId) {
// faderChange takes a value from 0-100 // faderChange takes a value from 0-100
@ -199,14 +200,14 @@
}); });
} }
function testComplete() { async function testComplete() {
logger.debug("Test complete"); logger.debug("Test complete");
var latencyMS = context.JK.FtueWizard.latencyMS; var latencyMS = context.JK.FtueWizard.latencyMS;
var ftueSucceeded = latencyMS <= 20; var ftueSucceeded = latencyMS <= 20;
if (ftueSucceeded) { if (ftueSucceeded) {
logger.debug(latencyMS + " is <= 20. Setting FTUE status to true"); logger.debug(latencyMS + " is <= 20. Setting FTUE status to true");
ftueSave(true); // Save the profile ftueSave(true); // Save the profile
context.jamClient.FTUESetStatus(true); // No FTUE wizard next time await context.jamClient.FTUESetStatus(true); // No FTUE wizard next time
rest.userCertifiedGear({success: true}); rest.userCertifiedGear({success: true});
// notify anyone curious about how it went // notify anyone curious about how it went
@ -300,36 +301,36 @@
} }
function testLatency() { async function testLatency() {
// we'll just register for call back right here and unregister in the callback. // we'll just register for call back right here and unregister in the callback.
context.JK.FtueWizard.latencyTimeout = true; context.JK.FtueWizard.latencyTimeout = true;
var cbFunc = 'JK.ftueLatencyCallback'; var cbFunc = 'JK.ftueLatencyCallback';
logger.debug("Registering latency callback: " + cbFunc); logger.debug("Registering latency callback: " + cbFunc);
jamClient.FTUERegisterLatencyCallback('JK.ftueLatencyCallback'); await jamClient.FTUERegisterLatencyCallback('JK.ftueLatencyCallback');
var now = new Date(); var now = new Date();
logger.debug("Starting Latency Test..." + now); logger.debug("Starting Latency Test..." + now);
context.setTimeout(latencyTimeoutCheck, 300 * 1000); // Timeout to 5 minutes context.setTimeout(latencyTimeoutCheck, 300 * 1000); // Timeout to 5 minutes
jamClient.FTUEStartLatency(); await jamClient.FTUEStartLatency();
} }
function openASIOControlPanel(evt) { async function openASIOControlPanel(evt) {
if (win32) { if (win32) {
logger.debug("Calling FTUEOpenControlPanel()"); logger.debug("Calling FTUEOpenControlPanel()");
jamClient.FTUEOpenControlPanel(); await jamClient.FTUEOpenControlPanel();
} }
} }
function asioResync(evt) { async function asioResync(evt) {
jamClient.FTUERefreshDevices(); await jamClient.FTUERefreshDevices();
ftueSave(false); ftueSave(false);
} }
function ftueSave(persist) { async function ftueSave(persist) {
// Explicitly set inputs and outputs to dropdown values // Explicitly set inputs and outputs to dropdown values
// before save as the client seems to want this on changes to // before save as the client seems to want this on changes to
// things like frame size, etc.. // things like frame size, etc..
var $audioSelects = $('[layout-wizard-step="2"] .settings-controls select'); var $audioSelects = $('[layout-wizard-step="2"] .settings-controls select');
$.each($audioSelects, function (index, value) { $.each($audioSelects, async function (index, value) {
var $select = $(value); var $select = $(value);
setAudioDevice($select); setAudioDevice($select);
}); });
@ -341,16 +342,16 @@
// that we're using music for voice-chat. // that we're using music for voice-chat.
if ($('[layout-wizard-step="2"] select[data-device="voice-chat-input"]').val()) { if ($('[layout-wizard-step="2"] select[data-device="voice-chat-input"]').val()) {
// Voice input selected // Voice input selected
jamClient.TrackSetChatEnable(true); await jamClient.TrackSetChatEnable(true);
} else { } else {
// No voice input selected. // No voice input selected.
jamClient.TrackSetChatEnable(false); await jamClient.TrackSetChatEnable(false);
} }
setDefaultInstrumentFromProfile(); setDefaultInstrumentFromProfile();
logger.debug("Calling FTUESave(" + persist + ")"); logger.debug("Calling FTUESave(" + persist + ")");
var response = jamClient.FTUESave(persist); var response = await jamClient.FTUESave(persist);
//setLevels(0); //setLevels(0);
if (response) { if (response) {
logger.warn(response); logger.warn(response);
@ -363,33 +364,33 @@
} }
} }
function setAsioFrameSize(evt) { async function setAsioFrameSize(evt) {
var val = parseFloat($(evt.currentTarget).val(), 10); var val = parseFloat($(evt.currentTarget).val(), 10);
if (isNaN(val)) { if (isNaN(val)) {
return; return;
} }
logger.debug("Calling FTUESetFrameSize(" + val + ")"); logger.debug("Calling FTUESetFrameSize(" + val + ")");
jamClient.FTUESetFrameSize(val); await jamClient.FTUESetFrameSize(val);
ftueSave(false); ftueSave(false);
} }
function setAsioInputLatency(evt) { async function setAsioInputLatency(evt) {
var val = parseInt($(evt.currentTarget).val(), 10); var val = parseInt($(evt.currentTarget).val(), 10);
if (isNaN(val)) { if (isNaN(val)) {
return; return;
} }
logger.debug("Calling FTUESetInputLatency(" + val + ")"); logger.debug("Calling FTUESetInputLatency(" + val + ")");
jamClient.FTUESetInputLatency(val); await jamClient.FTUESetInputLatency(val);
ftueSave(false); ftueSave(false);
} }
function setAsioOutputLatency(evt) { async function setAsioOutputLatency(evt) {
var val = parseInt($(evt.currentTarget).val(), 10); var val = parseInt($(evt.currentTarget).val(), 10);
if (isNaN(val)) { if (isNaN(val)) {
return; return;
} }
logger.debug("Calling FTUESetOutputLatency(" + val + ")"); logger.debug("Calling FTUESetOutputLatency(" + val + ")");
jamClient.FTUESetOutputLatency(val); await jamClient.FTUESetOutputLatency(val);
ftueSave(false); ftueSave(false);
} }
@ -402,8 +403,8 @@
return false; return false;
} }
function videoLinkClicked(evt) { async function videoLinkClicked(evt) {
var myOS = jamClient.GetOSAsString(); var myOS = await jamClient.GetOSAsString();
var link; var link;
if (myOS === 'MacOSX') { if (myOS === 'MacOSX') {
link = $(evt.currentTarget).attr('external-link-mac'); link = $(evt.currentTarget).attr('external-link-mac');
@ -411,7 +412,7 @@
link = $(evt.currentTarget).attr('external-link-win'); link = $(evt.currentTarget).attr('external-link-win');
} }
if (link) { if (link) {
context.jamClient.OpenSystemBrowser(link); await context.jamClient.OpenSystemBrowser(link);
} }
} }
@ -449,7 +450,7 @@
* This function loads the available audio devices from jamClient, and * This function loads the available audio devices from jamClient, and
* builds up the select dropdowns in the audio-settings step of the FTUE wizard. * builds up the select dropdowns in the audio-settings step of the FTUE wizard.
*/ */
function loadAudioDevices() { async function loadAudioDevices() {
var funcs = [ var funcs = [
jamClient.FTUEGetMusicInputs, jamClient.FTUEGetMusicInputs,
jamClient.FTUEGetChatInputs, jamClient.FTUEGetChatInputs,
@ -461,13 +462,13 @@
'[layout-wizard-step="2"] .audio-output select' '[layout-wizard-step="2"] .audio-output select'
]; ];
var optionsHtml = ''; var optionsHtml = '';
var deviceOptionFunc = function (deviceKey, index, list) { var deviceOptionFunc = async function (deviceKey, index, list) {
optionsHtml += '<option title="' + devices[deviceKey] + '" value="' + deviceKey + '">' + devices[deviceKey] + '</option>'; optionsHtml += '<option title="' + devices[deviceKey] + '" value="' + deviceKey + '">' + devices[deviceKey] + '</option>';
}; };
for (var i = 0; i < funcs.length; i++) { for (var i = 0; i < funcs.length; i++) {
optionsHtml = '<option selected="selected" value="">Choose...</option>'; optionsHtml = '<option selected="selected" value="">Choose...</option>';
var devices = funcs[i](); // returns hash of device id: device name var devices = await funcs[i](); // returns hash of device id: device name
var $select = $(selectors[i]); var $select = $(selectors[i]);
$select.empty(); $select.empty();
var sortedDeviceKeys = context._.keys(devices).sort(); var sortedDeviceKeys = context._.keys(devices).sort();
@ -481,8 +482,8 @@
$('#asio-input-latency').val('0').change(); $('#asio-input-latency').val('0').change();
$('#asio-output-latency').val('0').change(); $('#asio-output-latency').val('0').change();
// Special-case for a non-ASIO device, set to 1 // Special-case for a non-ASIO device, set to 1
if (jamClient.GetOSAsString() === "Win32") { // Limit this check to Windows only. if (await jamClient.GetOSAsString() === "Win32") { // Limit this check to Windows only.
if (!(jamClient.FTUEHasControlPanel())) { if (!(await jamClient.FTUEHasControlPanel())) {
$('#asio-input-latency').val('1').change(); $('#asio-input-latency').val('1').change();
$('#asio-output-latency').val('1').change(); $('#asio-output-latency').val('1').change();
} }
@ -493,9 +494,9 @@
/** /**
* Load available drivers and populate the driver select box. * Load available drivers and populate the driver select box.
*/ */
function loadAudioDrivers() { async function loadAudioDrivers() {
var drivers = context.jamClient.FTUEGetDevices(false); var drivers = await context.jamClient.FTUEGetDevices(false);
var chatDrivers = jamClient.FTUEGetChatInputs(false, false); var chatDrivers = await jamClient.FTUEGetChatInputs(false, false);
var optionsHtml = '<option selected="selected" value="">Choose...</option>'; var optionsHtml = '<option selected="selected" value="">Choose...</option>';
var chatOptionsHtml = '<option selected="selected" value="">Choose...</option>'; var chatOptionsHtml = '<option selected="selected" value="">Choose...</option>';
@ -558,7 +559,7 @@
/** /**
* Handler for the new FTUE save button. * Handler for the new FTUE save button.
*/ */
function newFtueSaveSettingsHandler(evt) { async function newFtueSaveSettingsHandler(evt) {
evt.preventDefault(); evt.preventDefault();
var $saveButton = $('#btn-ftue-2-save'); var $saveButton = $('#btn-ftue-2-save');
if ($saveButton.hasClass('disabled')) { if ($saveButton.hasClass('disabled')) {
@ -576,8 +577,8 @@
setDefaultInstrumentFromProfile(); setDefaultInstrumentFromProfile();
logger.debug("Calling FTUESave(" + true + ")"); logger.debug("Calling FTUESave(" + true + ")");
jamClient.FTUESave(true); await jamClient.FTUESave(true);
jamClient.FTUESetStatus(true); // No FTUE wizard next time await jamClient.FTUESetStatus(true); // No FTUE wizard next time
rest.userCertifiedGear({success: true}); rest.userCertifiedGear({success: true});
// notify anyone curious about how it went // notify anyone curious about how it went
$('div[layout-id=ftue]').trigger('ftue_success'); $('div[layout-id=ftue]').trigger('ftue_success');
@ -585,7 +586,7 @@
app.layout.closeDialog('ftue'); app.layout.closeDialog('ftue');
if (app.afterFtue) { if (app.afterFtue) {
// If there's a function to invoke, invoke it. // If there's a function to invoke, invoke it.
app.afterFtue(); await app.afterFtue();
app.afterFtue = null; app.afterFtue = null;
app.cancelFtue = null; app.cancelFtue = null;
} }
@ -607,7 +608,7 @@
// { latency: 11.1875, latencyknown: true, latencyvar: 1} // { latency: 11.1875, latencyknown: true, latencyvar: 1}
function newFtueAudioDeviceChanged(evt) { function newFtueAudioDeviceChanged(evt) {
releaseDropdown(function () { releaseDropdown(async function () {
renderStartNewFtueLatencyTesting(); renderStartNewFtueLatencyTesting();
var $select = $(evt.currentTarget); var $select = $(evt.currentTarget);
@ -615,12 +616,12 @@
var $voiceSelect = $('.ftue-new .settings-2-voice select'); var $voiceSelect = $('.ftue-new .settings-2-voice select');
var audioDriverId = $audioSelect.val(); var audioDriverId = $audioSelect.val();
var voiceDriverId = $voiceSelect.val(); var voiceDriverId = $voiceSelect.val();
jamClient.FTUESetMusicDevice(audioDriverId); await jamClient.FTUESetMusicDevice(audioDriverId);
jamClient.FTUESetChatInput(voiceDriverId); await jamClient.FTUESetChatInput(voiceDriverId);
if (voiceDriverId) { // Let the back end know whether a voice device is selected if (voiceDriverId) { // Let the back end know whether a voice device is selected
jamClient.TrackSetChatEnable(true); await jamClient.TrackSetChatEnable(true);
} else { } else {
jamClient.TrackSetChatEnable(false); await jamClient.TrackSetChatEnable(false);
} }
if (!audioDriverId) { if (!audioDriverId) {
console.log("no audio driver ID"); console.log("no audio driver ID");
@ -629,8 +630,8 @@
newFtueEnableControls(false); newFtueEnableControls(false);
return; return;
} }
var musicInputs = jamClient.FTUEGetMusicInputs(); var musicInputs = await jamClient.FTUEGetMusicInputs();
var musicOutputs = jamClient.FTUEGetMusicOutputs(); var musicOutputs = await jamClient.FTUEGetMusicOutputs();
// set the music input to the first available input, // set the music input to the first available input,
// and output to the first available output // and output to the first available output
@ -649,8 +650,8 @@
} }
var result; var result;
if (kin && kout) { if (kin && kout) {
jamClient.FTUESetMusicInput(kin); await jamClient.FTUESetMusicInput(kin);
jamClient.FTUESetMusicOutput(kout); await jamClient.FTUESetMusicOutput(kout);
} else { } else {
// TODO FIXME - how to handle a driver selection where we are unable to // TODO FIXME - how to handle a driver selection where we are unable to
// autoset both inputs and outputs? (I'd think this could happen if either // autoset both inputs and outputs? (I'd think this could happen if either
@ -680,22 +681,22 @@
renderVolumes(); renderVolumes();
logger.debug("Calling FTUESave(" + false + ")"); logger.debug("Calling FTUESave(" + false + ")");
jamClient.FTUESave(false) await jamClient.FTUESave(false)
pendingFtueSave = false; // this is not really used in any real fashion. just setting back to false due to batch modify above pendingFtueSave = false; // this is not really used in any real fashion. just setting back to false due to batch modify above
setVuCallbacks(); setVuCallbacks();
var latency = jamClient.FTUEGetExpectedLatency(); var latency = await jamClient.FTUEGetExpectedLatency();
console.log("FTUEGetExpectedLatency: %o", latency); console.log("FTUEGetExpectedLatency: %o", latency);
newFtueUpdateLatencyView(latency); newFtueUpdateLatencyView(latency);
}); });
} }
function newFtueSave(persist) { async function newFtueSave(persist) {
logger.debug("newFtueSave persist(" + persist + ")") logger.debug("newFtueSave persist(" + persist + ")")
newFtueUpdateLatencyView('loading'); newFtueUpdateLatencyView('loading');
logger.debug("Calling FTUESave(" + persist + ")"); logger.debug("Calling FTUESave(" + persist + ")");
jamClient.FTUESave(persist); await jamClient.FTUESave(persist);
var latency = jamClient.FTUEGetExpectedLatency(); var latency = jamClient.FTUEGetExpectedLatency();
newFtueUpdateLatencyView(latency); newFtueUpdateLatencyView(latency);
} }
@ -709,7 +710,7 @@
} }
// simply tells backend what frontend shows in the UI // simply tells backend what frontend shows in the UI
function newFtueAsioFrameSizeToBackend($input) { async function newFtueAsioFrameSizeToBackend($input) {
var val = parseFloat($input.val(), 10); var val = parseFloat($input.val(), 10);
if (isNaN(val)) { if (isNaN(val)) {
logger.warn("unable to get value from framesize input: %o", $input.val()); logger.warn("unable to get value from framesize input: %o", $input.val());
@ -738,35 +739,35 @@
logger.debug("Defaulting WDM input/output"); logger.debug("Defaulting WDM input/output");
logger.debug("Calling FTUESetInputLatency(" + defaultInput + ")"); logger.debug("Calling FTUESetInputLatency(" + defaultInput + ")");
jamClient.FTUESetInputLatency(defaultInput); await jamClient.FTUESetInputLatency(defaultInput);
logger.debug("Calling FTUESetOutputLatency(" + defaultOutput + ")"); logger.debug("Calling FTUESetOutputLatency(" + defaultOutput + ")");
jamClient.FTUESetOutputLatency(defaultOutput); await jamClient.FTUESetOutputLatency(defaultOutput);
} }
logger.debug("Calling FTUESetFrameSize(" + val + ")"); logger.debug("Calling FTUESetFrameSize(" + val + ")");
jamClient.FTUESetFrameSize(val); await jamClient.FTUESetFrameSize(val);
return true; return true;
} }
function newFtueAsioInputLatencyToBackend($input) { async function newFtueAsioInputLatencyToBackend($input) {
var val = parseInt($input.val(), 10); var val = parseInt($input.val(), 10);
if (isNaN(val)) { if (isNaN(val)) {
logger.warn("unable to get value from input latency input: %o", $input.val()); logger.warn("unable to get value from input latency input: %o", $input.val());
return false; return false;
} }
logger.debug("Calling FTUESetInputLatency(" + val + ")"); logger.debug("Calling FTUESetInputLatency(" + val + ")");
jamClient.FTUESetInputLatency(val); await jamClient.FTUESetInputLatency(val);
return true; return true;
} }
function newFtueAsioOutputLatencyToBackend($input) { async function newFtueAsioOutputLatencyToBackend($input) {
var val = parseInt($input.val(), 10); var val = parseInt($input.val(), 10);
if (isNaN(val)) { if (isNaN(val)) {
logger.warn("unable to get value from output latency input: %o", $input.val()); logger.warn("unable to get value from output latency input: %o", $input.val());
return false; return false;
} }
logger.debug("Calling FTUESetOutputLatency(" + val + ")"); logger.debug("Calling FTUESetOutputLatency(" + val + ")");
jamClient.FTUESetOutputLatency(val); await jamClient.FTUESetOutputLatency(val);
return true; return true;
} }
@ -835,8 +836,9 @@
} }
} }
function isWDM() { async function isWDM() {
return jamClient.GetOSAsString() === "Win32" && !jamClient.FTUEHasControlPanel(); let [osaStr, controlPanel] = await Promise.all([jamClient.GetOSAsString(), jamClient.FTUEHasControlPanel()])
return (osaStr === "Win32" && !controlPanel);
} }
// Based on OS and Audio Hardware, set Frame/Buffer settings appropriately // Based on OS and Audio Hardware, set Frame/Buffer settings appropriately
@ -942,10 +944,10 @@
} }
} }
function audioDriverChanged(evt) { async function audioDriverChanged(evt) {
var $select = $(evt.currentTarget); var $select = $(evt.currentTarget);
currentAudioDriverId = $select.val(); currentAudioDriverId = $select.val();
jamClient.FTUESetMusicDevice(currentAudioDriverId); await jamClient.FTUESetMusicDevice(currentAudioDriverId);
loadAudioDevices(); loadAudioDevices();
setAsioSettingsVisibility(); setAsioSettingsVisibility();
checkValidStateForTesting(); checkValidStateForTesting();
@ -980,13 +982,13 @@
return (audioInput && audioOutput); return (audioInput && audioOutput);
} }
function setVuCallbacks() { async function setVuCallbacks() {
jamClient.FTUERegisterVUCallbacks( await jamClient.FTUERegisterVUCallbacks(
"JK.ftueAudioOutputVUCallback", "JK.ftueAudioOutputVUCallback",
"JK.ftueAudioInputVUCallback", "JK.ftueAudioInputVUCallback",
"JK.ftueChatInputVUCallback" "JK.ftueChatInputVUCallback"
); );
jamClient.SetVURefreshRate(200); await jamClient.SetVURefreshRate(200);
} }
function setAsioSettingsVisibility() { function setAsioSettingsVisibility() {
@ -1061,7 +1063,7 @@
}; };
// Latency Callback // Latency Callback
context.JK.ftueLatencyCallback = function (latencyMS) { context.JK.ftueLatencyCallback = async function (latencyMS) {
// We always show gauge screen if we hit this. // We always show gauge screen if we hit this.
// Clear out the 'timeout' variable. // Clear out the 'timeout' variable.
context.JK.FtueWizard.latencyTimeout = false; context.JK.FtueWizard.latencyTimeout = false;
@ -1070,7 +1072,7 @@
context.JK.FtueWizard.latencyMS = latencyMS; context.JK.FtueWizard.latencyMS = latencyMS;
// Unregister callback: // Unregister callback:
context.jamClient.FTUERegisterLatencyCallback(''); await context.jamClient.FTUERegisterLatencyCallback('');
// Go to 'congrats' screen -- although latency may be too high. // Go to 'congrats' screen -- although latency may be too high.
context.JK.app.setWizardStep("6"); context.JK.app.setWizardStep("6");
}; };

View File

@ -0,0 +1,48 @@
(function (context, $) {
"use strict";
context.JK = context.JK || {};
context.JK.GearSetupReminder = function (app) {
function showModal(options) {
options = options || {};
$('#gear_setup_reminder').attr('data-mode', 'gear-setup-reminder');
$('body').on('keyup', cancelModal);
$("#gear_setup_reminder a.close-modal").click(function () {
app.layout.closeDialog('gear-setup-reminder');
$('body').off('keyup', cancelModal);
return false;
})
$("#gear_setup_reminder a.setup-gear").click(function () {
app.layout.closeDialog('gear-setup-reminder');
$('body').off('keyup', cancelModal);
window.location.hash = '#/account/audio';
return false;
})
if(!app.layout.isDialogShowing('gear-setup-reminder')) {
app.layout.showDialog('gear-setup-reminder')
}
}
function cancelModal(e) {
if ((e.ctrlKey || e.metaKey) && e.keyCode == 78) {
console.log("update canceled!");
app.layout.closeDialog('gear-setup-reminder');
}
}
// Expose publics
this.show = showModal;
}
return this;
})(window, jQuery);

View File

@ -1,71 +1,88 @@
/** /**
* Static, simple definitions like strings, hashes, enums * Static, simple definitions like strings, hashes, enums
*/ */
(function(context,$) { (function (context, $) {
"use strict"; "use strict";
context.JK = context.JK || {}; context.JK = context.JK || {};
var logger = context.JK.logger; var logger = context.JK.logger;
context.JK.MIDI_TRACK = 100 context.JK.isQWebEngine = !!navigator.userAgent.match("(JamKazam)")
context.JK.CLIENT_ROLE = { context.JK.MIDI_TRACK = 100
CHILD: 0,
PARENT: 1
}
context.JK.OS = { context.JK.CLIENT_ROLE = {
WIN32: "Win32", CHILD: 0,
OSX: "MacOSX", PARENT: 1
UNIX: "Unix" }
};
context.JK.ASSIGNMENT = { context.JK.OS = {
CHAT: -2, WIN32: "Win32",
OUTPUT: -1, OSX: "MacOSX",
UNASSIGNED: 0, UNIX: "Unix"
TRACK1: 1, };
TRACK2: 2
};
context.JK.VOICE_CHAT = { context.JK.ASSIGNMENT = {
NO_CHAT: "0", CHAT: -2,
CHAT: "1" OUTPUT: -1,
}; UNASSIGNED: 0,
TRACK1: 1,
TRACK2: 2
};
context.JK.AVAILABILITY_US = "United States"; context.JK.VOICE_CHAT = {
context.JK.MASTER_TRACK = "Master"; NO_CHAT: "0",
CHAT: "1"
};
context.JK.EVENTS = { context.JK.AUDIO_FORMATS = ['.mp3', '.ogg', '.wav', '.flac', '.au'];
DIALOG_CLOSED : 'dialog_closed', context.JK.VIDEO_FORMATS = ['.mp4', '.mov'];
SHOW_SIGNUP : 'show_signup', context.JK.AUDIO_STORE_TYPE_MIX_AND_STEMS = {
SHOW_SIGNIN : 'show_signin', key: 'session_mix_and_steams',
RSVP_SUBMITTED: 'rsvp_submitted', value: 'Session mix + individual parts (streams)',
RSVP_CANCELED : 'rsvp_canceled', backendValues: [2, 3]
USER_UPDATED : 'user_updated', };
SESSION_STARTED : 'session_started', context.JK.AUDIO_STORE_TYPE_MIX_ONLY = {
SESSION_ENDED : 'session_stopped', key: 'session_mix_only',
FILE_MANAGER_CMD_START : 'file_manager_cmd_start', value: 'Session mix only',
FILE_MANAGER_CMD_STOP : 'file_manager_cmd_stop', backendValues: [1]
FILE_MANAGER_CMD_PROGRESS : 'file_manager_cmd_progress', };
FILE_MANAGER_CMD_ASAP_UPDATE : 'file_manager_cmd_asap_update', context.JK.RECORD_TYPE_AUDIO = 'audio-only'
MIXER_MODE_CHANGED : 'mixer_mode_changed', context.JK.RECORD_TYPE_BOTH = 'audio-video'
MUTE_SELECTED: 'mute_selected',
SUBSCRIBE_NOTIFICATION: 'subscribe_notification', context.JK.AVAILABILITY_US = "United States";
CONNECTION_UP: 'connection_up', context.JK.MASTER_TRACK = "Master";
CONNECTION_DOWN: 'connection_down',
SCREEN_CHANGED: 'screen_changed', context.JK.EVENTS = {
JAMTRACK_DOWNLOADER_STATE_CHANGED: 'jamtrack_downloader_state', DIALOG_CLOSED: 'dialog_closed',
METRONOME_PLAYBACK_MODE_SELECTED: 'metronome_playback_mode_selected', SHOW_SIGNUP: 'show_signup',
CHECKOUT_SIGNED_IN: 'checkout_signed_in', SHOW_SIGNIN: 'show_signin',
CHECKOUT_SKIP_SIGN_IN: 'checkout_skip_sign_in', RSVP_SUBMITTED: 'rsvp_submitted',
PREVIEW_PLAYED: 'preview_played', RSVP_CANCELED: 'rsvp_canceled',
VST_OPERATION_SELECTED: 'vst_operation_selected', USER_UPDATED: 'user_updated',
VST_EFFECT_SELECTED: 'vst_effect_selected', SESSION_STARTED: 'session_started',
LESSON_SESSION_ACTION: 'lesson_session_action', SESSION_ENDED: 'session_stopped',
JAMBLASTER_ACTION: 'jamblaster_action' FILE_MANAGER_CMD_START: 'file_manager_cmd_start',
}; FILE_MANAGER_CMD_STOP: 'file_manager_cmd_stop',
FILE_MANAGER_CMD_PROGRESS: 'file_manager_cmd_progress',
FILE_MANAGER_CMD_ASAP_UPDATE: 'file_manager_cmd_asap_update',
MIXER_MODE_CHANGED: 'mixer_mode_changed',
MUTE_SELECTED: 'mute_selected',
SUBSCRIBE_NOTIFICATION: 'subscribe_notification',
CONNECTION_UP: 'connection_up',
CONNECTION_DOWN: 'connection_down',
SCREEN_CHANGED: 'screen_changed',
JAMTRACK_DOWNLOADER_STATE_CHANGED: 'jamtrack_downloader_state',
METRONOME_PLAYBACK_MODE_SELECTED: 'metronome_playback_mode_selected',
CHECKOUT_SIGNED_IN: 'checkout_signed_in',
CHECKOUT_SKIP_SIGN_IN: 'checkout_skip_sign_in',
PREVIEW_PLAYED: 'preview_played',
VST_OPERATION_SELECTED: 'vst_operation_selected',
VST_EFFECT_SELECTED: 'vst_effect_selected',
LESSON_SESSION_ACTION: 'lesson_session_action',
JAMBLASTER_ACTION: 'jamblaster_action'
};
context.JK.PLAYBACK_MONITOR_MODE = { context.JK.PLAYBACK_MONITOR_MODE = {
MEDIA_FILE: 'MEDIA_FILE', MEDIA_FILE: 'MEDIA_FILE',
@ -74,288 +91,288 @@
BROWSER_MEDIA: 'BROWSER_MEDIA' BROWSER_MEDIA: 'BROWSER_MEDIA'
} }
context.JK.ALERT_NAMES = { context.JK.ALERT_NAMES = {
NO_EVENT : 0, NO_EVENT: 0,
BACKEND_ERROR : 1, //generic error - eg P2P message error BACKEND_ERROR: 1, //generic error - eg P2P message error
BACKEND_MIXER_CHANGE : 2, //event that controls have been regenerated BACKEND_MIXER_CHANGE: 2, //event that controls have been regenerated
//network related //network related
PACKET_JTR : 3, PACKET_JTR: 3,
PACKET_LOSS : 4, PACKET_LOSS: 4,
PACKET_LATE : 5, PACKET_LATE: 5,
JTR_QUEUE_DEPTH : 6, JTR_QUEUE_DEPTH: 6,
NETWORK_JTR : 7, NETWORK_JTR: 7,
NETWORK_PING : 8, NETWORK_PING: 8,
BITRATE_THROTTLE_WARN : 9, BITRATE_THROTTLE_WARN: 9,
BANDWIDTH_LOW : 10, BANDWIDTH_LOW: 10,
//IO related events //IO related events
INPUT_IO_RATE : 11, INPUT_IO_RATE: 11,
INPUT_IO_JTR : 12, INPUT_IO_JTR: 12,
OUTPUT_IO_RATE : 13, OUTPUT_IO_RATE: 13,
OUTPUT_IO_JTR : 14, OUTPUT_IO_JTR: 14,
// CPU load related // CPU load related
CPU_LOAD : 15, CPU_LOAD: 15,
DECODE_VIOLATIONS : 16, DECODE_VIOLATIONS: 16,
LAST_THRESHOLD : 17, LAST_THRESHOLD: 17,
WIFI_NETWORK_ALERT : 18, //user or peer is using wifi WIFI_NETWORK_ALERT: 18, //user or peer is using wifi
NO_VALID_AUDIO_CONFIG : 19, // alert the user to popup a config NO_VALID_AUDIO_CONFIG: 19, // alert the user to popup a config
AUDIO_DEVICE_NOT_PRESENT : 20, // the audio device is not connected AUDIO_DEVICE_NOT_PRESENT: 20, // the audio device is not connected
RECORD_PLAYBACK_STATE : 21, // record/playback events have occurred RECORD_PLAYBACK_STATE: 21, // record/playback events have occurred
RUN_UPDATE_CHECK_BACKGROUND : 22, //this is auto check - do RUN_UPDATE_CHECK_BACKGROUND: 22, //this is auto check - do
RUN_UPDATE_CHECK_INTERACTIVE : 23, //this is initiated by user RUN_UPDATE_CHECK_INTERACTIVE: 23, //this is initiated by user
STUN_EVENT : 24, // system completed stun test... come get the result STUN_EVENT: 24, // system completed stun test... come get the result
DEAD_USER_WARN_EVENT : 25, //the backend is not receiving audio from this peer DEAD_USER_WARN_EVENT: 25, //the backend is not receiving audio from this peer
DEAD_USER_REMOVE_EVENT : 26, //the backend is removing the user from session as no audio is coming from this peer DEAD_USER_REMOVE_EVENT: 26, //the backend is removing the user from session as no audio is coming from this peer
WINDOW_CLOSE_BACKGROUND_MODE : 27, //the user has closed the window and the client is now in background mode WINDOW_CLOSE_BACKGROUND_MODE: 27, //the user has closed the window and the client is now in background mode
WINDOW_OPEN_FOREGROUND_MODE : 28, //the user has opened the window and the client is now in forground mode/ WINDOW_OPEN_FOREGROUND_MODE: 28, //the user has opened the window and the client is now in forground mode/
SESSION_LIVEBROADCAST_FAIL : 29, //error of some sort - so can't broadcast SESSION_LIVEBROADCAST_FAIL: 29, //error of some sort - so can't broadcast
SESSION_LIVEBROADCAST_ACTIVE : 30, //active SESSION_LIVEBROADCAST_ACTIVE: 30, //active
SESSION_LIVEBROADCAST_STOPPED : 31, //stopped by server/user SESSION_LIVEBROADCAST_STOPPED: 31, //stopped by server/user
SESSION_LIVEBROADCAST_PINNED : 32, //node pinned by user SESSION_LIVEBROADCAST_PINNED: 32, //node pinned by user
SESSION_LIVEBROADCAST_UNPINNED : 33, //node unpinned by user SESSION_LIVEBROADCAST_UNPINNED: 33, //node unpinned by user
BACKEND_STATUS_MSG : 34, //status/informational message BACKEND_STATUS_MSG: 34, //status/informational message
LOCAL_NETWORK_VARIANCE_HIGH : 35,//the ping time via a hairpin for the user network is unnaturally high or variable. LOCAL_NETWORK_VARIANCE_HIGH: 35,//the ping time via a hairpin for the user network is unnaturally high or variable.
//indicates problem with user computer stack or network itself (wifi, antivirus etc) //indicates problem with user computer stack or network itself (wifi, antivirus etc)
LOCAL_NETWORK_LATENCY_HIGH : 36, LOCAL_NETWORK_LATENCY_HIGH: 36,
RECORDING_CLOSE : 37, //update and remove tracks from front-end RECORDING_CLOSE: 37, //update and remove tracks from front-end
PEER_REPORTS_NO_AUDIO_RECV : 38, //letting front-end know audio is not being received from a user in session PEER_REPORTS_NO_AUDIO_RECV: 38, //letting front-end know audio is not being received from a user in session
SHOW_PREFERENCES : 39, // tell frontend to show preferences dialog SHOW_PREFERENCES: 39, // tell frontend to show preferences dialog
USB_CONNECTED : 40, // tell frontend that a USB device was connected USB_CONNECTED: 40, // tell frontend that a USB device was connected
USB_DISCONNECTED : 41, // tell frontend that a USB device was disconnected USB_DISCONNECTED: 41, // tell frontend that a USB device was disconnected
JAM_TRACK_SERVER_ERROR : 42, //error talking with server JAM_TRACK_SERVER_ERROR: 42, //error talking with server
BAD_INTERVAL_RATE : 43, //the audio gear is calling back at rate that does not match the expected interval BAD_INTERVAL_RATE: 43, //the audio gear is calling back at rate that does not match the expected interval
FIRST_AUDIO_PACKET : 44,// we are receiving audio from peer FIRST_AUDIO_PACKET: 44,// we are receiving audio from peer
NETWORK_PORT_MANGLED : 45, // packet from peer indicates network port is being mangled NETWORK_PORT_MANGLED: 45, // packet from peer indicates network port is being mangled
NO_GLOBAL_CLOCK_SERVER : 46, //can't reach global clock NTP server NO_GLOBAL_CLOCK_SERVER: 46, //can't reach global clock NTP server
GLOBAL_CLOCK_SYNCED : 47, //clock synced GLOBAL_CLOCK_SYNCED: 47, //clock synced
RECORDING_DONE :48, //the recording writer thread is done RECORDING_DONE: 48, //the recording writer thread is done
VIDEO_WINDOW_OPENED :49, //video window opened VIDEO_WINDOW_OPENED: 49, //video window opened
VIDEO_WINDOW_CLOSED :50, VIDEO_WINDOW_CLOSED: 50,
VST_CHANGED: 51, // VST state changed VST_CHANGED: 51, // VST state changed
SAMPLERATE_CONFIGURATION_BAD: 52, SAMPLERATE_CONFIGURATION_BAD: 52,
SHOW_NETWORK_TEST: 53, SHOW_NETWORK_TEST: 53,
LAST_ALERT : 54 LAST_ALERT: 54
} }
// recreate eThresholdType enum from MixerDialog.h // recreate eThresholdType enum from MixerDialog.h
context.JK.ALERT_TYPES = { context.JK.ALERT_TYPES = {
0: {"title": "", "message": ""}, // NO_EVENT, 0: { "title": "", "message": "" }, // NO_EVENT,
1: {"title": "", "message": ""}, // BACKEND_ERROR: generic error - eg P2P message error 1: { "title": "", "message": "" }, // BACKEND_ERROR: generic error - eg P2P message error
2: {"title": "", "message": ""}, // BACKEND_MIXER_CHANGE, - event that controls have been regenerated 2: { "title": "", "message": "" }, // BACKEND_MIXER_CHANGE, - event that controls have been regenerated
3: {"title": "High Packet Jitter", "message": "Your network connection is currently experiencing packet jitter at a level that is too high to deliver good audio quality. For troubleshooting tips, click the '?'.", help: "https://jamkazam.desk.com/customer/portal/articles/1288778-troubleshoot-session-quality-problems"}, // PACKET_JTR, 3: { "title": "High Packet Jitter", "message": "Your network connection is currently experiencing packet jitter at a level that is too high to deliver good audio quality. For troubleshooting tips, click the '?'.", help: "https://jamkazam.desk.com/customer/portal/articles/1288778-troubleshoot-session-quality-problems" }, // PACKET_JTR,
4: {"title": "High Packet Loss", "message": "Your network connection is currently experiencing packet loss at a rate that is too high to deliver good audio quality. For troubleshooting tips, click the '?'.", help: "https://jamkazam.desk.com/customer/portal/articles/1288778-troubleshoot-session-quality-problems" }, // PACKET_LOSS 4: { "title": "High Packet Loss", "message": "Your network connection is currently experiencing packet loss at a rate that is too high to deliver good audio quality. For troubleshooting tips, click the '?'.", help: "https://jamkazam.desk.com/customer/portal/articles/1288778-troubleshoot-session-quality-problems" }, // PACKET_LOSS
5: {"title": "High Packet Late", "message": "Your network connection is currently experiencing packet loss at a rate that is too high to deliver good audio quality. For troubleshooting tips, click the '?'.", help: "https://jamkazam.desk.com/customer/portal/articles/1288778-troubleshoot-session-quality-problems"}, // PACKET_LATE, 5: { "title": "High Packet Late", "message": "Your network connection is currently experiencing packet loss at a rate that is too high to deliver good audio quality. For troubleshooting tips, click the '?'.", help: "https://jamkazam.desk.com/customer/portal/articles/1288778-troubleshoot-session-quality-problems" }, // PACKET_LATE,
6: {"title": "Large Jitter Queue", "message": "Your network connection is currently experiencing packet jitter at a level that is too high to deliver good audio quality. For troubleshooting tips, click the '?'.", help: "https://jamkazam.desk.com/customer/portal/articles/1288778-troubleshoot-session-quality-problems"}, // JTR_QUEUE_DEPTH, 6: { "title": "Large Jitter Queue", "message": "Your network connection is currently experiencing packet jitter at a level that is too high to deliver good audio quality. For troubleshooting tips, click the '?'.", help: "https://jamkazam.desk.com/customer/portal/articles/1288778-troubleshoot-session-quality-problems" }, // JTR_QUEUE_DEPTH,
7: {"title": "High Network Jitter", "message": "Your network connection is currently experiencing network jitter at a level that is too high to deliver good audio quality. For troubleshooting tips, click the '?'.", help: "https://jamkazam.desk.com/customer/portal/articles/1288778-troubleshoot-session-quality-problems"}, // NETWORK_JTR, 7: { "title": "High Network Jitter", "message": "Your network connection is currently experiencing network jitter at a level that is too high to deliver good audio quality. For troubleshooting tips, click the '?'.", help: "https://jamkazam.desk.com/customer/portal/articles/1288778-troubleshoot-session-quality-problems" }, // NETWORK_JTR,
8: {"title": "High Session Latency", "message": "The latency of your audio device combined with your Internet connection has become high enough to impact your session quality. For troubleshooting tips, click the '?'.", help: "https://jamkazam.desk.com/customer/portal/articles/1288778-troubleshoot-session-quality-problems" }, // NETWORK_PING, 8: { "title": "High Session Latency", "message": "The latency of your audio device combined with your Internet connection has become high enough to impact your session quality. For troubleshooting tips, click the '?'.", help: "https://jamkazam.desk.com/customer/portal/articles/1288778-troubleshoot-session-quality-problems" }, // NETWORK_PING,
9: {"title": "Bandwidth Throttled", "message": "The available bandwidth on your network has diminished, and this may impact your audio quality. For troubleshooting tips, click the '?'.", help: "https://jamkazam.desk.com/customer/portal/articles/1288778-troubleshoot-session-quality-problems"}, // BITRATE_THROTTLE_WARN, 9: { "title": "Bandwidth Throttled", "message": "The available bandwidth on your network has diminished, and this may impact your audio quality. For troubleshooting tips, click the '?'.", help: "https://jamkazam.desk.com/customer/portal/articles/1288778-troubleshoot-session-quality-problems" }, // BITRATE_THROTTLE_WARN,
10:{"title": "Low Bandwidth", "message": "The available bandwidth on your network has become too low, and this may impact your audio quality. For troubleshooting tips, click the '?'.", help: "https://jamkazam.desk.com/customer/portal/articles/1288778-troubleshoot-session-quality-problems" }, // BANDWIDTH_LOW 10: { "title": "Low Bandwidth", "message": "The available bandwidth on your network has become too low, and this may impact your audio quality. For troubleshooting tips, click the '?'.", help: "https://jamkazam.desk.com/customer/portal/articles/1288778-troubleshoot-session-quality-problems" }, // BANDWIDTH_LOW
// IO related events // IO related events
11:{"title": "Variable Input Rate", "message": "The input rate of your audio device is varying too much to deliver good audio quality. For troubleshooting tips, click the '?'.", help: "https://jamkazam.desk.com/customer/portal/articles/1288778-troubleshoot-session-quality-problems" }, // INPUT_IO_RATE 11: { "title": "Variable Input Rate", "message": "The input rate of your audio device is varying too much to deliver good audio quality. For troubleshooting tips, click the '?'.", help: "https://jamkazam.desk.com/customer/portal/articles/1288778-troubleshoot-session-quality-problems" }, // INPUT_IO_RATE
12:{"title": "High Input Jitter", "message": "The input rate of your audio device is varying too much to deliver good audio quality. For troubleshooting tips, click the '?'.", help: "https://jamkazam.desk.com/customer/portal/articles/1288778-troubleshoot-session-quality-problems"}, // INPUT_IO_JTR, 12: { "title": "High Input Jitter", "message": "The input rate of your audio device is varying too much to deliver good audio quality. For troubleshooting tips, click the '?'.", help: "https://jamkazam.desk.com/customer/portal/articles/1288778-troubleshoot-session-quality-problems" }, // INPUT_IO_JTR,
13:{"title": "Variable Output Rate", "message": "The output rate of your audio device is varying too much to deliver good audio quality. For troubleshooting tips, click the '?'.", help: "https://jamkazam.desk.com/customer/portal/articles/1288778-troubleshoot-session-quality-problems"}, // OUTPUT_IO_RATE 13: { "title": "Variable Output Rate", "message": "The output rate of your audio device is varying too much to deliver good audio quality. For troubleshooting tips, click the '?'.", help: "https://jamkazam.desk.com/customer/portal/articles/1288778-troubleshoot-session-quality-problems" }, // OUTPUT_IO_RATE
14:{"title": "High Output Jitter", "message": "The output rate of your audio device is varying too much to deliver good audio quality. For troubleshooting tips, click the '?'.", help: "https://jamkazam.desk.com/customer/portal/articles/1288778-troubleshoot-session-quality-problems"}, // OUTPUT_IO_JTR, 14: { "title": "High Output Jitter", "message": "The output rate of your audio device is varying too much to deliver good audio quality. For troubleshooting tips, click the '?'.", help: "https://jamkazam.desk.com/customer/portal/articles/1288778-troubleshoot-session-quality-problems" }, // OUTPUT_IO_JTR,
// CPU load related // CPU load related
15: { "title": "CPU Utilization High", "message": "The CPU of your computer is unable to keep up with the current processing load, and this may impact your audio quality. For troubleshooting tips, click the '?'.", help: "https://jamkazam.desk.com/customer/portal/articles/1288778-troubleshoot-session-quality-problems"}, // CPU_LOAD 15: { "title": "CPU Utilization High", "message": "The CPU of your computer is unable to keep up with the current processing load, and this may impact your audio quality. For troubleshooting tips, click the '?'.", help: "https://jamkazam.desk.com/customer/portal/articles/1288778-troubleshoot-session-quality-problems" }, // CPU_LOAD
16: {"title": "Decode Violations", "message": ""}, // DECODE_VIOLATIONS, 16: { "title": "Decode Violations", "message": "" }, // DECODE_VIOLATIONS,
17: {"title": "", "message": ""}, // LAST_THRESHOLD 17: { "title": "", "message": "" }, // LAST_THRESHOLD
18: {"title": "Wifi Alert", "message": ""}, // WIFI_NETWORK_ALERT, //user or peer is using wifi 18: { "title": "Wifi Alert", "message": "" }, // WIFI_NETWORK_ALERT, //user or peer is using wifi
19: {"title": "No Audio Configuration", "message": "You cannot join the session because you do not have a valid audio configuration."}, // NO_VALID_AUDIO_CONFIG, 19: { "title": "No Audio Configuration", "message": "You cannot join the session because you do not have a valid audio configuration." }, // NO_VALID_AUDIO_CONFIG,
20: {"title": "", "message": ""}, // AUDIO_DEVICE_NOT_PRESENT, // the audio device is not connected 20: { "title": "", "message": "" }, // AUDIO_DEVICE_NOT_PRESENT, // the audio device is not connected
//20: {"title": "Audio Device Not Present", "message": ""}, // AUDIO_DEVICE_NOT_PRESENT, // the audio device is not connected //20: {"title": "Audio Device Not Present", "message": ""}, // AUDIO_DEVICE_NOT_PRESENT, // the audio device is not connected
21: {"title": "", "message": ""}, // RECORD_PLAYBACK_STATE, // record/playback events have occurred 21: { "title": "", "message": "" }, // RECORD_PLAYBACK_STATE, // record/playback events have occurred
22: {"title": "", "message": ""}, // RUN_UPDATE_CHECK_BACKGROUND, //this is auto check - do 22: { "title": "", "message": "" }, // RUN_UPDATE_CHECK_BACKGROUND, //this is auto check - do
23: {"title": "", "message": ""}, // RUN_UPDATE_CHECK_INTERACTIVE, //this is initiated by user 23: { "title": "", "message": "" }, // RUN_UPDATE_CHECK_INTERACTIVE, //this is initiated by user
24: {"title": "", "message": ""}, // STUN_EVENT, // system completed stun test... come get the result 24: { "title": "", "message": "" }, // STUN_EVENT, // system completed stun test... come get the result
25: {"title": "No Audio", "message": "Your system is no longer transmitting audio. Other session members are unable to hear you."}, // DEAD_USER_WARN_EVENT, //the backend is not receiving audio from this peer 25: { "title": "No Audio", "message": "Your system is no longer transmitting audio. Other session members are unable to hear you." }, // DEAD_USER_WARN_EVENT, //the backend is not receiving audio from this peer
26: {"title": "No Audio", "message": "Your system is no longer transmitting audio. Other session members are unable to hear you."}, // DEAD_USER_REMOVE_EVENT, //the backend is removing the user from session as no audio is coming from this peer 26: { "title": "No Audio", "message": "Your system is no longer transmitting audio. Other session members are unable to hear you." }, // DEAD_USER_REMOVE_EVENT, //the backend is removing the user from session as no audio is coming from this peer
27: {"title": "", "message": ""}, // WINDOW_CLOSE_BACKGROUND_MODE, //the user has closed the window and the client is now in background mode 27: { "title": "", "message": "" }, // WINDOW_CLOSE_BACKGROUND_MODE, //the user has closed the window and the client is now in background mode
28: {"title": "", "message": ""}, // WINDOW_OPEN_FOREGROUND_MODE, //the user has opened the window and the client is now in forground mode/ 28: { "title": "", "message": "" }, // WINDOW_OPEN_FOREGROUND_MODE, //the user has opened the window and the client is now in forground mode/
29: {"title": "Failed to Broadcast", "message": ""}, // SESSION_LIVEBROADCAST_FAIL, //error of some sort - so can't broadcast 29: { "title": "Failed to Broadcast", "message": "" }, // SESSION_LIVEBROADCAST_FAIL, //error of some sort - so can't broadcast
30: {"title": "", "message": ""}, // SESSION_LIVEBROADCAST_ACTIVE, //active 30: { "title": "", "message": "" }, // SESSION_LIVEBROADCAST_ACTIVE, //active
31: {"title": "", "message": ""}, // SESSION_LIVEBROADCAST_STOPPED, //stopped by server/user 31: { "title": "", "message": "" }, // SESSION_LIVEBROADCAST_STOPPED, //stopped by server/user
32: {"title": "Client Pinned", "message": "This client will be the source of a broadcast."}, // SESSION_LIVEBROADCAST_PINNED, //node pinned by user 32: { "title": "Client Pinned", "message": "This client will be the source of a broadcast." }, // SESSION_LIVEBROADCAST_PINNED, //node pinned by user
33: {"title": "Client No Longer Pinned", "message": "This client is no longer designated as the source of the broadcast."}, // SESSION_LIVEBROADCAST_UNPINNED, //node unpinned by user 33: { "title": "Client No Longer Pinned", "message": "This client is no longer designated as the source of the broadcast." }, // SESSION_LIVEBROADCAST_UNPINNED, //node unpinned by user
34: {"title": "", "message": ""}, // BACKEND_STATUS_MSG, //status/informational message 34: { "title": "", "message": "" }, // BACKEND_STATUS_MSG, //status/informational message
35: {"title": "LAN Unpredictable", "message": "Your local network is adding considerable variance to transmit times. For troubleshooting tips, click the '?'.", help: "https://jamkazam.desk.com/customer/portal/articles/1288778-troubleshoot-session-quality-problems"}, // LOCAL_NETWORK_VARIANCE_HIGH,//the ping time via a hairpin for the user network is unnaturally high or variable. 35: { "title": "LAN Unpredictable", "message": "Your local network is adding considerable variance to transmit times. For troubleshooting tips, click the '?'.", help: "https://jamkazam.desk.com/customer/portal/articles/1288778-troubleshoot-session-quality-problems" }, // LOCAL_NETWORK_VARIANCE_HIGH,//the ping time via a hairpin for the user network is unnaturally high or variable.
//indicates problem with user computer stack or network itself (wifi, antivirus etc) //indicates problem with user computer stack or network itself (wifi, antivirus etc)
36: {"title": "LAN High Latency", "message": "Your local network is adding considerable latency. For troubleshooting tips, click the '?'.", help: "https://jamkazam.desk.com/customer/portal/articles/1288778-troubleshoot-session-quality-problems"}, // LOCAL_NETWORK_LATENCY_HIGH, 36: { "title": "LAN High Latency", "message": "Your local network is adding considerable latency. For troubleshooting tips, click the '?'.", help: "https://jamkazam.desk.com/customer/portal/articles/1288778-troubleshoot-session-quality-problems" }, // LOCAL_NETWORK_LATENCY_HIGH,
37: {"title": "", "message": ""}, // RECORDING_CLOSE, //update and remove tracks from front-end 37: { "title": "", "message": "" }, // RECORDING_CLOSE, //update and remove tracks from front-end
38: {"title": "No Audio Sent", "message": ""}, // PEER_REPORTS_NO_AUDIO_RECV, //update and remove tracks from front-end 38: { "title": "No Audio Sent", "message": "" }, // PEER_REPORTS_NO_AUDIO_RECV, //update and remove tracks from front-end
39: {"title": "", "message": ""}, // SHOW_PREFERENCES, //show preferences dialog 39: { "title": "", "message": "" }, // SHOW_PREFERENCES, //show preferences dialog
40: {"title": "", "message": ""}, // USB_CONNECTED 40: { "title": "", "message": "" }, // USB_CONNECTED
41: {"title": "", "message": ""}, // USB_DISCONNECTED, // tell frontend that a USB device was disconnected 41: { "title": "", "message": "" }, // USB_DISCONNECTED, // tell frontend that a USB device was disconnected
42: {"title": "", "message": ""}, // JAM_TRACK_SERVER_ERROR 42: { "title": "", "message": "" }, // JAM_TRACK_SERVER_ERROR
43: {"title": "", "message": ""}, // BAD_INTERVAL_RATE 43: { "title": "", "message": "" }, // BAD_INTERVAL_RATE
44: {"title": "", "message": ""}, // FIRST_AUDIO_PACKET 44: { "title": "", "message": "" }, // FIRST_AUDIO_PACKET
45: {"title": "", "message": ""}, // NETWORK_PORT_MANGLED 45: { "title": "", "message": "" }, // NETWORK_PORT_MANGLED
46: {"title": "", "message": ""}, // NO_GLOBAL_CLOCK_SERVER 46: { "title": "", "message": "" }, // NO_GLOBAL_CLOCK_SERVER
47: {"title": "", "message": ""}, // GLOBAL_CLOCK_SYNCED 47: { "title": "", "message": "" }, // GLOBAL_CLOCK_SYNCED
48: {"title": "", "message": ""}, // RECORDING_DONE 48: { "title": "", "message": "" }, // RECORDING_DONE
49: {"title": "", "message": ""}, // VIDEO_WINDOW_OPENED 49: { "title": "", "message": "" }, // VIDEO_WINDOW_OPENED
50: {"title": "", "message": ""}, // VIDEO_WINDOW_CLOSED 50: { "title": "", "message": "" }, // VIDEO_WINDOW_CLOSED
51: {"title": "", "message": ""}, // VST_CHANGED 51: { "title": "", "message": "" }, // VST_CHANGED
52: {"title": "", "message": ""}, // SAMPLERATE_CONFIGURATION_BAD 52: { "title": "", "message": "" }, // SAMPLERATE_CONFIGURATION_BAD
53: {"title": "", "message": ""}, // SHOW_NETWORK_TEST 53: { "title": "", "message": "" }, // SHOW_NETWORK_TEST
54: {"title": "", "message": ""} // LAST_ALERT 54: { "title": "", "message": "" } // LAST_ALERT
}; };
// add the alert's name to the ALERT_TYPES structure // add the alert's name to the ALERT_TYPES structure
context._.each(context.JK.ALERT_NAMES, function(alert_code, alert_name) { context._.each(context.JK.ALERT_NAMES, function (alert_code, alert_name) {
var alert_data = context.JK.ALERT_TYPES[alert_code]; var alert_data = context.JK.ALERT_TYPES[alert_code];
alert_data.name = alert_name; alert_data.name = alert_name;
}) })
context.JK.MAX_TRACKS = 6; context.JK.MAX_TRACKS = 6;
context.JK.MAX_OUTPUTS = 2; context.JK.MAX_OUTPUTS = 2;
// TODO: store these client_id values in instruments table, or store // TODO: store these client_id values in instruments table, or store
// server_id as the client_id to prevent maintenance nightmares. As it's // server_id as the client_id to prevent maintenance nightmares. As it's
// set up now, we will have to deploy each time we add new instruments. // set up now, we will have to deploy each time we add new instruments.
context.JK.server_to_client_instrument_map = { context.JK.server_to_client_instrument_map = {
"Acoustic Guitar": { "client_id": 10, "server_id": "acoustic guitar" }, "Acoustic Guitar": { "client_id": 10, "server_id": "acoustic guitar" },
"Bass Guitar": { "client_id": 20, "server_id": "bass guitar" }, "Bass Guitar": { "client_id": 20, "server_id": "bass guitar" },
"Computer": { "client_id": 30, "server_id": "computer" }, "Computer": { "client_id": 30, "server_id": "computer" },
"Drums": { "client_id": 40, "server_id": "drums" }, "Drums": { "client_id": 40, "server_id": "drums" },
"Percussion": { "client_id": 41, "server_id": "percussion" }, "Percussion": { "client_id": 41, "server_id": "percussion" },
"Electric Guitar": { "client_id": 50, "server_id": "electric guitar" }, "Electric Guitar": { "client_id": 50, "server_id": "electric guitar" },
"Keyboard": { "client_id": 60, "server_id": "keyboard" }, "Keyboard": { "client_id": 60, "server_id": "keyboard" },
"Piano": { "client_id": 61, "server_id": "piano" }, "Piano": { "client_id": 61, "server_id": "piano" },
"Double Bass": { "client_id": 62, "server_id": "double bass" }, "Double Bass": { "client_id": 62, "server_id": "double bass" },
"Voice": { "client_id": 70, "server_id": "voice" }, "Voice": { "client_id": 70, "server_id": "voice" },
"Flute": { "client_id": 80, "server_id": "flute" }, "Flute": { "client_id": 80, "server_id": "flute" },
"Clarinet": { "client_id": 90, "server_id": "clarinet" }, "Clarinet": { "client_id": 90, "server_id": "clarinet" },
"Saxophone": { "client_id": 100, "server_id": "saxophone" }, "Saxophone": { "client_id": 100, "server_id": "saxophone" },
"Trumpet": { "client_id": 110, "server_id": "trumpet" }, "Trumpet": { "client_id": 110, "server_id": "trumpet" },
"Violin": { "client_id": 120, "server_id": "violin" }, "Violin": { "client_id": 120, "server_id": "violin" },
"Trombone": { "client_id": 130, "server_id": "trombone" }, "Trombone": { "client_id": 130, "server_id": "trombone" },
"Banjo": { "client_id": 140, "server_id": "banjo" }, "Banjo": { "client_id": 140, "server_id": "banjo" },
"Harmonica": { "client_id": 150, "server_id": "harmonica" }, "Harmonica": { "client_id": 150, "server_id": "harmonica" },
"Accordion": { "client_id": 160, "server_id": "accordion" }, "Accordion": { "client_id": 160, "server_id": "accordion" },
"French Horn": { "client_id": 170, "server_id": "french horn" }, "French Horn": { "client_id": 170, "server_id": "french horn" },
"Euphonium": { "client_id": 180, "server_id": "euphonium" }, "Euphonium": { "client_id": 180, "server_id": "euphonium" },
"Tuba": { "client_id": 190, "server_id": "tuba" }, "Tuba": { "client_id": 190, "server_id": "tuba" },
"Oboe": { "client_id": 200, "server_id": "oboe" }, "Oboe": { "client_id": 200, "server_id": "oboe" },
"Ukulele": { "client_id": 210, "server_id": "ukulele" }, "Ukulele": { "client_id": 210, "server_id": "ukulele" },
"Cello": { "client_id": 220, "server_id": "cello" }, "Cello": { "client_id": 220, "server_id": "cello" },
"Viola": { "client_id": 230, "server_id": "viola" }, "Viola": { "client_id": 230, "server_id": "viola" },
"Mandolin": { "client_id": 240, "server_id": "mandolin" }, "Mandolin": { "client_id": 240, "server_id": "mandolin" },
"Other": { "client_id": 250, "server_id": "other" } "Other": { "client_id": 250, "server_id": "other" }
}; };
context.JK.client_to_server_instrument_map = { context.JK.client_to_server_instrument_map = {
10: { "server_id": "acoustic guitar" }, 10: { "server_id": "acoustic guitar" },
20: { "server_id": "bass guitar" }, 20: { "server_id": "bass guitar" },
30: { "server_id": "computer" }, 30: { "server_id": "computer" },
40: { "server_id": "drums" }, 40: { "server_id": "drums" },
41: { "server_id": "percussion" }, 41: { "server_id": "percussion" },
50: { "server_id": "electric guitar" }, 50: { "server_id": "electric guitar" },
60: { "server_id": "keyboard" }, 60: { "server_id": "keyboard" },
61: { "server_id": "piano"} , 61: { "server_id": "piano" },
62: { "server_id": "double bass"} , 62: { "server_id": "double bass" },
70: { "server_id": "voice" }, 70: { "server_id": "voice" },
80: { "server_id": "flute" }, 80: { "server_id": "flute" },
90: { "server_id": "clarinet" }, 90: { "server_id": "clarinet" },
100: { "server_id": "saxophone" }, 100: { "server_id": "saxophone" },
110: { "server_id": "trumpet" }, 110: { "server_id": "trumpet" },
120: { "server_id": "violin" }, 120: { "server_id": "violin" },
130: { "server_id": "trombone" }, 130: { "server_id": "trombone" },
140: { "server_id": "banjo" }, 140: { "server_id": "banjo" },
150: { "server_id": "harmonica" }, 150: { "server_id": "harmonica" },
160: { "server_id": "accordion" }, 160: { "server_id": "accordion" },
170: { "server_id": "french horn" }, 170: { "server_id": "french horn" },
180: { "server_id": "euphonium" }, 180: { "server_id": "euphonium" },
190: { "server_id": "tuba" }, 190: { "server_id": "tuba" },
200: { "server_id": "oboe" }, 200: { "server_id": "oboe" },
210: { "server_id": "ukulele" }, 210: { "server_id": "ukulele" },
220: { "server_id": "cello" }, 220: { "server_id": "cello" },
230: { "server_id": "viola" }, 230: { "server_id": "viola" },
240: { "server_id": "mandolin" }, 240: { "server_id": "mandolin" },
250: { "server_id": "other" } 250: { "server_id": "other" }
}; };
context.JK.instrument_id_to_instrument = {}; context.JK.instrument_id_to_instrument = {};
context.JK.server_to_client_instrument_alpha = []; context.JK.server_to_client_instrument_alpha = [];
(function() { (function () {
$.each(context.JK.server_to_client_instrument_map, function(key, value) { $.each(context.JK.server_to_client_instrument_map, function (key, value) {
context.JK.instrument_id_to_instrument[value.server_id] = { client_id: value.client_id, display: key } context.JK.instrument_id_to_instrument[value.server_id] = { client_id: value.client_id, display: key }
context.JK.server_to_client_instrument_alpha.push({ client_id: value.client_id, display: key, server_id: value.server_id }) context.JK.server_to_client_instrument_alpha.push({ client_id: value.client_id, display: key, server_id: value.server_id })
}); });
context.JK.server_to_client_instrument_alpha.sort(function(a, b){ context.JK.server_to_client_instrument_alpha.sort(function (a, b) {
if ( a.display < b.display ) if (a.display < b.display)
return -1; return -1;
if ( a.display > b.display ) if (a.display > b.display)
return 1; return 1;
return 0; return 0;
}); });
})(); })();
context.JK.entityToPrintable = { context.JK.entityToPrintable = {
music_session: "music session", music_session: "music session",
slot: "Requested time" slot: "Requested time"
} }
context.JK.AUDIO_DEVICE_BEHAVIOR = { context.JK.AUDIO_DEVICE_BEHAVIOR = {
MacOSX_builtin: { MacOSX_builtin: {
display: 'MacOSX Built-In', display: 'MacOSX Built-In',
shortName: 'Built-In', shortName: 'Built-In',
videoURL: "https://www.youtube.com/watch?v=7-9PW50ygHk", videoURL: "https://www.youtube.com/watch?v=7-9PW50ygHk",
showKnobs: true, showKnobs: true,
showASIO: false showASIO: false
}, },
MacOSX_interface: { MacOSX_interface: {
display: 'MacOSX external interface', display: 'MacOSX external interface',
shortName: 'External', shortName: 'External',
videoURL: "https://www.youtube.com/watch?v=7BLld6ogm14", videoURL: "https://www.youtube.com/watch?v=7BLld6ogm14",
showKnobs: true, showKnobs: true,
showASIO: false showASIO: false
}, },
Win32_wdm: { Win32_wdm: {
display: 'Windows WDM', display: 'Windows WDM',
shortName : 'WDM', shortName: 'WDM',
videoURL: "https://www.youtube.com/watch?v=L36UBkAV14c", videoURL: "https://www.youtube.com/watch?v=L36UBkAV14c",
showKnobs: true, showKnobs: true,
showASIO: false showASIO: false
}, },
Win32_asio: { Win32_asio: {
display: 'Windows ASIO', display: 'Windows ASIO',
shortName : 'ASIO', shortName: 'ASIO',
videoURL: "https://www.youtube.com/watch?v=PGUmISTVVMY", videoURL: "https://www.youtube.com/watch?v=PGUmISTVVMY",
showKnobs: true, showKnobs: true,
showASIO: true showASIO: true
}, },
Win32_asio4all: { Win32_asio4all: {
display: 'Windows ASIO4ALL', display: 'Windows ASIO4ALL',
shortName : 'ASIO4ALL', shortName: 'ASIO4ALL',
videoURL: "https://www.youtube.com/watch?v=PGUmISTVVMY", videoURL: "https://www.youtube.com/watch?v=PGUmISTVVMY",
showKnobs: true, showKnobs: true,
showASIO: true showASIO: true
}, },
Linux: { Linux: {
display: 'Linux', display: 'Linux',
shortName : 'linux', shortName: 'linux',
videoURL: undefined, videoURL: undefined,
showKnobs: true, showKnobs: true,
showASIO: false showASIO: false
}
} }
}
context.JK.MIX_MODES = { context.JK.MIX_MODES = {
MASTER: true, MASTER: true,
@ -364,23 +381,27 @@
/** NAMED_MESSAGES means messages that we show to the user (dialogs/banners/whatever), that we have formally named */ /** NAMED_MESSAGES means messages that we show to the user (dialogs/banners/whatever), that we have formally named */
context.JK.NAMED_MESSAGES = { context.JK.NAMED_MESSAGES = {
MASTER_VS_PERSONAL_MIX : 'master_vs_personal_mix', MASTER_VS_PERSONAL_MIX: 'master_vs_personal_mix',
HOWTO_USE_VIDEO_NOSHOW : 'how-to-use-video', HOWTO_USE_VIDEO_NOSHOW: 'how-to-use-video',
CONFIGURE_VIDEO_NOSHOW : 'configure-video', CONFIGURE_VIDEO_NOSHOW: 'configure-video',
TEACHER_MUSICIAN_PROFILE : 'teacher-musician-profile' TEACHER_MUSICIAN_PROFILE: 'teacher-musician-profile'
}
context.JK.ALERT_MESSAGES = {
OBS_UNAVAILABLE: 'To make a video recording in JamKazam, you must first install and configure OBS software. Click the link below for a help article that explains how to do this. <a href="" target="_blank" title="Install OBS">View Help Article</a>'
} }
context.JK.ChannelGroupIds = { context.JK.ChannelGroupIds = {
"MasterGroup": 0, "MasterGroup": 0,
"MonitorGroup": 1, "MonitorGroup": 1,
"MasterCatGroup" : 2, "MasterCatGroup": 2,
"MonitorCatGroup" : 3, "MonitorCatGroup": 3,
"AudioInputMusicGroup": 4, "AudioInputMusicGroup": 4,
"AudioInputChatGroup": 5, "AudioInputChatGroup": 5,
"MediaTrackGroup": 6, "MediaTrackGroup": 6,
"StreamOutMusicGroup": 7, "StreamOutMusicGroup": 7,
"StreamOutChatGroup": 8, "StreamOutChatGroup": 8,
"StreamOutMediaGroup" : 9, "StreamOutMediaGroup": 9,
"UserMusicInputGroup": 10, "UserMusicInputGroup": 10,
"UserChatInputGroup": 11, "UserChatInputGroup": 11,
"UserMediaInputGroup": 12, "UserMediaInputGroup": 12,
@ -416,13 +437,13 @@
18: "PeerMidiInputMusicGroup" 18: "PeerMidiInputMusicGroup"
} }
context.JK.CategoryGroupIds = { context.JK.CategoryGroupIds = {
"AudioInputMusic" : "AudioInputMusic", "AudioInputMusic": "AudioInputMusic",
"AudioInputChat" : "AudioInputChat", "AudioInputChat": "AudioInputChat",
"UserMusic" : "UserMusic", "UserMusic": "UserMusic",
"UserChat" : "UserChat", "UserChat": "UserChat",
"UserMedia" : "UserMedia", "UserMedia": "UserMedia",
"MediaTrack" : "MediaTrack", "MediaTrack": "MediaTrack",
"Metronome" : "Metronome" "Metronome": "Metronome"
} }
})(window,jQuery); })(window, jQuery);

View File

@ -56,6 +56,28 @@
}); });
} }
// function createScheduledSessionPromise(options) {
// return new Promise((resolve, reject) => {
// $.ajax({
// type: "POST",
// dataType: "json",
// contentType: 'application/json',
// url: "/api/sessions",
// processData: false,
// data: JSON.stringify(options)
// })
// .done(resp => {
// console.log("Session created", resp);
// resolve(resp)
// })
// .fail(error => {
// console.log("Session create error", error);
// reject(error)
// })
// })
// }
function getBroadcastNotification(options) { function getBroadcastNotification(options) {
var userId = getId(options); var userId = getId(options);
return $.ajax({ return $.ajax({
@ -131,6 +153,29 @@
}); });
} }
function joinSessionPromise(options) {
console.log('joinSessionOpts', options);
var sessionId = options["session_id"];
delete options["session_id"];
return new Promise(function(resolve, reject){
$.ajax({
type: "POST",
dataType: "json",
contentType: 'application/json',
url: "/api/sessions/" + sessionId + "/participants",
data: JSON.stringify(options),
processData: false
})
.done(function(resp){
resolve(resp);
})
.fail(function(xhr){
reject(xhr)
})
})
}
function cancelSession(options) { function cancelSession(options) {
var sessionId = options["session_id"]; var sessionId = options["session_id"];
delete options["session_id"]; delete options["session_id"];
@ -220,6 +265,26 @@
}); });
} }
function getSessionHistoryPromise(id, includePending) {
var includeFlag = 'false';
if (includePending) {
includeFlag = 'true';
}
return new Promise(function(resolve, reject){
$.ajax({
type: "GET",
dataType: "json",
url: '/api/sessions/' + id + '/history?includePending=' + includeFlag,
contentType: 'application/json',
processData: false
}).done(function(resp){
resolve(resp)
}).fail(function(err){
reject(err)
})
})
}
function addSessionInfoComment(sessionId, comment) { function addSessionInfoComment(sessionId, comment) {
return $.ajax({ return $.ajax({
url: '/api/sessions/' + sessionId + "/details/comments", url: '/api/sessions/' + sessionId + "/details/comments",
@ -1113,17 +1178,24 @@
}) })
} }
function getUserSyncs(options) { async function getUserSyncs(options) {
if (!options) { if (!options) {
options = {}; options = {};
} }
var userId = getId(options) var userId = getId(options)
return $.ajax({
type: 'GET', try {
dataType: "json", return await $.ajax({
url: "/api/users/" + userId + "/syncs?" + $.param(options), type: 'GET',
processData: false dataType: "json",
}) url: "/api/users/" + userId + "/syncs?" + $.param(options),
processData: false
})
} catch (error) {
console.error(error);
throw(error)
}
} }
function getUserSync(options) { function getUserSync(options) {
@ -1302,6 +1374,23 @@
}) })
} }
function startRecordingPromise(options) {
return new Promise(function(resolve, reject){
$.ajax({
type: "POST",
dataType: "json",
contentType: 'application/json',
url: "/api/recordings/start",
data: JSON.stringify(options)
}).done(function(resp){
resolve(resp)
}).fail(function(jqXHR){
reject(jqXHR)
})
})
}
function stopRecording(options) { function stopRecording(options) {
var recordingId = options["id"] var recordingId = options["id"]
@ -1354,6 +1443,8 @@
function getRecording(options) { function getRecording(options) {
var recordingId = options["id"]; var recordingId = options["id"];
console.log("getRecording: ", options)
return $.ajax({ return $.ajax({
type: "GET", type: "GET",
dataType: "json", dataType: "json",
@ -1362,6 +1453,24 @@
}); });
} }
function getRecordingPromise(options) {
return new Promise(function(resolve, reject){
console.log("getRecordingPromise: ", options)
var recordingId = options["id"];
$.ajax({
type: "GET",
dataType: "json",
contentType: 'application/json',
url: "/api/recordings/" + recordingId
}).done(function(resp){
resolve(resp)
}).fail(function(jqXHR){
reject(jqXHR)
});
})
}
function getClaimedRecordings(options) { function getClaimedRecordings(options) {
return $.ajax({ return $.ajax({
type: "GET", type: "GET",
@ -1372,6 +1481,23 @@
}); });
} }
function getClaimedRecordingsPromise(options) {
return new Promise(function(resolve, reject){
$.ajax({
type: "GET",
dataType: "json",
contentType: 'application/json',
url: "/api/claimed_recordings",
data: options
}).done(function(data, textStatus, jqXHR){
resolve([data, textStatus, jqXHR]);
}).fail(function(jqXHR, textStatus, errorMessage){
reject([jqXHR, textStatus, errorMessage]);
});
});
}
function getClaimedRecording(id) { function getClaimedRecording(id) {
return $.ajax({ return $.ajax({
type: "GET", type: "GET",
@ -1404,11 +1530,11 @@
function deleteRecordingClaim(id) { function deleteRecordingClaim(id) {
return $.ajax({ return $.ajax({
type: "DELETE", type: "DELETE",
dataType: "json", dataType: "json",
contentType: 'application/json', contentType: 'application/json',
url: "/api/recordings/" + id + "/claim" url: "/api/recordings/" + id + "/claim"
}); });
} }
function claimRecording(options) { function claimRecording(options) {
@ -1429,13 +1555,22 @@
delete options["id"]; delete options["id"];
delete options["claimed_recording_id"]; delete options["claimed_recording_id"];
return $.ajax({ return new Promise(function(resolve, reject){
type: "POST", $.ajax({
dataType: "json", type: "POST",
contentType: 'application/json', dataType: "json",
url: "/api/sessions/" + musicSessionId + "/claimed_recording/" + claimedRecordingId + "/start", contentType: 'application/json',
data: JSON.stringify(options) url: "/api/sessions/" + musicSessionId + "/claimed_recording/" + claimedRecordingId + "/start",
data: JSON.stringify(options)
})
.done(function(resp){
resolve(resp);
}).fail(function(jqXHR){
reject(jqXHR)
})
}) })
} }
function stopPlayClaimedRecording(options) { function stopPlayClaimedRecording(options) {
@ -1456,13 +1591,20 @@
function openBackingTrack(options) { function openBackingTrack(options) {
var musicSessionId = options["id"]; var musicSessionId = options["id"];
delete options["id"]; delete options["id"];
return new Promise(function(resolve, reject){
return $.ajax({ $.ajax({
type: "POST", type: "POST",
dataType: "json", dataType: "json",
contentType: 'application/json', contentType: 'application/json',
url: "/api/sessions/" + musicSessionId + "/backing_tracks/open", url: "/api/sessions/" + musicSessionId + "/backing_tracks/open",
data: JSON.stringify(options) data: JSON.stringify(options)
})
.done(function(resp){
resolve(resp);
})
.fail(function(xhr){
reject(xhr)
})
}) })
} }
@ -1611,13 +1753,20 @@
function closeMetronome(options) { function closeMetronome(options) {
var musicSessionId = options["id"]; var musicSessionId = options["id"];
delete options["id"]; delete options["id"];
return new Promise((resolve, reject) => {
return $.ajax({ $.ajax({
type: "POST", type: "POST",
dataType: "json", dataType: "json",
contentType: 'application/json', contentType: 'application/json',
url: "/api/sessions/" + musicSessionId + "/metronome/close", url: "/api/sessions/" + musicSessionId + "/metronome/close",
data: JSON.stringify(options) data: JSON.stringify(options)
})
.done((resp) => {
resolve(resp)
})
.fail(jqXHR => {
reject(jqXHR);
})
}) })
} }
@ -2968,6 +3117,7 @@
this.quietBroadcastNotification = quietBroadcastNotification; this.quietBroadcastNotification = quietBroadcastNotification;
this.legacyJoinSession = legacyJoinSession; this.legacyJoinSession = legacyJoinSession;
this.joinSession = joinSession; this.joinSession = joinSession;
this.joinSessionPromise = joinSessionPromise;
this.cancelSession = cancelSession; this.cancelSession = cancelSession;
this.updateScheduledSession = updateScheduledSession; this.updateScheduledSession = updateScheduledSession;
this.getUserDetail = getUserDetail; this.getUserDetail = getUserDetail;
@ -3047,11 +3197,13 @@
this.updateJoinRequest = updateJoinRequest; this.updateJoinRequest = updateJoinRequest;
this.updateUser = updateUser; this.updateUser = updateUser;
this.startRecording = startRecording; this.startRecording = startRecording;
this.startRecordingPromise = startRecordingPromise;
this.stopRecording = stopRecording; this.stopRecording = stopRecording;
this.getRecording = getRecording; this.getRecording = getRecording;
this.getRecordedTrack = getRecordedTrack; this.getRecordedTrack = getRecordedTrack;
this.getRecordedBackingTrack = getRecordedBackingTrack; this.getRecordedBackingTrack = getRecordedBackingTrack;
this.getClaimedRecordings = getClaimedRecordings; this.getClaimedRecordings = getClaimedRecordings;
this.getClaimedRecordingsPromise = getClaimedRecordingsPromise;
this.getClaimedRecording = getClaimedRecording; this.getClaimedRecording = getClaimedRecording;
this.updateClaimedRecording = updateClaimedRecording; this.updateClaimedRecording = updateClaimedRecording;
this.deleteClaimedRecording = deleteClaimedRecording; this.deleteClaimedRecording = deleteClaimedRecording;
@ -3216,6 +3368,9 @@
this.listInvoices = listInvoices; this.listInvoices = listInvoices;
this.getVideoConferencingRoomUrl = getVideoConferencingRoomUrl; this.getVideoConferencingRoomUrl = getVideoConferencingRoomUrl;
this.getLatencyToUsers = getLatencyToUsers; this.getLatencyToUsers = getLatencyToUsers;
this.getSessionHistoryPromise = getSessionHistoryPromise;
this.getRecordingPromise = getRecordingPromise;
return this; return this;
}; };
})(window, jQuery); })(window, jQuery);

View File

@ -91,8 +91,8 @@
/** /**
* This occurs when a new download from a recording has become available * This occurs when a new download from a recording has become available
*/ */
function downloadAvailable() { async function downloadAvailable() {
context.jamClient.OnDownloadAvailable(); await context.jamClient.OnDownloadAvailable();
} }
/** /**
@ -352,6 +352,18 @@
return; return;
} }
//force user to new jamtrack page (beta site)
if(hash && hash == '#/jamtrack') {
var urlToOpen = gon.spa_origin + '/jamtracks';
if(gon.isNativeClient) {
context.JK.popExternalLink(urlToOpen);
}else{
context.location.href = urlToOpen;
}
hash = '#/home';
}
var url = '/client#/' + screen; var url = '/client#/' + screen;
if (hash) { if (hash) {
url = hash; url = hash;
@ -406,19 +418,18 @@
context.JK.JamServer.updateNotificationSeen(notificationId, notificationCreatedAt); context.JK.JamServer.updateNotificationSeen(notificationId, notificationCreatedAt);
} }
this.unloadFunction = function () { this.unloadFunction = async function () {
logger.debug("window.unload function called."); logger.debug("window.unload function called.");
context.JK.JamServer.close(false); context.JK.JamServer.close(false);
if (context.jamClient) { if (context.jamClient) {
// Unregister for callbacks. // Unregister for callbacks.
context.jamClient.RegisterRecordingCallbacks("", "", "", "", ""); await context.jamClient.RegisterRecordingCallbacks("", "", "", "", "");
context.jamClient.SessionRegisterCallback(""); await context.jamClient.SessionSetAlertCallback("");
context.jamClient.SessionSetAlertCallback(""); await context.jamClient.FTUERegisterVUCallbacks("", "", "");
context.jamClient.FTUERegisterVUCallbacks("", "", ""); await context.jamClient.FTUERegisterLatencyCallback("");
context.jamClient.FTUERegisterLatencyCallback(""); await context.jamClient.RegisterVolChangeCallBack("");
context.jamClient.RegisterVolChangeCallBack("");
} }
}; };
@ -475,6 +486,9 @@
this.clientId = null; this.clientId = null;
this.initialRouting = initialRouting; this.initialRouting = initialRouting;
//video server
this.videoIsOngoing = false;
$(document).triggerHandler('JAMKAZAM_CONSTRUCTED', {app:this}) $(document).triggerHandler('JAMKAZAM_CONSTRUCTED', {app:this})
return this; return this;
}; };

View File

@ -85,6 +85,7 @@
//= require ../web/affiliate_program //= require ../web/affiliate_program
//= require ../web/affiliate_links //= require ../web/affiliate_links
//= require fakeJamClient //= require fakeJamClient
//= require fakeJamClientProxy
//= require fakeJamClientMessages //= require fakeJamClientMessages
//= require fakeJamClientRecordings //= require fakeJamClientRecordings
//= require JamServer //= require JamServer

View File

@ -43,10 +43,10 @@
url: url, url: url,
data: JSON.stringify(data), data: JSON.stringify(data),
processData:false, processData:false,
success: function(response) { success: async function(response) {
context.JK.Sessions.JoinSession(session_id); context.JK.Sessions.JoinSession(session_id);
if (client !== undefined) { if (client !== undefined) {
client.JoinSession({ sessionID: session_id }); await client.JoinSession({ sessionID: session_id });
} }
context.JK.refreshMusicSession(session_id); context.JK.refreshMusicSession(session_id);
}, },

View File

@ -38,7 +38,7 @@
var value = options.mode; var value = options.mode;
setValue(options.mode, $parent) setValue(options.mode, $parent)
function onModeSelected() { async function onModeSelected() {
var $li = $(this); var $li = $(this);
var playbackMode = $li.attr('data-playback-option'); var playbackMode = $li.attr('data-playback-option');
@ -50,7 +50,7 @@
else { else {
// if no playback mode, then this must be an attempt to open metronome window // if no playback mode, then this must be an attempt to open metronome window
close(); close();
context.jamClient.SessionShowMetronomeGui(); await context.jamClient.SessionShowMetronomeGui();
} }
return false; return false;
}; };

View File

@ -482,6 +482,18 @@
var destination = $(evt.currentTarget).attr('layout-link'); var destination = $(evt.currentTarget).attr('layout-link');
var $destination = $('[layout-id="' + destination + '"]'); var $destination = $('[layout-id="' + destination + '"]');
//force user to the new site if they click on the jamtrack tile
if(destination === "jamtrack") {
var urlToOpen = gon.spa_origin + '/jamtracks';
if(gon.isNativeClient) {
context.JK.popExternalLink(urlToOpen);
return;
}else{
window.open(urlToOpen, '_blank');
return;
}
}
var destinationType = $destination.attr("layout"); var destinationType = $destination.attr("layout");
if (destinationType === "screen") { if (destinationType === "screen") {
if(!context.JK.currentUserId && !$destination.is('.no-login-required')) { if(!context.JK.currentUserId && !$destination.is('.no-login-required')) {

View File

@ -21,10 +21,10 @@
$.ajax({ $.ajax({
type: "DELETE", type: "DELETE",
url: url url: url
}).done(function (response) { }).done(async function (response) {
context.JK.Sessions.LeaveSession(session_id); context.JK.Sessions.LeaveSession(session_id);
if (client !== undefined) { if (client !== undefined) {
client.LeaveSession({ sessionID: session_id }); await client.LeaveSession({ sessionID: session_id });
} }
}); });
}; };

View File

@ -254,6 +254,7 @@ context.JK.MusicianSearchFilter = class MusicianSearchFilter extends BaseSearchF
super() super()
loadSearchFilter: (sFilter) => loadSearchFilter: (sFilter) =>
super(sFilter) super(sFilter)
@searchFilter = JSON.parse(sFilter) @searchFilter = JSON.parse(sFilter)

View File

@ -0,0 +1,117 @@
/**
* meta_tracking.js
* A standalone module to capture and persist Meta attribution signals (fbclid, _fbp) in cookies.
*
* Logic adapted for legacy environment (no React hooks).
* - Checks URL for `fbclid` and sets `_fbc` cookie.
* - Checks for `_fbp` cookie; if missing, generates and sets it.
*/
(function (window, document) {
'use strict';
var MetaTracking = {
init: function () {
var location = window.location;
this.handleFbc(location.search);
this.handleFbp();
this.handleUtm(location.search);
},
// 1. Parsing and storing _fbc (Click ID)
handleFbc: function (searchParams) {
var fbclid = this.getQueryParam('fbclid', searchParams);
if (fbclid) {
var version = 'fb';
var subdomainIndex = 1; // 1 = example.com
var creationTime = new Date().getTime(); // Unix timestamp in ms
// Format: fb.1.timestamp.id
var fbcValue = version + '.' + subdomainIndex + '.' + creationTime + '.' + fbclid;
this.setCookie('_fbc', fbcValue, 90);
}
},
handleUtm: function (searchParams) {
var self = this;
if (!searchParams) return;
// Logically, we want to capture all utm_ parameters.
// We can either iterate a list or dynamic regex.
// Given the requirement to be robust, let's look for "utm_"
var query = searchParams.substring(1); // remove '?'
var vars = query.split('&');
for (var i = 0; i < vars.length; i++) {
var pair = vars[i].split('=');
if (pair.length === 2) {
var key = decodeURIComponent(pair[0]);
var value = decodeURIComponent(pair[1]);
if (key.indexOf('utm_') === 0) {
self.setCookie(key, value, 90);
}
}
}
},
// 2. Handling _fbp (Browser ID)
handleFbp: function () {
if (!this.getCookie('_fbp')) {
var version = 'fb';
var subdomainIndex = 1;
var creationTime = new Date().getTime();
var randomInt = Math.floor(Math.random() * 10000000000); // 10-digit random number
// Format: fb.1.timestamp.randomDigits
var fbpValue = version + '.' + subdomainIndex + '.' + creationTime + '.' + randomInt;
this.setCookie('_fbp', fbpValue, 90);
}
},
// Helper: Get query param by name
getQueryParam: function (name, search) {
name = name.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]');
var regex = new RegExp('[\\?&]' + name + '=([^&#]*)');
var results = regex.exec(search);
return results === null ? '' : decodeURIComponent(results[1].replace(/\+/g, ' '));
},
// Helper: Set cookie
setCookie: function (name, value, days) {
var expires = "";
if (days) {
var date = new Date();
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
expires = "; expires=" + date.toUTCString();
}
// Ensure path is root and domain is included if needed (defaults to current host)
document.cookie = name + "=" + (value || "") + expires + "; path=/";
},
// Helper: Get cookie
getCookie: function (name) {
var nameEQ = name + "=";
var ca = document.cookie.split(';');
for (var i = 0; i < ca.length; i++) {
var c = ca[i];
while (c.charAt(0) == ' ') c = c.substring(1, c.length);
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length);
}
return null;
}
};
// Initialize on ready
if (document.readyState === 'complete' || document.readyState === 'interactive') {
MetaTracking.init();
} else {
// IE9+ support for DOMContentLoaded
document.addEventListener('DOMContentLoaded', function () {
MetaTracking.init();
});
}
})(window, document);

View File

@ -641,13 +641,13 @@
} }
if(!clientType) { if(!clientType) {
clientType = context.JK.clientType(); context.JK.clientType().then(resp => clientType = resp).catch(error => logger.error('Error fetching clientType', error));
} }
if(!mode) { if(!mode) {
mode = 'client' mode = 'client'
if (context.jamClient && context.jamClient.getOperatingMode) { //if (context.jamClient && context.jamClient.getOperatingMode) {
mode = context.jamClient.getOperatingMode() context.jamClient.getOperatingMode().then(resp => mode = resp).catch(error => logger.error('Error fetching operatingMode', error));
} //}
isLatencyTesterMode = mode == 'server'; isLatencyTesterMode = mode == 'server';
} }
@ -670,9 +670,11 @@
if (isClientMode()) { if (isClientMode()) {
var client_type = context.JK.clientType() var client_type;
context.JK.clientType().then(resp => client_type = resp).catch(error => logger.error('Error fetching clientType', error));
var client_id = (gon.global.env == "development" ? $.cookie('client_id') : null) var client_id = (gon.global.env == "development" ? $.cookie('client_id') : null)
var machine = context.jamClient.SessionGetMacHash() var machine;
context.jamClient.SessionGetMacHash().then(resp => machine = resp).catch(error => logger.error('Error fetching machine', error));
if (machine) { if (machine) {
machine = machine.all machine = machine.all
} }
@ -927,7 +929,7 @@
} }
// Callbacks from jamClient // Callbacks from jamClient
if (context.jamClient !== undefined && context.jamClient.IsNativeClient()) { if (context.JK.isQWebEngine) {
context.jamClient.SendP2PMessage.connect(server.sendP2PMessage); context.jamClient.SendP2PMessage.connect(server.sendP2PMessage);
if (context.jamClient.SendLogin) { if (context.jamClient.SendLogin) {

View File

@ -18,6 +18,7 @@
//= require modern/JamServer_copy //= require modern/JamServer_copy
//= require fakeJamClient //= require fakeJamClient
//= require fakeJamClientProxy
//= require fakeJamClientMessages //= require fakeJamClientMessages
//= require fakeJamClientRecordings //= require fakeJamClientRecordings

View File

@ -229,10 +229,10 @@
$testScoreVideo.removeClass('testing'); $testScoreVideo.removeClass('testing');
} }
function postDiagnostic() { async function postDiagnostic() {
rest.createDiagnostic({ rest.createDiagnostic({
type: 'NETWORK_TEST_RESULT', type: 'NETWORK_TEST_RESULT',
data: {client_type: context.JK.clientType(), client_id: context.JK.JamServer.clientID, summary: testSummary} data: {client_type: 'client', client_id: context.JK.JamServer.clientID, summary: testSummary}
}); });
} }
@ -249,8 +249,8 @@
return lastNetworkFailure; return lastNetworkFailure;
} }
function haltScoring() { async function haltScoring() {
context.jamClient.SetLatencyTestBlocked(true) await context.jamClient.SetLatencyTestBlocked(true)
rest.updateNetworkTesting({client_id: app.clientId, is_network_testing: true}) rest.updateNetworkTesting({client_id: app.clientId, is_network_testing: true})
.fail(function(jqXHR) { .fail(function(jqXHR) {
@ -264,8 +264,8 @@
}) })
} }
function resumeScoring() { async function resumeScoring() {
context.jamClient.SetLatencyTestBlocked(false) await context.jamClient.SetLatencyTestBlocked(false)
rest.updateNetworkTesting({client_id: app.clientId, is_network_testing: false}) rest.updateNetworkTesting({client_id: app.clientId, is_network_testing: false})
.fail(function(jqXHR) { .fail(function(jqXHR) {
if(jqXHR.status == 404) { if(jqXHR.status == 404) {
@ -284,7 +284,7 @@
} }
} }
function testFinishedAudio() { async function testFinishedAudio() {
var attempt = getCurrentAttemptAudio(); var attempt = getCurrentAttemptAudio();
if (!testSummary.final) { if (!testSummary.final) {
@ -302,13 +302,13 @@
} }
// context.jamClient.GetNetworkTestScore() == 0 is a rough approximation if the user has passed the FTUE before // context.jamClient.GetNetworkTestScore() == 0 is a rough approximation if the user has passed the FTUE before
if (inGearWizard || context.jamClient.GetNetworkTestScore() == 0) { if (inGearWizard || await context.jamClient.GetNetworkTestScore() == 0) {
trackedPass = true; trackedPass = true;
lastNetworkFailure = null; lastNetworkFailure = null;
context.JK.GA.trackNetworkTest(context.JK.detectOS(), testSummary.final.num_clients); context.JK.GA.trackNetworkTest(context.JK.detectOS(), testSummary.final.num_clients);
} }
context.jamClient.SetNetworkTestScore(attempt.num_clients); await context.jamClient.SetNetworkTestScore(attempt.num_clients);
if (testSummary.final.num_clients == 2) { if (testSummary.final.num_clients == 2) {
$testScoreAudio.addClass('acceptable'); $testScoreAudio.addClass('acceptable');
} }
@ -318,12 +318,12 @@
success = true; success = true;
} }
else if (reason == "minimum_client_threshold") { else if (reason == "minimum_client_threshold") {
context.jamClient.SetNetworkTestScore(0); await context.jamClient.SetNetworkTestScore(0);
renderStopTestAudio('', "We're sorry, but your router and Internet service will not effectively support JamKazam sessions. Please click the HELP button for more information.") renderStopTestAudio('', "We're sorry, but your router and Internet service will not effectively support JamKazam sessions. Please click the HELP button for more information.")
storeLastNetworkFailure(context.JK.GA.NetworkTestFailReasons.bandwidth, avgBandwidth(attempt.num_clients - 1)); storeLastNetworkFailure(context.JK.GA.NetworkTestFailReasons.bandwidth, avgBandwidth(attempt.num_clients - 1));
} }
else if (reason == "unreachable" || reason == "no-transmit") { else if (reason == "unreachable" || reason == "no-transmit") {
context.jamClient.SetNetworkTestScore(0); await context.jamClient.SetNetworkTestScore(0);
// https://jamkazam.atlassian.net/browse/VRFS-2323 // https://jamkazam.atlassian.net/browse/VRFS-2323
renderStopTestAudio('', "We're sorry, but your router will not support JamKazam in its current configuration. Please click <a rel='external' href='https://jamkazam.desk.com/customer/portal/articles/1716139-what-to-do-if-you-cannot-pass-the-network-test'>HERE</a> for more information."); renderStopTestAudio('', "We're sorry, but your router will not support JamKazam in its current configuration. Please click <a rel='external' href='https://jamkazam.desk.com/customer/portal/articles/1716139-what-to-do-if-you-cannot-pass-the-network-test'>HERE</a> for more information.");
storeLastNetworkFailure(context.JK.GA.NetworkTestFailReasons.stun, attempt.num_clients); storeLastNetworkFailure(context.JK.GA.NetworkTestFailReasons.stun, attempt.num_clients);
@ -415,7 +415,7 @@
} }
} }
function testFinishedVideo() { async function testFinishedVideo() {
var attempt = getCurrentAttemptVideo(); var attempt = getCurrentAttemptVideo();
@ -440,13 +440,13 @@
} }
// context.jamClient.GetNetworkTestScore() == 0 is a rough approximation if the user has passed the FTUE before // context.jamClient.GetNetworkTestScore() == 0 is a rough approximation if the user has passed the FTUE before
if (inGearWizard || context.jamClient.GetVideoNetworkTestScore() == 0) { if (inGearWizard || await context.jamClient.GetVideoNetworkTestScore() == 0) {
//trackedPass = true; //trackedPass = true;
//lastNetworkFailure = null; //lastNetworkFailure = null;
//context.JK.GA.trackNetworkTest(context.JK.detectOS(), testSummary.final.num_clients); //context.JK.GA.trackNetworkTest(context.JK.detectOS(), testSummary.final.num_clients);
} }
context.jamClient.SetVideoNetworkTestScore(attempt.num_clients); await context.jamClient.SetVideoNetworkTestScore(attempt.num_clients);
if (!testSummary.video_final.num_clients) { if (!testSummary.video_final.num_clients) {
$testScoreVideo.addClass('acceptable'); $testScoreVideo.addClass('acceptable');
} }
@ -459,12 +459,12 @@
success = true; success = true;
} }
else if (reason == "minimum_client_threshold") { else if (reason == "minimum_client_threshold") {
context.jamClient.SetVideoNetworkTestScore(testSummary.video_final.num_clients - 1); await context.jamClient.SetVideoNetworkTestScore(testSummary.video_final.num_clients - 1);
renderStopTestVideo(testSummary.video_final.num_clients - 1, reason) renderStopTestVideo(testSummary.video_final.num_clients - 1, reason)
//storeLastNetworkFailure(context.JK.GA.NetworkTestFailReasons.bandwidth, avgBandwidth(attempt.num_clients - 1)); //storeLastNetworkFailure(context.JK.GA.NetworkTestFailReasons.bandwidth, avgBandwidth(attempt.num_clients - 1));
} }
else if (reason == "unreachable" || reason == "no-transmit") { else if (reason == "unreachable" || reason == "no-transmit") {
context.jamClient.SetVideoNetworkTestScore(testSummary.video_final.num_clients - 1); await context.jamClient.SetVideoNetworkTestScore(testSummary.video_final.num_clients - 1);
// https://jamkazam.atlassian.net/browse/VRFS-2323 // https://jamkazam.atlassian.net/browse/VRFS-2323
renderStopTestVideo(testSummary.video_final.num_clients - 1, reason); renderStopTestVideo(testSummary.video_final.num_clients - 1, reason);
// storeLastNetworkFailure(context.JK.GA.NetworkTestFailReasons.stun, attempt.num_clients); // storeLastNetworkFailure(context.JK.GA.NetworkTestFailReasons.stun, attempt.num_clients);
@ -664,7 +664,7 @@
}, (gon.ftue_network_test_duration + 5) * 1000); }, (gon.ftue_network_test_duration + 5) * 1000);
} }
function attemptTestPassAudio() { async function attemptTestPassAudio() {
var attempt = {}; var attempt = {};
attempt.payload_size = AUDIO_PAYLOAD_SIZE; attempt.payload_size = AUDIO_PAYLOAD_SIZE;
@ -687,14 +687,14 @@
audioScoring = true; audioScoring = true;
logger.debug("network test attempt: " + numClientToTestAudio + "-person audio session, 400 packets/s, " + AUDIO_PAYLOAD_SIZE + " byte payload") logger.debug("network test attempt: " + numClientToTestAudio + "-person audio session, 400 packets/s, " + AUDIO_PAYLOAD_SIZE + " byte payload")
context.jamClient.TestNetworkPktBwRate(serverClientId, createSuccessCallbackName(false), createTimeoutCallbackName(false), await context.jamClient.TestNetworkPktBwRate(serverClientId, createSuccessCallbackName(false), createTimeoutCallbackName(false),
NETWORK_TEST_TYPES.PktTest400LowLatency, NETWORK_TEST_TYPES.PktTest400LowLatency,
gon.ftue_network_test_duration, gon.ftue_network_test_duration,
numClientToTestAudio - 1, numClientToTestAudio - 1,
AUDIO_PAYLOAD_SIZE, gon.global.ftue_network_test_backend_retries); AUDIO_PAYLOAD_SIZE, gon.global.ftue_network_test_backend_retries);
} }
function attemptTestPassVideo() { async function attemptTestPassVideo() {
var attempt = {}; var attempt = {};
attempt.payload_size = VIDEO_PAYLOAD_SIZE; attempt.payload_size = VIDEO_PAYLOAD_SIZE;
@ -715,7 +715,7 @@
setBackendGuard(); setBackendGuard();
logger.debug("network test attempt: " + numClientToTestVideo + "-person video session, 400 packets/s, " + VIDEO_PAYLOAD_SIZE + " byte payload") logger.debug("network test attempt: " + numClientToTestVideo + "-person video session, 400 packets/s, " + VIDEO_PAYLOAD_SIZE + " byte payload")
context.jamClient.TestNetworkPktBwRate(serverClientId, createSuccessCallbackName(false), createTimeoutCallbackName(false), await context.jamClient.TestNetworkPktBwRate(serverClientId, createSuccessCallbackName(false), createTimeoutCallbackName(false),
NETWORK_TEST_TYPES.PktTest400LowLatency, NETWORK_TEST_TYPES.PktTest400LowLatency,
gon.ftue_network_test_duration, gon.ftue_network_test_duration,
numClientToTestVideo - 1, numClientToTestVideo - 1,
@ -723,13 +723,13 @@
} }
// you have to score a little to 'prime' the logic to know whether it's on wireless or not // you have to score a little to 'prime' the logic to know whether it's on wireless or not
function primePump() { async function primePump() {
audioScoring = true; audioScoring = true;
primeDeferred = new $.Deferred(); primeDeferred = new $.Deferred();
setPrimeGuard(); setPrimeGuard();
context.jamClient.TestNetworkPktBwRate(serverClientId, createSuccessCallbackName(true), createTimeoutCallbackName(true), await context.jamClient.TestNetworkPktBwRate(serverClientId, createSuccessCallbackName(true), createTimeoutCallbackName(true),
NETWORK_TEST_TYPES.PktTest400LowLatency, NETWORK_TEST_TYPES.PktTest400LowLatency,
PRIME_PUMP_TIME, PRIME_PUMP_TIME,
2, 2,
@ -746,9 +746,9 @@
$self.triggerHandler(NETWORK_TEST_CANCEL) $self.triggerHandler(NETWORK_TEST_CANCEL)
} }
function postPumpRun() { async function postPumpRun() {
// check if on Wifi 1st // check if on Wifi 1st
var isWireless = context.jamClient.IsMyNetworkWireless(); var isWireless = await context.jamClient.IsMyNetworkWireless();
if (isWireless == -1) { if (isWireless == -1) {
logger.warn("unable to determine if the user is on wireless or not for network test. skipping prompt.") logger.warn("unable to determine if the user is on wireless or not for network test. skipping prompt.")
} }
@ -773,8 +773,8 @@
} }
} }
function pauseForRecentScoresTime() { async function pauseForRecentScoresTime() {
var lastScoreTimes = context.jamClient.GetLastLatencyTestTimes() var lastScoreTimes = await context.jamClient.GetLastLatencyTestTimes()
console.log(lastScoreTimes) console.log(lastScoreTimes)
@ -1271,7 +1271,7 @@
} }
} }
function initialize(_$step, _inGearWizard) { async function initialize(_$step, _inGearWizard) {
$step = _$step; $step = _$step;
inGearWizard = _inGearWizard; inGearWizard = _inGearWizard;
@ -1320,7 +1320,7 @@
}).show(); }).show();
} }
operatingSystem = context.JK.GetOSAsString(); operatingSystem = await context.JK.GetOSAsString();
initializeVideoWatchButton(); initializeVideoWatchButton();

View File

@ -253,7 +253,7 @@
currentNotificationPage++; currentNotificationPage++;
} }
function initializeActions(payload, type) { async function initializeActions(payload, type) {
var $notification = $('li[notification-id=' + payload.notification_id + ']'); var $notification = $('li[notification-id=' + payload.notification_id + ']');
var $btnNotificationAction = '#btn-notification-action'; var $btnNotificationAction = '#btn-notification-action';
@ -393,13 +393,13 @@
else if (type === context.JK.MessageType.RECORDING_MASTER_MIX_COMPLETE) { else if (type === context.JK.MessageType.RECORDING_MASTER_MIX_COMPLETE) {
$notification.find('#div-actions').hide(); $notification.find('#div-actions').hide();
logger.debug("context.jamClient.OnDownloadAvailable!") logger.debug("context.jamClient.OnDownloadAvailable!")
context.jamClient.OnDownloadAvailable(); // poke backend, letting it know a download is available await context.jamClient.OnDownloadAvailable(); // poke backend, letting it know a download is available
} }
else if (type === context.JK.MessageType.JAM_TRACK_SIGN_COMPLETE) { else if (type === context.JK.MessageType.JAM_TRACK_SIGN_COMPLETE) {
$notification.find('#div-actions').hide(); $notification.find('#div-actions').hide();
logger.debug("context.jamClient.OnDownloadAvailable!") logger.debug("context.jamClient.OnDownloadAvailable!")
context.jamClient.OnDownloadAvailable(); // poke backend, letting it know a download is available await context.jamClient.OnDownloadAvailable(); // poke backend, letting it know a download is available
} }
else if (type === context.JK.MessageType.BAND_INVITATION) { else if (type === context.JK.MessageType.BAND_INVITATION) {
@ -592,7 +592,7 @@
function registerJoinRequest() { function registerJoinRequest() {
context.JK.JamServer.registerMessageCallback(context.JK.MessageType.JOIN_REQUEST, function(header, payload) { context.JK.JamServer.registerMessageCallback(context.JK.MessageType.JOIN_REQUEST, async function(header, payload) {
logger.debug("Handling JOIN_REQUEST msg " + JSON.stringify(payload)); logger.debug("Handling JOIN_REQUEST msg " + JSON.stringify(payload));
handleNotification(payload, header.type); handleNotification(payload, header.type);

View File

@ -43,7 +43,7 @@
paginator.data('working', true); paginator.data('working', true);
onPageSelected(targetPage) onPageSelected(targetPage)
.done(function(data, textStatus, jqXHR) { .then(function(data, textStatus, jqXHR) {
totalEntries = data.total_entries || parseInt(jqXHR.getResponseHeader('total-entries')); totalEntries = data.total_entries || parseInt(jqXHR.getResponseHeader('total-entries'));
pages = calculatePages(totalEntries, perPage); pages = calculatePages(totalEntries, perPage);
options = { pages: pages, options = { pages: pages,
@ -54,8 +54,10 @@
registerEvents(newPaginator); registerEvents(newPaginator);
paginator.replaceWith(newPaginator); paginator.replaceWith(newPaginator);
paginator = newPaginator; paginator = newPaginator;
paginator.data('working', false);
}) })
.always(function() { .catch(function(err){
paginator.data('working', false); paginator.data('working', false);
}); });
} }

View File

@ -303,7 +303,7 @@
} }
} }
function monitorRecordingPlayback() { async function monitorRecordingPlayback() {
if (!monitoring) { if (!monitoring) {
return; return;
} }
@ -312,10 +312,10 @@
} }
else { else {
if (playbackMonitorMode == PLAYBACK_MONITOR_MODE.JAMTRACK) { if (playbackMonitorMode == PLAYBACK_MONITOR_MODE.JAMTRACK) {
var positionMs = context.jamClient.SessionCurrrentJamTrackPlayPosMs(); var positionMs = await context.jamClient.SessionCurrrentJamTrackPlayPosMs();
var duration = context.jamClient.SessionGetJamTracksPlayDurationMs(); var duration = await context.jamClient.SessionGetJamTracksPlayDurationMs();
var durationMs = duration.media_len; var durationMs = duration.media_len;
var isPlaying = context.jamClient.isSessionTrackPlaying(); var isPlaying = await context.jamClient.isSessionTrackPlaying();
} }
else if(playbackMonitorMode == PLAYBACK_MONITOR_MODE.BROWSER_MEDIA) { else if(playbackMonitorMode == PLAYBACK_MONITOR_MODE.BROWSER_MEDIA) {
var positionMs = BrowserMediaStore.onGetPlayPosition() || 0 var positionMs = BrowserMediaStore.onGetPlayPosition() || 0
@ -323,9 +323,9 @@
var isPlaying = BrowserMediaStore.playing; var isPlaying = BrowserMediaStore.playing;
} }
else { else {
var positionMs = context.jamClient.SessionCurrrentPlayPosMs(); var positionMs = await context.jamClient.SessionCurrrentPlayPosMs();
var durationMs = context.jamClient.SessionGetTracksPlayDurationMs(); var durationMs = await context.jamClient.SessionGetTracksPlayDurationMs();
var isPlaying = context.jamClient.isSessionTrackPlaying(); var isPlaying = await context.jamClient.isSessionTrackPlaying();
} }
executeMonitor(positionMs, durationMs, isPlaying) executeMonitor(positionMs, durationMs, isPlaying)

View File

@ -0,0 +1,430 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Copyright (C) 2014 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Milian Wolff <milian.wolff@kdab.com>
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtWebChannel module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** BSD License Usage
** Alternatively, you may use this file under the terms of the BSD license
** as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of The Qt Company Ltd nor the names of its
** contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
"use strict";
var QWebChannelMessageTypes = {
signal: 1,
propertyUpdate: 2,
init: 3,
idle: 4,
debug: 5,
invokeMethod: 6,
connectToSignal: 7,
disconnectFromSignal: 8,
setProperty: 9,
response: 10,
};
var QWebChannel = function(transport, initCallback)
{
if (typeof transport !== "object" || typeof transport.send !== "function") {
console.error("The QWebChannel expects a transport object with a send function and onmessage callback property." +
" Given is: transport: " + typeof(transport) + ", transport.send: " + typeof(transport.send));
return;
}
var channel = this;
this.transport = transport;
this.send = function(data)
{
if (typeof(data) !== "string") {
data = JSON.stringify(data);
}
channel.transport.send(data);
}
this.transport.onmessage = function(message)
{
var data = message.data;
if (typeof data === "string") {
data = JSON.parse(data);
}
switch (data.type) {
case QWebChannelMessageTypes.signal:
channel.handleSignal(data);
break;
case QWebChannelMessageTypes.response:
channel.handleResponse(data);
break;
case QWebChannelMessageTypes.propertyUpdate:
channel.handlePropertyUpdate(data);
break;
default:
console.error("invalid message received:", message.data);
break;
}
}
this.execCallbacks = {};
this.execId = 0;
this.exec = function(data, callback)
{
if (!callback) {
// if no callback is given, send directly
channel.send(data);
return;
}
if (channel.execId === Number.MAX_VALUE) {
// wrap
channel.execId = Number.MIN_VALUE;
}
if (data.hasOwnProperty("id")) {
console.error("Cannot exec message with property id: " + JSON.stringify(data));
return;
}
data.id = channel.execId++;
channel.execCallbacks[data.id] = callback;
channel.send(data);
};
this.objects = {};
this.handleSignal = function(message)
{
var object = channel.objects[message.object];
if (object) {
object.signalEmitted(message.signal, message.args);
} else {
console.warn("Unhandled signal: " + message.object + "::" + message.signal);
}
}
this.handleResponse = function(message)
{
if (!message.hasOwnProperty("id")) {
console.error("Invalid response message received: ", JSON.stringify(message));
return;
}
channel.execCallbacks[message.id](message.data);
delete channel.execCallbacks[message.id];
}
this.handlePropertyUpdate = function(message)
{
for (var i in message.data) {
var data = message.data[i];
var object = channel.objects[data.object];
if (object) {
object.propertyUpdate(data.signals, data.properties);
} else {
console.warn("Unhandled property update: " + data.object + "::" + data.signal);
}
}
channel.exec({type: QWebChannelMessageTypes.idle});
}
this.debug = function(message)
{
channel.send({type: QWebChannelMessageTypes.debug, data: message});
};
channel.exec({type: QWebChannelMessageTypes.init}, function(data) {
for (var objectName in data) {
var object = new QObject(objectName, data[objectName], channel);
}
// now unwrap properties, which might reference other registered objects
for (var objectName in channel.objects) {
channel.objects[objectName].unwrapProperties();
}
if (initCallback) {
initCallback(channel);
}
channel.exec({type: QWebChannelMessageTypes.idle});
});
};
function QObject(name, data, webChannel)
{
this.__id__ = name;
webChannel.objects[name] = this;
// List of callbacks that get invoked upon signal emission
this.__objectSignals__ = {};
// Cache of all properties, updated when a notify signal is emitted
this.__propertyCache__ = {};
var object = this;
// ----------------------------------------------------------------------
this.unwrapQObject = function(response)
{
if (response instanceof Array) {
// support list of objects
var ret = new Array(response.length);
for (var i = 0; i < response.length; ++i) {
ret[i] = object.unwrapQObject(response[i]);
}
return ret;
}
if (!response
|| !response["__QObject*__"]
|| response.id === undefined) {
return response;
}
var objectId = response.id;
if (webChannel.objects[objectId])
return webChannel.objects[objectId];
if (!response.data) {
console.error("Cannot unwrap unknown QObject " + objectId + " without data.");
return;
}
var qObject = new QObject( objectId, response.data, webChannel );
qObject.destroyed.connect(function() {
if (webChannel.objects[objectId] === qObject) {
delete webChannel.objects[objectId];
// reset the now deleted QObject to an empty {} object
// just assigning {} though would not have the desired effect, but the
// below also ensures all external references will see the empty map
// NOTE: this detour is necessary to workaround QTBUG-40021
var propertyNames = [];
for (var propertyName in qObject) {
propertyNames.push(propertyName);
}
for (var idx in propertyNames) {
delete qObject[propertyNames[idx]];
}
}
});
// here we are already initialized, and thus must directly unwrap the properties
qObject.unwrapProperties();
return qObject;
}
this.unwrapProperties = function()
{
for (var propertyIdx in object.__propertyCache__) {
object.__propertyCache__[propertyIdx] = object.unwrapQObject(object.__propertyCache__[propertyIdx]);
}
}
function addSignal(signalData, isPropertyNotifySignal)
{
var signalName = signalData[0];
var signalIndex = signalData[1];
object[signalName] = {
connect: function(callback) {
if (typeof(callback) !== "function") {
console.error("Bad callback given to connect to signal " + signalName);
return;
}
object.__objectSignals__[signalIndex] = object.__objectSignals__[signalIndex] || [];
object.__objectSignals__[signalIndex].push(callback);
if (!isPropertyNotifySignal && signalName !== "destroyed") {
// only required for "pure" signals, handled separately for properties in propertyUpdate
// also note that we always get notified about the destroyed signal
webChannel.exec({
type: QWebChannelMessageTypes.connectToSignal,
object: object.__id__,
signal: signalIndex
});
}
},
disconnect: function(callback) {
if (typeof(callback) !== "function") {
console.error("Bad callback given to disconnect from signal " + signalName);
return;
}
object.__objectSignals__[signalIndex] = object.__objectSignals__[signalIndex] || [];
var idx = object.__objectSignals__[signalIndex].indexOf(callback);
if (idx === -1) {
console.error("Cannot find connection of signal " + signalName + " to " + callback.name);
return;
}
object.__objectSignals__[signalIndex].splice(idx, 1);
if (!isPropertyNotifySignal && object.__objectSignals__[signalIndex].length === 0) {
// only required for "pure" signals, handled separately for properties in propertyUpdate
webChannel.exec({
type: QWebChannelMessageTypes.disconnectFromSignal,
object: object.__id__,
signal: signalIndex
});
}
}
};
}
/**
* Invokes all callbacks for the given signalname. Also works for property notify callbacks.
*/
function invokeSignalCallbacks(signalName, signalArgs)
{
var connections = object.__objectSignals__[signalName];
if (connections) {
connections.forEach(function(callback) {
callback.apply(callback, signalArgs);
});
}
}
this.propertyUpdate = function(signals, propertyMap)
{
// update property cache
for (var propertyIndex in propertyMap) {
var propertyValue = propertyMap[propertyIndex];
object.__propertyCache__[propertyIndex] = propertyValue;
}
for (var signalName in signals) {
// Invoke all callbacks, as signalEmitted() does not. This ensures the
// property cache is updated before the callbacks are invoked.
invokeSignalCallbacks(signalName, signals[signalName]);
}
}
this.signalEmitted = function(signalName, signalArgs)
{
invokeSignalCallbacks(signalName, signalArgs);
}
function addMethod(methodData)
{
var methodName = methodData[0];
var methodIdx = methodData[1];
object[methodName] = function() {
var args = [];
var callback;
for (var i = 0; i < arguments.length; ++i) {
if (typeof arguments[i] === "function")
callback = arguments[i];
else
args.push(arguments[i]);
}
webChannel.exec({
"type": QWebChannelMessageTypes.invokeMethod,
"object": object.__id__,
"method": methodIdx,
"args": args
}, function(response) {
if (response !== undefined) {
var result = object.unwrapQObject(response);
if (callback) {
(callback)(result);
}
}
});
};
}
function bindGetterSetter(propertyInfo)
{
var propertyIndex = propertyInfo[0];
var propertyName = propertyInfo[1];
var notifySignalData = propertyInfo[2];
// initialize property cache with current value
// NOTE: if this is an object, it is not directly unwrapped as it might
// reference other QObject that we do not know yet
object.__propertyCache__[propertyIndex] = propertyInfo[3];
if (notifySignalData) {
if (notifySignalData[0] === 1) {
// signal name is optimized away, reconstruct the actual name
notifySignalData[0] = propertyName + "Changed";
}
addSignal(notifySignalData, true);
}
Object.defineProperty(object, propertyName, {
configurable: true,
get: function () {
var propertyValue = object.__propertyCache__[propertyIndex];
if (propertyValue === undefined) {
// This shouldn't happen
console.warn("Undefined value in property cache for property \"" + propertyName + "\" in object " + object.__id__);
}
return propertyValue;
},
set: function(value) {
if (value === undefined) {
console.warn("Property setter for " + propertyName + " called with undefined value!");
return;
}
object.__propertyCache__[propertyIndex] = value;
webChannel.exec({
"type": QWebChannelMessageTypes.setProperty,
"object": object.__id__,
"property": propertyIndex,
"value": value
});
}
});
}
// ----------------------------------------------------------------------
data.methods.forEach(addMethod);
data.properties.forEach(bindGetterSetter);
data.signals.forEach(function(signal) { addSignal(signal, false); });
for (var name in data.enums) {
object[name] = data.enums[name];
}
}
//required for use with nodejs
if (typeof module === 'object') {
module.exports = {
QWebChannel: QWebChannel
};
}

View File

@ -32,7 +32,7 @@ profileUtils = context.JK.ProfileUtils
@root = $(@getDOMNode()) @root = $(@getDOMNode())
componentDidUpdate: () -> componentDidUpdate: () ->
datePicked = @datePicked.bind(this) datePicked = @datePicked
@sessionDate = @root.find('.date-picker') @sessionDate = @root.find('.date-picker')
@sessionDate.each(() -> @sessionDate.each(() ->
$this = $(this) $this = $(this)

View File

@ -537,7 +537,7 @@ profileUtils = context.JK.ProfileUtils
context.JK.popExternalLink("/client#/account/paymentHistory", true) context.JK.popExternalLink("/client#/account/paymentHistory", true)
paymentMethod: () -> paymentMethod: () ->
if context.jamClient.IsNativeClient() if context.JK.isQWebEngine
return `<div> return `<div>
<div classNames="column column-left"> <div classNames="column column-left">
<p>Updating payment is only supported in a web browser. Please click the button below to open this page in your system web browser.</p> <p>Updating payment is only supported in a web browser. Please click the button below to open this page in your system web browser.</p>

View File

@ -129,7 +129,7 @@ SessionStore = @SessionStore
activeChannel = @state.channel activeChannel = @state.channel
if activeChannel == 'global' if activeChannel == 'global'
openBig = `<a className="make-big" href="#" onClick={this.openChatDialog.bind(this)}>Expand</a>` openBig = `<a className="make-big" href="#" onClick={this.openChatDialog}>Expand</a>`
activeMsgs = @state.msgs[activeChannel] || [] activeMsgs = @state.msgs[activeChannel] || []

View File

@ -110,7 +110,7 @@ ConfigureTracksStore = @ConfigureTracksStore
</div> </div>
<div className="instrument-selection"> <div className="instrument-selection">
<h3>Instrument</h3> <h3>Instrument</h3>
<select className="instrument-pick" name="instrument" onChange={this.instrumentSelected} value={selectedInstrument} disabled={instrumentDisabled}> <select className="instrument-pick" name="instrument" onChange={this.audioInstrumentSelected} value={selectedInstrument} disabled={instrumentDisabled}>
{instruments} {instruments}
</select> </select>
</div> </div>
@ -187,8 +187,8 @@ ConfigureTracksStore = @ConfigureTracksStore
<a className="scan-midi" onClick={this.scanMidi}>scan for connected MIDI interfaces</a> <a className="scan-midi" onClick={this.scanMidi}>scan for connected MIDI interfaces</a>
</div> </div>
<div className="instrument-selection"> <div className="instrument-selection">
<h3>Instrument</h3> <h3>Instrument Display Name</h3>
<select className="instrument-pick" name="instrument" onChange={this.instrumentSelected} value={selectedInstrument} disabled={instrumentDisabled}> <select className="midi-instrument-pick" name="instrument" onChange={this.midiInstrumentSelected} value={selectedInstrument} disabled={instrumentDisabled}>
{instruments} {instruments}
</select> </select>
</div> </div>
@ -204,6 +204,15 @@ ConfigureTracksStore = @ConfigureTracksStore
{initialScan} {initialScan}
{scan} {scan}
</div> </div>
<div className="midi-selection-instructions">
<u>Instructions:</u>
<ol>
<li>Select your MIDI interface.</li>
<li>Select your MIDI instrument and set its settings as needed. The instrument is ready to play after you select it, and you can test it.</li>
<li>Select the Instrument you want displayed in the Session window.</li>
<li>Click Add Track, then Save Settings.</li>
</ol>
</div>
</div>` </div>`
render: () -> render: () ->
@ -286,13 +295,30 @@ ConfigureTracksStore = @ConfigureTracksStore
@setState({midiInterface: null}) @setState({midiInterface: null})
instrumentSelected: (e) -> audioInstrumentSelected: (e) ->
$root = $(@getDOMNode()) $root = $(@getDOMNode())
$select = $root.find('.instrument-pick') instrumentId = $root.find('.instrument-pick').val()
instrumentId = $select.val()
ConfigureTracksActions.associateInstrumentWithTrack(instrumentId) ConfigureTracksActions.associateInstrumentWithTrack(instrumentId)
midiInstrumentSelected: (e) ->
$root = $(@getDOMNode())
midiInstrumentId = $root.find('.midi-instrument-pick').val()
midiSelVal = $root.find('.midi-select').val()
vstsSelVal = $root.find('.vsts').val()
if midiSelVal == "" || vstsSelVal == "NONE"
context.JK.Banner.showAlert("MIDI interface and MIDI plugin must be selected.")
else
ConfigureTracksActions.associateInstrumentWithTrack(midiInstrumentId)
# instrumentSelected: `async function(e) {
# const $root = $(this.getDOMNode());
# const $select = $root.find('.instrument-pick');
# const instrumentId = $select.val();
# await ConfigureTracksActions.associateInstrumentWithTrack(instrumentId);
# }`
doClose: (e) -> doClose: (e) ->
e.preventDefault() e.preventDefault()
@ -342,20 +368,41 @@ ConfigureTracksStore = @ConfigureTracksStore
componentWillUpdate: () -> componentWillUpdate: () ->
$root = $(@getDOMNode()) $root = $(@getDOMNode())
componentDidUpdate: () -> # componentDidUpdate: () ->
$root = $(@getDOMNode()) # $root = $(@getDOMNode())
$manageAudioPlugins = $root.find('.manage-audio-plugins') # $manageAudioPlugins = $root.find('.manage-audio-plugins')
unless $manageAudioPlugins.data('initialized') # unless $manageAudioPlugins.data('initialized')
$manageAudioPlugins.manageVsts().on(context.JK.EVENTS.VST_OPERATION_SELECTED, @vstOperation).data('initialized', true) # $manageAudioPlugins.manageVsts().on(context.JK.EVENTS.VST_OPERATION_SELECTED, @vstOperation).data('initialized', true)
if true # easyDropdown support # if true # easyDropdown support
# context.JK.dropdown($root.find('select'))
# $root.find('select.input-selectors').unbind('change').change(@inputChanged)
# $root.find('select.instrument-pick').unbind('change').change(@instrumentSelected)
# $root.find('select.vsts').unbind('change').change(@vstsChanged)
componentDidUpdate: `function() {
const $root = $(this.getDOMNode());
const $manageAudioPlugins = $root.find('.manage-audio-plugins');
if (!$manageAudioPlugins.data('initialized')) {
$manageAudioPlugins.manageVsts().on(context.JK.EVENTS.VST_OPERATION_SELECTED, this.vstOperation).data('initialized', true);
}
if (true) { // easyDropdown support
context.JK.dropdown($root.find('select'));
$root.find('select.input-selectors').unbind('change').change(this.inputChanged);
$root.find('select.instrument-pick').unbind('change').change(this.audioInstrumentSelected);
$root.find('select.midi-instrument-pick').unbind('change').change(this.midiInstrumentSelected);
$root.find('select.vsts').unbind('change').change(this.vstsChanged);
$root.find('select.midi-select').unbind('change').change(this.midiInterfaceChanged);
}
}`
context.JK.dropdown($root.find('select'))
$root.find('select.input-selectors').unbind('change').change(@inputChanged)
$root.find('select.instrument-pick').unbind('change').change(@instrumentSelected)
$root.find('select.vsts').unbind('change').change(@vstsChanged)
trackTypeChanged: (event) -> trackTypeChanged: (event) ->
if @ignoreICheck if @ignoreICheck
@ -399,7 +446,6 @@ ConfigureTracksStore = @ConfigureTracksStore
midiInterfaceChanged: (e) -> midiInterfaceChanged: (e) ->
@updateMidiAssociations() @updateMidiAssociations()
updateMidiAssociations: (e) -> updateMidiAssociations: (e) ->
@ -411,10 +457,10 @@ ConfigureTracksStore = @ConfigureTracksStore
vstSelected = $select.val() vstSelected = $select.val()
logger.debug("updateMidiAssocations", vstSelected, midiInterface) logger.debug("updateMidiAssocations", vstSelected, midiInterface)
#if vstSelected != 'NONE' if vstSelected != 'NONE'
vstSelected = {file: vstSelected} vstSelected = {file: vstSelected}
#else else
# vstSelected = null vstSelected = null
if midiInterface == '' if midiInterface == ''
midiInterface = null midiInterface = null

View File

@ -46,7 +46,7 @@ ConfigureTracksStore = @ConfigureTracksStore
$output1 = $root.find('.output-1') $output1 = $root.find('.output-1')
$output2 = $root.find('.output-2') $output2 = $root.find('.output-2')
if @state.configureTracks? && @state.configureTracks.trackAssignments.outputs.assigned.length == 2 if @state.configureTracks? && @state.configureTracks.trackAssignments && @state.configureTracks.trackAssignments.outputs.assigned.length == 2
output1 = @state.configureTracks.trackAssignments.outputs.assigned[0].id output1 = @state.configureTracks.trackAssignments.outputs.assigned[0].id
output2 = @state.configureTracks.trackAssignments.outputs.assigned[1].id output2 = @state.configureTracks.trackAssignments.outputs.assigned[1].id

Some files were not shown because too many files have changed in this diff Show More