Compare commits
No commits in common. "f879a49e7d10aebf9ac69d890a67179b3ed57071" and "74a9482dbc0dffec48c2e60fa1e31619f1dfb707" have entirely different histories.
f879a49e7d
...
74a9482dbc
@ -1,4 +1,4 @@
|
|||||||
INSTALLDIR = ~/Library/Application\ Support/com.elgato.StreamDeck/Plugins/com.dlprows.macvolumecontrol.sdPlugin
|
INSTALLDIR = "~/Library/Application\ Support/com.elgato.StreamDeck/Plugins/com.dlprows.macvolumecontrol.sdPlugin"
|
||||||
#BUILDDIR = build
|
#BUILDDIR = build
|
||||||
#RELEASEDIR = release
|
#RELEASEDIR = release
|
||||||
#SDPLUGINDIR = "./com.dlprows.macvolumecontrol.sdPlugin"
|
#SDPLUGINDIR = "./com.dlprows.macvolumecontrol.sdPlugin"
|
||||||
|
Binary file not shown.
43
src/keyboard/keyboard.go
Normal file
43
src/keyboard/keyboard.go
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
package keyboard
|
||||||
|
|
||||||
|
/*
|
||||||
|
#cgo CFLAGS: -x objective-c
|
||||||
|
#cgo LDFLAGS: -framework AppKit
|
||||||
|
#import <AppKit/AppKit.h>
|
||||||
|
NSEvent* createEvent(int k, bool down) {
|
||||||
|
int flags = down ? 0xa00 : 0xb00;
|
||||||
|
NSEvent* event = [NSEvent otherEventWithType:NSEventTypeSystemDefined
|
||||||
|
location:NSZeroPoint
|
||||||
|
modifierFlags:flags
|
||||||
|
timestamp:0
|
||||||
|
windowNumber:0
|
||||||
|
context:nil
|
||||||
|
subtype:8
|
||||||
|
data1:(k << 16 | flags)
|
||||||
|
data2:-1
|
||||||
|
];
|
||||||
|
return event;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pressKey(int k) {
|
||||||
|
@autoreleasepool {
|
||||||
|
NSEvent* down = createEvent(k, true);
|
||||||
|
NSEvent* up = createEvent(k, false);
|
||||||
|
|
||||||
|
CGEventPost(kCGHIDEventTap, down.CGEvent);
|
||||||
|
usleep(1000);
|
||||||
|
CGEventPost(kCGHIDEventTap, up.CGEvent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
func PressMediaKey(key int) {
|
||||||
|
C.pressKey(C.int(key))
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
VOLUMEUP = 0
|
||||||
|
VOLUMEDOWN = 1
|
||||||
|
MUTE = 7
|
||||||
|
)
|
@ -20,9 +20,8 @@ func directory() string {
|
|||||||
// Enable turns logging on for the StreamDeck API client as well as the global
|
// Enable turns logging on for the StreamDeck API client as well as the global
|
||||||
// log object. It sends both to a temp file that contains <project_directory>.log.
|
// log object. It sends both to a temp file that contains <project_directory>.log.
|
||||||
func Enable() {
|
func Enable() {
|
||||||
os.Mkdir("./logs/", 0775)
|
|
||||||
d := directory()
|
d := directory()
|
||||||
f, err := os.CreateTemp("./logs/", fmt.Sprintf("%s.log", d))
|
f, err := os.CreateTemp("./", fmt.Sprintf("%s.log", d))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("error creating temp file: %v", err)
|
log.Fatalf("error creating temp file: %v", err)
|
||||||
}
|
}
|
||||||
|
135
src/main.go
135
src/main.go
@ -3,20 +3,16 @@ package main
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"macvolumecontrol/keyboard"
|
||||||
"macvolumecontrol/logging"
|
"macvolumecontrol/logging"
|
||||||
"macvolumecontrol/volume"
|
|
||||||
|
|
||||||
"code.encyclopediaofdaniel.com/dlprows/streamdeck-sdk"
|
"code.encyclopediaofdaniel.com/dlprows/streamdeck-sdk"
|
||||||
sdcontext "code.encyclopediaofdaniel.com/dlprows/streamdeck-sdk/context"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var _currentSettings *volume.VolumeSettings = &volume.VolumeSettings{}
|
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
logging.Enable()
|
logging.Enable()
|
||||||
log.Println("Starting plugin")
|
log.Println("Starting plugin")
|
||||||
@ -40,62 +36,46 @@ func setup(client *streamdeck.Client) {
|
|||||||
log.Println("Registering actions")
|
log.Println("Registering actions")
|
||||||
action := client.Action("com.dlprows.macvolumecontrol.dialaction")
|
action := client.Action("com.dlprows.macvolumecontrol.dialaction")
|
||||||
|
|
||||||
|
debounce := time.Now()
|
||||||
contexts := make(map[string]struct{})
|
contexts := make(map[string]struct{})
|
||||||
|
|
||||||
action.RegisterHandler(streamdeck.DialRotate, func(ctx context.Context, client *streamdeck.Client, event streamdeck.Event) error {
|
action.RegisterHandler(streamdeck.DialRotate, func(ctx context.Context, client *streamdeck.Client, event streamdeck.Event) error {
|
||||||
log.Println("dial rotate")
|
log.Println("dial rotate")
|
||||||
|
|
||||||
|
t := time.Now()
|
||||||
|
elapsed := t.Sub(debounce)
|
||||||
|
|
||||||
|
if elapsed.Milliseconds() < 50 {
|
||||||
|
log.Println("dial rotate skipped")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
debounce = t
|
||||||
|
|
||||||
p := streamdeck.DialRotatePayload[any]{}
|
p := streamdeck.DialRotatePayload[any]{}
|
||||||
|
|
||||||
if err := json.Unmarshal(event.Payload, &p); err != nil {
|
if err := json.Unmarshal(event.Payload, &p); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
//volume.ChangeVolumeWithKeyboard(p.Ticks)
|
if p.Ticks > 0 {
|
||||||
newSettings, err := volume.ChangeVolume(p.Ticks)
|
keyboard.PressMediaKey(keyboard.VOLUMEUP)
|
||||||
|
} else {
|
||||||
if err != nil {
|
keyboard.PressMediaKey(keyboard.VOLUMEDOWN)
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return setFeedbackIfNeeded(ctx, client, newSettings)
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
action.RegisterHandler(streamdeck.DialDown, func(ctx context.Context, client *streamdeck.Client, event streamdeck.Event) error {
|
action.RegisterHandler(streamdeck.DialDown, func(ctx context.Context, client *streamdeck.Client, event streamdeck.Event) error {
|
||||||
log.Println("dial down")
|
log.Println("dial down")
|
||||||
|
keyboard.PressMediaKey(keyboard.MUTE)
|
||||||
newSettings, err := volume.ToggleMute()
|
return nil
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return setFeedbackIfNeeded(ctx, client, newSettings)
|
|
||||||
})
|
|
||||||
|
|
||||||
action.RegisterHandler(streamdeck.TouchTap, func(ctx context.Context, client *streamdeck.Client, event streamdeck.Event) error {
|
|
||||||
log.Println("touch tap")
|
|
||||||
|
|
||||||
newSettings, err := volume.ToggleMute()
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return setFeedbackIfNeeded(ctx, client, newSettings)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
action.RegisterHandler(streamdeck.WillAppear, func(ctx context.Context, client *streamdeck.Client, event streamdeck.Event) error {
|
action.RegisterHandler(streamdeck.WillAppear, func(ctx context.Context, client *streamdeck.Client, event streamdeck.Event) error {
|
||||||
log.Println("Will Appear")
|
log.Println("Will Appear")
|
||||||
contexts[event.Context] = struct{}{}
|
contexts[event.Context] = struct{}{}
|
||||||
|
return nil
|
||||||
newSettings, err := volume.GetVolumeSettings()
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return setFeedbackIfNeeded(ctx, client, newSettings)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
action.RegisterHandler(streamdeck.WillDisappear, func(ctx context.Context, client *streamdeck.Client, event streamdeck.Event) error {
|
action.RegisterHandler(streamdeck.WillDisappear, func(ctx context.Context, client *streamdeck.Client, event streamdeck.Event) error {
|
||||||
@ -105,63 +85,44 @@ func setup(client *streamdeck.Client) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
//start background thread to keep the display up to date if changed outside the stream deck
|
//start background thread to keep the display up to date if changed outside the stream deck
|
||||||
go func() {
|
//go func() {
|
||||||
for range time.Tick(time.Second * 1) {
|
|
||||||
newSettings, err := volume.GetVolumeSettings()
|
|
||||||
|
|
||||||
if err != nil {
|
//}()
|
||||||
log.Fatal(err)
|
}
|
||||||
}
|
|
||||||
|
|
||||||
for ctxStr := range contexts {
|
/*
|
||||||
//for each context
|
osascript -e 'output volume of (get volume settings)'
|
||||||
//build a new context that can be used to perform outbound requests
|
osascript -e 'set volume output volume 50'
|
||||||
|
osascript -e 'output muted of (get volume settings)'
|
||||||
|
osascript -e 'set volume output muted true'
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
for ctxStr := range contexts {
|
||||||
|
//for each context
|
||||||
|
//build a new context that can be used to perform outbound requests
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
ctx = sdcontext.WithContext(ctx, ctxStr)
|
ctx = sdcontext.WithContext(ctx, ctxStr)
|
||||||
|
|
||||||
setFeedbackIfNeeded(ctx, client, newSettings)
|
img, err := streamdeck.Image(graph(readings))
|
||||||
}
|
if err != nil {
|
||||||
}
|
log.Printf("error creating image: %v\n", err)
|
||||||
}()
|
continue
|
||||||
}
|
|
||||||
|
|
||||||
func setFeedbackIfNeeded(ctx context.Context, client *streamdeck.Client, newSettings *volume.VolumeSettings) error {
|
|
||||||
|
|
||||||
if _currentSettings.OutputVolume == newSettings.OutputVolume && _currentSettings.OutputMuted == newSettings.OutputMuted {
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
payload := FeedbackPayload{}
|
if err := client.SetImage(ctx, img, streamdeck.HardwareAndSoftware); err != nil {
|
||||||
|
log.Printf("error setting image: %v\n", err)
|
||||||
opacity := 1.0
|
continue
|
||||||
|
|
||||||
if newSettings.OutputMuted {
|
|
||||||
opacity = 0.5
|
|
||||||
}
|
}
|
||||||
|
|
||||||
payload.Value = ValueWithOpacity[string]{
|
title := ""
|
||||||
fmt.Sprintf("%d%%", newSettings.OutputVolume),
|
if pi.ShowText {
|
||||||
opacity,
|
title = fmt.Sprintf("CPU\n%d%%", int(r[0]))
|
||||||
}
|
}
|
||||||
|
|
||||||
payload.Indicator = ValueWithOpacity[int]{
|
if err := client.SetTitle(ctx, title, streamdeck.HardwareAndSoftware); err != nil {
|
||||||
newSettings.OutputVolume,
|
log.Printf("error setting title: %v\n", err)
|
||||||
opacity,
|
continue
|
||||||
}
|
}
|
||||||
|
}
|
||||||
payload.Icon = ValueWithOpacity[any]{nil, opacity}
|
*/
|
||||||
|
|
||||||
_currentSettings = newSettings
|
|
||||||
return client.SetFeedback(ctx, payload)
|
|
||||||
}
|
|
||||||
|
|
||||||
type FeedbackPayload struct {
|
|
||||||
Value ValueWithOpacity[string] `json:"value"`
|
|
||||||
Indicator ValueWithOpacity[int] `json:"indicator"`
|
|
||||||
Icon ValueWithOpacity[any] `json:"icon"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ValueWithOpacity[T any] struct {
|
|
||||||
Value T `json:"value,omitempty"`
|
|
||||||
Opacity float64 `json:"opacity"`
|
|
||||||
}
|
|
||||||
|
@ -1,134 +0,0 @@
|
|||||||
package volume
|
|
||||||
|
|
||||||
/*
|
|
||||||
#cgo CFLAGS: -x objective-c
|
|
||||||
#cgo LDFLAGS: -framework CoreAudio
|
|
||||||
#include <CoreAudio/CoreAudio.h>
|
|
||||||
*/
|
|
||||||
import "C"
|
|
||||||
import (
|
|
||||||
"unsafe"
|
|
||||||
)
|
|
||||||
|
|
||||||
type OSStatus C.OSStatus
|
|
||||||
|
|
||||||
const (
|
|
||||||
AudioHardwareNoError = C.kAudioHardwareNoError
|
|
||||||
)
|
|
||||||
|
|
||||||
type AudioObjectID uint32
|
|
||||||
|
|
||||||
func GetDefaultOutputDevice() (AudioObjectID, OSStatus) {
|
|
||||||
properties := C.AudioObjectPropertyAddress{
|
|
||||||
C.kAudioHardwarePropertyDefaultOutputDevice,
|
|
||||||
C.kAudioObjectPropertyScopeGlobal,
|
|
||||||
C.kAudioObjectPropertyElementMain,
|
|
||||||
}
|
|
||||||
|
|
||||||
var data C.AudioObjectID
|
|
||||||
dataSize := C.UInt32(unsafe.Sizeof(data))
|
|
||||||
|
|
||||||
result := C.AudioObjectGetPropertyData(
|
|
||||||
C.kAudioObjectSystemObject,
|
|
||||||
&properties,
|
|
||||||
C.UInt32(0),
|
|
||||||
unsafe.Pointer(nil),
|
|
||||||
&dataSize,
|
|
||||||
unsafe.Pointer(&data),
|
|
||||||
)
|
|
||||||
|
|
||||||
return AudioObjectID(data), OSStatus(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetVolume(objectID AudioObjectID) (float32, OSStatus) {
|
|
||||||
|
|
||||||
properties := C.AudioObjectPropertyAddress{
|
|
||||||
C.kAudioDevicePropertyVolumeScalar,
|
|
||||||
C.kAudioDevicePropertyScopeOutput,
|
|
||||||
0, //main channel
|
|
||||||
}
|
|
||||||
|
|
||||||
var data C.Float32
|
|
||||||
dataSize := C.UInt32(unsafe.Sizeof(data))
|
|
||||||
|
|
||||||
result := C.AudioObjectGetPropertyData(
|
|
||||||
C.AudioObjectID(objectID),
|
|
||||||
&properties,
|
|
||||||
C.UInt32(0),
|
|
||||||
unsafe.Pointer(nil),
|
|
||||||
&dataSize,
|
|
||||||
unsafe.Pointer(&data),
|
|
||||||
)
|
|
||||||
|
|
||||||
return float32(data), OSStatus(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
func SetVolume(objectID AudioObjectID, volume float32) OSStatus {
|
|
||||||
|
|
||||||
properties := C.AudioObjectPropertyAddress{
|
|
||||||
C.kAudioDevicePropertyVolumeScalar,
|
|
||||||
C.kAudioDevicePropertyScopeOutput,
|
|
||||||
0, //main channel
|
|
||||||
}
|
|
||||||
|
|
||||||
data := C.Float32(volume)
|
|
||||||
|
|
||||||
result := C.AudioObjectSetPropertyData(
|
|
||||||
C.AudioObjectID(objectID),
|
|
||||||
&properties,
|
|
||||||
C.UInt32(0),
|
|
||||||
unsafe.Pointer(nil),
|
|
||||||
C.UInt32(unsafe.Sizeof(data)),
|
|
||||||
unsafe.Pointer(&data),
|
|
||||||
)
|
|
||||||
|
|
||||||
return OSStatus(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetMute(objectID AudioObjectID) (bool, OSStatus) {
|
|
||||||
|
|
||||||
properties := C.AudioObjectPropertyAddress{
|
|
||||||
C.kAudioDevicePropertyMute,
|
|
||||||
C.kAudioDevicePropertyScopeOutput,
|
|
||||||
0, //main channel
|
|
||||||
}
|
|
||||||
|
|
||||||
var data C.UInt32
|
|
||||||
dataSize := C.UInt32(unsafe.Sizeof(data))
|
|
||||||
|
|
||||||
result := C.AudioObjectGetPropertyData(
|
|
||||||
C.AudioObjectID(objectID),
|
|
||||||
&properties,
|
|
||||||
C.UInt32(0),
|
|
||||||
unsafe.Pointer(nil),
|
|
||||||
&dataSize,
|
|
||||||
unsafe.Pointer(&data),
|
|
||||||
)
|
|
||||||
|
|
||||||
dataAsBool := uint32(data) != 0
|
|
||||||
return dataAsBool, OSStatus(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
func SetMute(objectID AudioObjectID, mute bool) OSStatus {
|
|
||||||
|
|
||||||
properties := C.AudioObjectPropertyAddress{
|
|
||||||
C.kAudioDevicePropertyMute,
|
|
||||||
C.kAudioDevicePropertyScopeOutput,
|
|
||||||
0, //main channel
|
|
||||||
}
|
|
||||||
|
|
||||||
data := C.UInt32(0)
|
|
||||||
if mute {
|
|
||||||
data = C.UInt32(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
result := C.AudioObjectSetPropertyData(
|
|
||||||
C.AudioObjectID(objectID),
|
|
||||||
&properties,
|
|
||||||
C.UInt32(0),
|
|
||||||
unsafe.Pointer(nil),
|
|
||||||
C.UInt32(unsafe.Sizeof(data)),
|
|
||||||
unsafe.Pointer(&data),
|
|
||||||
)
|
|
||||||
return OSStatus(result)
|
|
||||||
}
|
|
@ -1,212 +0,0 @@
|
|||||||
package volume
|
|
||||||
|
|
||||||
/*
|
|
||||||
#cgo CFLAGS: -x objective-c
|
|
||||||
#cgo LDFLAGS: -framework AppKit
|
|
||||||
#import <AppKit/AppKit.h>
|
|
||||||
NSEvent* createEvent(int k, bool down) {
|
|
||||||
int flags = down ? 0xa00 : 0xb00;
|
|
||||||
NSEvent* event = [NSEvent otherEventWithType:NSEventTypeSystemDefined
|
|
||||||
location:NSZeroPoint
|
|
||||||
modifierFlags:flags
|
|
||||||
timestamp:0
|
|
||||||
windowNumber:0
|
|
||||||
context:nil
|
|
||||||
subtype:8
|
|
||||||
data1:(k << 16 | flags)
|
|
||||||
data2:-1
|
|
||||||
];
|
|
||||||
return event;
|
|
||||||
}
|
|
||||||
|
|
||||||
void pressKey(int k) {
|
|
||||||
@autoreleasepool {
|
|
||||||
NSEvent* down = createEvent(k, true);
|
|
||||||
NSEvent* up = createEvent(k, false);
|
|
||||||
|
|
||||||
CGEventPost(kCGHIDEventTap, down.CGEvent);
|
|
||||||
usleep(100);
|
|
||||||
CGEventPost(kCGHIDEventTap, up.CGEvent);
|
|
||||||
usleep(100);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
import "C"
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
)
|
|
||||||
|
|
||||||
/*
|
|
||||||
osascript -e 'output volume of (get volume settings)'
|
|
||||||
osascript -e 'set volume output volume 50'
|
|
||||||
osascript -e 'output muted of (get volume settings)'
|
|
||||||
osascript -e 'set volume output muted true'
|
|
||||||
*/
|
|
||||||
type VolumeSettings struct {
|
|
||||||
OutputVolume int
|
|
||||||
OutputMuted bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetVolumeSettings() (*VolumeSettings, error) {
|
|
||||||
//osascript -e "get volume settings"
|
|
||||||
//output volume:81, input volume:50, alert volume:100, output muted:false
|
|
||||||
|
|
||||||
device, result := GetDefaultOutputDevice()
|
|
||||||
|
|
||||||
if result != AudioHardwareNoError {
|
|
||||||
return nil, errors.New(fmt.Sprintf("Unable to get device: %d", result))
|
|
||||||
}
|
|
||||||
|
|
||||||
return getVolumeSettings(device)
|
|
||||||
}
|
|
||||||
|
|
||||||
func getVolumeSettings(device AudioObjectID) (*VolumeSettings, error) {
|
|
||||||
|
|
||||||
volume, result := GetVolume(device)
|
|
||||||
if result != AudioHardwareNoError {
|
|
||||||
return nil, errors.New(fmt.Sprintf("Unable to get volume: %d", result))
|
|
||||||
}
|
|
||||||
|
|
||||||
muted, result := GetMute(device)
|
|
||||||
if result != AudioHardwareNoError {
|
|
||||||
return nil, errors.New(fmt.Sprintf("Unable to get mute: %d", result))
|
|
||||||
}
|
|
||||||
|
|
||||||
settings := VolumeSettings{
|
|
||||||
int(volume * 100),
|
|
||||||
muted,
|
|
||||||
}
|
|
||||||
|
|
||||||
return &settings, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func ChangeVolume(ticks int) (*VolumeSettings, error) {
|
|
||||||
|
|
||||||
device, result := GetDefaultOutputDevice()
|
|
||||||
|
|
||||||
if result != AudioHardwareNoError {
|
|
||||||
return nil, errors.New(fmt.Sprintf("Unable to get device: %d", result))
|
|
||||||
}
|
|
||||||
|
|
||||||
volume, result := GetVolume(device)
|
|
||||||
if result != AudioHardwareNoError {
|
|
||||||
return nil, errors.New(fmt.Sprintf("Unable to get volume: %d", result))
|
|
||||||
}
|
|
||||||
|
|
||||||
volume = volume * 64 //convert from fractional volume to 64 steps that mac supports
|
|
||||||
volume += float32(ticks) //add number of ticks
|
|
||||||
volume = volume / 64 //convert back to fractional volume that mac supports
|
|
||||||
|
|
||||||
SetVolume(device, volume)
|
|
||||||
|
|
||||||
return getVolumeSettings(device)
|
|
||||||
}
|
|
||||||
|
|
||||||
func ToggleMute() (*VolumeSettings, error) {
|
|
||||||
device, result := GetDefaultOutputDevice()
|
|
||||||
|
|
||||||
if result != AudioHardwareNoError {
|
|
||||||
return nil, errors.New(fmt.Sprintf("Unable to get device: %d", result))
|
|
||||||
}
|
|
||||||
|
|
||||||
muted, result := GetMute(device)
|
|
||||||
if result != AudioHardwareNoError {
|
|
||||||
return nil, errors.New(fmt.Sprintf("Unable to get volume: %d", result))
|
|
||||||
}
|
|
||||||
|
|
||||||
SetMute(device, !muted)
|
|
||||||
|
|
||||||
return getVolumeSettings(device)
|
|
||||||
}
|
|
||||||
|
|
||||||
func ChangeVolumeWithKeyboard(ticks int) {
|
|
||||||
key := volumeup
|
|
||||||
|
|
||||||
if ticks < 0 {
|
|
||||||
key = volumedown
|
|
||||||
ticks = -1 * ticks
|
|
||||||
}
|
|
||||||
|
|
||||||
for x := 0; x < ticks; x++ {
|
|
||||||
C.pressKey(C.int(key))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func ToggleMuteWithKeyboard() {
|
|
||||||
C.pressKey(C.int(mute))
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
volumeup = 0
|
|
||||||
volumedown = 1
|
|
||||||
mute = 7
|
|
||||||
)
|
|
||||||
|
|
||||||
/*
|
|
||||||
Get volume in applescript
|
|
||||||
out, err := exec.Command("osascript", "-e", "get volume settings").Output()
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
split1 := strings.Split(string(out), ",")
|
|
||||||
|
|
||||||
settings := VolumeSettings{}
|
|
||||||
|
|
||||||
for _, sub := range split1 {
|
|
||||||
|
|
||||||
if strings.HasPrefix(sub, "output volume:") {
|
|
||||||
outputVolume, err := strconv.Atoi(strings.Split(sub, ":")[1])
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
settings.OutputVolume = outputVolume
|
|
||||||
|
|
||||||
} else if strings.HasPrefix(sub, "output muted:") {
|
|
||||||
|
|
||||||
outputMuted, err := strconv.ParseBool(strings.Split(sub, ":")[1])
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
settings.OutputMuted = outputMuted
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
set volume in applescript
|
|
||||||
|
|
||||||
//script := "set volume output muted (not output muted of (get volume settings))"
|
|
||||||
settings, err := GetVolumeSettings()
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
volume := float64(settings.OutputVolume) * 64 / 100
|
|
||||||
volume += float64(ticks)
|
|
||||||
newVolume := int(math.Round(volume * 100 / 64))
|
|
||||||
|
|
||||||
if newVolume > 100 {
|
|
||||||
newVolume = 100
|
|
||||||
}
|
|
||||||
if newVolume < 0 {
|
|
||||||
newVolume = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
settings.OutputVolume = newVolume
|
|
||||||
|
|
||||||
script := fmt.Sprintf("set volume output volume %d", newVolume)
|
|
||||||
|
|
||||||
return settings, exec.Command("osascript", "-e", script).Run()
|
|
||||||
*/
|
|
||||||
|
|
||||||
//script := "set volume output muted (not output muted of (get volume settings))"
|
|
||||||
//return exec.Command("osascript", "-e", "set volume output muted (not output muted of (get volume settings))").Run()
|
|
Loading…
Reference in New Issue
Block a user