plugins/multimedia/v4l/radio/v4lradiocontrol_maemo5.cpp
changeset 0 876b1a06bc25
equal deleted inserted replaced
-1:000000000000 0:876b1a06bc25
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the Qt Mobility Components.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include "v4lradiocontrol_maemo5.h"
       
    43 #include "v4lradioservice.h"
       
    44 
       
    45 #include "linux/videodev2.h"
       
    46 #include <linux/videodev.h>
       
    47 #include <sys/soundcard.h>
       
    48 #include <stdio.h>
       
    49 #include <sys/types.h>
       
    50 #include <sys/ioctl.h>
       
    51 #include <fcntl.h>
       
    52 #include <unistd.h>
       
    53 
       
    54 #define HEADPHONE_STATE_FILE "/sys/devices/platform/gpio-switch/headphone/state"
       
    55 #define HEADPHONE_CONNECTED_STATE "connected"
       
    56 #define HEADPHONE_DISCONNECTED_STATE "disconnected"
       
    57 
       
    58 #define FMRXENABLER_DBUS_SERVICE "de.pycage.FMRXEnabler"
       
    59 #define FMRXENABLER_DBUS_OBJ_PATH "/de/pycage/FMRXEnabler"
       
    60 #define FMRXENABLER_DBUS_IFACE_NAME "de.pycage.FMRXEnabler"
       
    61 
       
    62 gboolean
       
    63 state_file_changed(GIOChannel* source, GIOCondition /*condition*/, gpointer data)
       
    64 {
       
    65     V4LRadioControl* radioControl = (V4LRadioControl*)data;
       
    66     gchar* result;
       
    67 
       
    68     g_io_channel_seek_position(source, 0, G_SEEK_SET, NULL);
       
    69     g_io_channel_read_line(source, &result, NULL, NULL, NULL);
       
    70     g_strstrip(result);
       
    71 
       
    72     if (g_ascii_strcasecmp(result, HEADPHONE_DISCONNECTED_STATE) == 0) {
       
    73         radioControl->enablePipeline(false);
       
    74     } else if (g_ascii_strcasecmp(result, HEADPHONE_CONNECTED_STATE) == 0) {
       
    75         // Wait 400ms until audio is routed again to headphone to prevent sound coming from speakers
       
    76         QTimer::singleShot(400,radioControl,SLOT(enablePipeline()));
       
    77     }
       
    78 
       
    79 #ifdef MULTIMEDIA_MAEMO_DEBUG
       
    80     qDebug() << "Headphone is now" << result;
       
    81 #endif
       
    82 
       
    83     g_free(result);
       
    84     return true;
       
    85 }
       
    86 
       
    87 V4LRadioControl::V4LRadioControl(QObject *parent)
       
    88     : QRadioTunerControl(parent)
       
    89     , fd(1)
       
    90     , m_error(false)
       
    91     , muted(false)
       
    92     , stereo(false)
       
    93     , step(100000)
       
    94     , sig(0)
       
    95     , scanning(false)
       
    96     , currentBand(QRadioTuner::FM)
       
    97     , pipeline(0)
       
    98 {
       
    99     if (QDBusConnection::systemBus().isConnected()) {
       
   100         FMRXEnablerIFace = new QDBusInterface(FMRXENABLER_DBUS_SERVICE,
       
   101                                               FMRXENABLER_DBUS_OBJ_PATH,
       
   102                                               FMRXENABLER_DBUS_IFACE_NAME,
       
   103                                               QDBusConnection::systemBus());
       
   104     }
       
   105 
       
   106     createGstPipeline();
       
   107 
       
   108     GIOChannel* headphoneStateFile = NULL;
       
   109     headphoneStateFile = g_io_channel_new_file(HEADPHONE_STATE_FILE, "r", NULL);
       
   110     if (headphoneStateFile != NULL) {
       
   111         g_io_add_watch(headphoneStateFile, G_IO_PRI, state_file_changed, this);
       
   112     } else {
       
   113 #ifdef MULTIMEDIA_MAEMO_DEBUG
       
   114         qWarning() << QString("File %1 can't be read!").arg(HEADPHONE_STATE_FILE) ;
       
   115         qWarning() << "Monitoring headphone state isn't possible!";
       
   116 #endif
       
   117     }
       
   118 
       
   119     enableFMRX();
       
   120     initRadio();
       
   121     setupHeadPhone();
       
   122 
       
   123     setMuted(false);
       
   124 
       
   125     timer = new QTimer(this);
       
   126     timer->setInterval(200);
       
   127     connect(timer,SIGNAL(timeout()),this,SLOT(search()));
       
   128 
       
   129     tickTimer = new QTimer(this);
       
   130     tickTimer->setInterval(10000);
       
   131     connect(tickTimer,SIGNAL(timeout()),this,SLOT(enableFMRX()));
       
   132     tickTimer->start();
       
   133 }
       
   134 
       
   135 V4LRadioControl::~V4LRadioControl()
       
   136 {
       
   137     if (pipeline)
       
   138     {
       
   139         gst_element_set_state (pipeline, GST_STATE_NULL);
       
   140         gst_object_unref (GST_OBJECT (pipeline));
       
   141     }
       
   142 
       
   143     if(fd > 0)
       
   144         ::close(fd);
       
   145 }
       
   146 
       
   147 void V4LRadioControl::enablePipeline(bool enable)
       
   148 {
       
   149     if (enable == true)
       
   150         gst_element_set_state (pipeline, GST_STATE_PLAYING);
       
   151     else
       
   152         gst_element_set_state (pipeline, GST_STATE_NULL);
       
   153 }
       
   154 
       
   155 void V4LRadioControl::enableFMRX()
       
   156 {
       
   157     if (FMRXEnablerIFace && FMRXEnablerIFace->isValid()) {
       
   158         FMRXEnablerIFace->call("request"); // Return value ignored
       
   159     }
       
   160 }
       
   161 
       
   162 // Workaround to capture sound from the PGA line and play it back using gstreamer
       
   163 // because N900 doesn't output sound directly to speakers
       
   164 bool V4LRadioControl::createGstPipeline()
       
   165 {
       
   166     GstElement *source, *sink;
       
   167 
       
   168     gst_init (NULL, NULL);
       
   169     pipeline = gst_pipeline_new("my-pipeline");
       
   170 
       
   171     source = gst_element_factory_make ("pulsesrc", "source");
       
   172     sink = gst_element_factory_make ("pulsesink", "sink");
       
   173 
       
   174     gst_bin_add_many (GST_BIN (pipeline), source, sink, (char *)NULL);
       
   175 
       
   176     if (!gst_element_link_many (source, sink, (char *)NULL)) {
       
   177         return false;
       
   178     }
       
   179 
       
   180     gst_element_set_state (pipeline, GST_STATE_PLAYING);
       
   181 
       
   182     return true;
       
   183 }
       
   184 
       
   185 bool V4LRadioControl::isAvailable() const
       
   186 {
       
   187     return available;
       
   188 }
       
   189 
       
   190 QtMultimediaKit::AvailabilityError V4LRadioControl::availabilityError() const
       
   191 {
       
   192     if (fd > 0)
       
   193         return QtMultimediaKit::NoError;
       
   194     else
       
   195         return QtMultimediaKit::ResourceError;
       
   196 }
       
   197 
       
   198 QRadioTuner::State V4LRadioControl::state() const
       
   199 {
       
   200     return fd > 0 ? QRadioTuner::ActiveState : QRadioTuner::StoppedState;
       
   201 }
       
   202 
       
   203 QRadioTuner::Band V4LRadioControl::band() const
       
   204 {
       
   205     return currentBand;
       
   206 }
       
   207 
       
   208 bool V4LRadioControl::isBandSupported(QRadioTuner::Band b) const
       
   209 {
       
   210     QRadioTuner::Band bnd = (QRadioTuner::Band)b;
       
   211     switch(bnd) {
       
   212         case QRadioTuner::FM:
       
   213             if(freqMin <= 87500000 && freqMax >= 108000000)
       
   214                 return true;
       
   215             break;
       
   216         case QRadioTuner::LW:
       
   217             if(freqMin <= 148500 && freqMax >= 283500)
       
   218                 return true;
       
   219         case QRadioTuner::AM:
       
   220             if(freqMin <= 520000 && freqMax >= 1610000)
       
   221                 return true;
       
   222         default:
       
   223             if(freqMin <= 1711000 && freqMax >= 30000000)
       
   224                 return true;
       
   225     }
       
   226 
       
   227     return false;
       
   228 }
       
   229 
       
   230 void V4LRadioControl::setBand(QRadioTuner::Band b)
       
   231 {
       
   232     if(freqMin <= 87500000 && freqMax >= 108000000 && b == QRadioTuner::FM) {
       
   233         // FM 87.5 to 108.0 MHz, except Japan 76-90 MHz
       
   234         currentBand =  (QRadioTuner::Band)b;
       
   235         step = 100000; // 100kHz steps
       
   236         emit bandChanged(currentBand);
       
   237 
       
   238     } else if(freqMin <= 148500 && freqMax >= 283500 && b == QRadioTuner::LW) {
       
   239         // LW 148.5 to 283.5 kHz, 9kHz channel spacing (Europe, Africa, Asia)
       
   240         currentBand =  (QRadioTuner::Band)b;
       
   241         step = 1000; // 1kHz steps
       
   242         emit bandChanged(currentBand);
       
   243 
       
   244     } else if(freqMin <= 520000 && freqMax >= 1610000 && b == QRadioTuner::AM) {
       
   245         // AM 520 to 1610 kHz, 9 or 10kHz channel spacing, extended 1610 to 1710 kHz
       
   246         currentBand =  (QRadioTuner::Band)b;
       
   247         step = 1000; // 1kHz steps
       
   248         emit bandChanged(currentBand);
       
   249 
       
   250     } else if(freqMin <= 1711000 && freqMax >= 30000000 && b == QRadioTuner::SW) {
       
   251         // SW 1.711 to 30.0 MHz, divided into 15 bands. 5kHz channel spacing
       
   252         currentBand =  (QRadioTuner::Band)b;
       
   253         step = 500; // 500Hz steps
       
   254         emit bandChanged(currentBand);
       
   255     }
       
   256 }
       
   257 
       
   258 int V4LRadioControl::frequency() const
       
   259 {
       
   260     return currentFreq;
       
   261 }
       
   262 
       
   263 int V4LRadioControl::frequencyStep(QRadioTuner::Band b) const
       
   264 {
       
   265     int step = 0;
       
   266 
       
   267     if(b == QRadioTuner::FM)
       
   268         step = 100000; // 100kHz steps
       
   269     else if(b == QRadioTuner::LW)
       
   270         step = 1000; // 1kHz steps
       
   271     else if(b == QRadioTuner::AM)
       
   272         step = 1000; // 1kHz steps
       
   273     else if(b == QRadioTuner::SW)
       
   274         step = 500; // 500Hz steps
       
   275 
       
   276     return step;
       
   277 }
       
   278 
       
   279 QPair<int,int> V4LRadioControl::frequencyRange(QRadioTuner::Band b) const
       
   280 {
       
   281     if(b == QRadioTuner::AM)
       
   282         return qMakePair<int,int>(520000,1710000);
       
   283     else if(b == QRadioTuner::FM)
       
   284         return qMakePair<int,int>(87500000,108000000);
       
   285     else if(b == QRadioTuner::SW)
       
   286         return qMakePair<int,int>(1711111,30000000);
       
   287     else if(b == QRadioTuner::LW)
       
   288         return qMakePair<int,int>(148500,283500);
       
   289 
       
   290     return qMakePair<int,int>(0,0);
       
   291 }
       
   292 
       
   293 void V4LRadioControl::setFrequency(int frequency)
       
   294 {
       
   295     qint64 f = frequency;
       
   296 
       
   297     v4l2_frequency freq;
       
   298 
       
   299     if(frequency < freqMin)
       
   300         f = freqMax;
       
   301     if(frequency > freqMax)
       
   302         f = freqMin;
       
   303 
       
   304     if(fd > 0) {
       
   305         memset(&freq, 0, sizeof(freq));
       
   306         // Use the first tuner
       
   307         freq.tuner = 0;
       
   308         if (::ioctl(fd, VIDIOC_G_FREQUENCY, &freq) >= 0) {
       
   309             if(low) {
       
   310                 // For low, freq in units of 62.5Hz, so convert from Hz to units.
       
   311                 freq.frequency = (int)(f/62.5);
       
   312             } else {
       
   313                 // For high, freq in units of 62.5kHz, so convert from Hz to units.
       
   314                 freq.frequency = (int)(f/62500);
       
   315             }
       
   316             ::ioctl(fd, VIDIOC_S_FREQUENCY, &freq);
       
   317             currentFreq = f;
       
   318             emit frequencyChanged(currentFreq);
       
   319 	    
       
   320             int signal = signalStrength();
       
   321             if(sig != signal) {
       
   322                 sig = signal;
       
   323                 emit signalStrengthChanged(sig);
       
   324             }
       
   325         }
       
   326     }
       
   327 }
       
   328 
       
   329 bool V4LRadioControl::isStereo() const
       
   330 {
       
   331     return stereo;
       
   332 }
       
   333 
       
   334 QRadioTuner::StereoMode V4LRadioControl::stereoMode() const
       
   335 {
       
   336     return QRadioTuner::Auto;
       
   337 }
       
   338 
       
   339 void V4LRadioControl::setStereoMode(QRadioTuner::StereoMode mode)
       
   340 {
       
   341     bool stereo = true;
       
   342 
       
   343     if(mode == QRadioTuner::ForceMono)
       
   344         stereo = false;
       
   345 
       
   346     v4l2_tuner tuner;
       
   347 
       
   348     memset(&tuner, 0, sizeof(tuner));
       
   349 
       
   350     if (ioctl(fd, VIDIOC_G_TUNER, &tuner) >= 0) {
       
   351         if(stereo)
       
   352             tuner.audmode = V4L2_TUNER_MODE_STEREO;
       
   353         else
       
   354             tuner.audmode = V4L2_TUNER_MODE_MONO;
       
   355 
       
   356         if (ioctl(fd, VIDIOC_S_TUNER, &tuner) >= 0) {
       
   357             emit stereoStatusChanged(stereo);
       
   358         }
       
   359     }
       
   360 }
       
   361 
       
   362 int V4LRadioControl::signalStrength() const
       
   363 {
       
   364     v4l2_tuner tuner;
       
   365 
       
   366     tuner.index = 0;
       
   367     if (ioctl(fd, VIDIOC_G_TUNER, &tuner) < 0 || tuner.type != V4L2_TUNER_RADIO)
       
   368         return 0;
       
   369     return tuner.signal*100/65535;
       
   370 }
       
   371 
       
   372 int  V4LRadioControl::vol(snd_hctl_elem_t *elem) const
       
   373 {
       
   374     const QString card("hw:0");
       
   375     int err;
       
   376     snd_ctl_elem_id_t *id;
       
   377     snd_ctl_elem_info_t *info;
       
   378     snd_ctl_elem_value_t *control;
       
   379     snd_ctl_elem_id_alloca(&id);
       
   380     snd_ctl_elem_info_alloca(&info);
       
   381     snd_ctl_elem_value_alloca(&control);
       
   382     if ((err = snd_hctl_elem_info(elem, info)) < 0) {
       
   383         return 0;
       
   384     }
       
   385 
       
   386     snd_hctl_elem_get_id(elem, id);
       
   387     snd_hctl_elem_read(elem, control);
       
   388 
       
   389     return snd_ctl_elem_value_get_integer(control, 0);
       
   390 }
       
   391 
       
   392 int V4LRadioControl::volume() const
       
   393 {
       
   394     const QString ctlName("Line DAC Playback Volume");
       
   395     const QString card("hw:0");
       
   396 
       
   397     int volume = 0;
       
   398     int err;
       
   399     static snd_ctl_t *handle = NULL;
       
   400     snd_ctl_elem_info_t *info;
       
   401     snd_ctl_elem_id_t *id;
       
   402     snd_ctl_elem_value_t *control;
       
   403 
       
   404     snd_ctl_elem_info_alloca(&info);
       
   405     snd_ctl_elem_id_alloca(&id);
       
   406     snd_ctl_elem_value_alloca(&control);
       
   407     snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER);	/* MIXER */
       
   408 
       
   409     snd_ctl_elem_id_set_name(id, ctlName.toAscii());
       
   410 
       
   411     if ((err = snd_ctl_open(&handle, card.toAscii(), 0)) < 0) {
       
   412         return 0;
       
   413     }
       
   414 
       
   415     snd_ctl_elem_info_set_id(info, id);
       
   416     if ((err = snd_ctl_elem_info(handle, info)) < 0) {
       
   417         snd_ctl_close(handle);
       
   418         handle = NULL;
       
   419         return 0;
       
   420     }
       
   421 
       
   422     snd_ctl_elem_info_get_id(info, id);	/* FIXME: Remove it when hctl find works ok !!! */
       
   423     snd_ctl_elem_value_set_id(control, id);
       
   424 
       
   425     snd_ctl_close(handle);
       
   426     handle = NULL;
       
   427 
       
   428     snd_hctl_t *hctl;
       
   429     snd_hctl_elem_t *elem;
       
   430     if ((err = snd_hctl_open(&hctl, card.toAscii(), 0)) < 0) {
       
   431         return 0;
       
   432     }
       
   433     if ((err = snd_hctl_load(hctl)) < 0) {
       
   434         return 0;
       
   435     }
       
   436     elem = snd_hctl_find_elem(hctl, id);
       
   437     if (elem)
       
   438         volume = vol(elem);
       
   439 
       
   440     snd_hctl_close(hctl);
       
   441 
       
   442     return (volume/118.0) * 100;
       
   443 }
       
   444 
       
   445 void V4LRadioControl::setVolume(int volume)
       
   446 {
       
   447     int vol = (volume / 100.0) * 118; // 118 is a headphone max setting
       
   448     callAmixer("Line DAC Playback Volume", QString().setNum(vol)+QString(",")+QString().setNum(vol));
       
   449 }
       
   450 
       
   451 bool V4LRadioControl::isMuted() const
       
   452 {
       
   453     return muted;
       
   454 }
       
   455 
       
   456 void V4LRadioControl::setMuted(bool muted)
       
   457 {
       
   458     struct v4l2_control vctrl;
       
   459     vctrl.id = V4L2_CID_AUDIO_MUTE;
       
   460     vctrl.value = muted ? 1 : 0;
       
   461     ioctl(fd, VIDIOC_S_CTRL, &vctrl);
       
   462 }
       
   463 
       
   464 void V4LRadioControl::setupHeadPhone()
       
   465 {
       
   466     QMap<QString, QString> settings;
       
   467 
       
   468     settings["Jack Function"] = "Headset";
       
   469     settings["Left DAC_L1 Mixer HP Switch"] = "off";
       
   470     settings["Right DAC_R1 Mixer HP Switch"] = "off";
       
   471     settings["Line DAC Playback Switch"] = "on";
       
   472     settings["Line DAC Playback Volume"] = "118,118"; // Volume is set to 100%
       
   473     settings["HPCOM DAC Playback Switch"] = "off";
       
   474     settings["Left DAC_L1 Mixer HP Switch"] = "off";
       
   475     settings["Left DAC_L1 Mixer Line Switch"] = "on";
       
   476     settings["Right DAC_R1 Mixer HP Switch"] = "off";
       
   477     settings["Right DAC_R1 Mixer Line Switch"] = "on";
       
   478     settings["Speaker Function"] = "Off";
       
   479 
       
   480     settings["Input Select"] = "ADC";
       
   481     settings["Left PGA Mixer Line1L Switch"] = "off";
       
   482     settings["Right PGA Mixer Line1L Switch"] = "off";
       
   483     settings["Right PGA Mixer Line1R Switch"] = "off";
       
   484     settings["PGA Capture Volume"] = "0,0";
       
   485 
       
   486     settings["PGA Capture Switch"] = "on";
       
   487 
       
   488     settings["Left PGA Mixer Line2L Switch"] = "on";
       
   489     settings["Right PGA Mixer Line2R Switch"] = "on";
       
   490 
       
   491     QMapIterator<QString, QString> i(settings);
       
   492     while (i.hasNext()) {
       
   493         i.next();
       
   494         callAmixer(i.key(), i.value());
       
   495     }
       
   496 }
       
   497 
       
   498 void V4LRadioControl::callAmixer(const QString& target, const QString& value)
       
   499 {
       
   500     int err;
       
   501     long tmp;
       
   502     unsigned int count;
       
   503     static snd_ctl_t *handle = NULL;
       
   504     QString card("hw:0");
       
   505     snd_ctl_elem_info_t *info;
       
   506     snd_ctl_elem_id_t *id;
       
   507     snd_ctl_elem_value_t *control;
       
   508     snd_ctl_elem_type_t type;
       
   509 
       
   510     snd_ctl_elem_info_alloca(&info);
       
   511     snd_ctl_elem_id_alloca(&id);
       
   512     snd_ctl_elem_value_alloca(&control);
       
   513     snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER);	/* MIXER */
       
   514 
       
   515     // in amixer parse func
       
   516     // char target[64];
       
   517     // e.g. PGA CAPTure Switch
       
   518     snd_ctl_elem_id_set_name(id, target.toAscii());
       
   519 
       
   520     if (handle == NULL && (err = snd_ctl_open(&handle, card.toAscii(), 0)) < 0)
       
   521     {
       
   522         return;
       
   523     }
       
   524 
       
   525     snd_ctl_elem_info_set_id(info, id);
       
   526     if ((err = snd_ctl_elem_info(handle, info)) < 0)
       
   527     {
       
   528         snd_ctl_close(handle);
       
   529         handle = NULL;
       
   530         return;
       
   531     }
       
   532 
       
   533     snd_ctl_elem_info_get_id(info, id);	/* FIXME: Remove it when hctl find works ok !!! */
       
   534     type = snd_ctl_elem_info_get_type(info);
       
   535     count = snd_ctl_elem_info_get_count(info);
       
   536 
       
   537     snd_ctl_elem_value_set_id(control, id);
       
   538 
       
   539     tmp = 0;
       
   540     for (uint idx = 0; idx < count && idx < 128; idx++)
       
   541     {
       
   542         switch (type)
       
   543         {
       
   544             case SND_CTL_ELEM_TYPE_BOOLEAN:
       
   545 #ifdef MULTIMEDIA_MAEMO_DEBUG
       
   546                 qDebug() << "SND_CTL_ELEM_TYPE_BOOLEAN" << SND_CTL_ELEM_TYPE_BOOLEAN;
       
   547 #endif
       
   548                 if ((value == "on") ||(value == "1"))
       
   549                 {
       
   550                     tmp = 1;
       
   551                 }
       
   552                 snd_ctl_elem_value_set_boolean(control, idx, tmp);
       
   553                 break;
       
   554             case SND_CTL_ELEM_TYPE_ENUMERATED:
       
   555                 tmp = getEnumItemIndex(handle, info, value);
       
   556                 snd_ctl_elem_value_set_enumerated(control, idx, tmp);
       
   557                 break;
       
   558             case SND_CTL_ELEM_TYPE_INTEGER:
       
   559 #ifdef MULTIMEDIA_MAEMO_DEBUG
       
   560                 qDebug() << "SND_CTL_ELEM_TYPE_INTEGER" << SND_CTL_ELEM_TYPE_INTEGER;
       
   561 #endif
       
   562                 tmp = atoi(value.toAscii());
       
   563                 if (tmp <  snd_ctl_elem_info_get_min(info))
       
   564                     tmp = snd_ctl_elem_info_get_min(info);
       
   565                 else if (tmp > snd_ctl_elem_info_get_max(info))
       
   566                     tmp = snd_ctl_elem_info_get_max(info);
       
   567                 snd_ctl_elem_value_set_integer(control, idx, tmp);
       
   568                 break;
       
   569             default:
       
   570                 break;
       
   571 
       
   572         }
       
   573     }
       
   574 
       
   575     if ((err = snd_ctl_elem_write(handle, control)) < 0) {
       
   576         snd_ctl_close(handle);
       
   577         handle = NULL;
       
   578         return;
       
   579     }
       
   580 
       
   581     snd_ctl_close(handle);
       
   582     handle = NULL;
       
   583 }
       
   584 
       
   585 
       
   586 int V4LRadioControl::getEnumItemIndex(snd_ctl_t *handle, snd_ctl_elem_info_t *info,
       
   587        const QString &value)
       
   588 {
       
   589     int items, i;
       
   590 
       
   591     items = snd_ctl_elem_info_get_items(info);
       
   592     if (items <= 0)
       
   593         return -1;
       
   594 
       
   595     for (i = 0; i < items; i++)
       
   596     {
       
   597         snd_ctl_elem_info_set_item(info, i);
       
   598         if (snd_ctl_elem_info(handle, info) < 0)
       
   599             return -1;
       
   600         QString name = snd_ctl_elem_info_get_item_name(info);
       
   601         if(name == value)
       
   602         {
       
   603             return i;
       
   604         }
       
   605     }
       
   606     return -1;
       
   607 }
       
   608 
       
   609 bool V4LRadioControl::isSearching() const
       
   610 {
       
   611     return scanning;
       
   612 }
       
   613 
       
   614 void V4LRadioControl::cancelSearch()
       
   615 {
       
   616     scanning = false;
       
   617     timer->stop();
       
   618 }
       
   619 
       
   620 void V4LRadioControl::searchForward()
       
   621 {
       
   622     // Scan up
       
   623     if(scanning) {
       
   624         cancelSearch();
       
   625         return;
       
   626     }
       
   627     scanning = true;
       
   628     forward  = true;
       
   629     timer->start();
       
   630 }
       
   631 
       
   632 void V4LRadioControl::searchBackward()
       
   633 {
       
   634     // Scan down
       
   635     if(scanning) {
       
   636         cancelSearch();
       
   637         return;
       
   638     }
       
   639     scanning = true;
       
   640     forward  = false;
       
   641     timer->start();
       
   642 }
       
   643 
       
   644 void V4LRadioControl::start()
       
   645 {
       
   646 }
       
   647 
       
   648 void V4LRadioControl::stop()
       
   649 {
       
   650 }
       
   651 
       
   652 QRadioTuner::Error V4LRadioControl::error() const
       
   653 {
       
   654     if(m_error)
       
   655         return QRadioTuner::OpenError;
       
   656 
       
   657     return QRadioTuner::NoError;
       
   658 }
       
   659 
       
   660 QString V4LRadioControl::errorString() const
       
   661 {
       
   662     return QString();
       
   663 }
       
   664 
       
   665 void V4LRadioControl::search()
       
   666 {
       
   667     if(!scanning) return;
       
   668 
       
   669     if(forward) {
       
   670         setFrequency(currentFreq+step);
       
   671     } else {
       
   672         setFrequency(currentFreq-step);
       
   673     }
       
   674     
       
   675     int signal = signalStrength();
       
   676     if(sig != signal) {
       
   677         sig = signal;
       
   678         emit signalStrengthChanged(sig);
       
   679     }
       
   680     
       
   681     if (signal > 25) {
       
   682         cancelSearch();
       
   683         return;
       
   684     }
       
   685 }
       
   686 
       
   687 bool V4LRadioControl::initRadio()
       
   688 {
       
   689     v4l2_tuner tuner;
       
   690     v4l2_frequency freq;
       
   691     v4l2_capability cap;
       
   692 
       
   693     low = false;
       
   694     available = false;
       
   695     freqMin = freqMax = currentFreq = 0;
       
   696 
       
   697     fd = ::open("/dev/radio1", O_RDWR);
       
   698 
       
   699     if(fd != -1) {
       
   700         // Capabilites
       
   701         memset(&cap, 0, sizeof(cap));
       
   702         if(::ioctl(fd, VIDIOC_QUERYCAP, &cap ) >= 0) {
       
   703             available = true;
       
   704         }
       
   705 
       
   706         tuner.index = 0;
       
   707 
       
   708         if (ioctl(fd, VIDIOC_G_TUNER, &tuner) < 0) {
       
   709             return false;
       
   710         }
       
   711 
       
   712         if (tuner.type != V4L2_TUNER_RADIO)
       
   713             return false;
       
   714 
       
   715         if ((tuner.capability & V4L2_TUNER_CAP_LOW) != 0) {
       
   716             // Units are 1/16th of a kHz.
       
   717             low = true;
       
   718         }
       
   719 
       
   720         if(low) {
       
   721             freqMin = tuner.rangelow * 62.5;
       
   722             freqMax = tuner.rangehigh * 62.5;
       
   723         } else {
       
   724             freqMin = tuner.rangelow * 62500;
       
   725             freqMax = tuner.rangehigh * 62500;
       
   726         }
       
   727 
       
   728         // frequency
       
   729         memset(&freq, 0, sizeof(freq));
       
   730 
       
   731         if(::ioctl(fd, VIDIOC_G_FREQUENCY, &freq) >= 0) {
       
   732             if (((int)freq.frequency) != -1) {    // -1 means not set.
       
   733                 if(low)
       
   734                     currentFreq = freq.frequency * 62.5;
       
   735                 else
       
   736                     currentFreq = freq.frequency * 62500;
       
   737             }
       
   738         }
       
   739 
       
   740         // stereo
       
   741         bool stereo = false;
       
   742         memset(&tuner, 0, sizeof(tuner));
       
   743         if (ioctl(fd, VIDIOC_G_TUNER, &tuner) >= 0) {
       
   744             if((tuner.rxsubchans & V4L2_TUNER_SUB_STEREO) != 0)
       
   745                 stereo = true;
       
   746         }
       
   747 
       
   748         return true;
       
   749     }
       
   750 
       
   751     m_error = true;
       
   752     emit error();
       
   753 
       
   754     return false;
       
   755 }