• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 AudioFacadeError(Exception):
12    """Errors in audio facade."""
13    pass
14
15
16class AudioFacadeRemoteAdapter(object):
17    """AudioFacadeRemoteAdapter is an adapter to remotely control DUT audio.
18
19    The Autotest host object representing the remote DUT, passed to this
20    class on initialization, can be accessed from its _client property.
21
22    """
23    def __init__(self, host, remote_facade_proxy):
24        """Construct an AudioFacadeRemoteAdapter.
25
26        @param host: Host object representing a remote host.
27        @param remote_facade_proxy: RemoteFacadeProxy object.
28
29        """
30        self._client = host
31        self._proxy = remote_facade_proxy
32
33
34    @property
35    def _audio_proxy(self):
36        """Gets the proxy to DUT audio facade.
37
38        @return XML RPC proxy to DUT audio facade.
39
40        """
41        return self._proxy.audio
42
43
44    def playback(self, client_path, data_format, blocking=False,
45                 node_type=None, block_size=None):
46        """Playback an audio file on DUT.
47
48        @param client_path: The path to the file on DUT.
49        @param data_format: A dict containing data format including
50                            file_type, sample_format, channel, and rate.
51                            file_type: file type e.g. 'raw' or 'wav'.
52                            sample_format: One of the keys in
53                                           audio_data.SAMPLE_FORMAT.
54                            channel: number of channels.
55                            rate: sampling rate.
56        @param blocking: Blocks this call until playback finishes.
57        @param node_type: A Cras node type defined in cras_utils.CRAS_NODE_TYPES
58                          that we like to pin at. None to have the playback on
59                          active selected device.
60        @param block_size: The number for frames per callback.
61
62        """
63        self._audio_proxy.playback(
64                client_path, data_format, blocking, node_type, block_size)
65
66
67    def stop_playback(self):
68        """Stops playback process."""
69        self._audio_proxy.stop_playback()
70
71
72    def set_playback_file(self, path):
73        """Copies a file to client.
74
75        @param path: A path to the file.
76
77        @returns: A new path to the file on client.
78
79        """
80        _, ext = os.path.splitext(path)
81        _, client_file_path = tempfile.mkstemp(
82                prefix='playback_', suffix=ext)
83        self._client.send_file(path, client_file_path)
84        return client_file_path
85
86
87    def start_recording(self, data_format, node_type=None, block_size=None):
88        """Starts recording an audio file on DUT.
89
90        @param data_format: A dict containing:
91                            file_type: 'raw'.
92                            sample_format: 'S16_LE' for 16-bit signed integer in
93                                           little-endian.
94                            channel: channel number.
95                            rate: sampling rate.
96        @param node_type: A Cras node type defined in cras_utils.CRAS_NODE_TYPES
97                          that we like to pin at. None to have the recording
98                          from active selected device.
99        @param block_size: The number for frames per callback.
100
101        @returns: True
102
103        """
104        self._audio_proxy.start_recording(data_format, node_type, block_size)
105        return True
106
107
108    def stop_recording(self, node_type=None):
109        """Stops recording on DUT.
110
111        @param node_type: A Cras node type defined in cras_utils.CRAS_NODE_TYPES
112                          that we like to stop recording from. None to stop the
113                          recording from active selected device.
114
115        @returns: the path to the recorded file on DUT.
116
117        @raises: AudioFacadeError if recorded path is None
118        """
119        path = self._audio_proxy.stop_recording(node_type)
120        if not path:
121            raise AudioFacadeError(
122                    'Recording does not work on DUT. '
123                    'Suggest checking messages on DUT')
124        return path
125
126
127    def start_listening(self, data_format):
128        """Starts listening horword on DUT.
129
130        @param data_format: A dict containing:
131                            file_type: 'raw'.
132                            sample_format: 'S16_LE' for 16-bit signed integer in
133                                           little-endian.
134                            channel: channel number.
135                            rate: sampling rate.
136
137        @returns: True
138
139        """
140        self._audio_proxy.start_listening(data_format)
141        return True
142
143
144    def stop_listening(self):
145        """Stops listening on DUT.
146
147        @returns: the path to the recorded file on DUT.
148
149        @raises: AudioFacadeError if hotwording does not work on DUT.
150        """
151        path = self._audio_proxy.stop_listening()
152        if not path:
153            raise AudioFacadeError('Listening does not work on DUT.')
154        return path
155
156
157    def get_recorded_file(self, remote_path, local_path):
158        """Gets a recorded file from DUT.
159
160        @param remote_path: The path to the file on DUT.
161        @param local_path: The local path for copy destination.
162
163        """
164        self._client.get_file(remote_path, local_path)
165
166
167    def set_selected_output_volume(self, volume):
168        """Sets the selected output volume on DUT.
169
170        @param volume: the volume to be set(0-100).
171
172        """
173        self._audio_proxy.set_selected_output_volume(volume)
174
175
176    def set_input_gain(self, gain):
177        """Sets the system capture gain.
178
179        @param gain: the capture gain in db*100 (100 = 1dB)
180
181        """
182        self._audio_proxy.set_input_gain(gain)
183
184
185    def set_selected_node_types(self, output_node_types, input_node_types):
186        """Set selected node types.
187
188        The node types are defined in cras_utils.CRAS_NODE_TYPES.
189
190        @param output_node_types: A list of output node types.
191                                  None to skip setting.
192        @param input_node_types: A list of input node types.
193                                 None to skip setting.
194
195        """
196        self._audio_proxy.set_selected_node_types(
197                output_node_types, input_node_types)
198
199
200    def get_selected_node_types(self):
201        """Gets the selected output and input node types on DUT.
202
203        @returns: A tuple (output_node_types, input_node_types) where each
204                  field is a list of selected node types defined in
205                  cras_utils.CRAS_NODE_TYPES.
206
207        """
208        return self._audio_proxy.get_selected_node_types()
209
210
211    def get_plugged_node_types(self):
212        """Gets the plugged output and input node types on DUT.
213
214        @returns: A tuple (output_node_types, input_node_types) where each
215                  field is a list of plugged node types defined in
216                  cras_utils.CRAS_NODE_TYPES.
217
218        """
219        return self._audio_proxy.get_plugged_node_types()
220
221
222    def dump_diagnostics(self, file_path):
223        """Dumps audio diagnostics results to a file.
224
225        @param file_path: The path to dump results.
226
227        @returns: True
228
229        """
230        _, remote_path = tempfile.mkstemp(
231                prefix='audio_dump_', suffix='.txt')
232        self._audio_proxy.dump_diagnostics(remote_path)
233        self._client.get_file(remote_path, file_path)
234        return True
235
236
237    def start_counting_signal(self, signal_name):
238        """Starts counting DBus signal from Cras.
239
240        @param signal_name: Signal of interest.
241
242        """
243        self._audio_proxy.start_counting_signal(signal_name)
244
245
246    def stop_counting_signal(self):
247        """Stops counting DBus signal from Cras.
248
249        @returns: Number of signals counted starting from last
250                  start_counting_signal call.
251
252        """
253        return self._audio_proxy.stop_counting_signal()
254
255
256    def wait_for_unexpected_nodes_changed(self, timeout_secs):
257        """Waits for unexpected nodes changed signal.
258
259        @param timeout_secs: Timeout in seconds for waiting.
260
261        """
262        self._audio_proxy.wait_for_unexpected_nodes_changed(timeout_secs)
263
264
265    def get_chrome_audio_availablity(self):
266        """Gets if the chrome.audio API is ready.
267
268        @returns: chrome.audio is ready or not.
269        """
270        return self._audio_proxy.get_audio_availability()
271
272
273    def set_chrome_active_volume(self, volume):
274        """Sets the active audio output volume using chrome.audio API.
275
276        @param volume: Volume to set (0~100).
277
278        """
279        self._audio_proxy.set_chrome_active_volume(volume)
280
281
282    def set_chrome_mute(self, mute):
283        """Mutes the active audio output using chrome.audio API.
284
285        @param mute: True to mute. False otherwise.
286
287        """
288        self._audio_proxy.set_chrome_mute(mute)
289
290    def check_audio_stream_at_selected_device(self):
291        """Checks the audio output is at expected node"""
292        self._audio_proxy.check_audio_stream_at_selected_device()
293
294
295    def get_chrome_active_volume_mute(self):
296        """Gets the volume state of active audio output using chrome.audio API.
297
298        @param returns: A tuple (volume, mute), where volume is 0~100, and mute
299                        is True if node is muted, False otherwise.
300
301        """
302        return self._audio_proxy.get_chrome_active_volume_mute()
303
304
305    def set_chrome_active_node_type(self, output_node_type, input_node_type):
306        """Sets active node type through chrome.audio API.
307
308        The node types are defined in cras_utils.CRAS_NODE_TYPES.
309        The current active node will be disabled first if the new active node
310        is different from the current one.
311
312        @param output_node_type: A node type defined in
313                                 cras_utils.CRAS_NODE_TYPES. None to skip.
314        @param input_node_type: A node type defined in
315                                 cras_utils.CRAS_NODE_TYPES. None to skip
316
317        """
318        self._audio_proxy.set_chrome_active_node_type(
319                output_node_type, input_node_type)
320
321
322    def start_arc_recording(self):
323        """Starts recording using microphone app in container."""
324        self._audio_proxy.start_arc_recording()
325
326
327    def stop_arc_recording(self):
328        """Checks the recording is stopped and gets the recorded path.
329
330        The recording duration of microphone app is fixed, so this method just
331        asks Cros device to copy the recorded result from container to a path
332        on Cros device.
333
334        @returns: Path to the recorded file on DUT.
335
336        """
337        return self._audio_proxy.stop_arc_recording()
338
339
340    def set_arc_playback_file(self, path):
341        """Copies the file from server to Cros host and into container.
342
343        @param path: Path to the file on server.
344
345        @returns: Path to the file in container on Cros host.
346
347        """
348        client_file_path = self.set_playback_file(path)
349        return self._audio_proxy.set_arc_playback_file(client_file_path)
350
351
352    def start_arc_playback(self, path):
353        """Starts playback through ARC on Cros host.
354
355        @param path: Path to the file in container on Cros host.
356
357        """
358        self._audio_proxy.start_arc_playback(path)
359
360
361    def stop_arc_playback(self):
362        """Stops playback through ARC on Cros host."""
363        self._audio_proxy.stop_arc_playback()
364