You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

364 lines
11 KiB

# Copyright 2014 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""An adapter to remotely access the audio facade on DUT."""
import os
import tempfile
class AudioFacadeError(Exception):
"""Errors in audio facade."""
pass
class AudioFacadeRemoteAdapter(object):
"""AudioFacadeRemoteAdapter is an adapter to remotely control DUT audio.
The Autotest host object representing the remote DUT, passed to this
class on initialization, can be accessed from its _client property.
"""
def __init__(self, host, remote_facade_proxy):
"""Construct an AudioFacadeRemoteAdapter.
@param host: Host object representing a remote host.
@param remote_facade_proxy: RemoteFacadeProxy object.
"""
self._client = host
self._proxy = remote_facade_proxy
@property
def _audio_proxy(self):
"""Gets the proxy to DUT audio facade.
@return XML RPC proxy to DUT audio facade.
"""
return self._proxy.audio
def playback(self, client_path, data_format, blocking=False,
node_type=None, block_size=None):
"""Playback an audio file on DUT.
@param client_path: The path to the file on DUT.
@param data_format: A dict containing data format including
file_type, sample_format, channel, and rate.
file_type: file type e.g. 'raw' or 'wav'.
sample_format: One of the keys in
audio_data.SAMPLE_FORMAT.
channel: number of channels.
rate: sampling rate.
@param blocking: Blocks this call until playback finishes.
@param node_type: A Cras node type defined in cras_utils.CRAS_NODE_TYPES
that we like to pin at. None to have the playback on
active selected device.
@param block_size: The number for frames per callback.
"""
self._audio_proxy.playback(
client_path, data_format, blocking, node_type, block_size)
def stop_playback(self):
"""Stops playback process."""
self._audio_proxy.stop_playback()
def set_playback_file(self, path):
"""Copies a file to client.
@param path: A path to the file.
@returns: A new path to the file on client.
"""
_, ext = os.path.splitext(path)
_, client_file_path = tempfile.mkstemp(
prefix='playback_', suffix=ext)
self._client.send_file(path, client_file_path)
return client_file_path
def start_recording(self, data_format, node_type=None, block_size=None):
"""Starts recording an audio file on DUT.
@param data_format: A dict containing:
file_type: 'raw'.
sample_format: 'S16_LE' for 16-bit signed integer in
little-endian.
channel: channel number.
rate: sampling rate.
@param node_type: A Cras node type defined in cras_utils.CRAS_NODE_TYPES
that we like to pin at. None to have the recording
from active selected device.
@param block_size: The number for frames per callback.
@returns: True
"""
self._audio_proxy.start_recording(data_format, node_type, block_size)
return True
def stop_recording(self, node_type=None):
"""Stops recording on DUT.
@param node_type: A Cras node type defined in cras_utils.CRAS_NODE_TYPES
that we like to stop recording from. None to stop the
recording from active selected device.
@returns: the path to the recorded file on DUT.
@raises: AudioFacadeError if recorded path is None
"""
path = self._audio_proxy.stop_recording(node_type)
if not path:
raise AudioFacadeError(
'Recording does not work on DUT. '
'Suggest checking messages on DUT')
return path
def start_listening(self, data_format):
"""Starts listening horword on DUT.
@param data_format: A dict containing:
file_type: 'raw'.
sample_format: 'S16_LE' for 16-bit signed integer in
little-endian.
channel: channel number.
rate: sampling rate.
@returns: True
"""
self._audio_proxy.start_listening(data_format)
return True
def stop_listening(self):
"""Stops listening on DUT.
@returns: the path to the recorded file on DUT.
@raises: AudioFacadeError if hotwording does not work on DUT.
"""
path = self._audio_proxy.stop_listening()
if not path:
raise AudioFacadeError('Listening does not work on DUT.')
return path
def get_recorded_file(self, remote_path, local_path):
"""Gets a recorded file from DUT.
@param remote_path: The path to the file on DUT.
@param local_path: The local path for copy destination.
"""
self._client.get_file(remote_path, local_path)
def set_selected_output_volume(self, volume):
"""Sets the selected output volume on DUT.
@param volume: the volume to be set(0-100).
"""
self._audio_proxy.set_selected_output_volume(volume)
def set_input_gain(self, gain):
"""Sets the system capture gain.
@param gain: the capture gain in db*100 (100 = 1dB)
"""
self._audio_proxy.set_input_gain(gain)
def set_selected_node_types(self, output_node_types, input_node_types):
"""Set selected node types.
The node types are defined in cras_utils.CRAS_NODE_TYPES.
@param output_node_types: A list of output node types.
None to skip setting.
@param input_node_types: A list of input node types.
None to skip setting.
"""
self._audio_proxy.set_selected_node_types(
output_node_types, input_node_types)
def get_selected_node_types(self):
"""Gets the selected output and input node types on DUT.
@returns: A tuple (output_node_types, input_node_types) where each
field is a list of selected node types defined in
cras_utils.CRAS_NODE_TYPES.
"""
return self._audio_proxy.get_selected_node_types()
def get_plugged_node_types(self):
"""Gets the plugged output and input node types on DUT.
@returns: A tuple (output_node_types, input_node_types) where each
field is a list of plugged node types defined in
cras_utils.CRAS_NODE_TYPES.
"""
return self._audio_proxy.get_plugged_node_types()
def dump_diagnostics(self, file_path):
"""Dumps audio diagnostics results to a file.
@param file_path: The path to dump results.
@returns: True
"""
_, remote_path = tempfile.mkstemp(
prefix='audio_dump_', suffix='.txt')
self._audio_proxy.dump_diagnostics(remote_path)
self._client.get_file(remote_path, file_path)
return True
def start_counting_signal(self, signal_name):
"""Starts counting DBus signal from Cras.
@param signal_name: Signal of interest.
"""
self._audio_proxy.start_counting_signal(signal_name)
def stop_counting_signal(self):
"""Stops counting DBus signal from Cras.
@returns: Number of signals counted starting from last
start_counting_signal call.
"""
return self._audio_proxy.stop_counting_signal()
def wait_for_unexpected_nodes_changed(self, timeout_secs):
"""Waits for unexpected nodes changed signal.
@param timeout_secs: Timeout in seconds for waiting.
"""
self._audio_proxy.wait_for_unexpected_nodes_changed(timeout_secs)
def get_chrome_audio_availablity(self):
"""Gets if the chrome.audio API is ready.
@returns: chrome.audio is ready or not.
"""
return self._audio_proxy.get_audio_availability()
def set_chrome_active_volume(self, volume):
"""Sets the active audio output volume using chrome.audio API.
@param volume: Volume to set (0~100).
"""
self._audio_proxy.set_chrome_active_volume(volume)
def set_chrome_mute(self, mute):
"""Mutes the active audio output using chrome.audio API.
@param mute: True to mute. False otherwise.
"""
self._audio_proxy.set_chrome_mute(mute)
def check_audio_stream_at_selected_device(self):
"""Checks the audio output is at expected node"""
self._audio_proxy.check_audio_stream_at_selected_device()
def get_chrome_active_volume_mute(self):
"""Gets the volume state of active audio output using chrome.audio API.
@param returns: A tuple (volume, mute), where volume is 0~100, and mute
is True if node is muted, False otherwise.
"""
return self._audio_proxy.get_chrome_active_volume_mute()
def set_chrome_active_node_type(self, output_node_type, input_node_type):
"""Sets active node type through chrome.audio API.
The node types are defined in cras_utils.CRAS_NODE_TYPES.
The current active node will be disabled first if the new active node
is different from the current one.
@param output_node_type: A node type defined in
cras_utils.CRAS_NODE_TYPES. None to skip.
@param input_node_type: A node type defined in
cras_utils.CRAS_NODE_TYPES. None to skip
"""
self._audio_proxy.set_chrome_active_node_type(
output_node_type, input_node_type)
def start_arc_recording(self):
"""Starts recording using microphone app in container."""
self._audio_proxy.start_arc_recording()
def stop_arc_recording(self):
"""Checks the recording is stopped and gets the recorded path.
The recording duration of microphone app is fixed, so this method just
asks Cros device to copy the recorded result from container to a path
on Cros device.
@returns: Path to the recorded file on DUT.
"""
return self._audio_proxy.stop_arc_recording()
def set_arc_playback_file(self, path):
"""Copies the file from server to Cros host and into container.
@param path: Path to the file on server.
@returns: Path to the file in container on Cros host.
"""
client_file_path = self.set_playback_file(path)
return self._audio_proxy.set_arc_playback_file(client_file_path)
def start_arc_playback(self, path):
"""Starts playback through ARC on Cros host.
@param path: Path to the file in container on Cros host.
"""
self._audio_proxy.start_arc_playback(path)
def stop_arc_playback(self):
"""Stops playback through ARC on Cros host."""
self._audio_proxy.stop_arc_playback()