Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Checkbox 691/missing audio device (New) #622

Merged
merged 23 commits into from
Oct 12, 2023
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 0 additions & 34 deletions providers/base/bin/alsa_pcm_info.py

This file was deleted.

37 changes: 18 additions & 19 deletions providers/base/units/audio/jobs.pxu
Original file line number Diff line number Diff line change
Expand Up @@ -374,7 +374,7 @@ estimated_duration: 1.0
imports: from com.canonical.plainbox import manifest
requires:
package.name == 'pulseaudio-utils'
manifest.has_audio_playback == 'True'
audio_card.playback == 'supported'
diohe0311 marked this conversation as resolved.
Show resolved Hide resolved
command:
pactl_list.sh sinks
_description:
Expand All @@ -388,7 +388,7 @@ estimated_duration: 1.0
imports: from com.canonical.plainbox import manifest
requires:
package.name == 'pulseaudio-utils'
manifest.has_audio_capture == 'True'
audio_card.capture == 'supported'
command:
pactl_list.sh sources
_description:
Expand Down Expand Up @@ -695,32 +695,30 @@ _summary: Check that at least one audio playback device exits
plugin: shell
category_id: com.canonical.plainbox::audio
flags: also-after-suspend
imports: from com.canonical.plainbox import manifest
requires:
manifest.has_audio_playback == 'True'
audio_card.playback == 'supported'
diohe0311 marked this conversation as resolved.
Show resolved Hide resolved
command:
COUNT=$(alsa_pcm_info.py | grep -c Playback)
echo "Count: $COUNT"
if [ "$COUNT" -eq 0 ]; then
exit 1
fi
estimated_duration: 1s
COUNT=$(audio_card_resource.py | grep -c Playback)
echo "Count: $COUNT"
if [ "$COUNT" -eq 0 ]; then
exit 1
fi
estimated_duration: 0.5

id: audio/detect-capture-devices
_summary: Check that at least one audio capture device exists
plugin: shell
category_id: com.canonical.plainbox::audio
flags: also-after-suspend
imports: from com.canonical.plainbox import manifest
requires:
manifest.has_audio_capture == 'True'
audio_card.capture == 'supported'
command:
COUNT=$(alsa_pcm_info.py | grep -c Capture)
echo "Count: $COUNT"
if [ "$COUNT" -eq 0 ]; then
exit 1
fi
esimated_duration: 1s
COUNT=$(audio_card_resource.py | grep -c Capture)
echo "Count: $COUNT"
if [ "$COUNT" -eq 0 ]; then
exit 1
fi
esimated_duration: 0.5

id: audio/alsa-playback
_summary: Playback works
Expand Down Expand Up @@ -920,4 +918,5 @@ plugin: manual
flags: also-after-suspend
requires: snap.name == 'pulseaudio'
category_id: com.canonical.plainbox::audio
estimated_duration: 1m
estimated_duration: 1m

1 change: 1 addition & 0 deletions providers/base/units/audio/manifest.pxu
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,4 @@ id: has_audio_loopback_connector
_prompt: Does this device have the following?:
_name: Audio Loopback Connector
value-type: bool

9 changes: 0 additions & 9 deletions providers/base/units/audio/resource.pxu

This file was deleted.

9 changes: 8 additions & 1 deletion providers/base/units/audio/test-plan.pxu
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ include:
after-suspend-audio/detect_sinks
after-suspend-audio/detect_sources
after-suspend-audio/alsa_record_playback_automated
bootstrap_include:
audio_card

id: audio-full
unit: test plan
Expand Down Expand Up @@ -128,6 +130,8 @@ include:
audio/detect-playback-devices
audio/detect-capture-devices
audio/alsa-loopback-automated
bootstrap_include:
audio_card

id: after-suspend-audio-full
unit: test plan
Expand Down Expand Up @@ -164,4 +168,7 @@ _description: Automated audio tests for Snappy Ubuntu Core devices
include:
after-suspend-audio/detect-playback-devices
after-suspend-audio/detect-capture-devices
after-suspend-audio/alsa-loopback-automated
after-suspend-audio/alsa-loopback-automated
bootstrap_include:
audio_card

