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