audiopy revision 2c8b35bdd25b0946d4ea35e74a1e20ccd4679325
12a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw#! /usr/bin/env python
22a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw
32a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw"""Program to control the Solaris audio device.
42a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw
52a06084ed51d06cdea9544b5ab02586d300dec83Barry WarsawWhen no arguments are given, this pops up a graphical window which lets you
62a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsawchoose which audio output device you want sound to go to.
72a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw
82a06084ed51d06cdea9544b5ab02586d300dec83Barry WarsawThis program can be driven via the command line, and when done so, no window
92c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsawpops up.  Options have the general form:
102a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw
112c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw    --device[={0,1}]
122c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw    -d[={0,1}]
132c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        Set the I/O device.  With no value, it toggles the specified device.
142c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        With a value, 0 turns the device off and 1 turns the device on.
152a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw
162c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry WarsawThe list of devices and their short options are:
172a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw
182c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw (input)
192c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw    microphone  -- m
202c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw    linein      -- i
212c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw    cd          -- c
222c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw
232c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw (output)
242c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw    headphones  -- p
252c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw    speaker     -- s
262c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw    lineout     -- o
272c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw
282c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry WarsawOther options are:
292a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw
302a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw    --help
312a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw    -h
322a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        Print this message and exit.
332a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw
342a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw"""
352a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw
362a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsawimport sys
372a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsawfrom Tkinter import *
382a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsawimport sunaudiodev
392a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsawfrom SUNAUDIODEV import *
402a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw
412a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw# Milliseconds between interrupt checks
422a06084ed51d06cdea9544b5ab02586d300dec83Barry WarsawKEEPALIVE_TIMER = 500
432a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw
442a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw
452a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw
462a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsawclass MainWindow:
472c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw    def __init__(self, device):
482c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        self.__devctl = device
492c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        info = device.getinfo()
502c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        #
512a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        self.__tkroot = tkroot = Tk(className='Pynche')
522a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        tkroot.withdraw()
532a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        # now create the top level window
542c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        root = self.__root = Toplevel(tkroot, class_='Audiopy')
552a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        root.protocol('WM_DELETE_WINDOW', self.__quit)
562a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        root.title('Audiopy')
572a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        root.iconname('Audiopy')
582a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        root.tk.createtimerhandler(KEEPALIVE_TIMER, self.__keepalive)
592a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        #
602c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        buttons = []
612a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        #
62b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        # where does input come from?
63b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        frame = Frame(root, bd=1, relief=RAISED)
64b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        frame.grid(row=0, column=0)
65b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        label = Label(frame, text='Input From:')
66b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        label.grid(row=0, column=0, sticky=E)
67b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        self.__micvar = IntVar()
68b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        btn = Checkbutton(frame,
69b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw                          text='Microphone',
70b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw                          variable=self.__micvar,
71b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw                          onvalue=MICROPHONE,
72b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw                          command=self.__pushtodev,
73b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw                          underline=0)
74b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        btn.grid(row=0, column=1, sticky=W)
75b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        root.bind('<Alt-m>', self.__mic)
76b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        root.bind('<Alt-M>', self.__mic)
772c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        if not info.i_avail_ports & MICROPHONE:
782c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw            btn.configure(state=DISABLED)
792c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        buttons.append(btn)
802c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        ##
81b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        self.__lineinvar = IntVar()
82b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        btn = Checkbutton(frame,
83b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw                          text='Line In',
84b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw                          variable=self.__lineinvar,
85b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw                          onvalue=LINE_IN,
86b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw                          command=self.__pushtodev,
87b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw                          underline=5)
88b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        btn.grid(row=1, column=1, sticky=W)
89b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        root.bind('<Alt-i>', self.__linein)
90b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        root.bind('<Alt-I>', self.__linein)
912c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        if not info.i_avail_ports & LINE_IN:
922c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw            btn.configure(state=DISABLED)
932c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        buttons.append(btn)
942c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        ##
95b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        self.__cdvar = IntVar()
96b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        btn = Checkbutton(frame,
97b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw                          text='CD',
98b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw                          variable=self.__cdvar,
99b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw                          onvalue=CD,
100b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw                          command=self.__pushtodev,
101b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw                          underline=0)
102b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        btn.grid(row=2, column=1, sticky=W)
103b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        root.bind('<Alt-c>', self.__cd)
104b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        root.bind('<Alt-C>', self.__cd)
1052c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        if not info.i_avail_ports & CD:
1062c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw            btn.configure(state=DISABLED)
1072c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        buttons.append(btn)
108b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        #
109b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        # where does output go to?
110b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        frame = Frame(root, bd=1, relief=RAISED)
111b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        frame.grid(row=1, column=0)
112b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        label = Label(frame, text='Output To:')
1132a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        label.grid(row=0, column=0, sticky=E)
1142a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        self.__spkvar = IntVar()
115b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        btn = Checkbutton(frame,
1162a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw                          text='Speaker',
1172a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw                          variable=self.__spkvar,
1182a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw                          onvalue=SPEAKER,
119b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw                          command=self.__pushtodev,
1202a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw                          underline=0)
1212a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        btn.grid(row=0, column=1, sticky=W)
1222a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        root.bind('<Alt-s>', self.__speaker)
1232a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        root.bind('<Alt-S>', self.__speaker)
1242c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        if not info.o_avail_ports & SPEAKER:
1252c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw            btn.configure(state=DISABLED)
1262c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        buttons.append(btn)
1272c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        ##
1282a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        self.__headvar = IntVar()
129b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        btn = Checkbutton(frame,
1302a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw                          text='Headphones',
1312a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw                          variable=self.__headvar,
1322a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw                          onvalue=HEADPHONE,
133b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw                          command=self.__pushtodev,
1342a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw                          underline=0)
1352a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        btn.grid(row=1, column=1, sticky=W)
1362a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        root.bind('<Alt-h>', self.__headphones)
1372a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        root.bind('<Alt-H>', self.__headphones)
1382c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        if not info.o_avail_ports & HEADPHONE:
1392c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw            btn.configure(state=DISABLED)
1402c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        buttons.append(btn)
1412c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        ##
1422a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        self.__linevar = IntVar()
143b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        btn = Checkbutton(frame,
1442a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw                          variable=self.__linevar,
1452a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw                          onvalue=LINE_OUT,
146b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw                          text='Line Out',
147b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw                          command=self.__pushtodev,
1482a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw                          underline=0)
1492a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        btn.grid(row=2, column=1, sticky=W)
1502a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        root.bind('<Alt-l>', self.__lineout)
1512a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        root.bind('<Alt-L>', self.__lineout)
1522c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        if not info.o_avail_ports & LINE_OUT:
1532c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw            btn.configure(state=DISABLED)
1542c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        buttons.append(btn)
1552c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        #
1562c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        # Fix up widths
1572c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        widest = 0
1582c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        for b in buttons:
1592c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw            width = b['width']
1602c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw            if width > widest:
1612c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw                widest = width
1622c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        for b in buttons:
1632c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw            b.configure(width=widest)
1642c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        #
1652c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        # Add quit button
1662c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        frame = Frame(root)
1672c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        frame.grid(row=2, column=0, sticky='EW', ipady=5)
1682c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        btn = Button(frame,
1692c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw                     text='Quit',
1702c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw                     command=self.__quit,
1712c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw                     underline=0)
1722c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        btn.pack(expand=YES)
1732c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        root.bind('<Alt-q>', self.__quit)
1742c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        root.bind('<Alt-Q>', self.__quit)
175b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        #
176b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        # do we need to poll for changes?
177b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        self.__needtopoll = 1
178b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        try:
179b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw            fd = self.__devctl.fileno()
180b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw            self.__needtopoll = 0
181b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        except AttributeError:
182b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw            pass
183b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        else:
184b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw            import struct
185b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw            import fcntl
186b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw            import signal
187b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw            import FCNTL
188b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw            import STROPTS
189b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw            # set up the signal handler
190b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw            signal.signal(signal.SIGPOLL, self.__update)
191b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw            fcntl.ioctl(fd, STROPTS.I_SETSIG, STROPTS.S_MSG)
192b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw            self.__update()
193b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        
1942a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw    def __quit(self, event=None):
1952a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        self.__devctl.close()
1962a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        self.__root.quit()
1972a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw
1982a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw    def __keepalive(self):
1992a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        # Exercise the Python interpreter regularly so keyboard interrupts get
2002a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        # through.
2012a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        self.__tkroot.tk.createtimerhandler(KEEPALIVE_TIMER, self.__keepalive)
202b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        if self.__needtopoll:
203b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw            self.__update()
204b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw
205b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw    def __update(self, num=None, frame=None):
2062a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        # We have to poll because the device could have changed state and the
2072a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        # underlying module does not support the SIGPOLL notification
2082a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        # interface.
2092a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        info = self.__devctl.getinfo()
2102a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        self.__spkvar.set(info.o_port & SPEAKER)
2112a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        self.__headvar.set(info.o_port & HEADPHONE)
2122a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        self.__linevar.set(info.o_port & LINE_OUT)
213b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        self.__micvar.set(info.i_port & MICROPHONE)
214b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        self.__lineinvar.set(info.i_port & LINE_IN)
215b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        self.__cdvar.set(info.i_port & CD)
2162a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw
217b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw    def __pushtodev(self, event=None):
2182a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        info = self.__devctl.getinfo()
2192a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        info.o_port = self.__spkvar.get() + \
2202a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw                      self.__headvar.get() + \
2212a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw                      self.__linevar.get()
222b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        info.i_port = self.__micvar.get() + \
223b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw                      self.__lineinvar.get() + \
224b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw                      self.__cdvar.get()
2252a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        self.__devctl.setinfo(info)
2262a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw
2272a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw    def __getset(self, var, onvalue):
2282a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        if var.get():
2292a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw            var.set(0)
2302a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        else:
2312a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw            var.set(onvalue)
232b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        self.__pushtodev()
233b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw
234b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw    def __mic(self, event=None):
235b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        self.__getset(self.__micvar, MICROPHONE)
236b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw
237b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw    def __linein(self, event=None):
238b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        self.__getset(self.__lineinvar, LINE_IN)
239b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw
240b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw    def __cd(self, event=None):
2412c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        print 'pre:', self.__cdvar.get()
242b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        self.__getset(self.__cdvar, CD)
2432c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        print 'post:', self.__cdvar.get()
2442a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw
2452a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw    def __speaker(self, event=None):
2462a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        self.__getset(self.__spkvar, SPEAKER)
2472a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw
2482a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw    def __headphones(self, event=None):
2492a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        self.__getset(self.__headvar, HEADPHONE)
2502a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw
2512a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw    def __lineout(self, event=None):
2522a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        self.__getset(self.__linevar, LINE_OUT)
2532a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw
2542a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw    def start(self):
2552a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        self.__keepalive()
2562a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        self.__tkroot.mainloop()
2572a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw
2582a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw
2592a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw
2602a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsawdef usage(msg='', code=1):
2612a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw    print __doc__
2622a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw    print msg
2632a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw    sys.exit(code)
2642a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw
2652a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw
2662a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsawdef main():
2672c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw    #
2682c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw    # Open up the audio control device and query for the current output
2692c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw    # device
2702c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw    device = sunaudiodev.open('control')
2712c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw
2722a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw    if len(sys.argv) == 1:
2732a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        # GUI
2742c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        w = MainWindow(device)
275b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        try:
276b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw            w.start()
277b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        except KeyboardInterrupt:
278b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw            pass
2792a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        return
2802a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw
2812c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw    # spec:    LONG OPT, SHORT OPT, 0=input,1=output, MASK
2822c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw    options = (('--microphone', '-m', 0, MICROPHONE),
2832c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw               ('--linein',     '-i', 0, LINE_IN),
2842c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw               ('--cd',         '-c', 0, CD),
2852c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw               ('--headphones', '-p', 1, HEADPHONE),
2862c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw               ('--speaker',    '-s', 1, SPEAKER),
2872c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw               ('--lineout',    '-o', 1, LINE_OUT),
2882c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw               )
2892c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw    values = []
2902c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw    info = device.getinfo()
2912c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw    # first get the existing values
2922c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw    for long, short, io, mask in options:
2932c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        if io == 0:
2942c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw            flags = info.i_port
2952c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        else:
2962c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw            flags = info.o_port
2972c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        values.append(flags & mask)
2982c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw
2992a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw    sval = None
3002a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw    hval = None
3012a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw    lval = None
3022a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw    for arg in sys.argv[1:]:
3032a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        if arg in ('-h', '--help'):
3042a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw            usage(code=0)
3052a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        # SPEAKER
3062a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        elif arg in ('-s', '--speaker'):
3072a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw            sval = -1
3082a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        elif arg[:3] == '-s=':
3092a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw            try:
3102a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw                sval = int(arg[3:])
3112a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw            except ValueError:
3122a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw                pass
3132a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw            if sval <> 0 and sval <> 1:
3142a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw                usage('Invalid option: ' + arg)
3152a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        elif arg[:10] == '--speaker=':
3162a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw            try:
3172a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw                sval = int(arg[10:])
3182a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw            except ValueError:
3192a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw                pass
3202a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw            if sval <> 0 and sval <> 1:
3212a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw                usage('Invalid option: ' + arg)
3222a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        # HEADPHONES
3232a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        elif arg in ('-p', '--headphones'):
3242a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw            hval = -1
3252a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        elif arg[:3] == '-p=':
3262a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw            try:
3272a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw                hval = int(arg[3:])
3282a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw            except ValueError:
3292a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw                pass
3302a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw            if hval <> 0 and hval <> 1:
3312a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw                usage('Invalid option: ' + arg)
3322a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        elif arg[:13] == '--headphones=':
3332a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw            try:
3342a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw                hval = int(arg[130:])
3352a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw            except ValueError:
3362a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw                pass
3372a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw            if hval <> 0 and hval <> 1:
3382a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw                usage('Invalid option: ' + arg)
3392a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        # LINEOUT
3402a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        elif arg in ('-l', '--lineout'):
3412a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw            lval = -1
3422a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        elif arg[:3] == '-l=':
3432a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw            try:
3442a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw                lval = int(arg[3:])
3452a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw            except ValueError:
3462a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw                pass
3472a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw            if lval <> 0 and lval <> 1:
3482a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw                usage('Invalid option: ' + arg)
3492a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        elif arg[:10] == '--lineout=':
3502a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw            try:
3512a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw                lval = int(arg[10:])
3522a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw            except ValueError:
3532a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw                pass
3542a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw            if lval <> 0 and lval <> 1:
3552a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw                usage('Invalid option: ' + arg)
3562a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        else:
3572a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw            usage('Invalid option: ' + arg)
3582a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw    # now set the values
3592a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw    try:
3602a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        devctl = sunaudiodev.open('control')
3612a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        info = devctl.getinfo()
3622a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        if sval is not None:
3632a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw            if sval == -1:
3642a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw                if info.o_port & SPEAKER:
3652a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw                    sval = 0
3662a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw                else:
3672a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw                    sval = SPEAKER
3682a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw            else:
3692a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw                sval = sval * SPEAKER
3702a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        else:
3712a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw            sval = info.o_port & SPEAKER
3722a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        if hval is not None:
3732a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw            if hval == -1:
3742a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw                if info.o_port & HEADPHONE:
3752a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw                    hval = 0
3762a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw                else:
3772a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw                    hval = HEADPHONE
3782a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw            else:
3792a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw                hval = hval * HEADPHONE
3802a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        else:
3812a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw            hval = info.o_port & HEADPHONE
3822a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        if lval is not None:
3832a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw            if lval == -1:
3842a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw                if info.o_port & LINE_OUT:
3852a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw                    lval = 0
3862a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw                else:
3872a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw                    lval = LINE_OUT
3882a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw            else:
3892a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw                lval = lval * LINE_OUT
3902a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        else:
3912a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw            lval = info.o_port & LINE_OUT
3922a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        info.o_port = sval + hval + lval
3932a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        devctl.setinfo(info)
3942a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw    finally:
3952a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        devctl.close()
3962a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw            
3972a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw
3982a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw
3992a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsawif __name__ == '__main__':
4002a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw    main()
401