diff --git a/css/main.css b/css/main.css index c415a4f..c5e4d6f 100644 --- a/css/main.css +++ b/css/main.css @@ -75,6 +75,14 @@ dl.row dd { animation: glow 1.5s ease-in-out infinite !important; } +.accordion-item:has(.accordion-collapse.show) i.fas.test-icon-lights { + animation: glow 1.2s ease-in-out infinite !important; +} + +.accordion-item:has(.accordion-collapse.show) i.fas.test-icon-headphone { + animation: pulse 1s ease-in-out infinite !important; +} + /* Skip button hover behavior */ .skip-btn { opacity: 0; diff --git a/js/controller-manager.js b/js/controller-manager.js index 810f684..2082601 100644 --- a/js/controller-manager.js +++ b/js/controller-manager.js @@ -382,14 +382,15 @@ class ControllerManager { * Test speaker tone (DS5 only) * @param {number} duration - Duration in milliseconds (optional) * @param {Function} doneCb - Callback function called when tone ends (optional) + * @param {string} output - Audio output destination: "speaker" (default) or "headphones" (optional) */ - async setSpeakerTone(duration = 1000, doneCb = ({success}) => {}) { + async setSpeakerTone(duration = 1000, doneCb = ({success}) => {}, output = "speaker") { try { if (!this.currentController.setSpeakerTone) { throw new Error(this.l("Speaker tone not supported on this controller")); } - await this.currentController.setSpeakerTone(); + await this.currentController.setSpeakerTone(output); // If duration is specified, automatically reset speaker after the duration if (duration > 0) { diff --git a/js/controllers/ds5-controller.js b/js/controllers/ds5-controller.js index eb8b1c8..1ff2bfd 100644 --- a/js/controllers/ds5-controller.js +++ b/js/controllers/ds5-controller.js @@ -685,25 +685,33 @@ class DS5Controller extends BaseController { /** * Test speaker tone by controlling speaker volume and audio settings - * This creates a brief audio feedback through the controller's speaker + * This creates a brief audio feedback through the controller's speaker or headphones + * @param {string} output - Audio output destination: "speaker" (default) or "headphones" */ - async setSpeakerTone() { + async setSpeakerTone(output = "speaker") { try { const { validFlag0 } = this.currentOutputState; const outputStruct = new DS5OutputStruct({ ...this.currentOutputState, speakerVolume: 85, - validFlag0: validFlag0 | DS5_VALID_FLAG0.SPEAKER_VOLUME | DS5_VALID_FLAG0.AUDIO_CONTROL, + headphoneVolume: 55, + validFlag0: validFlag0 | DS5_VALID_FLAG0.HEADPHONE_VOLUME | DS5_VALID_FLAG0.SPEAKER_VOLUME | DS5_VALID_FLAG0.AUDIO_CONTROL, }); - await this.sendOutputReport(outputStruct.pack(), 'play speaker tone'); - outputStruct.validFlag0 &= ~(DS5_VALID_FLAG0.SPEAKER_VOLUME | DS5_VALID_FLAG0.AUDIO_CONTROL); + await this.sendOutputReport(outputStruct.pack(), output === "headphones" ? 'play headphone tone' : 'play speaker tone'); + outputStruct.validFlag0 &= ~(DS5_VALID_FLAG0.HEADPHONE_VOLUME | DS5_VALID_FLAG0.SPEAKER_VOLUME | DS5_VALID_FLAG0.AUDIO_CONTROL); - // Send feature reports to enable speaker audio - // Audio configuration command - await this.sendFeatureReport(128, [6, 4, 0, 0, 8]); - - // Enable speaker tone - await this.sendFeatureReport(128, [6, 2, 1, 1, 0]); + // Send feature reports to enable audio + if (output === "headphones") { + // Audio configuration command for headphones + await this.sendFeatureReport(128, [6, 4, 0, 0, 0, 0, 4, 0, 6]); + // Enable headphone tone + await this.sendFeatureReport(128, [6, 2, 1, 1, 0]); + } else { + // Audio configuration command for speakers + await this.sendFeatureReport(128, [6, 4, 0, 0, 8]); + // Enable speaker tone + await this.sendFeatureReport(128, [6, 2, 1, 1, 0]); + } // Update current state to reflect the changes this.updateCurrentOutputState(outputStruct); diff --git a/js/modals/quick-test-modal.js b/js/modals/quick-test-modal.js index 5f9d963..4f636f3 100644 --- a/js/modals/quick-test-modal.js +++ b/js/modals/quick-test-modal.js @@ -1,16 +1,6 @@ 'use strict'; -const ACCORDION_ELEMENTS = [ - 'usb-test-collapse', - 'buttons-test-collapse', - 'haptic-test-collapse', - 'adaptive-test-collapse', - 'lights-test-collapse', - 'speaker-test-collapse', - 'microphone-test-collapse' -]; - -const TEST_SEQUENCE = ['usb', 'buttons', 'haptic', 'adaptive', 'lights', 'speaker', 'microphone']; +const TEST_SEQUENCE = ['usb', 'buttons', 'haptic', 'adaptive', 'lights', 'speaker', 'headphone', 'microphone']; const TEST_NAMES = { 'usb': 'USB Connector', 'buttons': 'Buttons', @@ -18,7 +8,8 @@ const TEST_NAMES = { 'adaptive': 'Adaptive Trigger', 'lights': 'Lights', 'speaker': 'Speaker', - 'microphone': 'Microphone' + 'headphone': 'Headphone Jack', + 'microphone': 'Microphone', }; const BUTTONS = ['triangle', 'cross', 'circle', 'square', 'l1', 'r1', 'l2', 'r2', 'l3', 'r3', 'up', 'down', 'left', 'right', 'create', 'touchpad', 'options', 'ps', 'mute']; @@ -76,6 +67,7 @@ export class QuickTestModal { lights: null, speaker: null, microphone: null, + headphone: null, microphoneStream: null, microphoneContext: null, microphoneMonitoring: false, @@ -158,7 +150,8 @@ export class QuickTestModal { 'adaptive': 'fas fa-hand-pointer', 'lights': 'fas fa-lightbulb', 'speaker': 'fas fa-volume-up', - 'microphone': 'fas fa-microphone' + 'microphone': 'fas fa-microphone', + 'headphone': 'fas fa-headphones' }; const testContent = this._getTestContent(testType); @@ -308,6 +301,26 @@ export class QuickTestModal { `; + case 'headphone': + return ` +
This test checks the headphone jack functionality.
+Instructions:
+