Example #1
0
    def run_once(self):
        """Entry point of this test."""
        self.chrome.browser.platform.SetHTTPServerDirectories(self.bindir)

        video_url = self.chrome.browser.platform.http_server.UrlOf(
            os.path.join(self.bindir, 'youtube.html'))
        logging.info('Playing back youtube media file %s.', video_url)
        noise_file = os.path.join(self.resultsdir, "noise.wav")
        recorded_file = os.path.join(self.resultsdir, "recorded.wav")
        loopback_file = os.path.join(self.resultsdir, "loopback.wav")

        # Record a sample of "silence" to use as a noise profile.
        cras_utils.capture(noise_file, duration=3)

        # Play a video and record the audio output
        self.play_video(self.chrome.browser.tabs[0], video_url)

        p1 = cmd_utils.popen(
            cras_utils.capture_cmd(recorded_file, duration=TEST_DURATION))
        p2 = cmd_utils.popen(
            cras_utils.loopback_cmd(loopback_file, duration=TEST_DURATION))

        cmd_utils.wait_and_check_returncode(p1, p2)

        # See if we recorded something
        loopback_stats = [
            audio_helper.get_channel_sox_stat(loopback_file, i) for i in (1, 2)
        ]
        logging.info('loopback stats: %s', [str(s) for s in loopback_stats])
        rms_value = audio_helper.reduce_noise_and_get_rms(
            recorded_file, noise_file)[0]

        self.write_perf_keyval({'rms_value': rms_value})
def reduce_noise_and_get_rms(input_audio,
                             noise_file,
                             channels=1,
                             bits=16,
                             rate=48000):
    """Reduces noise in the input audio by the given noise file and then gets
    the RMS values of all channels of the input audio.

    @param input_audio: The input audio file to be analyzed.
    @param noise_file: The noise file used to reduce noise in the input audio.
    @param channels: The number of channels in the input audio.
    @param bits: The number of bits of each audio sample.
    @param rate: The sampling rate.
    """
    with tempfile.NamedTemporaryFile() as reduced_file:
        p1 = cmd_utils.popen(sox_utils.noise_profile_cmd(noise_file,
                                                         '-',
                                                         channels=channels,
                                                         bits=bits,
                                                         rate=rate),
                             stdout=subprocess.PIPE)
        p2 = cmd_utils.popen(sox_utils.noise_reduce_cmd(input_audio,
                                                        reduced_file.name,
                                                        '-',
                                                        channels=channels,
                                                        bits=bits,
                                                        rate=rate),
                             stdin=p1.stdout)
        cmd_utils.wait_and_check_returncode(p1, p2)
        return get_rms(reduced_file.name, channels, bits, rate)
    def rms_test(self, tab, media_file, noiseprof_file, test_duration):
        logging.info('rms test on media file %s.', media_file)
        recorded_file = os.path.join(self.resultsdir, 'recorded.wav')
        loopback_file = os.path.join(self.resultsdir, 'loopback.wav')

        # Plays the media_file in the browser.
        self.play_media(tab, media_file)

        # Record the audio output and also the CRAS loopback output.
        p1 = cmd_utils.popen(
            cras_utils.capture_cmd(recorded_file, duration=test_duration))
        p2 = cmd_utils.popen(
            cras_utils.loopback_cmd(loopback_file, duration=test_duration))
        cmd_utils.wait_and_check_returncode(p1, p2)

        # See if we recorded something.

        # We captured two channels of audio in the CRAS loopback.
        # The RMS values are for debugging only.
        loopback_stats = [
            audio_helper.get_channel_sox_stat(loopback_file, i) for i in (1, 2)
        ]
        logging.info('loopback stats: %s', [str(s) for s in loopback_stats])

        reduced_file = tempfile.NamedTemporaryFile()
        sox_utils.noise_reduce(recorded_file, reduced_file.name,
                               noiseprof_file)
        rms = audio_helper.get_rms(reduced_file.name)[0]

        self._rms_values['%s_rms_value' % media_file.replace('.', '_')] = rms

        # Make sure the audio can be played to the end.
        self.wait_player_end(tab)
