From patchwork Tue May 15 14:00:54 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Harsh Prateek Bora X-Patchwork-Id: 8658 Return-Path: X-Original-To: patchwork@peony.canonical.com Delivered-To: patchwork@peony.canonical.com Received: from fiordland.canonical.com (fiordland.canonical.com [91.189.94.145]) by peony.canonical.com (Postfix) with ESMTP id 2308423E13 for ; Tue, 15 May 2012 14:01:06 +0000 (UTC) Received: from mail-ee0-f52.google.com (mail-ee0-f52.google.com [74.125.83.52]) by fiordland.canonical.com (Postfix) with ESMTP id 16C57A1889C for ; Tue, 15 May 2012 14:01:06 +0000 (UTC) Received: by eeke53 with SMTP id e53so2056847eek.11 for ; Tue, 15 May 2012 07:01:06 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=x-forwarded-to:x-forwarded-for:delivered-to:received-spf:from:to:cc :subject:date:message-id:x-mailer:author:x-gm-message-state; bh=9L7AtieWVYKyx8s7VUC1I37yw9/8I/ETMhHv1Ka2EBA=; b=Xl6wEO7k+XwZWctabX2E+847//k+MFpWbxhBgf/1jZ2hsdJOpTxPW6G1v6Rcp3N9Us AZ7esX+4SwQw8mdAf1SQOedjDBG3tjepDlsHYs+DyNCxzIKLJYs6/X6YJCv0RIptcGtm P9zVAadG4EPanGPduJm//uY4Tq4oHTgZVa+EMXQ+0s1FpUSjg6/eSYTVvdlFO7rV4xvB tTr85AJf2lsy2ffSDxELlFZq35TqcWFpX/Ls2R5zeNJ2+bjpBZgRGhbFFQlZtrA50xgO YZ4TdTppqNdCkicJirAKkkO8UuT5sJsBytLPgiNZKkvsJ99hrcIQh6DuKHLZntQFmRvK 4u+w== Received: by 10.42.119.129 with SMTP id b1mr6149693icr.48.1337090465553; Tue, 15 May 2012 07:01:05 -0700 (PDT) X-Forwarded-To: linaro-patchwork@canonical.com X-Forwarded-For: patch@linaro.org linaro-patchwork@canonical.com Delivered-To: patches@linaro.org Received: by 10.231.35.72 with SMTP id o8csp422658ibd; Tue, 15 May 2012 07:01:04 -0700 (PDT) Received: by 10.68.203.202 with SMTP id ks10mr5915076pbc.11.1337090464643; Tue, 15 May 2012 07:01:04 -0700 (PDT) Received: from mail-pb0-f50.google.com (mail-pb0-f50.google.com [209.85.160.50]) by mx.google.com with ESMTPS id vv5si1494920pbc.127.2012.05.15.07.01.04 (version=TLSv1/SSLv3 cipher=OTHER); Tue, 15 May 2012 07:01:04 -0700 (PDT) Received-SPF: neutral (google.com: 209.85.160.50 is neither permitted nor denied by best guess record for domain of harsh.bora@linaro.org) client-ip=209.85.160.50; Authentication-Results: mx.google.com; spf=neutral (google.com: 209.85.160.50 is neither permitted nor denied by best guess record for domain of harsh.bora@linaro.org) smtp.mail=harsh.bora@linaro.org Received: by pbbrr4 with SMTP id rr4so9445969pbb.37 for ; Tue, 15 May 2012 07:01:04 -0700 (PDT) Received: by 10.68.240.135 with SMTP id wa7mr5952775pbc.7.1337090464215; Tue, 15 May 2012 07:01:04 -0700 (PDT) Received: from localhost.localdomain ([122.167.111.156]) by mx.google.com with ESMTPS id pp8sm1962178pbb.21.2012.05.15.07.01.01 (version=TLSv1/SSLv3 cipher=OTHER); Tue, 15 May 2012 07:01:03 -0700 (PDT) From: Harsh Prateek Bora To: linaro-dev@lists.linaro.org Cc: patches@linaro.org, tom.gall@linaro.org, Harsh Prateek Bora Subject: [RFC PATCH v1] AudiVal (Audio Validation Suite for Linux) Date: Tue, 15 May 2012 19:30:54 +0530 Message-Id: <1337090454-7702-1-git-send-email-harsh.bora@linaro.org> X-Mailer: git-send-email 1.7.5.4 Author: Harsh Bora X-Gm-Message-State: ALoCoQlCWoBE1kJDvo/6ZMLutbeaV3t/QM7tNfwLk2uf8iWyn1vWWP4qI/x745Kms0RdycTBfYgk AudiVal (Audio Validation Suite for Linux) This is an attempt to automate and integrate various audio related tests which can help validate audio on various boards supported by Linaro. Motivation for this project comes from various audio tests listed at: https://wiki.linaro.org/TomGall/LinaroAudioFeatureIndex The git repo for this project can be cloned from: git://git.linaro.org/people/harshbora/audival.git Various files required by this script are available in the git repo. Requesting all to test this script on various boards that you may have access to and share feedback to make it better. TODO: Add tests for Audio over USB, Bluetooth. Signed-off-by: Harsh Prateek Bora diff --git a/login.wav b/login.wav new file mode 100644 index 0000000..ec06433 Binary files /dev/null and b/login.wav differ diff --git a/AudiVal.py b/AudiVal.py new file mode 100755 index 0000000..7d56c4e --- /dev/null +++ b/AudiVal.py @@ -0,0 +1,247 @@ +#!/usr/bin/env python +# +# Audival : Audio Validation Suite for Linux. +# +# Author: Harsh Prateek Bora +# +# + +import os +import sys +import getopt +from subprocess import * # for calling external programs +import commands # deprecated since python 2.6, Python 3.0 uses subprocess + +def usage(): + print "=========================================" + print "AudiVal: Audio Validation Suite for Linux" + print "=========================================" + print "Usage:" + print sys.argv[0], "[--check-info]" + print + print "Supported HW: PandaBoard (ES), BeagleBoard (XM), i.MX53, i.MX6, Origen, Snowball" + sys.exit(1) + +SpeakerJack = { + 'GenuineIntel': 'Analog', + 'Panda': 'Headset', + 'Beagle': 'TWL4030', + 'i.MX53': 'HiFi', + 'i.MX6': 'HiFi', + 'ORIGEN': 'Pri_Dai', + 'Snowball': 'Headset' +} + +MicJack = { + 'GenuineIntel': 'Analog', + 'Panda': 'Headset', # not sure though, arecord doesnt work for me! + 'Beagle': 'TWL4030', + 'i.MX53': 'HiFi', + 'i.MX6': 'HiFi', + 'ORIGEN': 'Pri_Dai', + 'Snowball': 'Headset' +} + +# As and when HDMI out/in device string differs, we'll need 2 dictionaries. +HDMI_Audio = { + 'GenuineIntel': 'HDMI', + 'Panda': 'HDMI', + 'Beagle': 'HDMI', + 'i.MX53': 'HDMI', + 'i.MX6': 'HDMI', # audio out only supported, audio in not supported. + 'ORIGEN': 'HDMI', + 'Snowball': 'hdmi' # odd one, lowercase +} + +Audio_Devices = { + 'playback': 'aplay-l.log', + 'capture': 'arecord-l.log' +} + +def get_device_list(logfile): + fobj = open(logfile) + return fobj + +def get_card_device_info_by_name(devicestr, fobj): + """Helper routine to get card, device number by interface name""" + optxt = fobj.readlines() + card = "" + device = "" + for line in optxt: + if devicestr in line: + cardtext, colon, text = line.partition(':') + pre, sep, card = cardtext.partition(' ') + devtext, colon, text = text.partition(':') + pre, sep, device = devtext.partition('device ') + break + hwstr = 'plughw:' + card + ',' + device + if card is "" and device is "": + return None + return hwstr + +def speaker_test_audio_jack(board): + fobj = get_device_list(Audio_Devices['playback']) + print "speaker-test over audio jack .." + headset_jack_id = get_card_device_info_by_name(SpeakerJack[board], fobj) + fobj.close() + if headset_jack_id is None: + print "No Audio Jack found !" + return + call("date > speaker-test-jack.log", shell=True) + cmdstr = "speaker-test -D " + headset_jack_id + " -t s -c 2 -l 1 > speaker-test-jack.log 2>&1" + call(cmdstr, shell=True) + print "If you heard beeps from left and right speaker, test passed." + +def aplay_over_jack(board): + fobj = get_device_list(Audio_Devices['playback']) + headset_jack_id = get_card_device_info_by_name(SpeakerJack[board], fobj) + print "Testing aplay over audio jack .." + fobj.close() + if headset_jack_id is None: + print "No Audio Jack found !" + return + cmdstr = "aplay login.wav -D " + headset_jack_id + call(cmdstr, shell=True) + print "If you heard a stereo sound, test passed." + # Check dmesg to see if there is an error or I2C error + call("dmesg | tail | grep error", shell=True) + print "Note: Error, if any, shall be displayed above." + +def arecord_and_aplay_over_audio_jack(board): + # Record the WAV stream and play it back. + fobj = get_device_list(Audio_Devices['capture']) + mic_jack_id = get_card_device_info_by_name(MicJack[board], fobj) + if mic_jack_id is None: + print "No Mic Jack found !" + return + cmdstr = "arecord -c 2 -f S16_LE -d 10 -r 44100 aud44k16S.wav -D " + mic_jack_id + print "Testing arecord over audio jack .." + print "Started recording audio over jack for 10 seconds (replay follows) .." + call(cmdstr, shell=True) + print "Replaying the recorded audio now .." + call("aplay aud44k16S.wav", shell=True) + # Check dmesg to see if there is an error or I2C error + call("dmesg | tail | grep error", shell=True) + print "If you heard the recorded audio, test passed." + print "Note: Error, if any, shall be displayed above." + fobj.close() + +def speaker_test_over_hdmi(board): + """ speaker-test over HDMI audio interface. """ + fobj = get_device_list(Audio_Devices['playback']) + print "Running speaker-test over HDMI .." + # Automatic detection of card,device number for HDMI interface + hdmi_hw_id = get_card_device_info_by_name(HDMI_Audio[board], fobj) + if hdmi_hw_id is None: + print "No HDMI device found !" + return + cmdstr = "speaker-test -D " + hdmi_hw_id + " -t s -c 2 -l 1 > speaker-test-hdmi.log 2>&1" + print "speaker-test over HDMI .." + call(cmdstr, shell=True) + print "If you heard beeps from left and right speaker, test passed." + fobj.close() + +def arecord_and_aplay_over_hdmi(board): + """ arecord and aplay over HDMI audio interface. """ + fobj = get_device_list(Audio_Devices['capture']) + print "Testing arecord over HDMI .." + # Automatic detection of card,device number for HDMI interface + hdmi_hw_info = get_card_device_info_by_name(HDMI_Audio[board], fobj) + if hdmi_hw_info is None: + print "No HDMI device found !" + sys.exit(1) + return + arecord_cmd = "arecord -D " + hdmi_hw_info + " -c 2 -f S16_LE -d 10 -r 44100 aud44k16S.wav" + aplay_cmd = "aplay -D " + hdmi_hw_info + " aud44k16S.wav" + print "Started recording audio over HDMI for 10 seconds (replay follows).." + call(arecord_cmd, shell=True) + print "Replaying the recorded audio now .." + call(aplay_cmd, shell=True) + # Check dmesg to see if there is an error or I2C error + call("dmesg | tail | grep error", shell=True) + print "If you heard the recorded audio, test passed." + print "Note: Error, if any, shall be displayed above." + fobj.close() + +def mixer_panda(): + # silently setup mixer using -q + call("amixer sset Headset 10 -q", shell=True) + call("amixer sset 'Headset Left Playback' 'HS DAC' -q", shell=True) + call("amixer sset 'Headset Right Playback' 'HS DAC' -q", shell=True) + +def mixer_nop(): + pass # for unknown mixer settings + +MixerSetup = { + 'GenuineIntel': mixer_nop, + 'Panda': mixer_panda, + 'Beagle': mixer_nop, + 'i.MX53': mixer_nop, + 'i.MX6': mixer_nop, + 'ORIGEN': mixer_nop, + 'Snowball': mixer_nop +} + +def audio_tests(board): + MixerSetup[board]() + # minimal speaker test producing a sine wave tone. + speaker_test_audio_jack(board) + + # testing alsa with a stereo sound using aplay over jack + aplay_over_jack(board); + # Record a WAV stream using arecord and play it back over jack. + arecord_and_aplay_over_audio_jack(board) + + # speaker-test over HDMI + speaker_test_over_hdmi(board) # Need to test, dont have HDMI hw ! + # arecord and aplay over HDMI + arecord_and_aplay_over_hdmi(board) # Need to test, dont have HDMI hw ! + + +def check_sound_info(): + print + print "Running alsa-info.sh ..\n" + call("alsa-info.sh --stdout", shell=True) + print "************************************************\n" + +def main(): + cpuinfo = ["Beagle", "Panda", "i.MX6", "i.MX53", "ORIGEN", "Snowball", "GenuineIntel"] + long_options = ["check-info"] + runtest = "" + try: + opts, args = getopt.getopt(sys.argv[1:], "", long_options) + except getopt.GetoptError, err: + # print help information and exit + # will print something like "option -a not recognized" + sys.stderr.writelines(str(err)+"\n") + usage() + + call("aplay -l > aplay-l.log", shell=True) + call("arecord -l > arecord-l.log", shell=True) + + for opt, arg in opts: + if opt == '--check-info': + print "Checking Sound/Audio related info ..." + check_sound_info() + sys.exit(0) + else: + print "unhandled option:", opt + usage() + + cpufile = open("/proc/cpuinfo") + cputext = cpufile.readlines() + + for line in cputext: + for board in cpuinfo: + if board in line: + print "Hardware Detected: %s" % board + print "Running audiotests for %s .." % board + audio_tests(board) + sys.exit(0) + + print "Err, looks like your hardware is not supported." + print "Please report to harsh.bora@linaro.org" + sys.exit(1) + +if __name__ == "__main__": + main()