Skip to content

Commit

Permalink
Merge pull request #126 from digitaldrummerj/feature/multi-state-feed…
Browse files Browse the repository at this point in the history
…back

Update on Multi-State Feedback to Make It Play Nicer with the Original Feedback
  • Loading branch information
JeffreyDavidsz authored Jul 2, 2023
2 parents 18cefa8 + c23b294 commit f3a4697
Show file tree
Hide file tree
Showing 7 changed files with 438 additions and 473 deletions.
16 changes: 7 additions & 9 deletions companion/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@
{
"name": "JeffreyDavidsz",
"email": "[email protected]"
},
{
"name": "Justin James",
"email": "[email protected]"
}
],
"legacyIds": [],
Expand All @@ -21,12 +25,6 @@
"entrypoint": "../dist/index.js"
},
"manufacturer": "Zoom",
"products": [
"OSC/ISO"
],
"keywords": [
"zoom",
"ZoomOSC",
"ZoomISO"
]
}
"products": ["OSC/ISO"],
"keywords": ["zoom", "ZoomOSC", "ZoomISO"]
}
10 changes: 6 additions & 4 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,16 +91,18 @@ export const GetConfigFields = (): SomeCompanionConfigField[] => {
label: 'Number of selectable groups',
min: 1,
max: 100,
default: 2,
default: 3,
width: 6,
},
{
type: 'dropdown',
id: 'feedbackImagesWithIcons',
label: 'Participant Feedback With Icons',
label: 'Participant Multi-State Feedback Design',
choices: [
{ id: 0, label: 'Without Icons' },
{ id: 1, label: 'With Icons' },
{ id: 0, label: 'Bottom (On and Off For Mic/Camera, Only on for Hand Raise)' },
{ id: 2, label: 'Bottom (Only Active States)' },
{ id: 3, label: 'Bottom (On and Off States)' },
{ id: 4, label: 'Disable' },
],
default: 1,
width: 6,
Expand Down
302 changes: 182 additions & 120 deletions src/feedback-state-machine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,150 +3,212 @@ import { ZoomConfig } from './config'
import { InstanceBaseExt, userExist } from './utils'
const { images } = require('./images') // eslint-disable-line

type State = [boolean, boolean, boolean, boolean, boolean]
interface StateMachine {
states: State[]
imagesWithIcons: Record<string, string>
imagesWithoutIcons: Record<string, string>
type FeedbackMultiState = [boolean, boolean, boolean, boolean]
interface FeedbackMultiStateMachine {
states: FeedbackMultiState[]
atBottomOnOffForCameraMicActiveSpeakerAndOnlyOnForHandRaised: Record<string, string>
atBottomOnOffForCameraMicActiveSpeakerAndOnlyOnForHandRaised58Height: Record<string, string>
atBottom: Record<string, string>
atBottom58Height: Record<string, string>
atBottomAll: Record<string, string>
atBottom58HeightAll: Record<string, string>
}

const stateMachine: StateMachine = {
const stateMachine: FeedbackMultiStateMachine = {
states: [
[false, false, false, false, false],
[false, false, false, false, true],
[false, false, false, true, false],
[false, false, false, true, true],
[false, false, true, false, false],
[false, false, true, false, true],
[false, false, true, true, false],
[false, false, true, true, true],
[false, true, false, false, false],
[false, true, false, false, true],
[false, true, false, true, false],
[false, true, false, true, true],
[false, true, true, false, false],
[false, true, true, false, true],
[false, true, true, true, false],
[false, true, true, true, true],
[true, false, false, false, false],
[true, false, false, false, true],
[true, false, false, true, false],
[true, false, false, true, true],
[true, false, true, false, false],
[true, false, true, false, true],
[true, false, true, true, false],
[true, false, true, true, true],
[true, true, false, false, false],
[true, true, false, false, true],
[true, true, false, true, false],
[true, true, false, true, true],
[true, true, true, false, false],
[true, true, true, false, true],
[true, true, true, true, false],
[true, true, true, true, true],
[false, false, false, false],
[false, false, false, false],
[false, false, false, true],
[false, false, false, true],
[false, false, true, false],
[false, false, true, false],
[false, false, true, true],
[false, false, true, true],
[false, true, false, false],
[false, true, false, false],
[false, true, false, true],
[false, true, false, true],
[false, true, true, false],
[false, true, true, false],
[false, true, true, true],
[false, true, true, true],
[true, false, false, false],
[true, false, false, false],
[true, false, false, true],
[true, false, false, true],
[true, false, true, false],
[true, false, true, false],
[true, false, true, true],
[true, false, true, true],
[true, true, false, false],
[true, true, false, false],
[true, true, false, true],
[true, true, false, true],
[true, true, true, false],
[true, true, true, false],
[true, true, true, true],
[true, true, true, true],
],
imagesWithIcons: {
'false,false,false,false,false': images.LG1,
'false,false,false,false,true': images.LG2,
'false,false,false,true,false': images.LG3,
'false,false,false,true,true': images.LG4,
'false,false,true,false,false': images.LG5,
'false,false,true,false,true': images.LG6,
'false,false,true,true,false': images.LG7,
'false,false,true,true,true': images.LG8,
'false,true,false,false,false': images.LG9,
'false,true,false,false,true': images.LG10,
'false,true,false,true,false': images.LG11,
'false,true,false,true,true': images.LG12,
'false,true,true,false,false': images.LG13,
'false,true,true,false,true': images.LG14,
'false,true,true,true,false': images.LG15,
'false,true,true,true,true': images.LG16,
'true,false,false,false,false': images.LG17,
'true,false,false,false,true': images.LG18,
'true,false,false,true,false': images.LG19,
'true,false,false,true,true': images.LG20,
'true,false,true,false,false': images.LG21,
'true,false,true,false,true': images.LG22,
'true,false,true,true,false': images.LG23,
'true,false,true,true,true': images.LG24,
'true,true,false,false,false': images.LG25,
'true,true,false,false,true': images.LG26,
'true,true,false,true,false': images.LG27,
'true,true,false,true,true': images.LG28,
'true,true,true,false,false': images.LG29,
'true,true,true,false,true': images.LG30,
'true,true,true,true,false': images.LG31,
'true,true,true,true,true': images.LG32,
atBottomOnOffForCameraMicActiveSpeakerAndOnlyOnForHandRaised: {
'false,false,false,false': images.BottomHRAllMicOn,
'false,false,false,true': images.BottomHRAllMicOnActiveSpeaker,
'false,false,true,false': images.BottomHRAllMicOnHandRaised,
'false,false,true,true': images.BottomHRAllMicOnHandRaisedActiveSpeaker,
'false,true,false,false': images.BottomHRAllMicOnCameraOn,
'false,true,false,true': images.BottomHRAllMicOnCameraOnActiveSpeaker,
'false,true,true,false': images.BottomHRAllMicOnCameraOnHandRaised,
'false,true,true,true': images.BottomHRAllAllOn,
'true,false,false,false': images.BottomHRAllAllOff,
'true,false,false,true': images.BottomHRAllActiveSpeaker,
'true,false,true,false': images.BottomHRAllHandRaised,
'true,false,true,true': images.BottomHRAllHandRaisedActiveSpeaker,
'true,true,false,false': images.BottomHRAllCameraOn,
'true,true,false,true': images.BottomHRAllCameraOnActiveSpeaker,
'true,true,true,false': images.BottomHRAllCameraOnHandRaised,
'true,true,true,true': images.BottomHRAllCameraOnHandRaisedActiveSpeaker,
},
imagesWithoutIcons: {
'false,false,false,false,false': images.NOICONLG1,
'false,false,false,false,true': images.NOICONLG2,
'false,false,false,true,false': images.NOICONLG3,
'false,false,false,true,true': images.NOICONLG4,
'false,false,true,false,false': images.NOICONLG5,
'false,false,true,false,true': images.NOICONLG6,
'false,false,true,true,false': images.NOICONLG7,
'false,false,true,true,true': images.NOICONLG8,
'false,true,false,false,false': images.NOICONLG9,
'false,true,false,false,true': images.NOICONLG10,
'false,true,false,true,false': images.NOICONLG11,
'false,true,false,true,true': images.NOICONLG12,
'false,true,true,false,false': images.NOICONLG13,
'false,true,true,false,true': images.NOICONLG14,
'false,true,true,true,false': images.NOICONLG15,
'false,true,true,true,true': images.NOICONLG16,
'true,false,false,false,false': images.NOICONLG17,
'true,false,false,false,true': images.NOICONLG18,
'true,false,false,true,false': images.NOICONLG19,
'true,false,false,true,true': images.NOICONLG20,
'true,false,true,false,false': images.NOICONLG21,
'true,false,true,false,true': images.NOICONLG22,
'true,false,true,true,false': images.NOICONLG23,
'true,false,true,true,true': images.NOICONLG24,
'true,true,false,false,false': images.NOICONLG25,
'true,true,false,false,true': images.NOICONLG26,
'true,true,false,true,false': images.NOICONLG27,
'true,true,false,true,true': images.NOICONLG28,
'true,true,true,false,false': images.NOICONLG29,
'true,true,true,false,true': images.NOICONLG30,
'true,true,true,true,false': images.NOICONLG31,
'true,true,true,true,true': images.NOICONLG32,
atBottomOnOffForCameraMicActiveSpeakerAndOnlyOnForHandRaised58Height: {
'false,false,false,false': images.BottomHR58AllMicOn,
'false,false,false,true': images.BottomHR58AllMicOnActiveSpeaker,
'false,false,true,false': images.BottomHR58AllMicOnHandRaised,
'false,false,true,true': images.BottomHR58AllMicOnHandRaisedActiveSpeaker,
'false,true,false,false': images.BottomHR58AllMicOnCameraOn,
'false,true,false,true': images.BottomHR58AllMicOnCameraOnActiveSpeaker,
'false,true,true,false': images.BottomHR58AllMicOnCameraOnHandRaised,
'false,true,true,true': images.BottomHR58AllAllOn,
'true,false,false,false': images.BottomHR58AllAllOff,
'true,false,false,true': images.BottomHR58AllActiveSpeaker,
'true,false,true,false': images.BottomHR58AllHandRaised,
'true,false,true,true': images.BottomHR58AllHandRaisedActiveSpeaker,
'true,true,false,false': images.BottomHR58AllCameraOn,
'true,true,false,true': images.BottomHR58AllCameraOnActiveSpeaker,
'true,true,true,false': images.BottomHR58AllCameraOnHandRaised,
'true,true,true,true': images.BottomHR58AllCameraOnHandRaisedActiveSpeaker,
},
atBottom: {
'false,false,false,false': images.BottomMicOn,
'false,false,false,true': images.BottomMicOnActiveSpeaker,
'false,false,true,false': images.BottomMicOnHandRaised,
'false,false,true,true': images.BottomMicOnHandRaisedActiveSpeaker,
'false,true,false,false': images.BottomMicOnCameraOn,
'false,true,false,true': images.BottomMicOnCameraOnActiveSpeaker,
'false,true,true,false': images.BottomMicOnCameraOnHandRaised,
'false,true,true,true': images.BottomAllOn,
'true,false,false,false': images.BottomAllOff,
'true,false,false,true': images.BottomActiveSpeaker,
'true,false,true,false': images.BottomHandRaised,
'true,false,true,true': images.BottomHandRaisedActiveSpeaker,
'true,true,false,false': images.BottomCameraOn,
'true,true,false,true': images.BottomCameraOnActiveSpeaker,
'true,true,true,false': images.BottomCameraOnHandRaised,
'true,true,true,true': images.BottomCameraOnHandRaisedActiveSpeaker,
},
atBottom58Height: {
'false,false,false,false': images.Bottom58MicOn,
'false,false,false,true': images.Bottom58MicOnActiveSpeaker,
'false,false,true,false': images.Bottom58MicOnHandRaised,
'false,false,true,true': images.Bottom58MicOnHandRaisedActiveSpeaker,
'false,true,false,false': images.Bottom58MicOnCameraOn,
'false,true,false,true': images.Bottom58MicOnCameraOnActiveSpeaker,
'false,true,true,false': images.Bottom58MicOnCameraOnHandRaised,
'false,true,true,true': images.Bottom58AllOn,
'true,false,false,false': images.Bottom58AllOff,
'true,false,false,true': images.Bottom58ActiveSpeaker,
'true,false,true,false': images.Bottom58HandRaised,
'true,false,true,true': images.Bottom58HandRaisedActiveSpeaker,
'true,true,false,false': images.Bottom58CameraOn,
'true,true,false,true': images.Bottom58CameraOnActiveSpeaker,
'true,true,true,false': images.Bottom58CameraOnHandRaised,
'true,true,true,true': images.Bottom58CameraOnHandRaisedActiveSpeaker,
},
atBottomAll: {
'false,false,false,false': images.BottomAllMicOn,
'false,false,false,true': images.BottomAllMicOnActiveSpeaker,
'false,false,true,false': images.BottomAllMicOnHandRaised,
'false,false,true,true': images.BottomAllMicOnHandRaisedActiveSpeaker,
'false,true,false,false': images.BottomAllMicOnCameraOn,
'false,true,false,true': images.BottomAllMicOnCameraOnActiveSpeaker,
'false,true,true,false': images.BottomAllMicOnCameraOnHandRaised,
'false,true,true,true': images.BottomAllAllOn,
'true,false,false,false': images.BottomAllAllOff,
'true,false,false,true': images.BottomAllActiveSpeaker,
'true,false,true,false': images.BottomAllHandRaised,
'true,false,true,true': images.BottomAllHandRaisedActiveSpeaker,
'true,true,false,false': images.BottomAllCameraOn,
'true,true,false,true': images.BottomAllCameraOnActiveSpeaker,
'true,true,true,false': images.BottomAllCameraOnHandRaised,
'true,true,true,true': images.BottomAllCameraOnHandRaisedActiveSpeaker,
},
atBottom58HeightAll: {
'false,false,false,false': images.Bottom58AllMicOn,
'false,false,false,true': images.Bottom58AllMicOnActiveSpeaker,
'false,false,true,false': images.Bottom58AllMicOnHandRaised,
'false,false,true,true': images.Bottom58AllMicOnHandRaisedActiveSpeaker,
'false,true,false,false': images.Bottom58AllMicOnCameraOn,
'false,true,false,true': images.Bottom58AllMicOnCameraOnActiveSpeaker,
'false,true,true,false': images.Bottom58AllMicOnCameraOnHandRaised,
'false,true,true,true': images.Bottom58AllAllOn,
'true,false,false,false': images.Bottom58AllAllOff,
'true,false,false,true': images.Bottom58AllActiveSpeaker,
'true,false,true,false': images.Bottom58AllHandRaised,
'true,false,true,true': images.Bottom58AllHandRaisedActiveSpeaker,
'true,true,false,false': images.Bottom58AllCameraOn,
'true,true,false,true': images.Bottom58AllCameraOnActiveSpeaker,
'true,true,true,false': images.Bottom58AllCameraOnHandRaised,
'true,true,true,true': images.Bottom58AllCameraOnHandRaisedActiveSpeaker,
},
}

function getImageForState(state: State, feedbackWithIcons: number): string {
function getImageForState(state: FeedbackMultiState, feedbackImageType: number, imageSize: number): string {
const stateString = state.toString()
if (feedbackWithIcons === 1) {
return stateMachine.imagesWithIcons[stateString]
switch (feedbackImageType) {
case 0:
if (imageSize === 58) {
return stateMachine.atBottomOnOffForCameraMicActiveSpeakerAndOnlyOnForHandRaised58Height[stateString]
}
return stateMachine.atBottomOnOffForCameraMicActiveSpeakerAndOnlyOnForHandRaised[stateString]
case 2:
if (imageSize === 58) {
return stateMachine.atBottom58Height[stateString]
}
return stateMachine.atBottom[stateString]
case 3:
default:
if (imageSize === 58) {
return stateMachine.atBottom58HeightAll[stateString]
}
return stateMachine.atBottomAll[stateString]
}

return stateMachine.imagesWithoutIcons[stateString]
}

function getParticipantState(instance: InstanceBaseExt<ZoomConfig>, zoomID: number): State {
function getParticipantState(instance: InstanceBaseExt<ZoomConfig>, zoomID: number): FeedbackMultiState {
return [
instance.ZoomUserData[zoomID].mute || false,
instance.ZoomUserData[zoomID].videoOn || false,
instance.ZoomUserData[zoomID].handRaised || false,
instance.ZoomClientDataObj.activeSpeaker === instance.ZoomUserData[zoomID].userName || false,
instance.ZoomClientDataObj.selectedCallers.find((element: number) => element === zoomID) !== undefined || false,
instance.ZoomUserData[zoomID].mute || false, // false = muted, true = unmuted
instance.ZoomUserData[zoomID].videoOn || false, // false = camera off, true = camera on
instance.ZoomUserData[zoomID].handRaised || false, // false = hand lowered, true = hand raised
instance.ZoomUserData[zoomID].userName !== undefined &&
(instance.ZoomUserData[zoomID].mute || false) === false &&
instance.ZoomClientDataObj.activeSpeaker === instance.ZoomUserData[zoomID].userName, // ensure that user is unmuted for active speaker
]
}

export function feedbackResultsAdvanced(
export function feedbackResultsMultiState(
instance: InstanceBaseExt<ZoomConfig>,
zoomID: number
zoomID: number,
imageSize: number
): CompanionAdvancedFeedbackResult {
if (instance.config.feedbackImagesWithIcons !== undefined && instance.config.feedbackImagesWithIcons === 4) {
return {}
}

if (userExist(zoomID, instance.ZoomUserData)) {
const participantState = getParticipantState(instance, zoomID)
const stateIndex = stateMachine.states.findIndex((state) => state.toString() === participantState.toString())

const image = getImageForState(
stateMachine.states[stateIndex],
instance.config.feedbackImagesWithIcons !== undefined ? instance.config.feedbackImagesWithIcons : 1
instance.config.feedbackImagesWithIcons !== undefined ? instance.config.feedbackImagesWithIcons : 3,
imageSize
)

return {
png64: image,
}
Expand Down
Loading

0 comments on commit f3a4697

Please sign in to comment.