Example #4
0
def get_channel_sox_stat(
        input_audio, channel_index, channels=2, bits=16, rate=48000):
    """Gets the sox stat info of the selected channel in the input audio file.

    @param input_audio: The input audio file to be analyzed.
    @param channel_index: The index of the channel to be analyzed.
                          (1 for the first channel).
    @param channels: The number of channels in the input audio.
    @param bits: The number of bits of each audio sample.
    @param rate: The sampling rate.
    """
    if channel_index <= 0 or channel_index > channels:
        raise ValueError('incorrect channel_indexi: %d' % channel_index)

    if channels == 1:
        return sox_utils.get_stat(
                input_audio, channels=channels, bits=bits, rate=rate)

    p1 = cmd_utils.popen(
            sox_utils.extract_channel_cmd(
                    input_audio, '-', channel_index,
                    channels=channels, bits=bits, rate=rate),
            stdout=subprocess.PIPE)
    p2 = cmd_utils.popen(
            sox_utils.stat_cmd('-', channels=1, bits=bits, rate=rate),
            stdin=p1.stdout, stderr=subprocess.PIPE)
    stat_output = p2.stderr.read()
    cmd_utils.wait_and_check_returncode(p1, p2)
    return sox_utils.parse_stat_output(stat_output)
Example #5
0
 def play_sine_tone(self, frequence, rate):
     """Plays a sine tone by cras and returns the processes.
     Args:
         frequence: the frequence of the sine wave.
         rate: the sampling rate.
     """
     p1 = cmd_utils.popen(sox_utils.generate_sine_tone_cmd(
         filename='-', rate=rate, frequence=frequence, gain=-6),
                          stdout=cmd_utils.PIPE)
     p2 = cmd_utils.popen(cras_utils.playback_cmd(playback_file='-',
                                                  rate=rate),
                          stdin=p1.stdout)
     return [p1, p2]
Example #6
0
def get_default_record_device():
    '''Gets the first record device.

    Returns the first record device or None if it fails to find one.
    '''

    card_id = get_first_soundcard_with_control(cname='Mic Jack', scname='Mic')
    if card_id is None:
        return None

    # Get first device id of this card.
    cmd = ARECORD_PATH + ' -l'
    p = cmd_utils.popen(shlex.split(cmd), stdout=cmd_utils.PIPE)
    output, _ = p.communicate()
    if p.wait() != 0:
        raise RuntimeError('arecord -l command failed')

    dev_id = 0
    for line in output.splitlines():
        if 'card %d:' % card_id in line:
            match = DEV_NUM_RE.search(line)
            if match:
                dev_id = int(match.group(1))
                break
    return 'plughw:%d,%d' % (card_id, dev_id)
Example #7
0
def _get_soundcard_scontrols(card_id):
    '''Gets the simple mixer controls for a soundcard.

    @param card_id: Soundcard ID.
    @raise RuntimeError: If failed to get soundcard simple mixer controls.

    Simple mixer controls for a soundcard is retrieved by 'amixer scontrols'
    command.  amixer output format:

      Simple mixer control 'Master',0
      Simple mixer control 'Headphone',0
      Simple mixer control 'Speaker',0
      Simple mixer control 'PCM',0

    Simple controls are parsed from the output and returned in a set.
    '''

    cmd = AMIXER_PATH + ' -c %d scontrols' % card_id
    p = cmd_utils.popen(shlex.split(cmd), stdout=cmd_utils.PIPE)
    output, _ = p.communicate()
    if p.wait() != 0:
        raise RuntimeError('amixer command failed')

    scontrols = set()
    for line in output.splitlines():
        match = SCONTROL_NAME_RE.findall(line)
        if match:
            scontrols.add(match[0])
    return scontrols