82 changes: 82 additions & 0 deletions providers/resource/bin/audio_card_resource.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
#!/usr/bin/env python3
#
# This file is part of Checkbox.
#
# Copyright 2023 Canonical Ltd.
# Authors: Dio He <dio.he@canonical.com>
#
# Checkbox is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 3,
# as published by the Free Software Foundation.
#
# Checkbox is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.

from collections import namedtuple


def get_audio_cards():
"""Retrieve audio card information."""
AudioCard = namedtuple('AudioCard',
['card', 'device', 'name', 'playback', 'capture'])
audio_cards = []
PCM_FILE = '/proc/asound/pcm'
try:
with open(PCM_FILE, 'r') as f:
data = f.readlines()
except OSError:
print('Failed to access {}'.format(PCM_FILE))
return []

for line in data:
info = [device_line.strip() for device_line in line.split(':')]
ids = info[0].split('-')
card_id = ids[0]
device_id = ids[1]
device_name = info[1]
capabilities = info[3:]
playback = ("supported" if has_capability('playback', capabilities)
else "unsupported")
capture = ("supported" if has_capability('capture', capabilities)
else "unsupported")
audio_cards.append(AudioCard(card=card_id,
device=device_id,
name=device_name,
playback=playback,
capture=capture))

return audio_cards


def has_capability(capability_prefix: str, capabilities: list) -> bool:
return any(capability.startswith(capability_prefix)
for capability in capabilities)


def print_audio_cards(cards):
"""Print audio card information."""
for card in cards:
print("Card: {}".format(card.card))
print("Device: {}".format(card.device))
print("Name: {}".format(card.name))
if card.playback == "supported":
print("Playback: 1")
if card.capture == "supported":
print("Capture: 1")
diohe0311 marked this conversation as resolved.
Show resolved Hide resolved
diohe0311 marked this conversation as resolved.
Show resolved Hide resolved
print()


def main():
cards = get_audio_cards()

if cards:
print_audio_cards(cards)


if __name__ == "__main__":
main()
8 changes: 8 additions & 0 deletions providers/resource/jobs/resource.pxu
Original file line number Diff line number Diff line change
Expand Up @@ -468,3 +468,11 @@ command:
else
echo "detected: false"
fi

id: audio_card
estimated_duration: 0.05
plugin: resource
_summary: Collect information about the audio card
_description: Gets audio resource info from /proc/asound/pcm
command: audio_card_resource.py

38 changes: 38 additions & 0 deletions providers/resource/tests/test_audio_card_resource.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#!/usr/bin/env python3
diohe0311 marked this conversation as resolved.
Show resolved Hide resolved
#
# This file is part of Checkbox.
#
# Copyright 2023 Canonical Ltd.
# Authors: Dio He <dio.he@canonical.com>
#
# Checkbox is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 3,
# as published by the Free Software Foundation.
#
# Checkbox is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.

import unittest
from io import StringIO
from collections import namedtuple
from unittest.mock import Mock, patch, mock_open
from audio_card_resource import get_audio_cards


class GetAudioCardsTests(unittest.TestCase):
def test_get_audio_card_info(self):
with patch("os.path.exists") as mock_path:
mock_path.return_value = True
test_input = "00-00: HDA Analog (*) : : playback 1\n00-01: HDA Digital (*) : : capture 1s"
AudioCard = namedtuple('AudioCard', ['card', 'device', 'name', 'playback', 'capture'])
expected_audio_card1 = AudioCard(card="00", device="00", name="HDA Analog (*)", playback="supported", capture="unsupported")
expected_audio_card2 = AudioCard(card="00", device="01", name="HDA Digital (*)", playback="unsupported", capture="supported")
with patch("builtins.open", new=mock_open(read_data=test_input)):
audio_cards = get_audio_cards()
self.assertEqual(audio_cards[0], expected_audio_card1)
self.assertEqual(audio_cards[1], expected_audio_card2)
Loading