blob: f4b79e72cd0ae65f35b5f5a4736d936af3460a3c [file] [log] [blame]
# Copyright (c) 2012 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.
import logging
import os
import subprocess
import tempfile
import threading
import time
from autotest_lib.client.bin import test, utils
from autotest_lib.client.common_lib import error
from autotest_lib.client.common_lib.cros import chrome
from autotest_lib.client.cros import rtc
from autotest_lib.client.cros.audio import audio_helper
from autotest_lib.client.cros.power import power_utils
class power_AudioDetector(test.test):
"""Verifies that audio playback prevents powerd from suspending."""
version = 1
def initialize(self):
self._pref_change = None
def run_once(self, run_time_sec=60):
if run_time_sec < 10:
raise error.TestFail('Must run for at least 10 seconds')
with chrome.Chrome():
# Audio loop time should be significantly shorter than
# |run_time_sec| time, so that the total playback time doesn't
# exceed it by much.
audio_loop_time_sec = min(10, run_time_sec / 10 + 0.5)
# Set a low audio volume to avoid annoying people during tests.
audio_helper.set_volume_levels(10, 100)
# Start a subprocess that uses dbus-monitor to listen for suspend
# announcements from powerd and writes the output to a log.
dbus_log_fd, dbus_log_name = tempfile.mkstemp()
os.unlink(dbus_log_name)
dbus_log = os.fdopen(dbus_log_fd)
dbus_proc = subprocess.Popen(
'dbus-monitor --monitor --system ' +
'"type=\'signal\',interface=\'org.chromium.PowerManager\',' +
'member=\'SuspendImminent\'"', shell=True, stdout=dbus_log)
# Start playing audio file.
self._enable_audio_playback = True
thread = threading.Thread(target=self._play_audio,
args=(audio_loop_time_sec,))
thread.start()
# Restart powerd with timeouts for quick idle events.
gap_ms = run_time_sec * 1000 / 4
dim_ms = min(10000, gap_ms)
off_ms = min(20000, gap_ms * 2)
suspend_ms = min(30000, gap_ms * 3)
prefs = { 'disable_idle_suspend' : 0,
'ignore_external_policy' : 1,
'plugged_dim_ms' : dim_ms,
'plugged_off_ms' : off_ms,
'plugged_suspend_ms' : suspend_ms,
'unplugged_dim_ms' : dim_ms,
'unplugged_off_ms' : off_ms,
'unplugged_suspend_ms' : suspend_ms }
self._pref_change = power_utils.PowerPrefChanger(prefs)
# Set an alarm to wake up the system in case the audio detector
# fails and the system suspends.
alarm_time = rtc.get_seconds() + run_time_sec
rtc.set_wake_alarm(alarm_time)
time.sleep(run_time_sec)
# Stop powerd to avoid suspending when the audio stops.
utils.system_output('stop powerd')
# Stop audio and wait for the audio thread to terminate.
self._enable_audio_playback = False
thread.join(timeout=(audio_loop_time_sec * 2))
if thread.is_alive():
logging.error('Audio thread did not terminate at end of test.')
# Check the D-Bus log to make sure that no suspend took place.
# dbus-monitor logs messages about its initial connection to the bus
# in addition to the signals that we asked it for, so look for the
# signal name in its output.
dbus_proc.kill()
dbus_log.seek(0)
if 'SuspendImminent' in dbus_log.read():
err_str = 'System suspended while audio was playing.'
raise error.TestFail(err_str)
def cleanup(self):
# Restore powerd prefs.
del self._pref_change
def _play_audio(self, loop_time):
"""
Repeatedly plays audio until self._audio_playback_enabled == False.
"""
# TODO(crosbug.com/33988): Allow for pauses in audio playback to
# simulate delays in loading the next song.
while self._enable_audio_playback:
audio_helper.play_sound(duration_seconds=loop_time)
logging.info('Done playing audio.')