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 stop_playback(self):
60        """Stops playback process."""
61        self._audio_proxy.stop_playback()
62
63
64    def set_playback_file(self, path):
65        """Copies a file to client.
66
67        @param path: A path to the file.
68
69        @returns: A new path to the file on client.
70
71        """
72        _, ext = os.path.splitext(path)
73        _, client_file_path = tempfile.mkstemp(
74                prefix='playback_', suffix=ext)
75        self._client.send_file(path, client_file_path)
76        return client_file_path
77
78
79    def start_recording(self, data_format):
80        """Starts recording an audio file on DUT.
81
82        @param data_format: A dict containing:
83                            file_type: 'raw'.
84                            sample_format: 'S16_LE' for 16-bit signed integer in
85                                           little-endian.
86                            channel: channel number.
87                            rate: sampling rate.
88
89        @returns: True
90
91        """
92        self._audio_proxy.start_recording(data_format)
93        return True
94
95
96    def stop_recording(self):
97        """Stops recording on DUT.
98
99        @returns: the path to the recorded file on DUT.
100
101        """
102        return self._audio_proxy.stop_recording()
103
104
105    def get_recorded_file(self, remote_path, local_path):
106        """Gets a recorded file from DUT.
107
108        @param remote_path: The path to the file on DUT.
109        @param local_path: The local path for copy destination.
110
111        """
112        self._client.get_file(remote_path, local_path)
113
114
115    def set_selected_output_volume(self, volume):
116        """Sets the selected output volume on DUT.
117
118        @param volume: the volume to be set(0-100).
119
120        """
121        self._audio_proxy.set_selected_output_volume(volume)
122
123
124    def set_input_gain(self, gain):
125        """Sets the system capture gain.
126
127        @param gain: the capture gain in db*100 (100 = 1dB)
128
129        """
130        self._audio_proxy.set_input_gain(gain)
131
132
133    def set_selected_node_types(self, output_node_types, input_node_types):
134        """Set selected node types.
135
136        The node types are defined in cras_utils.CRAS_NODE_TYPES.
137
138        @param output_node_types: A list of output node types.
139                                  None to skip setting.
140        @param input_node_types: A list of input node types.
141                                 None to skip setting.
142
143        """
144        self._audio_proxy.set_selected_node_types(
145                output_node_types, input_node_types)
146
147
148    def get_selected_node_types(self):
149        """Gets the selected output and input node types on DUT.
150
151        @returns: A tuple (output_node_types, input_node_types) where each
152                  field is a list of selected node types defined in
153                  cras_utils.CRAS_NODE_TYPES.
154
155        """
156        return self._audio_proxy.get_selected_node_types()
157
158
159    def get_plugged_node_types(self):
160        """Gets the plugged output and input node types on DUT.
161
162        @returns: A tuple (output_node_types, input_node_types) where each
163                  field is a list of plugged node types defined in
164                  cras_utils.CRAS_NODE_TYPES.
165
166        """
167        return self._audio_proxy.get_plugged_node_types()
168
169
170    def dump_diagnostics(self, file_path):
171        """Dumps audio diagnostics results to a file.
172
173        @param file_path: The path to dump results.
174
175        @returns: True
176
177        """
178        _, remote_path = tempfile.mkstemp(
179                prefix='audio_dump_', suffix='.txt')
180        self._audio_proxy.dump_diagnostics(remote_path)
181        self._client.get_file(remote_path, file_path)
182        return True
183
184
185    def start_counting_signal(self, signal_name):
186        """Starts counting DBus signal from Cras.
187
188        @param signal_name: Signal of interest.
189
190        """
191        self._audio_proxy.start_counting_signal(signal_name)
192
193
194    def stop_counting_signal(self):
195        """Stops counting DBus signal from Cras.
196
197        @returns: Number of signals counted starting from last
198                  start_counting_signal call.
199
200        """
201        return self._audio_proxy.stop_counting_signal()
202
203
204    def wait_for_unexpected_nodes_changed(self, timeout_secs):
205        """Waits for unexpected nodes changed signal.
206
207        @param timeout_secs: Timeout in seconds for waiting.
208
209        """
210        self._audio_proxy.wait_for_unexpected_nodes_changed(timeout_secs)
211
212
213    def set_chrome_active_volume(self, volume):
214        """Sets the active audio output volume using chrome.audio API.
215
216        @param volume: Volume to set (0~100).
217
218        """
219        self._audio_proxy.set_chrome_active_volume(volume)
220
221
222    def set_chrome_mute(self, mute):
223        """Mutes the active audio output using chrome.audio API.
224
225        @param mute: True to mute. False otherwise.
226
227        """
228        self._audio_proxy.set_chrome_mute(mute)
229
230
231    def get_chrome_active_volume_mute(self):
232        """Gets the volume state of active audio output using chrome.audio API.
233
234        @param returns: A tuple (volume, mute), where volume is 0~100, and mute
235                        is True if node is muted, False otherwise.
236
237        """
238        return self._audio_proxy.get_chrome_active_volume_mute()
239
240
241    def set_chrome_active_node_type(self, output_node_type, input_node_type):
242        """Sets active node type through chrome.audio API.
243
244        The node types are defined in cras_utils.CRAS_NODE_TYPES.
245        The current active node will be disabled first if the new active node
246        is different from the current one.
247
248        @param output_node_type: A node type defined in
249                                 cras_utils.CRAS_NODE_TYPES. None to skip.
250        @param input_node_type: A node type defined in
251                                 cras_utils.CRAS_NODE_TYPES. None to skip
252
253        """
254        self._audio_proxy.set_chrome_active_node_type(
255                output_node_type, input_node_type)
256
257
258    def start_arc_recording(self):
259        """Starts recording using microphone app in container."""
260        self._audio_proxy.start_arc_recording()
261
262
263    def stop_arc_recording(self):
264        """Checks the recording is stopped and gets the recorded path.
265
266        The recording duration of microphone app is fixed, so this method just
267        asks Cros device to copy the recorded result from container to a path
268        on Cros device.
269
270        @returns: Path to the recorded file on DUT.
271
272        """
273        return self._audio_proxy.stop_arc_recording()
274
275
276    def set_arc_playback_file(self, path):
277        """Copies the file from server to Cros host and into container.
278
279        @param path: Path to the file on server.
280
281        @returns: Path to the file in container on Cros host.
282
283        """
284        client_file_path = self.set_playback_file(path)
285        return self._audio_proxy.set_arc_playback_file(client_file_path)
286
287
288    def start_arc_playback(self, path):
289        """Starts playback through ARC on Cros host.
290
291        @param path: Path to the file in container on Cros host.
292
293        """
294        self._audio_proxy.start_arc_playback(path)
295
296
297    def stop_arc_playback(self):
298        """Stops playback through ARC on Cros host."""
299        self._audio_proxy.stop_arc_playback()
300