私はどのようにLinuxのハードウェアミュートボタンを作成しました
20547 ワード
私は、パンデミックのために3月中旬から家で働いています.(私はこれを可能にする雇い主を持つのに十分な特権を与えられており、誰にでもできるだけリーンにスイッチを入れました)私は始めに苦労しました、しかし、突然、私が持っていたすべての会議は、ビデオ通話でした.初めに、私のカメラはLinuxでさえ動作しませんでした(私は以前にそれを使わなかったので、私は気にかけませんでした).私は以来ずっと家で私のセットアップを改善しました、そして、私は現在私の人生をこれまでに少しより便利にするために、より多くの仕掛けと道具を導入している点にいます.
このポストでは、私のセットアップへの最新の追加を説明します.
なぜですか。
PulseAudio(マイクを制御する)
bash ( pulseaudioコマンドの実行)
(デバイスドライバを書く)
システム(サービスとしてそれを可能にして、アップスタートまたは類似しているかもしれないトリックもする) Linuxを実行している場合は、すでにインストールされています.
ハードウェアの入手
このポストでは、私のセットアップへの最新の追加を説明します.
なぜですか。
いくつかの理由!まず第一に、それが楽しいから.話す前にボタンを押すと、このゲームショーを感じさせる.建物とテストも楽しい、私はティッカーと物事を作るのが大好きです.さらに:利便性.を目指して、目的と画面上のミュートボタンを押すだけではなく、単にハードウェアボタンを押すと、より便利な感じです.
いくつかの前提条件
私は次のことをインストールします.
私は次のことをインストールします.
PulseAudio(マイクを制御する)
bash ( pulseaudioコマンドの実行)
(デバイスドライバを書く)
システム(サービスとしてそれを可能にして、アップスタートまたは類似しているかもしれないトリックもする)
ハードウェアの入手
ハードウェアのミュートボタンでは、ハードウェアが必要です.数年前、私は夢の頬でいくつかの「大きな赤いボタン」を注文しました
( Amazon . comからのイメージ)
(私はちょっと技術的な……)しかし、明らかに会社は存在しません.そして、それは少し彼らを命じます.しかし、使用されるものを見つけることができます.そして、それがUSBであるので、基本的にどんなボタンもします.ちょうどそれが確認可能であり、USBコネクタを持っていることを確認します.“ビッグレッドボタンUSB”のインターネットを検索し、オプションの無数を見つけることができます.
準備ができたので、私は進んだ.
CLIでマイクを切り替える
私はpulseaudioで非常に味わっていませんでした.私がこのコマンドをコピーして、mictoggle.sh
と呼ばれるファイルにそれを置くところからの非常にLinuxの味わった友人pointed me to a post on AskUbuntu
#!/bin/bash
pacmd list-sources | \
grep -oP 'index: \d+' | \
awk '{ print $2 }' | \
xargs -I{} pactl set-source-mute {} toggle
すべてのオーディオソースをリストアップし、インデックスを抽出し、pactl
をコマンドset-source-mute
で呼び出して実行すると、これはマイクのミュート/ミュート状態を切り替えます.今、私はUSBボタンにそれをフックする必要がありました.
デバイスドライバの書き込み
JavaScriptで書くことができるすべては最終的にJavaScriptで書かれるので、なぜ、そのボタンのためにデバイス・ドライバーをノードを使用して書くか?
私はlibrary that more or less did what I wantedを見つけました、しかし、それが後ろで州の機械を使用したので、若干の欠点がありました(1つのプレスだけは認められました、そして、私はそれを閉じて、次のプレスを認めるために、ボタンのカバーを開けなければなりませんでした)、ボタンが切り離されたとき、衝突して、スクリプトが走っている間、新しく接続されるとき、ボタンを認識しませんでした.それで、私はこれから若干のインスピレーションとUSBインターフェース取扱いを描きました.
まず、usbというパッケージをインストールしました.
npm i usb
今、私は正しいインターフェイスに接続するためにボタンのvendoridとproductidを把握する必要がありました.通常、既存のLIBSとチュートリアルを通じて十分な掘削を使用すると、あなたの製品のためにそれらを見つけることができますが、接続時にUSBダンプはまた、必要な情報をもたらすことができます.夢の生意気なボタンのために、それらは0x1d34
(ベンダー)と0x000d
(製品)です.
最初に、これらの2つのIDでボタンをフェッチする関数を書きました.
const usb = require('usb')
const getButton = (idVendor, idProduct) => {
return usb.findByIds(idVendor, idProduct)
}
次に、ボタンのインターフェイスを取得し、必要に応じてカーネルドライバから切り離してこのプロセスを要求します.これはgetInterface
という関数で行います.
const getInterface = button => {
button.open()
const buttonInterface = button.interface(0)
if (button.interfaces.length !== 1 || buttonInterface.endpoints.length !== 1) {
// Maybe try to figure out which interface we care about?
throw new Error('Expected a single USB interface, but found: ' + buttonInterface.endpoints.length)
}
if (buttonInterface.isKernelDriverActive()) {
buttonInterface.detachKernelDriver()
}
buttonInterface.claim()
return buttonInterface
}
正しく状態を取得するには、いくつかのマジックナンバーが必要でした.
const bmRequestType = 0x21
const bRequest = 0x9
const wValue = 0x0200
const wIndex = 0x0
const transferBytes = 8
それらのマジックナンバーはparameters for the underlying libusb_control_transfer callです.十分に便利だったので、以前に述べたライブラリには、USBダンプを使って既に考え出したものがありました.
私は今、これらの関数を使ってボタンで何が起こっているかを聞くことができました.
const poll = button => {
const buttonInterface = getInterface(button)
const stateDict = {
21: 'close',
22: 'press',
23: 'open',
}
const endpointAddress = buttonInterface.endpoints[0].address
const endpoint = buttonInterface.endpoint(endpointAddress)
endpoint.timeout = 300
return new Promise((resolve, reject) => {
const buffer = new Buffer([0, 0, 0, 0, 0, 0, 0, 2])
button.controlTransfer(bmRequestType, bRequest, wValue, wIndex, buffer, (error, data) => {
if (error) {
reject(error)
}
endpoint.transfer(transferBytes, (error, data) )> {
if (error) {
reject(error)
}
resolve(stateDict[data[0]])
})
})
})
}
私はこのコードを使用して、まったく動作しているかどうかをテストします.
setInterval(() => {
const button = getButton(idVendor, idProduct)
if (!button) {
return
}
poll(button).then(state => {
console.log(state)
}).catch(() => {})
}, 15)
それで、15 msごとに、ボタンは、それからこのようにstdoutに印刷されるその状態を求められます(短縮版).
node ./bigRedButton.js
close
close
close
open
open
open
press
press
press
press
open
open
open
# ...
そして、問題があります:ボタンが押される限り、「プレス」状態は活発です.今、私はライブラリがステートマシンを使用している理由を理解しました:ボタンが押されるのではなく、ボタンが押されると、コールバックは実行されるべきです.これは私が働くことができました.私もコードをいくつかのコールバックを取る関数に詰め込みました.
const listenToButton = (openCallback, pressCallback, closeCallback) => {
var isPressed = false
setInterval(() => {
const button = getButton(idVendor, idProduct)
if (!button) {
return
}
poll(button).then(state => {
if (isPressed && state !== 'press') {
// Not pressing anymore
isPressed = false
}
if (!isPressed && state === 'press') {
isPressed = true
// Executes the callback at the beginning of a button press
pressCallback()
}
if (state === 'open') {
openCallback()
}
if (state === 'close') {
closeCallback()
}
}).catch(() => {})
}, 15)
}
module.exports = listenToButton
今、私は、マイクトグルスクリプトと一緒に使用するには、インポート可能なlibを持っていた.以来、それはボタンを請求するたびに、任意のエラーを飲み込む、ボタンを切断し、再接続すると、魅力のように動作します.
今、私は一緒に作品を接着する必要がありました
const bigRedButton = require('./bigRedButton')
const { exec } = require('child_process')
const openCallback = () => {}
const pushCallback = () => {
exec('XDG_RUNTIME_DIR=/run/user/1000 ./mictoggle.sh')
}
const closeCallback = () => {}
bigRedButton(openCallback, pushCallback, closeCallback)
( XDG_RUNTIME_DIR
ENV変数はone of two kinds of data echanges USB can do (the other being a a functional data exchange)に必要です.テスト中、これを考え出すまでは動作しませんでした)
このスクリプトを実行すると、ハードウェアのミュートボタンに大きな赤いボタンを回す!
非対話的シェルでPulseAudioコマンドを実行する
サービスにする
起動時にミュートボタンを作成するには、このコンテンツで/lib/systemd/system
の下にサービスファイルを作成しました.
[Unit]
Description=Hardware mute button
After=multi-user.target
[Service]
Type=simple
User=USER
ExecStart=/home/USER/.nvm/versions/node/v14.15.0/bin/node /home/USER/projects/mutebutton/index.js
Restart=on-failure
[Install]
WantedBy=multi-user.target
(単にExecStart
経路を調整し、ユーザ名でUSER
に置き換えます).
それから、私はサービス(sudo systemctl start mutebutton
)を始めました.そして、何度かボタンをためしました.そして、喜びでくすくすしました.そして、スタートアップ(sudo systemctl enable mutebutton
)の上でサービスを可能にしました.
テイクアウト思考
私はこの小さい側プロジェクトの前にUSBとLibusbについてあまり知りませんでした、しかし、私はその過程でたくさん学びました.このことは、“インターネットを検索”と“ちょうどそれが働くまで物事をしようとする”いくつかの偉大な教師のために作ることを証明した.
私はこのボタンをインストールして以来、私は今実際に多くのビデオ通話を楽しみにしているボタンを押すと、ビデオの呼び出しは、もっと楽しくなった.ゲームのショーと同じように!
この記事を読んで楽しんでください!もしそうならば❤️ または🦄! 私はフリータイムでハイテク記事を書き、毎回コーヒーを飲みたいです.
私の努力をサポートする場合は、
またはを考慮してください!
buying me a coffee ☕
Reference
この問題について(私はどのようにLinuxのハードウェアミュートボタンを作成しました), 我々は、より多くの情報をここで見つけました
https://dev.to/thormeier/game-show-feeling-how-i-created-a-hardware-mute-button-for-linux-2fk6
テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol
私はpulseaudioで非常に味わっていませんでした.私がこのコマンドをコピーして、
mictoggle.sh
と呼ばれるファイルにそれを置くところからの非常にLinuxの味わった友人pointed me to a post on AskUbuntu#!/bin/bash
pacmd list-sources | \
grep -oP 'index: \d+' | \
awk '{ print $2 }' | \
xargs -I{} pactl set-source-mute {} toggle
すべてのオーディオソースをリストアップし、インデックスを抽出し、pactl
をコマンドset-source-mute
で呼び出して実行すると、これはマイクのミュート/ミュート状態を切り替えます.今、私はUSBボタンにそれをフックする必要がありました.デバイスドライバの書き込み
JavaScriptで書くことができるすべては最終的にJavaScriptで書かれるので、なぜ、そのボタンのためにデバイス・ドライバーをノードを使用して書くか?
私はlibrary that more or less did what I wantedを見つけました、しかし、それが後ろで州の機械を使用したので、若干の欠点がありました(1つのプレスだけは認められました、そして、私はそれを閉じて、次のプレスを認めるために、ボタンのカバーを開けなければなりませんでした)、ボタンが切り離されたとき、衝突して、スクリプトが走っている間、新しく接続されるとき、ボタンを認識しませんでした.それで、私はこれから若干のインスピレーションとUSBインターフェース取扱いを描きました.
まず、usbというパッケージをインストールしました.
npm i usb
今、私は正しいインターフェイスに接続するためにボタンのvendoridとproductidを把握する必要がありました.通常、既存のLIBSとチュートリアルを通じて十分な掘削を使用すると、あなたの製品のためにそれらを見つけることができますが、接続時にUSBダンプはまた、必要な情報をもたらすことができます.夢の生意気なボタンのために、それらは0x1d34
(ベンダー)と0x000d
(製品)です.
最初に、これらの2つのIDでボタンをフェッチする関数を書きました.
const usb = require('usb')
const getButton = (idVendor, idProduct) => {
return usb.findByIds(idVendor, idProduct)
}
次に、ボタンのインターフェイスを取得し、必要に応じてカーネルドライバから切り離してこのプロセスを要求します.これはgetInterface
という関数で行います.
const getInterface = button => {
button.open()
const buttonInterface = button.interface(0)
if (button.interfaces.length !== 1 || buttonInterface.endpoints.length !== 1) {
// Maybe try to figure out which interface we care about?
throw new Error('Expected a single USB interface, but found: ' + buttonInterface.endpoints.length)
}
if (buttonInterface.isKernelDriverActive()) {
buttonInterface.detachKernelDriver()
}
buttonInterface.claim()
return buttonInterface
}
正しく状態を取得するには、いくつかのマジックナンバーが必要でした.
const bmRequestType = 0x21
const bRequest = 0x9
const wValue = 0x0200
const wIndex = 0x0
const transferBytes = 8
それらのマジックナンバーはparameters for the underlying libusb_control_transfer callです.十分に便利だったので、以前に述べたライブラリには、USBダンプを使って既に考え出したものがありました.
私は今、これらの関数を使ってボタンで何が起こっているかを聞くことができました.
const poll = button => {
const buttonInterface = getInterface(button)
const stateDict = {
21: 'close',
22: 'press',
23: 'open',
}
const endpointAddress = buttonInterface.endpoints[0].address
const endpoint = buttonInterface.endpoint(endpointAddress)
endpoint.timeout = 300
return new Promise((resolve, reject) => {
const buffer = new Buffer([0, 0, 0, 0, 0, 0, 0, 2])
button.controlTransfer(bmRequestType, bRequest, wValue, wIndex, buffer, (error, data) => {
if (error) {
reject(error)
}
endpoint.transfer(transferBytes, (error, data) )> {
if (error) {
reject(error)
}
resolve(stateDict[data[0]])
})
})
})
}
私はこのコードを使用して、まったく動作しているかどうかをテストします.
setInterval(() => {
const button = getButton(idVendor, idProduct)
if (!button) {
return
}
poll(button).then(state => {
console.log(state)
}).catch(() => {})
}, 15)
それで、15 msごとに、ボタンは、それからこのようにstdoutに印刷されるその状態を求められます(短縮版).
node ./bigRedButton.js
close
close
close
open
open
open
press
press
press
press
open
open
open
# ...
そして、問題があります:ボタンが押される限り、「プレス」状態は活発です.今、私はライブラリがステートマシンを使用している理由を理解しました:ボタンが押されるのではなく、ボタンが押されると、コールバックは実行されるべきです.これは私が働くことができました.私もコードをいくつかのコールバックを取る関数に詰め込みました.
const listenToButton = (openCallback, pressCallback, closeCallback) => {
var isPressed = false
setInterval(() => {
const button = getButton(idVendor, idProduct)
if (!button) {
return
}
poll(button).then(state => {
if (isPressed && state !== 'press') {
// Not pressing anymore
isPressed = false
}
if (!isPressed && state === 'press') {
isPressed = true
// Executes the callback at the beginning of a button press
pressCallback()
}
if (state === 'open') {
openCallback()
}
if (state === 'close') {
closeCallback()
}
}).catch(() => {})
}, 15)
}
module.exports = listenToButton
今、私は、マイクトグルスクリプトと一緒に使用するには、インポート可能なlibを持っていた.以来、それはボタンを請求するたびに、任意のエラーを飲み込む、ボタンを切断し、再接続すると、魅力のように動作します.
今、私は一緒に作品を接着する必要がありました
const bigRedButton = require('./bigRedButton')
const { exec } = require('child_process')
const openCallback = () => {}
const pushCallback = () => {
exec('XDG_RUNTIME_DIR=/run/user/1000 ./mictoggle.sh')
}
const closeCallback = () => {}
bigRedButton(openCallback, pushCallback, closeCallback)
( XDG_RUNTIME_DIR
ENV変数はone of two kinds of data echanges USB can do (the other being a a functional data exchange)に必要です.テスト中、これを考え出すまでは動作しませんでした)
このスクリプトを実行すると、ハードウェアのミュートボタンに大きな赤いボタンを回す!
非対話的シェルでPulseAudioコマンドを実行する
サービスにする
起動時にミュートボタンを作成するには、このコンテンツで/lib/systemd/system
の下にサービスファイルを作成しました.
[Unit]
Description=Hardware mute button
After=multi-user.target
[Service]
Type=simple
User=USER
ExecStart=/home/USER/.nvm/versions/node/v14.15.0/bin/node /home/USER/projects/mutebutton/index.js
Restart=on-failure
[Install]
WantedBy=multi-user.target
(単にExecStart
経路を調整し、ユーザ名でUSER
に置き換えます).
それから、私はサービス(sudo systemctl start mutebutton
)を始めました.そして、何度かボタンをためしました.そして、喜びでくすくすしました.そして、スタートアップ(sudo systemctl enable mutebutton
)の上でサービスを可能にしました.
テイクアウト思考
私はこの小さい側プロジェクトの前にUSBとLibusbについてあまり知りませんでした、しかし、私はその過程でたくさん学びました.このことは、“インターネットを検索”と“ちょうどそれが働くまで物事をしようとする”いくつかの偉大な教師のために作ることを証明した.
私はこのボタンをインストールして以来、私は今実際に多くのビデオ通話を楽しみにしているボタンを押すと、ビデオの呼び出しは、もっと楽しくなった.ゲームのショーと同じように!
この記事を読んで楽しんでください!もしそうならば❤️ または🦄! 私はフリータイムでハイテク記事を書き、毎回コーヒーを飲みたいです.
私の努力をサポートする場合は、
またはを考慮してください!
buying me a coffee ☕
Reference
この問題について(私はどのようにLinuxのハードウェアミュートボタンを作成しました), 我々は、より多くの情報をここで見つけました
https://dev.to/thormeier/game-show-feeling-how-i-created-a-hardware-mute-button-for-linux-2fk6
テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol
npm i usb
const usb = require('usb')
const getButton = (idVendor, idProduct) => {
return usb.findByIds(idVendor, idProduct)
}
const getInterface = button => {
button.open()
const buttonInterface = button.interface(0)
if (button.interfaces.length !== 1 || buttonInterface.endpoints.length !== 1) {
// Maybe try to figure out which interface we care about?
throw new Error('Expected a single USB interface, but found: ' + buttonInterface.endpoints.length)
}
if (buttonInterface.isKernelDriverActive()) {
buttonInterface.detachKernelDriver()
}
buttonInterface.claim()
return buttonInterface
}
const bmRequestType = 0x21
const bRequest = 0x9
const wValue = 0x0200
const wIndex = 0x0
const transferBytes = 8
const poll = button => {
const buttonInterface = getInterface(button)
const stateDict = {
21: 'close',
22: 'press',
23: 'open',
}
const endpointAddress = buttonInterface.endpoints[0].address
const endpoint = buttonInterface.endpoint(endpointAddress)
endpoint.timeout = 300
return new Promise((resolve, reject) => {
const buffer = new Buffer([0, 0, 0, 0, 0, 0, 0, 2])
button.controlTransfer(bmRequestType, bRequest, wValue, wIndex, buffer, (error, data) => {
if (error) {
reject(error)
}
endpoint.transfer(transferBytes, (error, data) )> {
if (error) {
reject(error)
}
resolve(stateDict[data[0]])
})
})
})
}
setInterval(() => {
const button = getButton(idVendor, idProduct)
if (!button) {
return
}
poll(button).then(state => {
console.log(state)
}).catch(() => {})
}, 15)
node ./bigRedButton.js
close
close
close
open
open
open
press
press
press
press
open
open
open
# ...
const listenToButton = (openCallback, pressCallback, closeCallback) => {
var isPressed = false
setInterval(() => {
const button = getButton(idVendor, idProduct)
if (!button) {
return
}
poll(button).then(state => {
if (isPressed && state !== 'press') {
// Not pressing anymore
isPressed = false
}
if (!isPressed && state === 'press') {
isPressed = true
// Executes the callback at the beginning of a button press
pressCallback()
}
if (state === 'open') {
openCallback()
}
if (state === 'close') {
closeCallback()
}
}).catch(() => {})
}, 15)
}
module.exports = listenToButton
const bigRedButton = require('./bigRedButton')
const { exec } = require('child_process')
const openCallback = () => {}
const pushCallback = () => {
exec('XDG_RUNTIME_DIR=/run/user/1000 ./mictoggle.sh')
}
const closeCallback = () => {}
bigRedButton(openCallback, pushCallback, closeCallback)
起動時にミュートボタンを作成するには、このコンテンツで
/lib/systemd/system
の下にサービスファイルを作成しました.[Unit]
Description=Hardware mute button
After=multi-user.target
[Service]
Type=simple
User=USER
ExecStart=/home/USER/.nvm/versions/node/v14.15.0/bin/node /home/USER/projects/mutebutton/index.js
Restart=on-failure
[Install]
WantedBy=multi-user.target
(単にExecStart
経路を調整し、ユーザ名でUSER
に置き換えます).それから、私はサービス(
sudo systemctl start mutebutton
)を始めました.そして、何度かボタンをためしました.そして、喜びでくすくすしました.そして、スタートアップ(sudo systemctl enable mutebutton
)の上でサービスを可能にしました.テイクアウト思考
私はこの小さい側プロジェクトの前にUSBとLibusbについてあまり知りませんでした、しかし、私はその過程でたくさん学びました.このことは、“インターネットを検索”と“ちょうどそれが働くまで物事をしようとする”いくつかの偉大な教師のために作ることを証明した.
私はこのボタンをインストールして以来、私は今実際に多くのビデオ通話を楽しみにしているボタンを押すと、ビデオの呼び出しは、もっと楽しくなった.ゲームのショーと同じように!
この記事を読んで楽しんでください!もしそうならば❤️ または🦄! 私はフリータイムでハイテク記事を書き、毎回コーヒーを飲みたいです.
私の努力をサポートする場合は、
またはを考慮してください!
buying me a coffee ☕
Reference
この問題について(私はどのようにLinuxのハードウェアミュートボタンを作成しました), 我々は、より多くの情報をここで見つけました
https://dev.to/thormeier/game-show-feeling-how-i-created-a-hardware-mute-button-for-linux-2fk6
テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol
Reference
この問題について(私はどのようにLinuxのハードウェアミュートボタンを作成しました), 我々は、より多くの情報をここで見つけました https://dev.to/thormeier/game-show-feeling-how-i-created-a-hardware-mute-button-for-linux-2fk6テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol