kmixer: implement backend error getter

Signed-off-by: Ivailo Monev <xakepa10@gmail.com>
This commit is contained in:
Ivailo Monev 2022-03-06 15:11:30 +02:00
parent 47c549a132
commit 5bea5abf8f
2 changed files with 90 additions and 74 deletions

View file

@ -194,7 +194,8 @@ QList<KSoundChannel> KSoundCard::channels() const
} }
KALSABackend::KALSABackend(QObject *parent) KALSABackend::KALSABackend(QObject *parent)
: QObject(parent) : QObject(parent),
m_alsaresult(0)
{ {
} }
@ -203,11 +204,10 @@ QList<KSoundCard> KALSABackend::soundCards()
QList<KSoundCard> result; QList<KSoundCard> result;
int alsacard = -1; int alsacard = -1;
int alsaresult = 0;
while (true) { while (true) {
alsaresult = snd_card_next(&alsacard); m_alsaresult = snd_card_next(&alsacard);
if (alsaresult != 0) { if (m_alsaresult != 0) {
kWarning() << "Could not get card" << snd_strerror(alsaresult); kWarning() << "Could not get card" << snd_strerror(m_alsaresult);
break; break;
} }
if (alsacard < 0) { if (alsacard < 0) {
@ -216,16 +216,16 @@ QList<KSoundCard> KALSABackend::soundCards()
const QByteArray alsacardname = "hw:" + QByteArray::number(alsacard); const QByteArray alsacardname = "hw:" + QByteArray::number(alsacard);
snd_ctl_t *alsactl = nullptr; snd_ctl_t *alsactl = nullptr;
alsaresult = snd_ctl_open(&alsactl, alsacardname.constData(), SND_CTL_NONBLOCK); m_alsaresult = snd_ctl_open(&alsactl, alsacardname.constData(), SND_CTL_NONBLOCK);
if (alsaresult != 0) { if (m_alsaresult != 0) {
kWarning() << "Could not open card" << snd_strerror(alsaresult); kWarning() << "Could not open card" << snd_strerror(m_alsaresult);
break; break;
} }
snd_ctl_card_info_t *alsacardinfo = nullptr; snd_ctl_card_info_t *alsacardinfo = nullptr;
snd_ctl_card_info_alloca(&alsacardinfo); snd_ctl_card_info_alloca(&alsacardinfo);
alsaresult = snd_ctl_card_info(alsactl, alsacardinfo); m_alsaresult = snd_ctl_card_info(alsactl, alsacardinfo);
if (alsaresult != 0) { if (m_alsaresult != 0) {
kWarning() << "Could not open card" << snd_strerror(alsaresult); kWarning() << "Could not open card" << snd_strerror(m_alsaresult);
break; break;
} }
KSoundCard kcard; KSoundCard kcard;
@ -253,7 +253,7 @@ QList<KSoundCard> KALSABackend::soundCards()
kchannel.m_capture = hascapture; kchannel.m_capture = hascapture;
kchannel.m_cardid = alsacard; kchannel.m_cardid = alsacard;
if (kchannel.m_playback) { if (kchannel.m_playback) {
alsaresult = snd_mixer_selem_has_playback_channel(alsaelement, SND_MIXER_SCHN_FRONT_LEFT); int alsaresult = snd_mixer_selem_has_playback_channel(alsaelement, SND_MIXER_SCHN_FRONT_LEFT);
if (alsaresult != 0) { if (alsaresult != 0) {
kchannel.m_type = KSoundChannel::KSoundChannelType::FrontLeft; kchannel.m_type = KSoundChannel::KSoundChannelType::FrontLeft;
kcard.m_channels.append(kchannel); kcard.m_channels.append(kchannel);
@ -299,7 +299,7 @@ QList<KSoundCard> KALSABackend::soundCards()
kcard.m_channels.append(kchannel); kcard.m_channels.append(kchannel);
} }
} else if (hascapture) { } else if (hascapture) {
alsaresult = snd_mixer_selem_has_capture_channel(alsaelement, SND_MIXER_SCHN_FRONT_LEFT); int alsaresult = snd_mixer_selem_has_capture_channel(alsaelement, SND_MIXER_SCHN_FRONT_LEFT);
if (alsaresult != 0) { if (alsaresult != 0) {
kchannel.m_type = KSoundChannel::KSoundChannelType::FrontLeft; kchannel.m_type = KSoundChannel::KSoundChannelType::FrontLeft;
kcard.m_channels.append(kchannel); kcard.m_channels.append(kchannel);
@ -394,9 +394,9 @@ int KALSABackend::playbackVolume(const KSoundChannel *channel) const
if (alsaid == channel->id() && alsaname == channel->name()) { if (alsaid == channel->id() && alsaname == channel->name()) {
kDebug() << "Device" << channel->id() << channel->name(); kDebug() << "Device" << channel->id() << channel->name();
long alsaplaybackvolume = 0; long alsaplaybackvolume = 0;
const int alsaresult = snd_mixer_selem_get_playback_volume(alsaelement, alsachanneltype, &alsaplaybackvolume); m_alsaresult = snd_mixer_selem_get_playback_volume(alsaelement, alsachanneltype, &alsaplaybackvolume);
if (alsaresult != 0) { if (m_alsaresult != 0) {
kWarning() << "Could not get playback channel volume" << snd_strerror(alsaresult); kWarning() << "Could not get playback channel volume" << snd_strerror(m_alsaresult);
snd_mixer_close(alsamixer); snd_mixer_close(alsamixer);
return 0; return 0;
} }
@ -419,7 +419,7 @@ KVolumeRange KALSABackend::playbackRange(const KSoundChannel *channel) const
return result; return result;
} }
snd_mixer_t* alsamixer = KALSABackend::mixerForCard(channel->cardID()); snd_mixer_t* alsamixer = mixerForCard(channel->cardID());
if (!alsamixer) { if (!alsamixer) {
return result; return result;
} }
@ -433,9 +433,9 @@ KVolumeRange KALSABackend::playbackRange(const KSoundChannel *channel) const
kDebug() << "Device" << channel->id() << channel->name(); kDebug() << "Device" << channel->id() << channel->name();
long alsaplaybackvolumemin = 0; long alsaplaybackvolumemin = 0;
long alsaplaybackvolumemax = 0; long alsaplaybackvolumemax = 0;
const int alsaresult = snd_mixer_selem_get_playback_volume_range(alsaelement, &alsaplaybackvolumemin, &alsaplaybackvolumemax); m_alsaresult = snd_mixer_selem_get_playback_volume_range(alsaelement, &alsaplaybackvolumemin, &alsaplaybackvolumemax);
if (alsaresult != 0) { if (m_alsaresult != 0) {
kWarning() << "Could not get playback channel volume range" << snd_strerror(alsaresult); kWarning() << "Could not get playback channel volume range" << snd_strerror(m_alsaresult);
snd_mixer_close(alsamixer); snd_mixer_close(alsamixer);
return result; return result;
} }
@ -459,7 +459,7 @@ bool KALSABackend::setPlaybackVolume(const KSoundChannel *channel, const int vol
return false; return false;
} }
snd_mixer_t* alsamixer = KALSABackend::mixerForCard(channel->cardID()); snd_mixer_t* alsamixer = mixerForCard(channel->cardID());
if (!alsamixer) { if (!alsamixer) {
return false; return false;
} }
@ -477,9 +477,9 @@ bool KALSABackend::setPlaybackVolume(const KSoundChannel *channel, const int vol
const QString alsaid = QString::number(snd_mixer_selem_get_index(alsaelement)); const QString alsaid = QString::number(snd_mixer_selem_get_index(alsaelement));
const QString alsaname = QString::fromLocal8Bit(snd_mixer_selem_get_name(alsaelement)); const QString alsaname = QString::fromLocal8Bit(snd_mixer_selem_get_name(alsaelement));
if (alsaid == channel->id() && alsaname == channel->name()) { if (alsaid == channel->id() && alsaname == channel->name()) {
const int alsaresult = snd_mixer_selem_set_playback_volume(alsaelement, alsachanneltype, long(volume)); m_alsaresult = snd_mixer_selem_set_playback_volume(alsaelement, alsachanneltype, long(volume));
if (alsaresult != 0) { if (m_alsaresult != 0) {
kWarning() << "Could not set playback volume" << snd_strerror(alsaresult); kWarning() << "Could not set playback volume" << snd_strerror(m_alsaresult);
snd_mixer_close(alsamixer); snd_mixer_close(alsamixer);
return false; return false;
} }
@ -489,6 +489,7 @@ bool KALSABackend::setPlaybackVolume(const KSoundChannel *channel, const int vol
} }
} }
kWarning() << "Could not find playback channel" << channel->id() << channel->name();
snd_mixer_close(alsamixer); snd_mixer_close(alsamixer);
return false; return false;
} }
@ -500,7 +501,7 @@ int KALSABackend::captureVolume(const KSoundChannel *channel) const
return 0; return 0;
} }
snd_mixer_t* alsamixer = KALSABackend::mixerForCard(channel->cardID()); snd_mixer_t* alsamixer = mixerForCard(channel->cardID());
if (!alsamixer) { if (!alsamixer) {
return 0; return 0;
} }
@ -520,9 +521,9 @@ int KALSABackend::captureVolume(const KSoundChannel *channel) const
if (alsaid == channel->id() && alsaname == channel->name()) { if (alsaid == channel->id() && alsaname == channel->name()) {
kDebug() << "Device" << channel->id() << channel->name(); kDebug() << "Device" << channel->id() << channel->name();
long alsacapturevolume = 0; long alsacapturevolume = 0;
const int alsaresult = snd_mixer_selem_get_capture_volume(alsaelement, alsachanneltype, &alsacapturevolume); m_alsaresult = snd_mixer_selem_get_capture_volume(alsaelement, alsachanneltype, &alsacapturevolume);
if (alsaresult != 0) { if (m_alsaresult != 0) {
kWarning() << "Could not get capture channel volume" << snd_strerror(alsaresult); kWarning() << "Could not get capture channel volume" << snd_strerror(m_alsaresult);
snd_mixer_close(alsamixer); snd_mixer_close(alsamixer);
return 0; return 0;
} }
@ -545,7 +546,7 @@ KVolumeRange KALSABackend::captureRange(const KSoundChannel *channel) const
return result; return result;
} }
snd_mixer_t* alsamixer = KALSABackend::mixerForCard(channel->cardID()); snd_mixer_t* alsamixer = mixerForCard(channel->cardID());
if (!alsamixer) { if (!alsamixer) {
return result; return result;
} }
@ -559,9 +560,9 @@ KVolumeRange KALSABackend::captureRange(const KSoundChannel *channel) const
kDebug() << "Device" << channel->id() << channel->name(); kDebug() << "Device" << channel->id() << channel->name();
long alsacapturevolumemin = 0; long alsacapturevolumemin = 0;
long alsacapturevolumemax = 0; long alsacapturevolumemax = 0;
const int alsaresult = snd_mixer_selem_get_capture_volume_range(alsaelement, &alsacapturevolumemin, &alsacapturevolumemax); m_alsaresult = snd_mixer_selem_get_capture_volume_range(alsaelement, &alsacapturevolumemin, &alsacapturevolumemax);
if (alsaresult != 0) { if (m_alsaresult != 0) {
kWarning() << "Could not get capture channel volume range" << snd_strerror(alsaresult); kWarning() << "Could not get capture channel volume range" << snd_strerror(m_alsaresult);
snd_mixer_close(alsamixer); snd_mixer_close(alsamixer);
return result; return result;
} }
@ -585,7 +586,7 @@ bool KALSABackend::setCaptureVolume(const KSoundChannel *channel, const int volu
return false; return false;
} }
snd_mixer_t* alsamixer = KALSABackend::mixerForCard(channel->cardID()); snd_mixer_t* alsamixer = mixerForCard(channel->cardID());
if (!alsamixer) { if (!alsamixer) {
return false; return false;
} }
@ -603,9 +604,9 @@ bool KALSABackend::setCaptureVolume(const KSoundChannel *channel, const int volu
const QString alsaid = QString::number(snd_mixer_selem_get_index(alsaelement)); const QString alsaid = QString::number(snd_mixer_selem_get_index(alsaelement));
const QString alsaname = QString::fromLocal8Bit(snd_mixer_selem_get_name(alsaelement)); const QString alsaname = QString::fromLocal8Bit(snd_mixer_selem_get_name(alsaelement));
if (alsaid == channel->id() && alsaname == channel->name()) { if (alsaid == channel->id() && alsaname == channel->name()) {
const int alsaresult = snd_mixer_selem_set_capture_volume(alsaelement, alsachanneltype, long(volume)); m_alsaresult = snd_mixer_selem_set_capture_volume(alsaelement, alsachanneltype, long(volume));
if (alsaresult != 0) { if (m_alsaresult != 0) {
kWarning() << "Could not set capture volume" << snd_strerror(alsaresult); kWarning() << "Could not set capture volume" << snd_strerror(m_alsaresult);
snd_mixer_close(alsamixer); snd_mixer_close(alsamixer);
return false; return false;
} }
@ -615,16 +616,17 @@ bool KALSABackend::setCaptureVolume(const KSoundChannel *channel, const int volu
} }
} }
kWarning() << "Could not find capture channel" << channel->id() << channel->name();
snd_mixer_close(alsamixer); snd_mixer_close(alsamixer);
return false; return false;
} }
bool KALSABackend::isAvailable() bool KALSABackend::isAvailable() const
{ {
snd_mixer_t *alsamixer = nullptr; snd_mixer_t *alsamixer = nullptr;
const int alsaresult = snd_mixer_open(&alsamixer, 0); m_alsaresult = snd_mixer_open(&alsamixer, 0);
if (alsaresult != 0) { if (m_alsaresult != 0) {
kWarning() << "ALSA is not available" << snd_strerror(alsaresult); kWarning() << "ALSA is not available" << snd_strerror(m_alsaresult);
return false; return false;
} }
kDebug() << "ALSA is available"; kDebug() << "ALSA is available";
@ -632,30 +634,36 @@ bool KALSABackend::isAvailable()
return true; return true;
} }
snd_mixer_t* KALSABackend::mixerForCard(const int card) QString KALSABackend::errorString() const
{
// TODO: translate errors
return QString::fromLocal8Bit(snd_strerror(m_alsaresult));
}
snd_mixer_t* KALSABackend::mixerForCard(const int card) const
{ {
const QByteArray alsacardname = "hw:" + QByteArray::number(card); const QByteArray alsacardname = "hw:" + QByteArray::number(card);
snd_mixer_t *alsamixer = nullptr; snd_mixer_t *alsamixer = nullptr;
int alsaresult = snd_mixer_open(&alsamixer, 0); m_alsaresult = snd_mixer_open(&alsamixer, 0);
if (alsaresult != 0) { if (m_alsaresult != 0) {
kWarning() << "Could not open mixer" << snd_strerror(alsaresult); kWarning() << "Could not open mixer" << snd_strerror(m_alsaresult);
return nullptr; return nullptr;
} }
alsaresult = snd_mixer_attach(alsamixer, alsacardname.constData()); m_alsaresult = snd_mixer_attach(alsamixer, alsacardname.constData());
if (alsaresult != 0) { if (m_alsaresult != 0) {
kWarning() << "Could not attach mixer" << snd_strerror(alsaresult); kWarning() << "Could not attach mixer" << snd_strerror(m_alsaresult);
snd_mixer_close(alsamixer); snd_mixer_close(alsamixer);
return nullptr; return nullptr;
} }
alsaresult = snd_mixer_selem_register(alsamixer, nullptr, nullptr); m_alsaresult = snd_mixer_selem_register(alsamixer, nullptr, nullptr);
if (alsaresult != 0) { if (m_alsaresult != 0) {
kWarning() << "Could not register mixer" << snd_strerror(alsaresult); kWarning() << "Could not register mixer" << snd_strerror(m_alsaresult);
snd_mixer_close(alsamixer); snd_mixer_close(alsamixer);
return nullptr; return nullptr;
} }
alsaresult = snd_mixer_load(alsamixer); m_alsaresult = snd_mixer_load(alsamixer);
if (alsaresult != 0) { if (m_alsaresult != 0) {
kWarning() << "Could not load mixer" << snd_strerror(alsaresult); kWarning() << "Could not load mixer" << snd_strerror(m_alsaresult);
snd_mixer_close(alsamixer); snd_mixer_close(alsamixer);
return nullptr; return nullptr;
} }
@ -742,31 +750,33 @@ bool KMixer::start(const QString &backend)
#endif #endif
return true; return true;
} else if (backend == "auto") { } else if (backend == "auto") {
if (KALSABackend::isAvailable()) { m_backend = new KALSABackend(this);
m_backend = new KALSABackend(this); if (!m_backend->isAvailable()) {
#if 1 return false;
foreach (const KSoundCard &kcard, m_backend->soundCards()) {
foreach (KSoundChannel kchannel, kcard.channels()) {
qDebug() << kcard.name() << kcard.description() << kchannel.name() << kchannel.description();
qDebug() << "Channel volume is" << kchannel.playbackVolume() << kchannel.captureVolume();
kchannel.setPlaybackVolume(10);
kchannel.setCaptureVolume(10);
qDebug() << "Channel volume is" << kchannel.playbackVolume() << kchannel.captureVolume();
qDebug() << "Channel volume range is" << kchannel.playbackRange().minvolume << kchannel.playbackRange().maxvolume;
}
}
#endif
return true;
} }
return false; #if 1
foreach (const KSoundCard &kcard, m_backend->soundCards()) {
foreach (KSoundChannel kchannel, kcard.channels()) {
qDebug() << kcard.name() << kcard.description() << kchannel.name() << kchannel.description();
qDebug() << "Channel volume is" << kchannel.playbackVolume() << kchannel.captureVolume();
kchannel.setPlaybackVolume(10);
kchannel.setCaptureVolume(10);
qDebug() << "Channel volume is" << kchannel.playbackVolume() << kchannel.captureVolume();
qDebug() << "Channel volume range is" << kchannel.playbackRange().minvolume << kchannel.playbackRange().maxvolume;
}
}
#endif
return true;
} }
return false; return false;
} }
QString KMixer::errorString() const QString KMixer::errorString() const
{ {
// TODO: error from backend if (!m_backend) {
return QString(); return i18n("No backend");
}
return m_backend->errorString();
} }
void KMixer::slotBackend() void KMixer::slotBackend()