Example #8
0
    def run_once(self):
        """Entry point of this test."""

        # Sine wav file lasts 5 seconds
        wav_path = os.path.join(self.bindir, '5SEC.wav')
        data_format = dict(file_type='wav',
                           sample_format='S16_LE',
                           channel=2,
                           rate=48000)
        wav_file = audio_test_data.GenerateAudioTestData(
            path=wav_path,
            data_format=data_format,
            duration_secs=5,
            frequencies=[440, 440],
            volume_scale=0.9)

        recorded_file = os.path.join(self.resultsdir, 'hw_recorded.wav')

        # Get selected input and output devices.
        cras_input = cras_utils.get_selected_input_device_name()
        cras_output = cras_utils.get_selected_output_device_name()
        logging.debug("Selected input=%s, output=%s", cras_input, cras_output)
        if cras_input is None:
            raise error.TestFail("Fail to get selected input device.")
        if cras_output is None:
            raise error.TestFail("Fail to get selected output device.")
        alsa_input = alsa_utils.convert_device_name(cras_input)
        alsa_output = alsa_utils.convert_device_name(cras_output)

        (output_type, input_type) = cras_utils.get_selected_node_types()
        if not any(t in input_type for t in ['MIC', 'USB']):
            raise error.TestFail("Wrong input type=%s", input_type)
        if not any(t in output_type for t in ['HEADPHONE', 'USB']):
            raise error.TestFail("Wrong output type=%s", output_type)

        # Stop CRAS to make sure the audio device won't be occupied.
        utils.stop_service('cras', ignore_status=True)

        p = cmd_utils.popen(
            alsa_utils.playback_cmd(wav_file.path, device=alsa_output))
        try:
            # Wait one second to make sure the playback has been started.
            time.sleep(1)
            alsa_utils.record(recorded_file,
                              duration=TEST_DURATION,
                              device=alsa_input)

            # Make sure the audio is still playing.
            if p.poll() != None:
                raise error.TestError('playback stopped')
        finally:
            cmd_utils.kill_or_log_returncode(p)
            wav_file.delete()

            # Restart CRAS.
            utils.start_service('cras', ignore_status=True)

        rms_value = audio_helper.get_rms(recorded_file)[0]

        self.write_perf_keyval({'rms_value': rms_value})
    def run_once(self):
        """Entry point of this test."""

        # Multitone wav file lasts 10 seconds
        wav_path = os.path.join(self.bindir, '10SEC.wav')

        noise_file = os.path.join(self.resultsdir, 'cras_noise.wav')
        recorded_file = os.path.join(self.resultsdir, 'cras_recorded.wav')

        # Record a sample of "silence" to use as a noise profile.
        cras_utils.capture(noise_file, duration=1)

        self.wait_for_active_stream_count(0)
        p = cmd_utils.popen(cras_utils.playback_cmd(wav_path))
        try:
            self.wait_for_active_stream_count(1)
            cras_utils.capture(recorded_file, duration=TEST_DURATION)

            # Make sure the audio is still playing.
            if p.poll() != None:
                raise error.TestError('playback stopped')
        finally:
            cmd_utils.kill_or_log_returncode(p)

        rms_value = audio_helper.reduce_noise_and_get_rms(
            recorded_file, noise_file)[0]
        self.write_perf_keyval({'rms_value': rms_value})
