Home | History | Annotate | Download | only in power_AudioDetector
      1 # Copyright (c) 2012 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 import logging
      6 import os
      7 import subprocess
      8 import tempfile
      9 import threading
     10 import time
     11 
     12 from autotest_lib.client.bin import test, utils
     13 from autotest_lib.client.common_lib import error
     14 from autotest_lib.client.common_lib.cros import chrome
     15 from autotest_lib.client.cros import rtc
     16 from autotest_lib.client.cros.audio import audio_helper
     17 from autotest_lib.client.cros.power import power_utils
     18 
     19 class power_AudioDetector(test.test):
     20     """Verifies that audio playback prevents powerd from suspending."""
     21     version = 1
     22 
     23     def initialize(self):
     24         self._pref_change = None
     25 
     26 
     27     def run_once(self, run_time_sec=60):
     28         if run_time_sec < 10:
     29             raise error.TestFail('Must run for at least 10 seconds')
     30 
     31         with chrome.Chrome():
     32             # Audio loop time should be significantly shorter than
     33             # |run_time_sec| time, so that the total playback time doesn't
     34             # exceed it by much.
     35             audio_loop_time_sec = min(10, run_time_sec / 10 + 0.5)
     36 
     37             # Set a low audio volume to avoid annoying people during tests.
     38             audio_helper.set_volume_levels(10, 100)
     39 
     40             # Start a subprocess that uses dbus-monitor to listen for suspend
     41             # announcements from powerd and writes the output to a log.
     42             dbus_log_fd, dbus_log_name = tempfile.mkstemp()
     43             os.unlink(dbus_log_name)
     44             dbus_log = os.fdopen(dbus_log_fd)
     45             dbus_proc = subprocess.Popen(
     46                 'dbus-monitor --monitor --system ' +
     47                 '"type=\'signal\',interface=\'org.chromium.PowerManager\',' +
     48                 'member=\'SuspendImminent\'"', shell=True, stdout=dbus_log)
     49 
     50             # Start playing audio file.
     51             self._enable_audio_playback = True
     52             thread = threading.Thread(target=self._play_audio,
     53                                       args=(audio_loop_time_sec,))
     54             thread.start()
     55 
     56             # Restart powerd with timeouts for quick idle events.
     57             gap_ms = run_time_sec * 1000 / 4
     58             dim_ms = min(10000, gap_ms)
     59             off_ms = min(20000, gap_ms * 2)
     60             suspend_ms = min(30000, gap_ms * 3)
     61             prefs = { 'disable_idle_suspend'   : 0,
     62                       'ignore_external_policy' : 1,
     63                       'plugged_dim_ms'         : dim_ms,
     64                       'plugged_off_ms'         : off_ms,
     65                       'plugged_suspend_ms'     : suspend_ms,
     66                       'unplugged_dim_ms'       : dim_ms,
     67                       'unplugged_off_ms'       : off_ms,
     68                       'unplugged_suspend_ms'   : suspend_ms }
     69             self._pref_change = power_utils.PowerPrefChanger(prefs)
     70 
     71             # Set an alarm to wake up the system in case the audio detector
     72             # fails and the system suspends.
     73             alarm_time = rtc.get_seconds() + run_time_sec
     74             rtc.set_wake_alarm(alarm_time)
     75 
     76             time.sleep(run_time_sec)
     77 
     78             # Stop powerd to avoid suspending when the audio stops.
     79             utils.system_output('stop powerd')
     80 
     81             # Stop audio and wait for the audio thread to terminate.
     82             self._enable_audio_playback = False
     83             thread.join(timeout=(audio_loop_time_sec * 2))
     84             if thread.is_alive():
     85                 logging.error('Audio thread did not terminate at end of test.')
     86 
     87             # Check the D-Bus log to make sure that no suspend took place.
     88             # dbus-monitor logs messages about its initial connection to the bus
     89             # in addition to the signals that we asked it for, so look for the
     90             # signal name in its output.
     91             dbus_proc.kill()
     92             dbus_log.seek(0)
     93             if 'SuspendImminent' in dbus_log.read():
     94                 err_str = 'System suspended while audio was playing.'
     95                 raise error.TestFail(err_str)
     96 
     97 
     98     def cleanup(self):
     99         # Restore powerd prefs.
    100         del self._pref_change
    101 
    102 
    103     def _play_audio(self, loop_time):
    104         """
    105         Repeatedly plays audio until self._audio_playback_enabled == False.
    106         """
    107         # TODO(crosbug.com/33988): Allow for pauses in audio playback to
    108         # simulate delays in loading the next song.
    109         while self._enable_audio_playback:
    110             audio_helper.play_sound(duration_seconds=loop_time)
    111         logging.info('Done playing audio.')
    112