-
-
Notifications
You must be signed in to change notification settings - Fork 444
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
separate out session to os-specific implementations, add baseSEssions…
… struct for embedding
- Loading branch information
Showing
4 changed files
with
200 additions
and
159 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
// +build linux | ||
|
||
package deej | ||
|
||
// implement PulseAudio session here |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,175 @@ | ||
// +build windows | ||
|
||
package deej | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
"strings" | ||
|
||
ole "github.com/go-ole/go-ole" | ||
ps "github.com/mitchellh/go-ps" | ||
wca "github.com/moutend/go-wca" | ||
"go.uber.org/zap" | ||
|
||
"github.com/omriharel/deej/util" | ||
) | ||
|
||
var errNoSuchProcess = errors.New("No such process") | ||
|
||
type wcaSession struct { | ||
baseSession | ||
|
||
pid uint32 | ||
processName string | ||
|
||
control *wca.IAudioSessionControl2 | ||
volume *wca.ISimpleAudioVolume | ||
|
||
eventCtx *ole.GUID | ||
} | ||
|
||
type masterSession struct { | ||
baseSession | ||
|
||
volume *wca.IAudioEndpointVolume | ||
|
||
eventCtx *ole.GUID | ||
} | ||
|
||
func newWCASession( | ||
logger *zap.SugaredLogger, | ||
control *wca.IAudioSessionControl2, | ||
volume *wca.ISimpleAudioVolume, | ||
pid uint32, | ||
eventCtx *ole.GUID, | ||
) (*wcaSession, error) { | ||
|
||
s := &wcaSession{ | ||
control: control, | ||
volume: volume, | ||
pid: pid, | ||
eventCtx: eventCtx, | ||
} | ||
|
||
// special treatment for system sounds session | ||
if pid == 0 { | ||
s.system = true | ||
s.name = systemSessionName | ||
s.humanReadableDesc = "system sounds" | ||
} else { | ||
|
||
// find our session's process name | ||
process, err := ps.FindProcess(int(pid)) | ||
if err != nil { | ||
logger.Warnw("Failed to find process name by ID", "pid", pid, "error", err) | ||
defer s.Release() | ||
|
||
return nil, fmt.Errorf("find process name by pid: %w", err) | ||
} | ||
|
||
// this PID may be invalid - this means the process has already been | ||
// closed and we shouldn't create a session for it. | ||
if process == nil { | ||
logger.Debugw("Process already exited, not creating audio session", "pid", pid) | ||
return nil, errNoSuchProcess | ||
} | ||
|
||
s.processName = process.Executable() | ||
s.name = s.processName | ||
s.humanReadableDesc = fmt.Sprintf("%s (pid %d)", s.processName, s.pid) | ||
} | ||
|
||
// use a self-identifying session name e.g. deej.sessions.chrome | ||
s.logger = logger.Named(strings.TrimSuffix(s.Key(), ".exe")) | ||
s.logger.Debugw(sessionCreationLogMessage, "session", s) | ||
|
||
return s, nil | ||
} | ||
|
||
func newMasterSession( | ||
logger *zap.SugaredLogger, | ||
volume *wca.IAudioEndpointVolume, | ||
eventCtx *ole.GUID, | ||
) (*masterSession, error) { | ||
|
||
s := &masterSession{ | ||
volume: volume, | ||
eventCtx: eventCtx, | ||
} | ||
|
||
s.logger = logger.Named(masterSessionName) | ||
s.master = true | ||
s.name = masterSessionName | ||
s.humanReadableDesc = masterSessionName | ||
|
||
s.logger.Debugw(sessionCreationLogMessage, "session", s) | ||
|
||
return s, nil | ||
} | ||
|
||
func (s *wcaSession) GetVolume() float32 { | ||
var level float32 | ||
|
||
if err := s.volume.GetMasterVolume(&level); err != nil { | ||
s.logger.Warnw("Failed to get session volume", "error", err) | ||
} | ||
|
||
return util.NormalizeScalar(level) | ||
} | ||
|
||
func (s *wcaSession) SetVolume(v float32) error { | ||
if err := s.volume.SetMasterVolume(v, s.eventCtx); err != nil { | ||
s.logger.Warnw("Failed to set session volume", "error", err) | ||
return fmt.Errorf("adjust session volume: %w", err) | ||
} | ||
|
||
s.logger.Debugw("Adjusting session volume", "to", fmt.Sprintf("%.2f", v)) | ||
|
||
return nil | ||
} | ||
|
||
func (s *wcaSession) Release() { | ||
s.logger.Debug("Releasing audio session") | ||
|
||
s.volume.Release() | ||
s.control.Release() | ||
} | ||
|
||
func (s *wcaSession) String() string { | ||
return fmt.Sprintf(sessionStringFormat, s.humanReadableDesc, s.GetVolume()) | ||
} | ||
|
||
func (s *masterSession) GetVolume() float32 { | ||
var level float32 | ||
|
||
if err := s.volume.GetMasterVolumeLevelScalar(&level); err != nil { | ||
s.logger.Warnw("Failed to get session volume", "error", err) | ||
} | ||
|
||
return util.NormalizeScalar(level) | ||
} | ||
|
||
func (s *masterSession) SetVolume(v float32) error { | ||
if err := s.volume.SetMasterVolumeLevelScalar(v, s.eventCtx); err != nil { | ||
s.logger.Warnw("Failed to set session volume", | ||
"error", err, | ||
"volume", v) | ||
|
||
return fmt.Errorf("adjust session volume: %w", err) | ||
} | ||
|
||
s.logger.Debugw("Adjusting session volume", "to", fmt.Sprintf("%.2f", v)) | ||
|
||
return nil | ||
} | ||
|
||
func (s *masterSession) Release() { | ||
s.logger.Debug("Releasing audio session") | ||
|
||
s.volume.Release() | ||
} | ||
|
||
func (s *masterSession) String() string { | ||
return fmt.Sprintf(sessionStringFormat, s.humanReadableDesc, s.GetVolume()) | ||
} |