12a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw#! /usr/bin/env python
22a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw
3d81d534aef5fe8d6c081121dd545623e7ea2e889Barry Warsaw"""audiopy -- a program to control the Solaris audio device.
42a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw
588604056c5d64cabfea975511c84155bbbc778e1Barry WarsawContact: 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
10a4b055ff8924b8965c8ac4f6d3b532a85f6ebd35Barry Warsawchoose the audio input and output devices, and set the output volume.
112a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw
122a06084ed51d06cdea9544b5ab02586d300dec83Barry WarsawThis program can be driven via the command line, and when done so, no window
13a4b055ff8924b8965c8ac4f6d3b532a85f6ebd35Barry Warsawpops up.  Most 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
34a4b055ff8924b8965c8ac4f6d3b532a85f6ebd35Barry Warsaw    --gain volume
35a4b055ff8924b8965c8ac4f6d3b532a85f6ebd35Barry Warsaw    -g volume
36a4b055ff8924b8965c8ac4f6d3b532a85f6ebd35Barry Warsaw        Sets the output gain to the specified volume, which must be an integer
37a4b055ff8924b8965c8ac4f6d3b532a85f6ebd35Barry Warsaw        in the range [%(MIN_GAIN)s..%(MAX_GAIN)s]
38a4b055ff8924b8965c8ac4f6d3b532a85f6ebd35Barry Warsaw
393febc2443cd3360c4da0dafae26b3530d363368aBarry Warsaw    --version
403febc2443cd3360c4da0dafae26b3530d363368aBarry Warsaw    -v
413febc2443cd3360c4da0dafae26b3530d363368aBarry Warsaw        Print the version number and exit.
423febc2443cd3360c4da0dafae26b3530d363368aBarry Warsaw
432a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw    --help
442a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw    -h
452a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        Print this message and exit.
462a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw"""
472a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw
482a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsawimport sys
49f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsawimport os
50d8d179d69d46a07923ad07b70a2d5f5e57f8030aBarry Warsawimport errno
512a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsawimport sunaudiodev
522a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsawfrom SUNAUDIODEV import *
532a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw
542a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw# Milliseconds between interrupt checks
552a06084ed51d06cdea9544b5ab02586d300dec83Barry WarsawKEEPALIVE_TIMER = 500
562a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw
57772d69676eba256d9b2706152114ffe243abf8b6Barry Warsaw__version__ = '1.1'
583febc2443cd3360c4da0dafae26b3530d363368aBarry Warsaw
592a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw
602a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw
612a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsawclass MainWindow:
622c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw    def __init__(self, device):
639ade9ddb147288478748c751ea715a708a7ed2cfBarry Warsaw        from Tkinter import *
64f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw        self.__helpwin = None
652c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        self.__devctl = device
662c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        info = device.getinfo()
672c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        #
683febc2443cd3360c4da0dafae26b3530d363368aBarry Warsaw        self.__tkroot = tkroot = Tk(className='Audiopy')
692a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        tkroot.withdraw()
70f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw        # create the menubar
71f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw        menubar = Menu(tkroot)
72f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw        filemenu = Menu(menubar, tearoff=0)
73f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw        filemenu.add_command(label='Quit',
74f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw                             command=self.__quit,
75f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw                             accelerator='Alt-Q',
76f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw                             underline=0)
77f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw        helpmenu = Menu(menubar, name='help', tearoff=0)
78f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw        helpmenu.add_command(label='About Audiopy...',
79f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw                             command=self.__popup_about,
80f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw                             underline=0)
81f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw        helpmenu.add_command(label='Help...',
82f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw                             command=self.__popup_using,
83f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw                             underline=0)
84f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw        menubar.add_cascade(label='File',
85f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw                            menu=filemenu,
86f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw                            underline=0)
87f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw        menubar.add_cascade(label='Help',
88f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw                            menu=helpmenu,
89f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw                            underline=0)
902a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        # now create the top level window
91f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw        root = self.__root = Toplevel(tkroot, class_='Audiopy', menu=menubar)
922a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        root.protocol('WM_DELETE_WINDOW', self.__quit)
933febc2443cd3360c4da0dafae26b3530d363368aBarry Warsaw        root.title('audiopy ' + __version__)
943febc2443cd3360c4da0dafae26b3530d363368aBarry Warsaw        root.iconname('audiopy ' + __version__)
952a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        root.tk.createtimerhandler(KEEPALIVE_TIMER, self.__keepalive)
962a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        #
972c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        buttons = []
982a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        #
99b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        # where does input come from?
100b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        frame = Frame(root, bd=1, relief=RAISED)
101f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw        frame.grid(row=1, column=0, sticky='NSEW')
102b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        label = Label(frame, text='Input From:')
103b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        label.grid(row=0, column=0, sticky=E)
104e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw        self.__inputvar = IntVar()
105441abb4c8fa5f37c9dd24dd2478c6df57860534cBarry Warsaw        ##
106441abb4c8fa5f37c9dd24dd2478c6df57860534cBarry Warsaw        btn = Radiobutton(frame,
107441abb4c8fa5f37c9dd24dd2478c6df57860534cBarry Warsaw                          text='None',
108441abb4c8fa5f37c9dd24dd2478c6df57860534cBarry Warsaw                          variable=self.__inputvar,
109441abb4c8fa5f37c9dd24dd2478c6df57860534cBarry Warsaw                          value=0,
110441abb4c8fa5f37c9dd24dd2478c6df57860534cBarry Warsaw                          command=self.__pushtodev,
111441abb4c8fa5f37c9dd24dd2478c6df57860534cBarry Warsaw                          underline=0)
112441abb4c8fa5f37c9dd24dd2478c6df57860534cBarry Warsaw        btn.grid(row=0, column=1, sticky=W)
113441abb4c8fa5f37c9dd24dd2478c6df57860534cBarry Warsaw        root.bind('<Alt-n>', self.__none)
114441abb4c8fa5f37c9dd24dd2478c6df57860534cBarry Warsaw        root.bind('<Alt-N>', self.__none)
115441abb4c8fa5f37c9dd24dd2478c6df57860534cBarry Warsaw        if not info.i_avail_ports & MICROPHONE:
116441abb4c8fa5f37c9dd24dd2478c6df57860534cBarry Warsaw            btn.configure(state=DISABLED)
117441abb4c8fa5f37c9dd24dd2478c6df57860534cBarry Warsaw        buttons.append(btn)
118441abb4c8fa5f37c9dd24dd2478c6df57860534cBarry Warsaw        ##
119e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw        btn = Radiobutton(frame,
120b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw                          text='Microphone',
121e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw                          variable=self.__inputvar,
122e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw                          value=MICROPHONE,
123b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw                          command=self.__pushtodev,
124b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw                          underline=0)
125441abb4c8fa5f37c9dd24dd2478c6df57860534cBarry Warsaw        btn.grid(row=1, column=1, sticky=W)
126b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        root.bind('<Alt-m>', self.__mic)
127b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        root.bind('<Alt-M>', self.__mic)
1282c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        if not info.i_avail_ports & MICROPHONE:
1292c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw            btn.configure(state=DISABLED)
1302c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        buttons.append(btn)
1312c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        ##
132e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw        btn = Radiobutton(frame,
133b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw                          text='Line In',
134e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw                          variable=self.__inputvar,
135e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw                          value=LINE_IN,
136b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw                          command=self.__pushtodev,
137b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw                          underline=5)
138441abb4c8fa5f37c9dd24dd2478c6df57860534cBarry Warsaw        btn.grid(row=2, column=1, sticky=W)
139b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        root.bind('<Alt-i>', self.__linein)
140b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        root.bind('<Alt-I>', self.__linein)
1412c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        if not info.i_avail_ports & LINE_IN:
1422c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw            btn.configure(state=DISABLED)
1432c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        buttons.append(btn)
144d55049aedea656a4509537a11853bd556ccfb013Barry Warsaw        ## if SUNAUDIODEV was built on an older version of Solaris, the CD
145d55049aedea656a4509537a11853bd556ccfb013Barry Warsaw        ## input device won't exist
146d55049aedea656a4509537a11853bd556ccfb013Barry Warsaw        try:
147d55049aedea656a4509537a11853bd556ccfb013Barry Warsaw            btn = Radiobutton(frame,
148d55049aedea656a4509537a11853bd556ccfb013Barry Warsaw                              text='CD',
149d55049aedea656a4509537a11853bd556ccfb013Barry Warsaw                              variable=self.__inputvar,
150d55049aedea656a4509537a11853bd556ccfb013Barry Warsaw                              value=CD,
151d55049aedea656a4509537a11853bd556ccfb013Barry Warsaw                              command=self.__pushtodev,
152d55049aedea656a4509537a11853bd556ccfb013Barry Warsaw                              underline=0)
153441abb4c8fa5f37c9dd24dd2478c6df57860534cBarry Warsaw            btn.grid(row=3, column=1, sticky=W)
154d55049aedea656a4509537a11853bd556ccfb013Barry Warsaw            root.bind('<Alt-c>', self.__cd)
155d55049aedea656a4509537a11853bd556ccfb013Barry Warsaw            root.bind('<Alt-C>', self.__cd)
156d55049aedea656a4509537a11853bd556ccfb013Barry Warsaw            if not info.i_avail_ports & CD:
157d55049aedea656a4509537a11853bd556ccfb013Barry Warsaw                btn.configure(state=DISABLED)
158d55049aedea656a4509537a11853bd556ccfb013Barry Warsaw            buttons.append(btn)
159d55049aedea656a4509537a11853bd556ccfb013Barry Warsaw        except NameError:
160d55049aedea656a4509537a11853bd556ccfb013Barry Warsaw            pass
161b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        #
162b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        # where does output go to?
163b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        frame = Frame(root, bd=1, relief=RAISED)
164f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw        frame.grid(row=2, column=0, sticky='NSEW')
165b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        label = Label(frame, text='Output To:')
1662a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        label.grid(row=0, column=0, sticky=E)
1672a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        self.__spkvar = IntVar()
168b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        btn = Checkbutton(frame,
1692a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw                          text='Speaker',
1702a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw                          variable=self.__spkvar,
1712a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw                          onvalue=SPEAKER,
172b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw                          command=self.__pushtodev,
1732a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw                          underline=0)
1742a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        btn.grid(row=0, column=1, sticky=W)
1752a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        root.bind('<Alt-s>', self.__speaker)
1762a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        root.bind('<Alt-S>', self.__speaker)
1772c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        if not info.o_avail_ports & SPEAKER:
1782c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw            btn.configure(state=DISABLED)
1792c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        buttons.append(btn)
1802c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        ##
1812a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        self.__headvar = IntVar()
182b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        btn = Checkbutton(frame,
1832a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw                          text='Headphones',
1842a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw                          variable=self.__headvar,
1852a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw                          onvalue=HEADPHONE,
186b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw                          command=self.__pushtodev,
187f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw                          underline=4)
1882a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        btn.grid(row=1, column=1, sticky=W)
189f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw        root.bind('<Alt-p>', self.__headphones)
190f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw        root.bind('<Alt-P>', self.__headphones)
1912c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        if not info.o_avail_ports & HEADPHONE:
1922c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw            btn.configure(state=DISABLED)
1932c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        buttons.append(btn)
1942c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        ##
1952a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        self.__linevar = IntVar()
196b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        btn = Checkbutton(frame,
1972a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw                          variable=self.__linevar,
1982a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw                          onvalue=LINE_OUT,
199b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw                          text='Line Out',
200b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw                          command=self.__pushtodev,
2012a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw                          underline=0)
2022a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        btn.grid(row=2, column=1, sticky=W)
2032a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        root.bind('<Alt-l>', self.__lineout)
2042a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        root.bind('<Alt-L>', self.__lineout)
2052c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        if not info.o_avail_ports & LINE_OUT:
2062c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw            btn.configure(state=DISABLED)
2072c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        buttons.append(btn)
2082c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        #
2092c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        # Fix up widths
2102c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        widest = 0
2112c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        for b in buttons:
2122c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw            width = b['width']
2132c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw            if width > widest:
2142c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw                widest = width
2152c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        for b in buttons:
2162c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw            b.configure(width=widest)
217f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw        # root bindings
2182c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        root.bind('<Alt-q>', self.__quit)
2192c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        root.bind('<Alt-Q>', self.__quit)
220b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        #
221a4b055ff8924b8965c8ac4f6d3b532a85f6ebd35Barry Warsaw        # Volume
222a4b055ff8924b8965c8ac4f6d3b532a85f6ebd35Barry Warsaw        frame = Frame(root, bd=1, relief=RAISED)
223a4b055ff8924b8965c8ac4f6d3b532a85f6ebd35Barry Warsaw        frame.grid(row=3, column=0, sticky='NSEW')
224a4b055ff8924b8965c8ac4f6d3b532a85f6ebd35Barry Warsaw        label = Label(frame, text='Output Volume:')
225a4b055ff8924b8965c8ac4f6d3b532a85f6ebd35Barry Warsaw        label.grid(row=0, column=0, sticky=W)
226a4b055ff8924b8965c8ac4f6d3b532a85f6ebd35Barry Warsaw        self.__scalevar = IntVar()
227a4b055ff8924b8965c8ac4f6d3b532a85f6ebd35Barry Warsaw        self.__scale = Scale(frame,
228a4b055ff8924b8965c8ac4f6d3b532a85f6ebd35Barry Warsaw                             orient=HORIZONTAL,
229a4b055ff8924b8965c8ac4f6d3b532a85f6ebd35Barry Warsaw                             from_=MIN_GAIN,
230a4b055ff8924b8965c8ac4f6d3b532a85f6ebd35Barry Warsaw                             to=MAX_GAIN,
231a4b055ff8924b8965c8ac4f6d3b532a85f6ebd35Barry Warsaw                             length=200,
232a4b055ff8924b8965c8ac4f6d3b532a85f6ebd35Barry Warsaw                             variable=self.__scalevar,
233a4b055ff8924b8965c8ac4f6d3b532a85f6ebd35Barry Warsaw                             command=self.__volume)
234a4b055ff8924b8965c8ac4f6d3b532a85f6ebd35Barry Warsaw        self.__scale.grid(row=1, column=0, sticky=EW)
235a4b055ff8924b8965c8ac4f6d3b532a85f6ebd35Barry Warsaw        #
236b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        # do we need to poll for changes?
237b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        self.__needtopoll = 1
238b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        try:
239b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw            fd = self.__devctl.fileno()
240b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw            self.__needtopoll = 0
241b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        except AttributeError:
242b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw            pass
243b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        else:
244b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw            import fcntl
245b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw            import signal
246b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw            import STROPTS
247b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw            # set up the signal handler
248b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw            signal.signal(signal.SIGPOLL, self.__update)
249b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw            fcntl.ioctl(fd, STROPTS.I_SETSIG, STROPTS.S_MSG)
250b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw            self.__update()
251b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        
2522a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw    def __quit(self, event=None):
2532a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        self.__devctl.close()
2542a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        self.__root.quit()
2552a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw
256f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw    def __popup_about(self, event=None):
257f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw        import tkMessageBox
258f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw        tkMessageBox.showinfo('About Audiopy ' + __version__,
259f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw                              '''\
260f622a33b295647acfa7d673cd82ac55002157e9aBarry WarsawAudiopy %s
261f622a33b295647acfa7d673cd82ac55002157e9aBarry WarsawControl the Solaris audio device
262f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw
26388604056c5d64cabfea975511c84155bbbc778e1Barry WarsawFor information
26488604056c5d64cabfea975511c84155bbbc778e1Barry WarsawContact: Barry A. Warsaw
26588604056c5d64cabfea975511c84155bbbc778e1Barry WarsawEmail:   bwarsaw@python.org''' % __version__)
266f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw
267f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw    def __popup_using(self, event=None):
268f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw        if not self.__helpwin:
269f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw            self.__helpwin = Helpwin(self.__tkroot, self.__quit)
270f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw        self.__helpwin.deiconify()
271f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw            
272f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw
2732a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw    def __keepalive(self):
2742a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        # Exercise the Python interpreter regularly so keyboard interrupts get
2752a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        # through.
2762a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        self.__tkroot.tk.createtimerhandler(KEEPALIVE_TIMER, self.__keepalive)
277b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        if self.__needtopoll:
278b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw            self.__update()
279b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw
280b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw    def __update(self, num=None, frame=None):
281772d69676eba256d9b2706152114ffe243abf8b6Barry Warsaw        # It's possible (although I have never seen it) to get an interrupted
282772d69676eba256d9b2706152114ffe243abf8b6Barry Warsaw        # system call during the getinfo() call.  If so, and we're polling,
283772d69676eba256d9b2706152114ffe243abf8b6Barry Warsaw        # don't sweat it because we'll come around again later.  Otherwise,
284772d69676eba256d9b2706152114ffe243abf8b6Barry Warsaw        # we'll give it a couple of tries and then give up until next time.
285772d69676eba256d9b2706152114ffe243abf8b6Barry Warsaw        tries = 0
286772d69676eba256d9b2706152114ffe243abf8b6Barry Warsaw        while 1:
287772d69676eba256d9b2706152114ffe243abf8b6Barry Warsaw            try:
288772d69676eba256d9b2706152114ffe243abf8b6Barry Warsaw                info = self.__devctl.getinfo()
289772d69676eba256d9b2706152114ffe243abf8b6Barry Warsaw                break
290772d69676eba256d9b2706152114ffe243abf8b6Barry Warsaw            except sunaudiodev.error:
291772d69676eba256d9b2706152114ffe243abf8b6Barry Warsaw                if self.__needtopoll or tries > 3:
292772d69676eba256d9b2706152114ffe243abf8b6Barry Warsaw                    return
293772d69676eba256d9b2706152114ffe243abf8b6Barry Warsaw                tries = tries + 1
294e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw        # input
295e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw        self.__inputvar.set(info.i_port)
296e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw        # output
2972a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        self.__spkvar.set(info.o_port & SPEAKER)
2982a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        self.__headvar.set(info.o_port & HEADPHONE)
2992a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        self.__linevar.set(info.o_port & LINE_OUT)
300a4b055ff8924b8965c8ac4f6d3b532a85f6ebd35Barry Warsaw        # volume
301a4b055ff8924b8965c8ac4f6d3b532a85f6ebd35Barry Warsaw        self.__scalevar.set(info.o_gain)
3022a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw
303b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw    def __pushtodev(self, event=None):
3042a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        info = self.__devctl.getinfo()
3052a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        info.o_port = self.__spkvar.get() + \
3062a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw                      self.__headvar.get() + \
3072a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw                      self.__linevar.get()
308e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw        info.i_port = self.__inputvar.get()
309a4b055ff8924b8965c8ac4f6d3b532a85f6ebd35Barry Warsaw        info.o_gain = self.__scalevar.get()
310bc9476ebe53516374ea1572432203c1a8dc0099eBarry Warsaw        try:
311bc9476ebe53516374ea1572432203c1a8dc0099eBarry Warsaw            self.__devctl.setinfo(info)
312bc9476ebe53516374ea1572432203c1a8dc0099eBarry Warsaw        except sunaudiodev.error, msg:
313bc9476ebe53516374ea1572432203c1a8dc0099eBarry Warsaw            # TBD: what to do?  it's probably temporary.
314bc9476ebe53516374ea1572432203c1a8dc0099eBarry Warsaw            pass
3152a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw
3162a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw    def __getset(self, var, onvalue):
317441abb4c8fa5f37c9dd24dd2478c6df57860534cBarry Warsaw        if var.get() == onvalue:
3182a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw            var.set(0)
3192a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        else:
3202a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw            var.set(onvalue)
321b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        self.__pushtodev()
322441abb4c8fa5f37c9dd24dd2478c6df57860534cBarry Warsaw
323441abb4c8fa5f37c9dd24dd2478c6df57860534cBarry Warsaw    def __none(self, event=None):
324441abb4c8fa5f37c9dd24dd2478c6df57860534cBarry Warsaw        self.__inputvar.set(0)
325441abb4c8fa5f37c9dd24dd2478c6df57860534cBarry Warsaw        self.__pushtodev()
326b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw
327b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw    def __mic(self, event=None):
328e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw        self.__getset(self.__inputvar, MICROPHONE)
329b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw
330b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw    def __linein(self, event=None):
331e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw        self.__getset(self.__inputvar, LINE_IN)
332b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw
333b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw    def __cd(self, event=None):
334e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw        self.__getset(self.__inputvar, CD)
3352a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw
3362a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw    def __speaker(self, event=None):
3372a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        self.__getset(self.__spkvar, SPEAKER)
3382a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw
3392a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw    def __headphones(self, event=None):
3402a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        self.__getset(self.__headvar, HEADPHONE)
3412a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw
3422a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw    def __lineout(self, event=None):
3432a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        self.__getset(self.__linevar, LINE_OUT)
3442a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw
345a4b055ff8924b8965c8ac4f6d3b532a85f6ebd35Barry Warsaw    def __volume(self, event=None):
346a4b055ff8924b8965c8ac4f6d3b532a85f6ebd35Barry Warsaw        self.__pushtodev()
347a4b055ff8924b8965c8ac4f6d3b532a85f6ebd35Barry Warsaw
3482a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw    def start(self):
3492a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        self.__keepalive()
3502a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        self.__tkroot.mainloop()
3512a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw
3522a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw
3532a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw
354f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsawclass Helpwin:
355f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw    def __init__(self, master, quitfunc):
356f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw        from Tkinter import *
357f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw        self.__root = root = Toplevel(master, class_='Audiopy')
358f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw        root.protocol('WM_DELETE_WINDOW', self.__withdraw)
359f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw        root.title('Audiopy Help Window')
360f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw        root.iconname('Audiopy Help Window')
361f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw        root.bind('<Alt-q>', quitfunc)
362f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw        root.bind('<Alt-Q>', quitfunc)
363f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw        root.bind('<Alt-w>', self.__withdraw)
364f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw        root.bind('<Alt-W>', self.__withdraw)
365f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw
366f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw        # more elaborate help is available in the README file
367f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw        readmefile = os.path.join(sys.path[0], 'README')
368f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw        try:
369f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw            fp = None
370f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw            try:
371f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw                fp = open(readmefile)
372f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw                contents = fp.read()
373f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw                # wax the last page, it contains Emacs cruft
374aaab30e00cc3e8d90c71b8657c284feeb4ac1413Walter Dörwald                i = contents.rfind('\f')
375f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw                if i > 0:
376aaab30e00cc3e8d90c71b8657c284feeb4ac1413Walter Dörwald                    contents = contents[:i].rstrip()
377f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw            finally:
378f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw                if fp:
379f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw                    fp.close()
380f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw        except IOError:
381f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw            sys.stderr.write("Couldn't open audiopy's README, "
382f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw                             'using docstring instead.\n')
383f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw            contents = __doc__ % globals()
384f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw
385f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw        self.__text = text = Text(root, relief=SUNKEN,
386f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw                                  width=80, height=24)
387f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw        text.insert(0.0, contents)
388f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw        scrollbar = Scrollbar(root)
389f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw        scrollbar.pack(fill=Y, side=RIGHT)
390f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw        text.pack(fill=BOTH, expand=YES)
391f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw        text.configure(yscrollcommand=(scrollbar, 'set'))
392f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw        scrollbar.configure(command=(text, 'yview'))
393f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw
394f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw    def __withdraw(self, event=None):
395f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw        self.__root.withdraw()
396f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw
397f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw    def deiconify(self):
398f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw        self.__root.deiconify()
399f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw
400f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw
401f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw
402f622a33b295647acfa7d673cd82ac55002157e9aBarry Warsaw
403a4b055ff8924b8965c8ac4f6d3b532a85f6ebd35Barry Warsawdef usage(code, msg=''):
404d81d534aef5fe8d6c081121dd545623e7ea2e889Barry Warsaw    print __doc__ % globals()
4052858b43613ca50f21aab629140ffc84278d3b0d8Barry Warsaw    if msg:
4062858b43613ca50f21aab629140ffc84278d3b0d8Barry Warsaw        print msg
4072a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw    sys.exit(code)
4082a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw
4092a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw
4102a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsawdef main():
4112c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw    #
4122c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw    # Open up the audio control device and query for the current output
4132c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw    # device
4142c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw    device = sunaudiodev.open('control')
4152c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw
4162a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw    if len(sys.argv) == 1:
4172a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        # GUI
4182c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw        w = MainWindow(device)
419b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        try:
420b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw            w.start()
421b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw        except KeyboardInterrupt:
422b7d1d63f00603acda29741e369c327f048571aedBarry Warsaw            pass
4232a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        return
4242a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw
4252c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw    # spec:    LONG OPT, SHORT OPT, 0=input,1=output, MASK
426d55049aedea656a4509537a11853bd556ccfb013Barry Warsaw    options = [('--microphone', '-m', 0, MICROPHONE),
4272c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw               ('--linein',     '-i', 0, LINE_IN),
4282c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw               ('--headphones', '-p', 1, HEADPHONE),
4292c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw               ('--speaker',    '-s', 1, SPEAKER),
4302c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw               ('--lineout',    '-o', 1, LINE_OUT),
431d55049aedea656a4509537a11853bd556ccfb013Barry Warsaw               ]
432d55049aedea656a4509537a11853bd556ccfb013Barry Warsaw    # See the comment above about `CD'
433d55049aedea656a4509537a11853bd556ccfb013Barry Warsaw    try:
434d55049aedea656a4509537a11853bd556ccfb013Barry Warsaw        options.append(('--cd',         '-c', 0, CD))
435d55049aedea656a4509537a11853bd556ccfb013Barry Warsaw    except NameError:
436d55049aedea656a4509537a11853bd556ccfb013Barry Warsaw        pass
437d55049aedea656a4509537a11853bd556ccfb013Barry Warsaw
4382c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw    info = device.getinfo()
4392c8b35bdd25b0946d4ea35e74a1e20ccd4679325Barry Warsaw    # first get the existing values
440a4b055ff8924b8965c8ac4f6d3b532a85f6ebd35Barry Warsaw    i = 0
441a4b055ff8924b8965c8ac4f6d3b532a85f6ebd35Barry Warsaw    while i < len(sys.argv)-1:
442a4b055ff8924b8965c8ac4f6d3b532a85f6ebd35Barry Warsaw        i = i + 1
443a4b055ff8924b8965c8ac4f6d3b532a85f6ebd35Barry Warsaw        arg = sys.argv[i]
4442a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        if arg in ('-h', '--help'):
445a4b055ff8924b8965c8ac4f6d3b532a85f6ebd35Barry Warsaw            usage(0)
446e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw            # does not return
447a4b055ff8924b8965c8ac4f6d3b532a85f6ebd35Barry Warsaw        elif arg in ('-g', '--gain'):
448a4b055ff8924b8965c8ac4f6d3b532a85f6ebd35Barry Warsaw            gainspec = '<missing>'
449a4b055ff8924b8965c8ac4f6d3b532a85f6ebd35Barry Warsaw            try:
450a4b055ff8924b8965c8ac4f6d3b532a85f6ebd35Barry Warsaw                gainspec = sys.argv[i+1]
451a4b055ff8924b8965c8ac4f6d3b532a85f6ebd35Barry Warsaw                gain = int(gainspec)
452a4b055ff8924b8965c8ac4f6d3b532a85f6ebd35Barry Warsaw            except (ValueError, IndexError):
453a4b055ff8924b8965c8ac4f6d3b532a85f6ebd35Barry Warsaw                usage(1, 'Bad gain specification: ' + gainspec)
454a4b055ff8924b8965c8ac4f6d3b532a85f6ebd35Barry Warsaw            info.o_gain = gain
455a4b055ff8924b8965c8ac4f6d3b532a85f6ebd35Barry Warsaw            i = i + 1
456a4b055ff8924b8965c8ac4f6d3b532a85f6ebd35Barry Warsaw            continue
4573febc2443cd3360c4da0dafae26b3530d363368aBarry Warsaw        elif arg in ('-v', '--version'):
458d81d534aef5fe8d6c081121dd545623e7ea2e889Barry Warsaw            print '''\
459d81d534aef5fe8d6c081121dd545623e7ea2e889Barry Warsawaudiopy -- a program to control the Solaris audio device.
46088604056c5d64cabfea975511c84155bbbc778e1Barry WarsawContact: Barry Warsaw
461d81d534aef5fe8d6c081121dd545623e7ea2e889Barry WarsawEmail:   bwarsaw@python.org
462d81d534aef5fe8d6c081121dd545623e7ea2e889Barry WarsawVersion: %s''' % __version__            
4633febc2443cd3360c4da0dafae26b3530d363368aBarry Warsaw            sys.exit(0)
464e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw        for long, short, io, mask in options:
465e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw            if arg in (long, short):
466e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw                # toggle the option
467e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw                if io == 0: 
468e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw                    info.i_port = info.i_port ^ mask
469e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw                else:
470e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw                    info.o_port = info.o_port ^ mask
471e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw                break
472e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw            val = None
4732a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw            try:
474e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw                if arg[:len(long)+1] == long+'=':
475e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw                    val = int(arg[len(long)+1:])
476e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw                elif arg[:len(short)+1] == short+'=':
477e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw                    val = int(arg[len(short)+1:])
4782a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw            except ValueError:
479a4b055ff8924b8965c8ac4f6d3b532a85f6ebd35Barry Warsaw                usage(1, msg='Invalid option: ' + arg)
480e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw                # does not return
481e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw            if val == 0:
482e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw                if io == 0:
483e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw                    info.i_port = info.i_port & ~mask
4842a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw                else:
485e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw                    info.o_port = info.o_port & ~mask
486e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw                break
487e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw            elif val == 1:
488e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw                if io == 0:
489e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw                    info.i_port = info.i_port | mask
4902a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw                else:
491e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw                    info.o_port = info.o_port | mask
492e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw                break
493e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw            # else keep trying next option
4942a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw        else:
495a4b055ff8924b8965c8ac4f6d3b532a85f6ebd35Barry Warsaw            usage(1, msg='Invalid option: ' + arg)
496e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw    # now set the values
497d8d179d69d46a07923ad07b70a2d5f5e57f8030aBarry Warsaw    try:
498d8d179d69d46a07923ad07b70a2d5f5e57f8030aBarry Warsaw        device.setinfo(info)
499d8d179d69d46a07923ad07b70a2d5f5e57f8030aBarry Warsaw    except sunaudiodev.error, (code, msg):
500c4eb6a6afd7d3a1e0c13b6b021f3bd91e3b47fd7Barry Warsaw        if code <> errno.EINVAL:
501c4eb6a6afd7d3a1e0c13b6b021f3bd91e3b47fd7Barry Warsaw            raise
502e77ec175d2cf36b4bb5e6a6d9957bf9cd8abf42dBarry Warsaw    device.close()
5032a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw            
5042a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw
5052a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw
5062a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsawif __name__ == '__main__':
5072a06084ed51d06cdea9544b5ab02586d300dec83Barry Warsaw    main()
508