def main(args=None):
	conf = Conf()
	conf_file = os.path.expanduser('~/.pulseaudio-mixer-cli.cfg')
	try: conf_file = open(conf_file)
	except (OSError, IOError) as err: pass
	else: update_conf_from_file(conf, conf_file)

	import argparse
	parser = argparse.ArgumentParser(description='Command-line PulseAudio mixer tool.')

	parser.add_argument('-a', '--adjust-step',
		action='store', type=int, metavar='step', default=conf.adjust_step,
		help='Adjustment for a single keypress in interactive mode (0-100%%, default: %(default)s%%).')
	parser.add_argument('-l', '--max-level',
		action='store', type=int, metavar='level', default=conf.max_level,
		help='Value to treat as max (default: %(default)s).')
	parser.add_argument('-n', '--use-media-name',
		action='store_true', default=conf.use_media_name,
		help='Display streams by "media.name" property, if possible.'
			' Default is to prefer application name and process properties.')

	parser.add_argument('-v', '--verbose',
		action='store_true', default=conf.verbose,
		help='Dont close stderr to see any sort of errors (which'
			' mess up curses interface, thus silenced that way by default).')
	parser.add_argument('-w', '--watchdog',
		action='store_true', default=conf.watchdog,
		help='Run watchdog pid to restart the thing if it hangs.')
	parser.add_argument('--dump-stream-params',
		action='store_true', help='Dump all parameters for each stream to stderr.')
	parser.add_argument('--debug', action='store_true', help='Verbose operation mode.')
	parser.add_argument('--debug-pipes', action='store_true',
		help='Also logs chatter between parent/child pids. Very noisy, only useful with --debug.')
	parser.add_argument('--fatal', action='store_true',
		help='Dont try too hard to recover from errors. For debugging purposes only.')

	parser.add_argument('--parent-pid-do-not-use', metavar='pid',
		help='Used internally to spawn dbus sub-pid, should not be used directly.')
	args = sys.argv[1:] if args is None else args
	opts = parser.parse_args(args)

	for k,v in vars(opts).viewitems(): setattr(conf, k, v)
	del opts

	global log, print
	log_pid = os.getpid()
	logging.basicConfig(
		level=logging.DEBUG if conf.debug else logging.WARNING,
		format='%(asctime)s :: {} %(levelname)s :: %(message)s'.format(uid_str(log_pid)),
		datefmt='%Y-%m-%d %H:%M:%S' )
	log = logging.getLogger()
	print= ft.partial(print, file=sys.stderr) # stdout is used by curses or as a pipe (child)
	log.debug('Starting script (child: %s, pid: %s)', bool(conf.parent_pid_do_not_use), log_pid)

	if conf.parent_pid_do_not_use:
		pid = conf.parent_pid_do_not_use
		if pid.startswith('w'): conf.watchdog_opts = map(int, pid.lstrip('w').split('-', 1))
		else:
			dbus_bridge = PAMixerDBusBridge(core_pid=int(pid), log_pipes=conf.debug_pipes)
			if conf.use_media_name: dbus_bridge.handle_proplist_updates = True
			try: return dbus_bridge.child_run()
			finally:
				if log.isEnabledFor(logging.INFO):
					log_lines( log.info,
						['Last pipe traffic (child pid side):'] + list(dbus_bridge.line_debug) )

	if not conf.watchdog_opts:
		if conf.watchdog:
			try: return watchdog_run(conf, args)
			except __HOLE__: return 0
	else:
		pid, fd = conf.watchdog_opts
		os.write(fd, '!')
		watchdog_handle(pid)

	dbus_bridge = ['--parent-pid-do-not-use', bytes(os.getpid())]
	if conf.debug:
		dbus_bridge += ['--debug']
		if conf.debug_pipes: dbus_bridge += ['--debug-pipes']
	if conf.use_media_name: dbus_bridge += ['--use-media-name']
	dbus_bridge = PAMixerDBusBridge(
		self_exec_cmd(*dbus_bridge), fatal=conf.fatal, log_pipes=conf.debug_pipes )

	menu = PAMixerMenu(dbus_bridge, conf, fatal=conf.fatal)
	dbus_bridge.install_signal_handler(menu.update_signal)
	dbus_bridge.child_start()

	with PAMixerUI(menu) as curses_ui:
		# Any output will mess-up curses ui, so try to close sys.stderr if possible
		if not conf.verbose and not conf.debug\
			and not conf.dump_stream_params: sys.stderr.close()
		log.debug('Entering curses ui loop...')
		try: curses_ui.run()
		except:
			if log.isEnabledFor(logging.INFO):
				log_lines( log.info,
					['Last pipe traffic (parent pid side):'] + list(dbus_bridge.line_debug) )
			raise
		log.debug('Finished')
dataset/ETHPy150Open mk-fg/pulseaudio-mixer-cli/pa-mixer-mk2.py/main