1# Copyright 2014 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""An adapter to remotely access the audio facade on DUT."""
6
7import os
8import tempfile
9
10
11class AudioFacadeRemoteAdapter(object):
12    """AudioFacadeRemoteAdapter is an adapter to remotely control DUT audio.
13
14    The Autotest host object representing the remote DUT, passed to this
15    class on initialization, can be accessed from its _client property.
16
17    """
18    def __init__(self, host, remote_facade_proxy):
19        """Construct an AudioFacadeRemoteAdapter.
20
21        @param host: Host object representing a remote host.
22        @param remote_facade_proxy: RemoteFacadeProxy object.
23
24        """
25        self._client = host
26        self._proxy = remote_facade_proxy
27
28
29    @property
30    def _audio_proxy(self):
31        """Gets the proxy to DUT audio facade.
32
33        @return XML RPC proxy to DUT audio facade.
34
35        """
36        return self._proxy.audio
37
38
39    def playback(self, client_path, data_format, blocking=False):
40        """Playback an audio file on DUT.
41
42        @param client_path: The path to the file on DUT.
43        @param data_format: A dict containing data format including
44                            file_type, sample_format, channel, and rate.
45                            file_type: file type e.g. 'raw' or 'wav'.
46                            sample_format: One of the keys in
47                                           audio_data.SAMPLE_FORMAT.
48                            channel: number of channels.
49                            rate: sampling rate.
50        @param blocking: Blocks this call until playback finishes.
51
52        @returns: True
53
54        """
55        self._audio_proxy.playback(
56                client_path, data_format, blocking)
57
58
59    def set_playback_file(self, path):
60        """Copies a file to client.
61
62        @param path: A path to the file.
63
64        @returns: A new path to the file on client.
65
66        """
67        _, ext = os.path.splitext(path)
68        _, client_file_path = tempfile.mkstemp(
69                prefix='playback_', suffix=ext)
70        self._client.send_file(path, client_file_path)
71        return client_file_path
72
73
74    def start_recording(self, data_format):
75        """Starts recording an audio file on DUT.
76
77        @param data_format: A dict containing:
78                            file_type: 'raw'.
79                            sample_format: 'S16_LE' for 16-bit signed integer in
80                                           little-endian.
81                            channel: channel number.
82                            rate: sampling rate.
83
84        @returns: True
85
86        """
87        self._audio_proxy.start_recording(data_format)
88        return True
89
90
91    def stop_recording(self):
92        """Stops recording on DUT.
93
94        @returns: the path to the recorded file on DUT.
95
96        """
97        return self._audio_proxy.stop_recording()
98
99
100    def get_recorded_file(self, remote_path, local_path):
101        """Gets a recorded file from DUT.
102
103        @param remote_path: The path to the file on DUT.
104        @param local_path: The local path for copy destination.
105
106        """
107        self._client.get_file(remote_path, local_path)
108
109
110    def set_selected_output_volume(self, volume):
111        """Sets the selected output volume on DUT.
112
113        @param volume: the volume to be set(0-100).
114
115        """
116        self._audio_proxy.set_selected_output_volume(volume)
117
118
119    def set_selected_node_types(self, output_node_types, input_node_types):
120        """Set selected node types.
121
122        The node types are defined in cras_utils.CRAS_NODE_TYPES.
123
124        @param output_node_types: A list of output node types.
125                                  None to skip setting.
126        @param input_node_types: A list of input node types.
127                                 None to skip setting.
128
129        """
130        self._audio_proxy.set_selected_node_types(
131                output_node_types, input_node_types)
132
133
134    def get_selected_node_types(self):
135        """Gets the selected output and input node types on DUT.
136
137        @returns: A tuple (output_node_types, input_node_types) where each
138                  field is a list of selected node types defined in
139                  cras_utils.CRAS_NODE_TYPES.
140
141        """
142        return self._audio_proxy.get_selected_node_types()
143
144
145    def get_plugged_node_types(self):
146        """Gets the plugged output and input node types on DUT.
147
148        @returns: A tuple (output_node_types, input_node_types) where each
149                  field is a list of plugged node types defined in
150                  cras_utils.CRAS_NODE_TYPES.
151
152        """
153        return self._audio_proxy.get_plugged_node_types()
154
155
156    def dump_diagnostics(self, file_path):
157        """Dumps audio diagnostics results to a file.
158
159        @param file_path: The path to dump results.
160
161        @returns: True
162
163        """
164        _, remote_path = tempfile.mkstemp(
165                prefix='audio_dump_', suffix='.txt')
166        self._audio_proxy.dump_diagnostics(remote_path)
167        self._client.get_file(remote_path, file_path)
168        return True
169
170
171    def start_counting_signal(self, signal_name):
172        """Starts counting DBus signal from Cras.
173
174        @param signal_name: Signal of interest.
175
176        """
177        self._audio_proxy.start_counting_signal(signal_name)
178
179
180    def stop_counting_signal(self):
181        """Stops counting DBus signal from Cras.
182
183        @returns: Number of signals counted starting from last
184                  start_counting_signal call.
185
186        """
187        return self._audio_proxy.stop_counting_signal()
188
189
190    def wait_for_unexpected_nodes_changed(self, timeout_secs):
191        """Waits for unexpected nodes changed signal.
192
193        @param timeout_secs: Timeout in seconds for waiting.
194
195        """
196        self._audio_proxy.wait_for_unexpected_nodes_changed(timeout_secs)
197
198
199    def set_chrome_active_volume(self, volume):
200        """Sets the active audio output volume using chrome.audio API.
201
202        @param volume: Volume to set (0~100).
203
204        """
205        self._audio_proxy.set_chrome_active_volume(volume)
206
207
208    def set_chrome_mute(self, mute):
209        """Mutes the active audio output using chrome.audio API.
210
211        @param mute: True to mute. False otherwise.
212
213        """
214        self._audio_proxy.set_chrome_mute(mute)
215
216
217    def get_chrome_active_volume_mute(self):
218        """Gets the volume state of active audio output using chrome.audio API.
219
220        @param returns: A tuple (volume, mute), where volume is 0~100, and mute
221                        is True if node is muted, False otherwise.
222
223        """
224        return self._audio_proxy.get_chrome_active_volume_mute()
225
226
227    def set_chrome_active_node_type(self, output_node_type, input_node_type):
228        """Sets active node type through chrome.audio API.
229
230        The node types are defined in cras_utils.CRAS_NODE_TYPES.
231        The current active node will be disabled first if the new active node
232        is different from the current one.
233
234        @param output_node_type: A node type defined in
235                                 cras_utils.CRAS_NODE_TYPES. None to skip.
236        @param input_node_type: A node type defined in
237                                 cras_utils.CRAS_NODE_TYPES. None to skip
238
239        """
240        self._audio_proxy.set_chrome_active_node_type(
241                output_node_type, input_node_type)
242