1#!/usr/bin/env python
2# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6"""XML RPC server for multimedia testing."""
7
8import argparse
9import code
10import logging
11import xmlrpclib
12import traceback
13import common   # pylint: disable=unused-import
14from autotest_lib.client.bin import utils
15from autotest_lib.client.common_lib import logging_config
16from autotest_lib.client.common_lib.cros import chrome
17from autotest_lib.client.cros import constants
18from autotest_lib.client.cros import xmlrpc_server
19from autotest_lib.client.cros.multimedia import audio_facade_native
20from autotest_lib.client.cros.multimedia import browser_facade_native
21from autotest_lib.client.cros.multimedia import display_facade_native
22from autotest_lib.client.cros.multimedia import system_facade_native
23from autotest_lib.client.cros.multimedia import usb_facade_native
24from autotest_lib.client.cros.multimedia import facade_resource
25
26
27class MultimediaXmlRpcDelegate(xmlrpc_server.XmlRpcDelegate):
28    """XML RPC delegate for multimedia testing."""
29
30    def __init__(self, resource):
31        """Initializes the facade objects."""
32        self._facades = {
33            'audio': audio_facade_native.AudioFacadeNative(resource),
34            'display': display_facade_native.DisplayFacadeNative(resource),
35            'system': system_facade_native.SystemFacadeNative(),
36            'usb': usb_facade_native.USBFacadeNative(),
37            'browser': browser_facade_native.BrowserFacadeNative(resource),
38        }
39
40
41    def __exit__(self, exception, value, traceback):
42        """Clean up the resources."""
43        self._facades['audio'].cleanup()
44
45
46    def _dispatch(self, method, params):
47        """Dispatches the method to the proper facade.
48
49        We turn off allow_dotted_names option. The method handles the dot
50        and dispatches the method to the proper native facade, like
51        DisplayFacadeNative.
52
53        """
54        try:
55            try:
56                if '.' not in method:
57                    func = getattr(self, method)
58                else:
59                    facade_name, method_name = method.split('.', 1)
60                    if facade_name in self._facades:
61                        func = getattr(self._facades[facade_name], method_name)
62                    else:
63                        raise Exception('unknown facade: %s' % facade_name)
64            except AttributeError:
65                raise Exception('method %s not supported' % method)
66
67            logging.info('Dispatching method %s with args %s',
68                         str(func), str(params))
69            return func(*params)
70        except:
71            # TODO(ihf): Try to return meaningful stacktraces from the client.
72            return traceback.format_exc()
73
74
75def config_logging():
76    """Configs logging to be verbose and use console handler."""
77    config = logging_config.LoggingConfig()
78    config.configure_logging(use_console=True, verbose=True)
79
80
81if __name__ == '__main__':
82    parser = argparse.ArgumentParser()
83    parser.add_argument('-d', '--debug', action='store_true', required=False,
84                        help=('create a debug console with a ServerProxy "s" '
85                              'connecting to the XML RPC sever at localhost'))
86    parser.add_argument('--restart', action='store_true', required=False,
87                        help=('restart the XML RPC server without clearing '
88                              'the previous state'))
89    args = parser.parse_args()
90
91    if args.debug:
92        s = xmlrpclib.ServerProxy('http://localhost:%d' %
93                                  constants.MULTIMEDIA_XMLRPC_SERVER_PORT,
94                                  allow_none=True)
95        code.interact(local=locals())
96    else:
97        config_logging()
98        logging.debug('multimedia_xmlrpc_server main...')
99
100
101        # Restart Cras to clean up any audio activities.
102        utils.restart_job('cras')
103
104        with facade_resource.FacadeResource(restart=args.restart) as res:
105            server = xmlrpc_server.XmlRpcServer(
106                    'localhost', constants.MULTIMEDIA_XMLRPC_SERVER_PORT)
107            server.register_delegate(MultimediaXmlRpcDelegate(res))
108            server.run()
109