===============
== bacardi55 ==
===============
ἕν οἶδα ὅτι οὐδὲν οἶδα

Using a Stream Deck Mini for online meetings and more with StreamController

- Permalink

Introduction

Someone I know was (almost) giving away an Elgato Stream Deck Mini. I’m saying almost because they sold it to me for 10€ because they bought a more advance model and didn’t need this one anymore. As I like (a bit too much) this kind of nerd gadgets (even though I’m usually good not to buy them), I decided to give it a try.

What was the intended usage you may ask? Well mainly for using it for remote calls. I (unfortunately) do many of them each day, working 100% remotely and talking to many internal and external people, so I thought that would be the primary use. I don’t stream or video edit a lot so nothing on that front.

I was a bit skeptical at first, thinking that it would mostly accumulate dust on desk like a few other things. But I was very wrong! I’m actually using it a lot for every calls and sometimes for other things too. So I thought I would describe here my use cases for such a device.

StreamController

First, I needed to find how to configure that thing. I quickly found this post about using streamdeck-linux-gui to manage the device. As I didn’t find the package on archlinux AUR, I looked around and found it was a fork of streamdeck-linux-ui. Looking more at the fork README on github, I understood that this package was also in maintenance mode only as the dev team was now focusing on contributing to another tool called StreamController made by Core447. And of course the great archlinux community already had my back as an AUR package was already available.

Great, all I needed was a simple yay -S streamcontroller and a few minutes later I could open the app to start configuring my StreamDeck Mini.

You can watch this video that shows StreamController in action.

One thing important to note is that for some features to work (eg: send a command), adding a udev rule is necessary. To do that, I created a new rule at /etc/udev/rules.d/55-streamcontroller.rules with the following content:

KERNEL=="uinput", SUBSYSTEM=="misc", OPTIONS+="static_node=uinput", TAG+="uaccess", GROUP="input", MODE="0660"

One last thing before going to the details. The way the StreamController app works is by defining different pages. On each pages, I see the 6 buttons of my Stream Deck. Each button can have one or more actions associated to them. One of the possible action is the ability to go to another page, listing other possible actions. It means that even with 6 buttons, you can manage a lot of possible actions.

You can even configure a page to automatically load if an app matching some criteria is open. For example, I have a “zoom” (well more like remote calls in general) screen that is open automatically when a Zoom or a Microsoft Teams (via Firefox) window is open. Pretty neat!

You can also configure the visual of the button a lot and make it really your own. Including a logo, some text (top middle and bottom), font and image sizes or background colors for each buttons. You can also have a “wallpaper” for each pages (which I don’t use).

Anyway, big thanks to Core447 and the contributors for a great tool. It has been working well so far even though it is still in beta. A few issues are still there (read bellow), but nothing major.

Ok, let’s look at my current setup.

Main Screen

My main screen is simple:

Figure 1: Image showing my main screen on the streamdeck mini

Figure 1: Image showing my main screen on the streamdeck mini

The buttons are:

  • A simple display of the current temperature in my city (will probably change at some point, that was just to test a built-in plugin)
  • A sound icon which will open the sound related page
  • A zoom icon which will open the Zoom / Calls related page
  • A counter (just to try the plugin, i don’t really use it and it waits for a better use case)
  • A power button that will open the power related page
  • A streamcontroller icon which will open the StreamController app.

The action used to change screen uses the “Deck” plugin and the “change screen” action.

As you can see, the main screen is mainly about accessing dedicated screens or open the StreamController app. Two are waiting to be put to better use.

Sound Screen

Figure 2: Image showing my sound screen on the streamdeck mini

Figure 2: Image showing my sound screen on the streamdeck mini

This screen doesn’t need a lot of explaination, but in a nutshell:

  • First button brings me back to the main screen
  • 2nd and 3rd button will decrease and increase sound by of 5% - uses the “Audio Control” plugin
  • 4th button will toggle mute / unmute microphone - uses the “Audio Control” plugin to mute, set volume and change states (see below)
  • 5th button will toggle mute / unmute audio - uses the same as the mic toggle.

The 4th button (mic mute/unmute toggle) is a bit special as it has 2 states. States can be configured per button and that is very handy to show different icons depending on status of the button / system. In this case, this button has 2 state:

The default state is the mic being unmuted with a default sound level of 40:

Figure 3: Image showing the mic button default state (not muted)

Figure 3: Image showing the mic button default state (not muted)

The second state is the mic being muted:

Figure 4: Image showing the mic button second state (muted)

Figure 4: Image showing the mic button second state (muted)

So pressing the button will switch between these 2 states.

Same thing for the 5th button that show 2 states:

The normal state (not muted):

Figure 5: Image showing the sound button default state (not muted)

Figure 5: Image showing the sound button default state (not muted)

The muted state:

Figure 6: Image showing the mic button second state (muted)

Figure 6: Image showing the mic button second state (muted)

Zoom / Calls Screen

Now this was my primary use case, so what did I do with that? Well it simple:

Figure 7: Image showing my zoom / calls screen on the streamdeck mini

Figure 7: Image showing my zoom / calls screen on the streamdeck mini

The buttons are:

  • Back: Go back to main screen
  • Zoom mute: toggle mute on zoom - use the “OS” plugin to run a custom script (see below)
  • Go to “sound”: Move to the sound related page (see above)
  • Zoom quit: Close zoom conversation - use the “OS” plugin to run a custom script (see below)
  • Microphone toggle: toggle the microphone between muted and unmuted (with a specific sound level). This is the same as the one described in the “Sound Screen”
  • Microsoft teams mute: toggle mute on MS team - use the “OS” plugin to run a custom script (see below)

One interesting feature of the StreamController app is the possibility to automatically open a screen when a specific app is opened. In my case, I simply open this specific screen if a zoom meeting window is detected. To do so, configure the zoom screen as follow:

  • Stay on page checked
  • Title regex: “meeting”
  • WM class regex: “zoom”

As shown in the screenshot:

Figure 8: Image showing my zoom screen configuratin for automatically opening the screen

Figure 8: Image showing my zoom screen configuratin for automatically opening the screen

Let’s look at some of the specificities for the zoom and teams toggle buttons that run custom scripts.

Muting zoom

To mute zoom, either you need to click on the mute button in the UI, or use the alt+a shortcut when the zoom window is active. No way of doing it via command line or shortcut when the window is not the active one… Well, there is still a way, by writing a script that will:

  • Find the zoom window
  • Make that window active
  • Use the “alt+a” shortcut
  • Go back to the previously active window

To do so, and with the help of this awesome shell script, I wrote the following:

#!/bin/bash

DEFAULT_SHORTCUT='alt+a'
SHORTCUT=${1:-$DEFAULT_SHORTCUT}

zoom=$(xdotool search --name "Meeting")
cur_active=$(xdotool getactivewindow)
cur_focus=$(xdotool getwindowfocus)

mouselocation=$(xdotool getmouselocation)
mouseX=$(echo "$mouselocation" | cut -d' ' -f1 | cut -d':' -f2)
mouseY=$(echo "$mouselocation" | cut -d' ' -f2 | cut -d':' -f2)
mouseScreen=$(echo "$mouselocation" | cut -d' ' -f3 | cut -d':' -f2)

xdotool windowfocus "$zoom"
xdotool windowactivate "$zoom"
# without this sleep zoom doesn't get the key press.
sleep 0.3
xdotool key --clearmodifiers "$SHORTCUT"

xdotool windowactivate "$cur_active"
xdotool windowfocus "$cur_focus"
xdotool mousemove --screen "$mouseScreen" "$mouseX" "$mouseY"

Then I made it executable (with chmod +x) and then use StreamController to launch it when clicking on the button.

Drawbacks:

  • The zoom window must be on a workspace displayed (in i3wm at least). Meaning it has to be on one of the 3 workspaces (as I have 3 screens). Not a big problem because I always have it available if needed so not big changes on my side.
  • The script doesn’t work when sharing a screen because I was unable to find the sharing mode window. In those case, I simply use the mic toggle button if needed.

Quitting zoom

Quitting zoom is more or less the same as the mute toggle, just firing a different script (or mostly a different shortcut, alt+q in this case):

#!/bin/bash

DEFAULT_SHORTCUT='alt+q'
SHORTCUT=${1:-$DEFAULT_SHORTCUT}

zoom=$(xdotool search --name "Meeting")
cur_active=$(xdotool getactivewindow)
cur_focus=$(xdotool getwindowfocus)

mouselocation=$(xdotool getmouselocation)
mouseX=$(echo "$mouselocation" | cut -d' ' -f1 | cut -d':' -f2)
mouseY=$(echo "$mouselocation" | cut -d' ' -f2 | cut -d':' -f2)
mouseScreen=$(echo "$mouselocation" | cut -d' ' -f3 | cut -d':' -f2)

