|
|
|
/***************************************************************************
|
|
|
|
alsa-sound-configuration.cpp - description
|
|
|
|
-------------------
|
|
|
|
begin : Thu Sep 30 2004
|
|
|
|
copyright : (C) 2004 by Martin Witte
|
|
|
|
email : witte@kawo1.rwth-aachen.de
|
|
|
|
***************************************************************************/
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
* *
|
|
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
|
|
* it under the terms of the GNU General Public License as published by *
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
|
|
* (at your option) any later version. *
|
|
|
|
* *
|
|
|
|
***************************************************************************/
|
|
|
|
|
|
|
|
#include <tqcheckbox.h>
|
|
|
|
#include <tqgroupbox.h>
|
|
|
|
#include <tqlayout.h>
|
|
|
|
#include <tqscrollview.h>
|
|
|
|
|
|
|
|
#include <kurlrequester.h>
|
|
|
|
#include <knuminput.h>
|
|
|
|
#include <klineedit.h>
|
|
|
|
#include <kcombobox.h>
|
|
|
|
#include <ktabwidget.h>
|
|
|
|
#include <tdelocale.h>
|
|
|
|
|
|
|
|
#include "alsa-mixer-element.h"
|
|
|
|
#include "alsa-sound-configuration.h"
|
|
|
|
#include "alsa-sound.h"
|
|
|
|
|
|
|
|
|
|
|
|
AlsaSoundConfiguration::AlsaSoundConfiguration (TQWidget *parent, AlsaSoundDevice *dev)
|
|
|
|
: AlsaSoundConfigurationUI(parent),
|
|
|
|
m_SoundDevice (dev),
|
|
|
|
m_groupMixerLayout(NULL),
|
|
|
|
m_groupMixerScrollView(NULL),
|
|
|
|
m_groupMixerSubFrame(NULL),
|
|
|
|
m_dirty(true),
|
|
|
|
m_ignore_updates(false)
|
|
|
|
{
|
|
|
|
TQObject::connect(m_comboPlaybackCard, TQ_SIGNAL(activated(int)), this, TQ_SLOT(slotSetDirty()));
|
|
|
|
TQObject::connect(m_comboCaptureCard, TQ_SIGNAL(activated(int)), this, TQ_SLOT(slotSetDirty()));
|
|
|
|
TQObject::connect(m_comboPlaybackDevice, TQ_SIGNAL(activated(int)), this, TQ_SLOT(slotSetDirty()));
|
|
|
|
TQObject::connect(m_comboCaptureDevice, TQ_SIGNAL(activated(int)), this, TQ_SLOT(slotSetDirty()));
|
|
|
|
TQObject::connect(editHWBufferSize, TQ_SIGNAL(valueChanged(int)), this, TQ_SLOT(slotSetDirty()));
|
|
|
|
TQObject::connect(editBufferSize, TQ_SIGNAL(valueChanged(int)), this, TQ_SLOT(slotSetDirty()));
|
|
|
|
TQObject::connect(chkDisablePlayback, TQ_SIGNAL(toggled(bool)), this, TQ_SLOT(slotSetDirty()));
|
|
|
|
TQObject::connect(chkDisableCapture, TQ_SIGNAL(toggled(bool)), this, TQ_SLOT(slotSetDirty()));
|
|
|
|
|
|
|
|
TQObject::connect(m_comboPlaybackCard, TQ_SIGNAL(activated(const TQString &)),
|
|
|
|
this, TQ_SLOT(slotPlaybackCardSelected(const TQString &)));
|
|
|
|
TQObject::connect(m_comboCaptureCard, TQ_SIGNAL(activated(const TQString &)),
|
|
|
|
this, TQ_SLOT(slotCaptureCardSelected(const TQString &)));
|
|
|
|
|
|
|
|
m_groupMixer->setColumnLayout(0, TQt::Horizontal );
|
|
|
|
|
|
|
|
TQHBoxLayout *tmp_layout = new TQHBoxLayout( m_groupMixer->layout() );
|
|
|
|
|
|
|
|
m_groupMixerScrollView = new TQScrollView (m_groupMixer);
|
|
|
|
m_groupMixerScrollView->setFrameShape(TQFrame::NoFrame);
|
|
|
|
m_groupMixerScrollView->setFrameShadow(TQFrame::Plain);
|
|
|
|
m_groupMixerScrollView->enableClipper(true);
|
|
|
|
m_groupMixerScrollView->setResizePolicy(TQScrollView::AutoOneFit);
|
|
|
|
//m_groupMixerScrollView->setHScrollBarMode(TQScrollView::AlwaysOn);
|
|
|
|
|
|
|
|
tmp_layout->addWidget(m_groupMixerScrollView);
|
|
|
|
|
|
|
|
|
|
|
|
int card = -1;
|
|
|
|
int ret = 0;
|
|
|
|
int idx_playback = 0;
|
|
|
|
int idx_capture = 0;
|
|
|
|
while ((ret = snd_card_next(&card)) == 0) {
|
|
|
|
char *name = NULL;
|
|
|
|
if (card >= 0 && snd_card_get_longname(card, &name) == 0) {
|
|
|
|
if (name) {
|
|
|
|
m_name2card[name] = card;
|
|
|
|
m_card2name[card] = name;
|
|
|
|
if (listSoundDevices(NULL, NULL, NULL, NULL, card, SND_PCM_STREAM_PLAYBACK)) {
|
|
|
|
m_comboPlaybackCard->insertItem(name);
|
|
|
|
m_playbackCard2idx[card] = idx_playback++;
|
|
|
|
}
|
|
|
|
if (listSoundDevices(NULL, NULL, NULL, NULL, card, SND_PCM_STREAM_CAPTURE)) {
|
|
|
|
m_comboCaptureCard->insertItem(name);
|
|
|
|
m_captureCard2idx[card] = idx_capture++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
slotCancel();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
AlsaSoundConfiguration::~AlsaSoundConfiguration ()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void AlsaSoundConfiguration::slotPlaybackCardSelected(const TQString &cardname)
|
|
|
|
{
|
|
|
|
if (!m_name2card.contains(cardname))
|
|
|
|
return;
|
|
|
|
|
|
|
|
listSoundDevices(m_comboPlaybackDevice, &m_playbackDeviceName2dev, &m_dev2playbackDeviceName, &m_playbackDevice2idx, m_name2card[cardname], SND_PCM_STREAM_PLAYBACK);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void AlsaSoundConfiguration::slotCaptureCardSelected(const TQString &cardname)
|
|
|
|
{
|
|
|
|
if (!m_name2card.contains(cardname))
|
|
|
|
return;
|
|
|
|
|
|
|
|
saveCaptureMixerSettings();
|
|
|
|
|
|
|
|
listSoundDevices(m_comboCaptureDevice, &m_captureDeviceName2dev, &m_dev2captureDeviceName, &m_captureDevice2idx, m_name2card[cardname], SND_PCM_STREAM_CAPTURE);
|
|
|
|
|
|
|
|
m_currentCaptureCard = m_name2card[cardname];
|
|
|
|
|
|
|
|
TQStringList vol_list, sw_list, all_list;
|
|
|
|
TQMap<TQString, AlsaMixerElement> vol_ch2id, sw_ch2id;
|
|
|
|
AlsaSoundDevice::getCaptureMixerChannels(m_name2card[cardname], NULL, vol_list, vol_ch2id, sw_list, sw_ch2id, &all_list);
|
|
|
|
|
|
|
|
for (TQMapIterator<TQString, QAlsaMixerElement*> it = m_MixerElements.begin(); it != m_MixerElements.end(); ++it) {
|
|
|
|
delete *it;
|
|
|
|
}
|
|
|
|
m_MixerElements.clear();
|
|
|
|
|
|
|
|
if (m_groupMixerSubFrame)
|
|
|
|
delete m_groupMixerSubFrame;
|
|
|
|
|
|
|
|
m_groupMixerSubFrame = new TQFrame(m_groupMixerScrollView->viewport());
|
|
|
|
m_groupMixerSubFrame->setSizePolicy(TQSizePolicy::Maximum, TQSizePolicy::Maximum);
|
|
|
|
m_groupMixerScrollView->addChild(m_groupMixerSubFrame);
|
|
|
|
|
|
|
|
int rows = 1;
|
|
|
|
int cols = (all_list.count()+rows-1)/rows;
|
|
|
|
m_groupMixerLayout = new TQGridLayout( m_groupMixerSubFrame, rows, cols, 0, 0 );
|
|
|
|
m_groupMixerLayout->setAlignment( TQt::AlignBottom );
|
|
|
|
|
|
|
|
int idx = 0;
|
|
|
|
for (TQValueListConstIterator<TQString> it = all_list.begin(); it != all_list.end(); ++it, ++idx) {
|
|
|
|
QAlsaMixerElement *e = new QAlsaMixerElement(m_groupMixerSubFrame, *it,
|
|
|
|
sw_list.contains(*it), vol_list.contains(*it));
|
|
|
|
TQObject::connect(e, TQ_SIGNAL(sigDirty()), this, TQ_SLOT(slotSetDirty()));
|
|
|
|
m_groupMixerLayout->addWidget(e, idx > cols, idx % cols);
|
|
|
|
e->show();
|
|
|
|
m_MixerElements.insert(*it, e);
|
|
|
|
}
|
|
|
|
restoreCaptureMixerSettings();
|
|
|
|
m_groupMixerSubFrame->show();
|
|
|
|
}
|
|
|
|
|
|
|
|
void AlsaSoundConfiguration::saveCaptureMixerSettings()
|
|
|
|
{
|
|
|
|
for (TQMapIterator<TQString, QAlsaMixerElement*> it = m_MixerElements.begin(); it != m_MixerElements.end(); ++it) {
|
|
|
|
const TQString &name = it.key();
|
|
|
|
int card = m_currentCaptureCard;
|
|
|
|
TQString id = AlsaConfigMixerSetting::getIDString(card, name);
|
|
|
|
QAlsaMixerElement *e = *it;
|
|
|
|
float vol = e->getVolume();
|
|
|
|
bool use = e->getOverride();
|
|
|
|
bool active = e->getActive();
|
|
|
|
e->slotResetDirty();
|
|
|
|
m_MixerSettings[id] = AlsaConfigMixerSetting(card,name,use,active,vol);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void AlsaSoundConfiguration::restoreCaptureMixerSettings()
|
|
|
|
{
|
|
|
|
for (TQMapIterator<TQString, QAlsaMixerElement*> it = m_MixerElements.begin(); it != m_MixerElements.end(); ++it) {
|
|
|
|
const TQString &name = it.key();
|
|
|
|
int card = m_currentCaptureCard;
|
|
|
|
TQString id = AlsaConfigMixerSetting::getIDString(card, name);
|
|
|
|
QAlsaMixerElement *e = *it;
|
|
|
|
|
|
|
|
if (m_MixerSettings.contains(id)) {
|
|
|
|
const AlsaConfigMixerSetting &s = m_MixerSettings[id];
|
|
|
|
e->setVolume(s.m_volume);
|
|
|
|
e->setOverride(s.m_use);
|
|
|
|
e->setActive(s.m_active);
|
|
|
|
e->slotResetDirty();
|
|
|
|
} else {
|
|
|
|
if (name == "ADC") {
|
|
|
|
e->setOverride(true);
|
|
|
|
e->setActive(true);
|
|
|
|
e->setVolume(1.0);
|
|
|
|
}
|
|
|
|
else if (name == "Digital") {
|
|
|
|
e->setOverride(true);
|
|
|
|
e->setActive(true);
|
|
|
|
e->setVolume(1.0);
|
|
|
|
}
|
|
|
|
else if (name == "Wave") {
|
|
|
|
e->setOverride(true);
|
|
|
|
e->setActive(false);
|
|
|
|
e->setVolume(0);
|
|
|
|
}
|
|
|
|
else if (name == "Capture") {
|
|
|
|
e->setOverride(true);
|
|
|
|
e->setActive(true);
|
|
|
|
e->setVolume(0.01);
|
|
|
|
}
|
|
|
|
e->slotSetDirty();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int AlsaSoundConfiguration::listSoundDevices(KComboBox *combobox, TQMap<TQString, int> *devname2dev, TQMap<int, TQString> *dev2devname, TQMap<int, int> *dev2idx, int card, snd_pcm_stream_t stream)
|
|
|
|
{
|
|
|
|
snd_ctl_t *handle = NULL;
|
|
|
|
int dev = -1;
|
|
|
|
snd_ctl_card_info_t *info = NULL;
|
|
|
|
snd_pcm_info_t *pcminfo = NULL;
|
|
|
|
|
|
|
|
snd_ctl_card_info_alloca(&info);
|
|
|
|
snd_pcm_info_alloca (&pcminfo);
|
|
|
|
|
|
|
|
TQString ctlname = "hw:"+TQString::number(card);
|
|
|
|
|
|
|
|
if (combobox)
|
|
|
|
combobox->clear();
|
|
|
|
if (devname2dev)
|
|
|
|
devname2dev->clear();
|
|
|
|
if (dev2devname)
|
|
|
|
dev2devname->clear();
|
|
|
|
if (dev2idx)
|
|
|
|
dev2idx->clear();
|
|
|
|
|
|
|
|
int count = 0;
|
|
|
|
|
|
|
|
if (snd_ctl_open (&handle, ctlname.ascii(), 0) == 0) {
|
|
|
|
if (snd_ctl_card_info(handle, info) == 0) {
|
|
|
|
|
|
|
|
dev = -1;
|
|
|
|
while (1) {
|
|
|
|
if (snd_ctl_pcm_next_device(handle, &dev) < 0) {
|
|
|
|
//logError("snd_ctl_pcm_next_device");
|
|
|
|
}
|
|
|
|
if (dev < 0)
|
|
|
|
break;
|
|
|
|
snd_pcm_info_set_device(pcminfo, dev);
|
|
|
|
snd_pcm_info_set_subdevice(pcminfo, 0);
|
|
|
|
snd_pcm_info_set_stream(pcminfo, stream);
|
|
|
|
int err = 0;
|
|
|
|
if ((err = snd_ctl_pcm_info(handle, pcminfo)) < 0) {
|
|
|
|
if (err != -ENOENT) {
|
|
|
|
//logError(TQString("control digital audio info (%1): %2").arg(card).arg(snd_strerror(err)));
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
const char *dev_name = snd_pcm_info_get_name(pcminfo);
|
|
|
|
TQString devname = i18n("context-card-plus-device-number", "%1 device %2").arg(dev_name).arg(dev);
|
|
|
|
if (combobox)
|
|
|
|
combobox->insertItem(devname);
|
|
|
|
if (devname2dev)
|
|
|
|
(*devname2dev)[devname] = dev;
|
|
|
|
if (dev2devname)
|
|
|
|
(*dev2devname)[dev] = devname;
|
|
|
|
if (dev2idx)
|
|
|
|
(*dev2idx)[dev] = count;
|
|
|
|
++count;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
snd_ctl_close(handle);
|
|
|
|
}
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AlsaSoundConfiguration::slotOK()
|
|
|
|
{
|
|
|
|
if (!m_dirty)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (m_SoundDevice) {
|
|
|
|
m_SoundDevice->setHWBufferSize ( editHWBufferSize ->value() * 1024);
|
|
|
|
m_SoundDevice->setBufferSize ( editBufferSize ->value() * 1024);
|
|
|
|
m_SoundDevice->enablePlayback (!chkDisablePlayback->isChecked());
|
|
|
|
m_SoundDevice->enableCapture (!chkDisableCapture ->isChecked());
|
|
|
|
|
|
|
|
int card = m_name2card[m_comboPlaybackCard->currentText()];
|
|
|
|
int device = m_playbackDeviceName2dev[m_comboPlaybackDevice->currentText()];
|
|
|
|
m_SoundDevice->setPlaybackDevice( card, device);
|
|
|
|
card = m_name2card[m_comboCaptureCard->currentText()];
|
|
|
|
device = m_captureDeviceName2dev[m_comboCaptureDevice->currentText()];
|
|
|
|
m_SoundDevice->setCaptureDevice ( card, device);
|
|
|
|
|
|
|
|
saveCaptureMixerSettings();
|
|
|
|
m_SoundDevice->setCaptureMixerSettings(m_MixerSettings);
|
|
|
|
}
|
|
|
|
m_dirty = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void AlsaSoundConfiguration::slotCancel()
|
|
|
|
{
|
|
|
|
if (!m_dirty)
|
|
|
|
return;
|
|
|
|
m_ignore_updates = true;
|
|
|
|
|
|
|
|
int card = m_SoundDevice ? m_SoundDevice->getPlaybackCard() : 0;
|
|
|
|
int dev = m_SoundDevice ? m_SoundDevice->getPlaybackDevice() : 0;
|
|
|
|
m_comboPlaybackCard ->setCurrentItem(m_playbackCard2idx[card]);
|
|
|
|
slotPlaybackCardSelected(m_comboPlaybackCard->currentText());
|
|
|
|
m_comboPlaybackDevice->setCurrentItem(m_playbackDevice2idx[dev]);
|
|
|
|
|
|
|
|
card = m_SoundDevice ? m_SoundDevice->getCaptureCard() : 0;
|
|
|
|
dev = m_SoundDevice ? m_SoundDevice->getCaptureDevice() : 0;
|
|
|
|
m_comboCaptureCard ->setCurrentItem(m_captureCard2idx[card]);
|
|
|
|
slotCaptureCardSelected(m_comboCaptureCard->currentText());
|
|
|
|
m_comboCaptureDevice->setCurrentItem(m_captureDevice2idx[dev]);
|
|
|
|
|
|
|
|
//IErrorLogClient::staticLogDebug(TQString("capture: card = %1(%2), dev = %3").arg(card).arg(m_captureCard2idx[card]).arg(dev));
|
|
|
|
|
|
|
|
editHWBufferSize ->setValue (m_SoundDevice ? m_SoundDevice->getHWBufferSize()/1024 : 4);
|
|
|
|
editBufferSize ->setValue (m_SoundDevice ? m_SoundDevice->getBufferSize()/1024 : 4);
|
|
|
|
chkDisablePlayback->setChecked(m_SoundDevice ? !m_SoundDevice->isPlaybackEnabled() : false);
|
|
|
|
chkDisableCapture ->setChecked(m_SoundDevice ? !m_SoundDevice->isCaptureEnabled() : false);
|
|
|
|
|
|
|
|
//IErrorLogClient::staticLogDebug(TQString("capture: card = %1").arg(m_comboCaptureCard->currentText()));
|
|
|
|
|
|
|
|
|
|
|
|
if (m_SoundDevice)
|
|
|
|
m_MixerSettings = m_SoundDevice->getCaptureMixerSettings();
|
|
|
|
else
|
|
|
|
m_MixerSettings.clear();
|
|
|
|
restoreCaptureMixerSettings();
|
|
|
|
|
|
|
|
m_ignore_updates = false;
|
|
|
|
m_dirty = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void AlsaSoundConfiguration::slotUpdateConfig()
|
|
|
|
{
|
|
|
|
slotSetDirty();
|
|
|
|
slotCancel();
|
|
|
|
}
|
|
|
|
|
|
|
|
void AlsaSoundConfiguration::slotSetDirty()
|
|
|
|
{
|
|
|
|
if (!m_dirty && !m_ignore_updates) {
|
|
|
|
m_dirty = true;
|
|
|
|
//emit sigDirty();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#include "alsa-sound-configuration.moc"
|