Example #10
0
def _get_soundcard_controls(card_id):
    '''Gets the controls for a soundcard.

    @param card_id: Soundcard ID.
    @raise RuntimeError: If failed to get soundcard controls.

    Controls for a soundcard is retrieved by 'amixer controls' command.
    amixer output format:

      numid=32,iface=CARD,name='Front Headphone Jack'
      numid=28,iface=CARD,name='Front Mic Jack'
      numid=1,iface=CARD,name='HDMI/DP,pcm=3 Jack'
      numid=8,iface=CARD,name='HDMI/DP,pcm=7 Jack'

    Controls with iface=CARD are parsed from the output and returned in a set.
    '''

    cmd = AMIXER_PATH + ' -c %d controls' % card_id
    p = cmd_utils.popen(shlex.split(cmd), stdout=cmd_utils.PIPE)
    output, _ = p.communicate()
    if p.wait() != 0:
        raise RuntimeError('amixer command failed')

    controls = set()
    for line in output.splitlines():
        if not 'iface=CARD' in line:
            continue
        match = CONTROL_NAME_RE.search(line)
        if match:
            controls.add(match.group(1))
    return controls
    def run_once(self):
        """Entry point of this test."""

        # Generate sine raw file that lasts 5 seconds.
        raw_path = os.path.join(self.bindir, '5SEC.raw')
        data_format = dict(file_type='raw', sample_format='S16_LE',
                channel=2, rate=48000)
        raw_file = audio_test_data.GenerateAudioTestData(
            path=raw_path,
            data_format=data_format,
            duration_secs=5,
            frequencies=[440, 440],
            volume_scale=0.9)

        recorded_file = os.path.join(self.resultsdir, 'cras_recorded.raw')

        self.wait_for_active_stream_count(0)
        p = cmd_utils.popen(cras_utils.playback_cmd(raw_file.path))
        try:
            self.wait_for_active_stream_count(1)
            cras_utils.capture(recorded_file, duration=TEST_DURATION)

            # Make sure the audio is still playing.
            if p.poll() != None:
                raise error.TestError('playback stopped')
        finally:
            cmd_utils.kill_or_log_returncode(p)
            raw_file.delete()

        rms_value = audio_helper.get_rms(recorded_file)[0]
        self.write_perf_keyval({'rms_value': rms_value})
Example #12
0
    def _test_audio_disabled(self, policy_value):
        """
        Verify the AudioOutputAllowed policy behaves as expected.

        Generate and play a sample audio file. When enabled, the difference
        between the muted and unmuted RMS should be greater than 0.75. When
        disabled, the RMS difference should be less than 0.05.

        @param policy_value: policy value for this case.

        @raises error.TestFail: In the case where the audio behavior
            does not match the policy value.

        """
        audio_allowed = policy_value or policy_value is None

        RAW_FILE = os.path.join(self.enterprise_dir, 'test_audio.raw')
        noise_file = os.path.join(self.resultsdir, 'noise.wav')
        recorded_file = os.path.join(self.resultsdir, 'recorded-cras.raw')
        recorded_rms = []

        # Record a sample of silence to use as a noise profile.
        cras_utils.capture(noise_file, duration=2)
        logging.info('NOISE: %s', audio_helper.get_rms(noise_file))

        # Get two RMS samples: one when muted and one when not
        for muted in [False, True]:
            cras_utils.set_system_mute(muted)

            # Play the audio file and capture the output
            self.wait_for_active_stream_count(0)
            p = cmd_utils.popen(cras_utils.playback_cmd(RAW_FILE))
            try:
                self.wait_for_active_stream_count(1)
                cras_utils.capture(recorded_file,
                                   duration=self.SAMPLE_DURATION)

                if p.poll() is not None:
                    raise error.TestError('Audio playback stopped prematurely')
            finally:
                cmd_utils.kill_or_log_returncode(p)

            rms_value = audio_helper.reduce_noise_and_get_rms(
                recorded_file, noise_file)[0]

            logging.info('muted (%s): %s' % (muted, rms_value))
            recorded_rms.append(rms_value)

        rms_diff = recorded_rms[0] - recorded_rms[1]
        self.write_perf_keyval({'rms_diff': rms_diff})

        if audio_allowed:
            if rms_diff < 0.4:
                raise error.TestFail('RMS difference not large enough between '
                                     'mute and ummute: %s' % rms_diff)
        else:
            if abs(rms_diff) > 0.05:
                raise error.TestFail('RMS difference too wide while audio '
                                     'disabled: %s' % rms_diff)
Example #13
0
    def run_in_parallel(self, *commands):
        env = os.environ.copy()

        # To clear the temparory files created by vea_unittest.
        env['TMPDIR'] = self.tmpdir
        if not utils.is_freon():
            env['DISPLAY'] = ':0'
            env['XAUTHORITY'] = '/home/chronos/.Xauthority'
        return map(lambda c: cmd_utils.popen(c, env=env), commands)