View file

@ -115,6 +115,9 @@ public:
virtual int captureVolume(const KSoundChannel *channel) const = 0; virtual int captureVolume(const KSoundChannel *channel) const = 0;
virtual KVolumeRange captureRange(const KSoundChannel *channel) const = 0; virtual KVolumeRange captureRange(const KSoundChannel *channel) const = 0;
virtual bool setCaptureVolume(const KSoundChannel *channel, const int volume) = 0; virtual bool setCaptureVolume(const KSoundChannel *channel, const int volume) = 0;
virtual bool isAvailable() const = 0;
virtual QString errorString() const = 0;
}; };
class KALSABackend : public QObject, public KMixerBackend class KALSABackend : public QObject, public KMixerBackend
@ -133,10 +136,13 @@ public:
KVolumeRange captureRange(const KSoundChannel *channel) const final; KVolumeRange captureRange(const KSoundChannel *channel) const final;
bool setCaptureVolume(const KSoundChannel *channel, const int volume) final; bool setCaptureVolume(const KSoundChannel *channel, const int volume) final;
static bool isAvailable(); bool isAvailable() const;
QString errorString() const final;
private: private:
static snd_mixer_t* mixerForCard(const int card); mutable int m_alsaresult;
snd_mixer_t* mixerForCard(const int card) const;
static snd_mixer_selem_channel_id_t channelType(const KSoundChannel *channel); static snd_mixer_selem_channel_id_t channelType(const KSoundChannel *channel);
}; };