xdotool windowfocus "$zoom"
xdotool windowactivate "$zoom"
# without this sleep zoom doesn't get the key press.
sleep 0.3
xdotool key --clearmodifiers "$SHORTCUT"

xdotool windowactivate "$cur_active"
xdotool windowfocus "$cur_focus"
xdotool mousemove --screen "$mouseScreen" "$mouseX" "$mouseY"

Muting Microsoft Teams

For Teams, I don’t use the app, just the web page. It means that the browser tab used for teams must be the active one (i just put it in its own window and leave it in a visible workspace, same as the zoom app). Script is more or less the same, just firing a different shortcut (ctrl+shift+m)

#!/bin/bash

DEFAULT_SHORTCUT='Ctrl+Shift+m'
SHORTCUT=${1:-$DEFAULT_SHORTCUT}

zoom=$(xdotool search --name "Microsoft Teams")
cur_active=$(xdotool getactivewindow)
cur_focus=$(xdotool getwindowfocus)

mouselocation=$(xdotool getmouselocation)
mouseX=$(echo "$mouselocation" | cut -d' ' -f1 | cut -d':' -f2)
mouseY=$(echo "$mouselocation" | cut -d' ' -f2 | cut -d':' -f2)
mouseScreen=$(echo "$mouselocation" | cut -d' ' -f3 | cut -d':' -f2)

xdotool windowfocus "$zoom"
xdotool windowactivate "$zoom"
# without this sleep zoom doesn't get the key press.
sleep 0.3
xdotool key --clearmodifiers "$SHORTCUT"

xdotool windowactivate "$cur_active"
xdotool windowfocus "$cur_focus"
xdotool mousemove --screen "$mouseScreen" "$mouseX" "$mouseY"

I could have done a quit script too, either by using the ctrl+shift+q teams shortcut or just using ctrl+w to quit the window, but I didn’t have a space available anymore :P.

Power Screen

Figure 9: Image showing my sound screen on the streamdeck mini

Figure 9: Image showing my sound screen on the streamdeck mini

In summary:

  • 1st button brings back to main screen as usual
  • 2nd button will suspend the laptop - use the “OS” plugin to run systemctl suspend-then-hibernate
  • 3rd button will lock the screen - use the “OS” plugin to run the same script as my i3wm shortcut (blur-lock, read more here)
  • 4th button will hibernate - use the “OS” plugin to run systemctl hibernate
  • 5th button will toggle the Stream Deck sleep mode (all button are black as shown below) - Use the “Deck” plugin to enable sleep mode
  • 6th button will switch off the laptop - use the “OS” plugin to run

Just to show (nothing), the deck in sleep mode looks like this:

Figure 10: Image showing the Stream Deck in sleep mode, all buttons are black

Figure 10: Image showing the Stream Deck in sleep mode, all buttons are black

Nothing fancy to see here :D.

Bugs

I did find one bug so far that I still haven’t reported: when changing pages, if the button pressed to change screen has a command start using the “OS” plugin (like starting a shell script), the action starts without needing to press it again, so it can’t be at the same place as the button used to go this page. Eg: if I use the “put to hibernation” script on the same button that the power button on the main script, clicking on it on the main script will change the screen but also fire the scripts… Not cool. That’s why the deck sleep mode is at this very specific stage.

If the bug is still there in the next release I’ll report it. So far, this workaround is enough :).

Remaining todos / ideas

I’m still toying around with it from time to time, but the main goals have been achieved. I’m still thinking about other usage, but so far I haven’t done anything around those

  • Window / I3wm management: It is easy to manipulate i3wm via scripts, so maybe there are some ideas behind that to play with, but I haven’t found good ones yet.
  • Screenshots: I use a variety of shortcuts to take screenshots (all screens, active window or manually selected area - described here), so I’m thinking to maybe copy them to the Stream Deck for simplicity
  • Home automation: Since moving out in the south of France, I’ve stopped using any type of home automation, but I’m sure that the day I’ll play with again, the Stream Deck will definitely be handy!

Conclusion

Playing with the Stream Deck was more fun than expected, and I must admit that I use it extensively during my too many remote calls. Even when I call familly via the signal desktop app, the microphone mute toggle can always be very useful :).

I’m sure I’ll find other ways of using it in the future, but the 10€ are already been a good investment from my point of view!


Contact

If you find any issue or have any question about this article, feel free to reach out to me via webmentions, email, mastodon, matrix or even IRC, see the About page for details.