Example #14
0
def _get_sysdefault(cmd):
    p = cmd_utils.popen(shlex.split(cmd), stdout=cmd_utils.PIPE)
    output, _ = p.communicate()
    if p.wait() != 0:
        raise RuntimeError('%s failed' % cmd)

    for line in output.splitlines():
        if 'sysdefault' in line:
            return line
    return None
Example #15
0
def get_stat(*args, **kargs):
    """A helper function to execute the stat_cmd.

    It returns the statistical information (in text) read from the standard
    error.
    """
    p = cmd_utils.popen(stat_cmd(*args, **kargs), stderr=cmd_utils.PIPE)

    #The output is read from the stderr instead of stdout
    stat_output = p.stderr.read()
    cmd_utils.wait_and_check_returncode(p)
    return parse_stat_output(stat_output)
Example #16
0
def playback(blocking=True, *args, **kargs):
    """A helper function to execute the playback_cmd.

    @param blocking: Blocks this call until playback finishes.
    @param args: args passed to playback_cmd.
    @param kargs: kargs passed to playback_cmd.

    @returns: The process running the playback command. Note that if the
              blocking parameter is true, this will return a finished process.
    """
    process = cmd_utils.popen(playback_cmd(*args, **kargs))
    if blocking:
        cmd_utils.wait_and_check_returncode(process)
    return process
def get_record_card_name(card_idx):
    '''Gets the recording sound card name for given card idx.

    Returns the card name inside the square brackets of arecord output lines.
    '''
    card_name_re = re.compile(r'card %d: .*?\[(.*?)\]' % card_idx)
    cmd = [ARECORD_PATH, '-l']
    p = cmd_utils.popen(cmd, stdout=subprocess.PIPE)
    output, _ = p.communicate()
    if p.wait() != 0:
        raise RuntimeError('arecord -l command failed')

    for line in output.splitlines():
        match = card_name_re.search(line)
        if match:
            return match.group(1)
    return None
Example #18
0
def mixer_cmd(card_id, cmd):
    '''Executes amixer command.

    @param card_id: Soundcard ID.
    @param cmd: Amixer command to execute.
    @raise RuntimeError: If failed to execute command.

    Amixer command like "set PCM 2dB+" with card_id 1 will be executed as:
        amixer -c 1 set PCM 2dB+

    Command output will be returned if any.
    '''

    cmd = AMIXER_PATH + ' -c %d ' % card_id + cmd
    p = cmd_utils.popen(shlex.split(cmd), stdout=cmd_utils.PIPE)
    output, _ = p.communicate()
    if p.wait() != 0:
        raise RuntimeError('amixer command failed')
    return output
def mixer_cmd(card_id, cmd):
    '''Executes amixer command.

    @param card_id: Soundcard ID.
    @param cmd: Amixer command to execute.
    @raise RuntimeError: If failed to execute command.

    Amixer command like ['set', 'PCM', '2dB+'] with card_id 1 will be executed
    as:
        amixer -c 1 set PCM 2dB+

    Command output will be returned if any.
    '''

    cmd = [AMIXER_PATH, '-c', str(card_id)] + cmd
    p = cmd_utils.popen(cmd, stdout=subprocess.PIPE)
    output, _ = p.communicate()
    if p.wait() != 0:
        raise RuntimeError('amixer command failed')
    return output
    def start(self, data_format):
        """Starts recording.

        Starts recording subprocess. It can be stopped by calling stop().

        @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.

        @raises: RecorderError: If recording subprocess is terminated
                 unexpectedly.

        """
        self._capture_subprocess = cmd_utils.popen(
            cras_utils.capture_cmd(capture_file=self.file_path,
                                   duration=None,
                                   channels=data_format['channel'],
                                   rate=data_format['rate']))
    def run_in_parallel(self, *commands):
        env = os.environ.copy()

        # To clear the temparory files created by vea_unittest.
        env['TMPDIR'] = self.tmpdir
        return map(lambda c: cmd_utils.popen(c, env=env), commands)