audiopy revision 2858b43613ca50f21aab629140ffc84278d3b0d8
12a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw#! /usr/bin/env python
22a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw
3d81d534aef5fe8d6c081121dd545623e7ea2e889Barry Warsaw"""audiopy -- a program to control the Solaris audio device.
42a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw
5d81d534aef5fe8d6c081121dd545623e7ea2e889Barry WarsawAuthor:  Barry Warsaw
6d81d534aef5fe8d6c081121dd545623e7ea2e889Barry WarsawEmail:   bwarsaw@python.org
7d81d534aef5fe8d6c081121dd545623e7ea2e889Barry WarsawVersion: %(__version__)s
8f79b7e274cfd7466115cce88c586d603a430122bBarry Warsaw
92a06084ed51d06cdea9544b5ab02586d300dec83Barry WarsawWhen no arguments are given, this pops up a graphical window which lets you
103febc2443cd3360c4da0dafae26b3530d363368aBarry Warsawchoose the audio input and output devices.
112a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw
122a06084ed51d06cdea9544b5ab02586d300dec83Barry WarsawThis program can be driven via the command line, and when done so, no window
132c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsawpops up.  Options have the general form:
142a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw
152c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw    --device[={0,1}]
162c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw    -d[={0,1}]
172c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        Set the I/O device.  With no value, it toggles the specified device.
182c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        With a value, 0 turns the device off and 1 turns the device on.
192a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw
202c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry WarsawThe list of devices and their short options are:
212a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw
222c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw (input)
232c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw    microphone  -- m
242c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw    linein      -- i
252c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw    cd          -- c
262c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw
272c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw (output)
282c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw    headphones  -- p
292c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw    speaker     -- s
302c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw    lineout     -- o
312c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw
322c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry WarsawOther options are:
332a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw
343febc2443cd3360c4da0dafae26b3530d363368aBarry Warsaw    --version
353febc2443cd3360c4da0dafae26b3530d363368aBarry Warsaw    -v
363febc2443cd3360c4da0dafae26b3530d363368aBarry Warsaw        Print the version number and exit.
373febc2443cd3360c4da0dafae26b3530d363368aBarry Warsaw
382a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw    --help
392a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw    -h
402a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        Print this message and exit.
412a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw"""
422a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw
432a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsawimport sys
442a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsawimport sunaudiodev
452a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsawfrom SUNAUDIODEV import *
462a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw
472a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw# Milliseconds between interrupt checks
482a06084ed51d06cdea9544b5ab02586d300dec83Barry WarsawKEEPALIVE_TIMER = 500
492a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw
50d81d534aef5fe8d6c081121dd545623e7ea2e889Barry Warsaw__version__ = '0.1'
513febc2443cd3360c4da0dafae26b3530d363368aBarry Warsaw
522a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw
532a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw
542a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsawclass MainWindow:
552c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw    def __init__(self, device):
569ade9ddb147288478748c751ea715a708a7ed2cfBarry Warsaw        from Tkinter import *
572c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        self.__devctl = device
582c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        info = device.getinfo()
592c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        #
603febc2443cd3360c4da0dafae26b3530d363368aBarry Warsaw        self.__tkroot = tkroot = Tk(className='Audiopy')
612a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        tkroot.withdraw()
622a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        # now create the top level window
632c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        root = self.__root = Toplevel(tkroot, class_='Audiopy')
642a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        root.protocol('WM_DELETE_WINDOW', self.__quit)
653febc2443cd3360c4da0dafae26b3530d363368aBarry Warsaw        root.title('audiopy ' + __version__)
663febc2443cd3360c4da0dafae26b3530d363368aBarry Warsaw        root.iconname('audiopy ' + __version__)
672a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        root.tk.createtimerhandler(KEEPALIVE_TIMER, self.__keepalive)
682a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        #
692c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        buttons = []
702a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        #
71b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        # where does input come from?
72b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        frame = Frame(root, bd=1, relief=RAISED)
73e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw        frame.grid(row=0, column=0, sticky='NSEW')
74b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        label = Label(frame, text='Input From:')
75b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        label.grid(row=0, column=0, sticky=E)
76e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw        self.__inputvar = IntVar()
77441abb4c8fa5f37c9dd24dd2478c6df57860534cBarry Warsaw        ##
78441abb4c8fa5f37c9dd24dd2478c6df57860534cBarry Warsaw        btn = Radiobutton(frame,
79441abb4c8fa5f37c9dd24dd2478c6df57860534cBarry Warsaw                          text='None',
80441abb4c8fa5f37c9dd24dd2478c6df57860534cBarry Warsaw                          variable=self.__inputvar,
81441abb4c8fa5f37c9dd24dd2478c6df57860534cBarry Warsaw                          value=0,
82441abb4c8fa5f37c9dd24dd2478c6df57860534cBarry Warsaw                          command=self.__pushtodev,
83441abb4c8fa5f37c9dd24dd2478c6df57860534cBarry Warsaw                          underline=0)
84441abb4c8fa5f37c9dd24dd2478c6df57860534cBarry Warsaw        btn.grid(row=0, column=1, sticky=W)
85441abb4c8fa5f37c9dd24dd2478c6df57860534cBarry Warsaw        root.bind('<Alt-n>', self.__none)
86441abb4c8fa5f37c9dd24dd2478c6df57860534cBarry Warsaw        root.bind('<Alt-N>', self.__none)
87441abb4c8fa5f37c9dd24dd2478c6df57860534cBarry Warsaw        if not info.i_avail_ports & MICROPHONE:
88441abb4c8fa5f37c9dd24dd2478c6df57860534cBarry Warsaw            btn.configure(state=DISABLED)
89441abb4c8fa5f37c9dd24dd2478c6df57860534cBarry Warsaw        buttons.append(btn)
90441abb4c8fa5f37c9dd24dd2478c6df57860534cBarry Warsaw        ##
91e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw        btn = Radiobutton(frame,
92b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw                          text='Microphone',
93e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw                          variable=self.__inputvar,
94e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw                          value=MICROPHONE,
95b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw                          command=self.__pushtodev,
96b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw                          underline=0)
97441abb4c8fa5f37c9dd24dd2478c6df57860534cBarry Warsaw        btn.grid(row=1, column=1, sticky=W)
98b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        root.bind('<Alt-m>', self.__mic)
99b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        root.bind('<Alt-M>', self.__mic)
1002c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        if not info.i_avail_ports & MICROPHONE:
1012c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw            btn.configure(state=DISABLED)
1022c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        buttons.append(btn)
1032c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        ##
104e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw        btn = Radiobutton(frame,
105b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw                          text='Line In',
106e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw                          variable=self.__inputvar,
107e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw                          value=LINE_IN,
108b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw                          command=self.__pushtodev,
109b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw                          underline=5)
110441abb4c8fa5f37c9dd24dd2478c6df57860534cBarry Warsaw        btn.grid(row=2, column=1, sticky=W)
111b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        root.bind('<Alt-i>', self.__linein)
112b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        root.bind('<Alt-I>', self.__linein)
1132c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        if not info.i_avail_ports & LINE_IN:
1142c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw            btn.configure(state=DISABLED)
1152c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        buttons.append(btn)
116d55049aedea656a4509537a11853bd556ccfb013Barry Warsaw        ## if SUNAUDIODEV was built on an older version of Solaris, the CD
117d55049aedea656a4509537a11853bd556ccfb013Barry Warsaw        ## input device won't exist
118d55049aedea656a4509537a11853bd556ccfb013Barry Warsaw        try:
119d55049aedea656a4509537a11853bd556ccfb013Barry Warsaw            btn = Radiobutton(frame,
120d55049aedea656a4509537a11853bd556ccfb013Barry Warsaw                              text='CD',
121d55049aedea656a4509537a11853bd556ccfb013Barry Warsaw                              variable=self.__inputvar,
122d55049aedea656a4509537a11853bd556ccfb013Barry Warsaw                              value=CD,
123d55049aedea656a4509537a11853bd556ccfb013Barry Warsaw                              command=self.__pushtodev,
124d55049aedea656a4509537a11853bd556ccfb013Barry Warsaw                              underline=0)
125441abb4c8fa5f37c9dd24dd2478c6df57860534cBarry Warsaw            btn.grid(row=3, column=1, sticky=W)
126d55049aedea656a4509537a11853bd556ccfb013Barry Warsaw            root.bind('<Alt-c>', self.__cd)
127d55049aedea656a4509537a11853bd556ccfb013Barry Warsaw            root.bind('<Alt-C>', self.__cd)
128d55049aedea656a4509537a11853bd556ccfb013Barry Warsaw            if not info.i_avail_ports & CD:
129d55049aedea656a4509537a11853bd556ccfb013Barry Warsaw                btn.configure(state=DISABLED)
130d55049aedea656a4509537a11853bd556ccfb013Barry Warsaw            buttons.append(btn)
131d55049aedea656a4509537a11853bd556ccfb013Barry Warsaw        except NameError:
132d55049aedea656a4509537a11853bd556ccfb013Barry Warsaw            pass
133b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        #
134b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        # where does output go to?
135b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        frame = Frame(root, bd=1, relief=RAISED)
136e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw        frame.grid(row=1, column=0, sticky='NSEW')
137b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        label = Label(frame, text='Output To:')
1382a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        label.grid(row=0, column=0, sticky=E)
1392a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        self.__spkvar = IntVar()
140b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        btn = Checkbutton(frame,
1412a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw                          text='Speaker',
1422a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw                          variable=self.__spkvar,
1432a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw                          onvalue=SPEAKER,
144b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw                          command=self.__pushtodev,
1452a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw                          underline=0)
1462a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        btn.grid(row=0, column=1, sticky=W)
1472a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        root.bind('<Alt-s>', self.__speaker)
1482a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        root.bind('<Alt-S>', self.__speaker)
1492c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        if not info.o_avail_ports & SPEAKER:
1502c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw            btn.configure(state=DISABLED)
1512c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        buttons.append(btn)
1522c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        ##
1532a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        self.__headvar = IntVar()
154b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        btn = Checkbutton(frame,
1552a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw                          text='Headphones',
1562a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw                          variable=self.__headvar,
1572a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw                          onvalue=HEADPHONE,
158b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw                          command=self.__pushtodev,
1592a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw                          underline=0)
1602a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        btn.grid(row=1, column=1, sticky=W)
1612a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        root.bind('<Alt-h>', self.__headphones)
1622a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        root.bind('<Alt-H>', self.__headphones)
1632c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        if not info.o_avail_ports & HEADPHONE:
1642c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw            btn.configure(state=DISABLED)
1652c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        buttons.append(btn)
1662c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        ##
1672a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        self.__linevar = IntVar()
168b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        btn = Checkbutton(frame,
1692a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw                          variable=self.__linevar,
1702a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw                          onvalue=LINE_OUT,
171b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw                          text='Line Out',
172b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw                          command=self.__pushtodev,
1732a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw                          underline=0)
1742a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        btn.grid(row=2, column=1, sticky=W)
1752a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        root.bind('<Alt-l>', self.__lineout)
1762a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        root.bind('<Alt-L>', self.__lineout)
1772c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        if not info.o_avail_ports & LINE_OUT:
1782c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw            btn.configure(state=DISABLED)
1792c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        buttons.append(btn)
1802c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        #
1812c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        # Fix up widths
1822c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        widest = 0
1832c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        for b in buttons:
1842c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw            width = b['width']
1852c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw            if width > widest:
1862c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw                widest = width
1872c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        for b in buttons:
1882c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw            b.configure(width=widest)
1892c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        #
1902c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        # Add quit button
1912c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        frame = Frame(root)
1922c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        frame.grid(row=2, column=0, sticky='EW', ipady=5)
1932c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        btn = Button(frame,
1942c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw                     text='Quit',
1952c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw                     command=self.__quit,
1962c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw                     underline=0)
1972c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        btn.pack(expand=YES)
1982c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        root.bind('<Alt-q>', self.__quit)
1992c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        root.bind('<Alt-Q>', self.__quit)
200b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        #
201b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        # do we need to poll for changes?
202b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        self.__needtopoll = 1
203b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        try:
204b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw            fd = self.__devctl.fileno()
205b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw            self.__needtopoll = 0
206b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        except AttributeError:
207b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw            pass
208b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        else:
209b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw            import fcntl
210b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw            import signal
211b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw            import STROPTS
212b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw            # set up the signal handler
213b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw            signal.signal(signal.SIGPOLL, self.__update)
214b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw            fcntl.ioctl(fd, STROPTS.I_SETSIG, STROPTS.S_MSG)
215b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw            self.__update()
216b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        
2172a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw    def __quit(self, event=None):
2182a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        self.__devctl.close()
2192a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        self.__root.quit()
2202a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw
2212a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw    def __keepalive(self):
2222a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        # Exercise the Python interpreter regularly so keyboard interrupts get
2232a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        # through.
2242a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        self.__tkroot.tk.createtimerhandler(KEEPALIVE_TIMER, self.__keepalive)
225b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        if self.__needtopoll:
226b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw            self.__update()
227b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw
228b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw    def __update(self, num=None, frame=None):
2292a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        # We have to poll because the device could have changed state and the
2302a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        # underlying module does not support the SIGPOLL notification
2312a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        # interface.
2322a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        info = self.__devctl.getinfo()
233e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw        # input
234e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw        self.__inputvar.set(info.i_port)
235e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw        # output
2362a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        self.__spkvar.set(info.o_port & SPEAKER)
2372a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        self.__headvar.set(info.o_port & HEADPHONE)
2382a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        self.__linevar.set(info.o_port & LINE_OUT)
2392a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw
240b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw    def __pushtodev(self, event=None):
2412a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        info = self.__devctl.getinfo()
2422a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        info.o_port = self.__spkvar.get() + \
2432a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw                      self.__headvar.get() + \
2442a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw                      self.__linevar.get()
245e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw        info.i_port = self.__inputvar.get()
2462a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        self.__devctl.setinfo(info)
2472a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw
2482a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw    def __getset(self, var, onvalue):
249441abb4c8fa5f37c9dd24dd2478c6df57860534cBarry Warsaw        if var.get() == onvalue:
2502a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw            var.set(0)
2512a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        else:
2522a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw            var.set(onvalue)
253b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        self.__pushtodev()
254441abb4c8fa5f37c9dd24dd2478c6df57860534cBarry Warsaw
255441abb4c8fa5f37c9dd24dd2478c6df57860534cBarry Warsaw    def __none(self, event=None):
256441abb4c8fa5f37c9dd24dd2478c6df57860534cBarry Warsaw        self.__inputvar.set(0)
257441abb4c8fa5f37c9dd24dd2478c6df57860534cBarry Warsaw        self.__pushtodev()
258b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw
259b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw    def __mic(self, event=None):
260e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw        self.__getset(self.__inputvar, MICROPHONE)
261b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw
262b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw    def __linein(self, event=None):
263e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw        self.__getset(self.__inputvar, LINE_IN)
264b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw
265b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw    def __cd(self, event=None):
266e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw        self.__getset(self.__inputvar, CD)
2672a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw
2682a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw    def __speaker(self, event=None):
2692a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        self.__getset(self.__spkvar, SPEAKER)
2702a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw
2712a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw    def __headphones(self, event=None):
2722a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        self.__getset(self.__headvar, HEADPHONE)
2732a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw
2742a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw    def __lineout(self, event=None):
2752a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        self.__getset(self.__linevar, LINE_OUT)
2762a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw
2772a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw    def start(self):
2782a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        self.__keepalive()
2792a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        self.__tkroot.mainloop()
2802a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw
2812a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw
2822a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw
2832a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsawdef usage(msg='', code=1):
284d81d534aef5fe8d6c081121dd545623e7ea2e889Barry Warsaw    print __doc__ % globals()
2852858b43613ca50f21aab629140ffc84278d3b0d8Barry Warsaw    if msg:
2862858b43613ca50f21aab629140ffc84278d3b0d8Barry Warsaw        print msg
2872a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw    sys.exit(code)
2882a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw
2892a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw
2902a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsawdef main():
2912c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw    #
2922c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw    # Open up the audio control device and query for the current output
2932c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw    # device
2942c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw    device = sunaudiodev.open('control')
2952c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw
2962a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw    if len(sys.argv) == 1:
2972a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        # GUI
2982c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        w = MainWindow(device)
299b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        try:
300b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw            w.start()
301b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        except KeyboardInterrupt:
302b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw            pass
3032a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        return
3042a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw
3052c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw    # spec:    LONG OPT, SHORT OPT, 0=input,1=output, MASK
306d55049aedea656a4509537a11853bd556ccfb013Barry Warsaw    options = [('--microphone', '-m', 0, MICROPHONE),
3072c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw               ('--linein',     '-i', 0, LINE_IN),
3082c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw               ('--headphones', '-p', 1, HEADPHONE),
3092c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw               ('--speaker',    '-s', 1, SPEAKER),
3102c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw               ('--lineout',    '-o', 1, LINE_OUT),
311d55049aedea656a4509537a11853bd556ccfb013Barry Warsaw               ]
312d55049aedea656a4509537a11853bd556ccfb013Barry Warsaw    # See the comment above about `CD'
313d55049aedea656a4509537a11853bd556ccfb013Barry Warsaw    try:
314d55049aedea656a4509537a11853bd556ccfb013Barry Warsaw        options.append(('--cd',         '-c', 0, CD))
315d55049aedea656a4509537a11853bd556ccfb013Barry Warsaw    except NameError:
316d55049aedea656a4509537a11853bd556ccfb013Barry Warsaw        pass
317d55049aedea656a4509537a11853bd556ccfb013Barry Warsaw
3182c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw    info = device.getinfo()
3192c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw    # first get the existing values
3202a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw    for arg in sys.argv[1:]:
3212a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        if arg in ('-h', '--help'):
3222a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw            usage(code=0)
323e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw            # does not return
3243febc2443cd3360c4da0dafae26b3530d363368aBarry Warsaw        elif arg in ('-v', '--version'):
325d81d534aef5fe8d6c081121dd545623e7ea2e889Barry Warsaw            print '''\
326d81d534aef5fe8d6c081121dd545623e7ea2e889Barry Warsawaudiopy -- a program to control the Solaris audio device.
327d81d534aef5fe8d6c081121dd545623e7ea2e889Barry WarsawAuthor:  Barry Warsaw
328d81d534aef5fe8d6c081121dd545623e7ea2e889Barry WarsawEmail:   bwarsaw@python.org
329d81d534aef5fe8d6c081121dd545623e7ea2e889Barry WarsawVersion: %s''' % __version__            
3303febc2443cd3360c4da0dafae26b3530d363368aBarry Warsaw            sys.exit(0)
331e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw        for long, short, io, mask in options:
332e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw            if arg in (long, short):
333e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw                # toggle the option
334e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw                if io == 0: 
335e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw                    info.i_port = info.i_port ^ mask
336e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw                else:
337e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw                    info.o_port = info.o_port ^ mask
338e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw                break
339e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw            val = None
3402a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw            try:
341e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw                if arg[:len(long)+1] == long+'=':
342e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw                    val = int(arg[len(long)+1:])
343e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw                elif arg[:len(short)+1] == short+'=':
344e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw                    val = int(arg[len(short)+1:])
3452a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw            except ValueError:
346e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw                usage(msg='Invalid option: ' + arg)
347e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw                # does not return
348e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw            if val == 0:
349e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw                if io == 0:
350e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw                    info.i_port = info.i_port & ~mask
3512a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw                else:
352e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw                    info.o_port = info.o_port & ~mask
353e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw                break
354e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw            elif val == 1:
355e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw                if io == 0:
356e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw                    info.i_port = info.i_port | mask
3572a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw                else:
358e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw                    info.o_port = info.o_port | mask
359e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw                break
360e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw            # else keep trying next option
3612a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        else:
362e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw            usage(msg='Invalid option: ' + arg)
363e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw    # now set the values
364e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw    device.setinfo(info)
365e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw    device.close()
3662a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw            
3672a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw
3682a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw
3692a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsawif __name__ == '__main__':
3702a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw    main()
371