qtmobility/plugins/multimedia/v4l/radio/v4lradiocontrol_maemo5.cpp
changeset 4 90517678cc4f
child 5 453da2cfceef
equal deleted inserted replaced
1:2b40d63a9c3d 4:90517678cc4f
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 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 V4LRadioControl::V4LRadioControl(QObject *parent)
       
    55     : QRadioTunerControl(parent)
       
    56     , fd(1)
       
    57     , m_error(false)
       
    58     , muted(false)
       
    59     , stereo(false)
       
    60     , step(100000)
       
    61     , sig(0)
       
    62     , scanning(false)
       
    63     , currentBand(QRadioTuner::FM)
       
    64     , pipeline(0)
       
    65 {
       
    66     if (QDBusConnection::systemBus().isConnected()) {
       
    67         FMRXEnablerIFace = new QDBusInterface("de.pycage.FMRXEnabler",
       
    68                                              "/de/pycage/FMRXEnabler",
       
    69                                              "de.pycage.FMRXEnabler",
       
    70                                              QDBusConnection::systemBus());
       
    71     }
       
    72 
       
    73     enableFMRX();
       
    74     createGstPipeline();
       
    75     initRadio();
       
    76     setupHeadPhone();
       
    77 
       
    78     setMuted(false);
       
    79 
       
    80     timer = new QTimer(this);
       
    81     timer->setInterval(200);
       
    82     connect(timer,SIGNAL(timeout()),this,SLOT(search()));
       
    83     timer->start();
       
    84 
       
    85     tickTimer = new QTimer(this);
       
    86     tickTimer->setInterval(10000);
       
    87     connect(tickTimer,SIGNAL(timeout()),this,SLOT(enableFMRX()));
       
    88     tickTimer->start();
       
    89 }
       
    90 
       
    91 V4LRadioControl::~V4LRadioControl()
       
    92 {
       
    93     if (pipeline)
       
    94     {
       
    95         gst_element_set_state (pipeline, GST_STATE_NULL);
       
    96         gst_object_unref (GST_OBJECT (pipeline));
       
    97     }
       
    98 
       
    99     if(fd > 0)
       
   100         ::close(fd);
       
   101 }
       
   102 
       
   103 void V4LRadioControl::enableFMRX()
       
   104 {
       
   105     if (FMRXEnablerIFace && FMRXEnablerIFace->isValid()) {
       
   106         FMRXEnablerIFace->call("request"); // Return value ignored
       
   107     }
       
   108 }
       
   109 
       
   110 // Workaround to capture sound from the PGA line and play it back using gstreamer
       
   111 // because N900 doesn't output sound directly to speakers
       
   112 bool V4LRadioControl::createGstPipeline()
       
   113 {
       
   114     GstElement *source, *sink;
       
   115 
       
   116     gst_init (NULL, NULL);
       
   117     pipeline = gst_pipeline_new("my-pipeline");
       
   118 
       
   119     source = gst_element_factory_make ("pulsesrc", "source");
       
   120     sink = gst_element_factory_make ("pulsesink", "sink");
       
   121 
       
   122     gst_bin_add_many (GST_BIN (pipeline), source, sink, (char *)NULL);
       
   123 
       
   124     if (!gst_element_link_many (source, sink, (char *)NULL)) {
       
   125         return false;
       
   126     }
       
   127 
       
   128     gst_element_set_state (pipeline, GST_STATE_PLAYING);
       
   129 
       
   130     return true;
       
   131 }
       
   132 
       
   133 bool V4LRadioControl::isAvailable() const
       
   134 {
       
   135     return available;
       
   136 }
       
   137 
       
   138 QtMedia::AvailabilityError V4LRadioControl::availabilityError() const
       
   139 {
       
   140     if (fd > 0)
       
   141         return QtMedia::NoError;
       
   142     else
       
   143         return QtMedia::ResourceError;
       
   144 }
       
   145 
       
   146 QRadioTuner::State V4LRadioControl::state() const
       
   147 {
       
   148     return fd > 0 ? QRadioTuner::ActiveState : QRadioTuner::StoppedState;
       
   149 }
       
   150 
       
   151 QRadioTuner::Band V4LRadioControl::band() const
       
   152 {
       
   153     return currentBand;
       
   154 }
       
   155 
       
   156 bool V4LRadioControl::isBandSupported(QRadioTuner::Band b) const
       
   157 {
       
   158     QRadioTuner::Band bnd = (QRadioTuner::Band)b;
       
   159     switch(bnd) {
       
   160         case QRadioTuner::FM:
       
   161             if(freqMin <= 87500000 && freqMax >= 108000000)
       
   162                 return true;
       
   163             break;
       
   164         case QRadioTuner::LW:
       
   165             if(freqMin <= 148500 && freqMax >= 283500)
       
   166                 return true;
       
   167         case QRadioTuner::AM:
       
   168             if(freqMin <= 520000 && freqMax >= 1610000)
       
   169                 return true;
       
   170         default:
       
   171             if(freqMin <= 1711000 && freqMax >= 30000000)
       
   172                 return true;
       
   173     }
       
   174 
       
   175     return false;
       
   176 }
       
   177 
       
   178 void V4LRadioControl::setBand(QRadioTuner::Band b)
       
   179 {
       
   180     if(freqMin <= 87500000 && freqMax >= 108000000 && b == QRadioTuner::FM) {
       
   181         // FM 87.5 to 108.0 MHz, except Japan 76-90 MHz
       
   182         currentBand =  (QRadioTuner::Band)b;
       
   183         step = 100000; // 100kHz steps
       
   184         emit bandChanged(currentBand);
       
   185 
       
   186     } else if(freqMin <= 148500 && freqMax >= 283500 && b == QRadioTuner::LW) {
       
   187         // LW 148.5 to 283.5 kHz, 9kHz channel spacing (Europe, Africa, Asia)
       
   188         currentBand =  (QRadioTuner::Band)b;
       
   189         step = 1000; // 1kHz steps
       
   190         emit bandChanged(currentBand);
       
   191 
       
   192     } else if(freqMin <= 520000 && freqMax >= 1610000 && b == QRadioTuner::AM) {
       
   193         // AM 520 to 1610 kHz, 9 or 10kHz channel spacing, extended 1610 to 1710 kHz
       
   194         currentBand =  (QRadioTuner::Band)b;
       
   195         step = 1000; // 1kHz steps
       
   196         emit bandChanged(currentBand);
       
   197 
       
   198     } else if(freqMin <= 1711000 && freqMax >= 30000000 && b == QRadioTuner::SW) {
       
   199         // SW 1.711 to 30.0 MHz, divided into 15 bands. 5kHz channel spacing
       
   200         currentBand =  (QRadioTuner::Band)b;
       
   201         step = 500; // 500Hz steps
       
   202         emit bandChanged(currentBand);
       
   203     }
       
   204 }
       
   205 
       
   206 int V4LRadioControl::frequency() const
       
   207 {
       
   208     return currentFreq;
       
   209 }
       
   210 
       
   211 int V4LRadioControl::frequencyStep(QRadioTuner::Band b) const
       
   212 {
       
   213     int step = 0;
       
   214 
       
   215     if(b == QRadioTuner::FM)
       
   216         step = 100000; // 100kHz steps
       
   217     else if(b == QRadioTuner::LW)
       
   218         step = 1000; // 1kHz steps
       
   219     else if(b == QRadioTuner::AM)
       
   220         step = 1000; // 1kHz steps
       
   221     else if(b == QRadioTuner::SW)
       
   222         step = 500; // 500Hz steps
       
   223 
       
   224     return step;
       
   225 }
       
   226 
       
   227 QPair<int,int> V4LRadioControl::frequencyRange(QRadioTuner::Band b) const
       
   228 {
       
   229     if(b == QRadioTuner::AM)
       
   230         return qMakePair<int,int>(520000,1710000);
       
   231     else if(b == QRadioTuner::FM)
       
   232         return qMakePair<int,int>(87500000,108000000);
       
   233     else if(b == QRadioTuner::SW)
       
   234         return qMakePair<int,int>(1711111,30000000);
       
   235     else if(b == QRadioTuner::LW)
       
   236         return qMakePair<int,int>(148500,283500);
       
   237 
       
   238     return qMakePair<int,int>(0,0);
       
   239 }
       
   240 
       
   241 void V4LRadioControl::setFrequency(int frequency)
       
   242 {
       
   243     qint64 f = frequency;
       
   244 
       
   245     v4l2_frequency freq;
       
   246 
       
   247     if(frequency < freqMin)
       
   248         f = freqMax;
       
   249     if(frequency > freqMax)
       
   250         f = freqMin;
       
   251 
       
   252     if(fd > 0) {
       
   253         memset(&freq, 0, sizeof(freq));
       
   254         // Use the first tuner
       
   255         freq.tuner = 0;
       
   256         if (::ioctl(fd, VIDIOC_G_FREQUENCY, &freq) >= 0) {
       
   257             if(low) {
       
   258                 // For low, freq in units of 62.5Hz, so convert from Hz to units.
       
   259                 freq.frequency = (int)(f/62.5);
       
   260             } else {
       
   261                 // For high, freq in units of 62.5kHz, so convert from Hz to units.
       
   262                 freq.frequency = (int)(f/62500);
       
   263             }
       
   264             ::ioctl(fd, VIDIOC_S_FREQUENCY, &freq);
       
   265             currentFreq = f;
       
   266             emit frequencyChanged(currentFreq);
       
   267         }
       
   268     }
       
   269 }
       
   270 
       
   271 bool V4LRadioControl::isStereo() const
       
   272 {
       
   273     return stereo;
       
   274 }
       
   275 
       
   276 QRadioTuner::StereoMode V4LRadioControl::stereoMode() const
       
   277 {
       
   278     return QRadioTuner::Auto;
       
   279 }
       
   280 
       
   281 void V4LRadioControl::setStereoMode(QRadioTuner::StereoMode mode)
       
   282 {
       
   283     bool stereo = true;
       
   284 
       
   285     if(mode == QRadioTuner::ForceMono)
       
   286         stereo = false;
       
   287 
       
   288     v4l2_tuner tuner;
       
   289 
       
   290     memset(&tuner, 0, sizeof(tuner));
       
   291 
       
   292     if (ioctl(fd, VIDIOC_G_TUNER, &tuner) >= 0) {
       
   293         if(stereo)
       
   294             tuner.audmode = V4L2_TUNER_MODE_STEREO;
       
   295         else
       
   296             tuner.audmode = V4L2_TUNER_MODE_MONO;
       
   297 
       
   298         if (ioctl(fd, VIDIOC_S_TUNER, &tuner) >= 0) {
       
   299             emit stereoStatusChanged(stereo);
       
   300         }
       
   301     }
       
   302 }
       
   303 
       
   304 int V4LRadioControl::signalStrength() const
       
   305 {
       
   306     v4l2_tuner tuner;
       
   307 
       
   308     tuner.index = 0;
       
   309     if (ioctl(fd, VIDIOC_G_TUNER, &tuner) < 0 || tuner.type != V4L2_TUNER_RADIO)
       
   310         return 0;
       
   311     return tuner.signal*100/65535;
       
   312 }
       
   313 
       
   314 int  V4LRadioControl::vol(snd_hctl_elem_t *elem) const
       
   315 {
       
   316     const QString card("hw:0");
       
   317     int err;
       
   318     snd_ctl_elem_id_t *id;
       
   319     snd_ctl_elem_info_t *info;
       
   320     snd_ctl_elem_value_t *control;
       
   321     snd_ctl_elem_id_alloca(&id);
       
   322     snd_ctl_elem_info_alloca(&info);
       
   323     snd_ctl_elem_value_alloca(&control);
       
   324     if ((err = snd_hctl_elem_info(elem, info)) < 0) {
       
   325         return 0;
       
   326     }
       
   327 
       
   328     snd_hctl_elem_get_id(elem, id);
       
   329     snd_hctl_elem_read(elem, control);
       
   330 
       
   331     return snd_ctl_elem_value_get_integer(control, 0);
       
   332 }
       
   333 
       
   334 int V4LRadioControl::volume() const
       
   335 {
       
   336     const QString ctlName("Line DAC Playback Volume");
       
   337     const QString card("hw:0");
       
   338 
       
   339     int volume = 0;
       
   340     int err;
       
   341     static snd_ctl_t *handle = NULL;
       
   342     snd_ctl_elem_info_t *info;
       
   343     snd_ctl_elem_id_t *id;
       
   344     snd_ctl_elem_value_t *control;
       
   345 
       
   346     snd_ctl_elem_info_alloca(&info);
       
   347     snd_ctl_elem_id_alloca(&id);
       
   348     snd_ctl_elem_value_alloca(&control);
       
   349     snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER);	/* MIXER */
       
   350 
       
   351     snd_ctl_elem_id_set_name(id, ctlName.toAscii());
       
   352 
       
   353     if ((err = snd_ctl_open(&handle, card.toAscii(), 0)) < 0) {
       
   354         return 0;
       
   355     }
       
   356 
       
   357     snd_ctl_elem_info_set_id(info, id);
       
   358     if ((err = snd_ctl_elem_info(handle, info)) < 0) {
       
   359         snd_ctl_close(handle);
       
   360         handle = NULL;
       
   361         return 0;
       
   362     }
       
   363 
       
   364     snd_ctl_elem_info_get_id(info, id);	/* FIXME: Remove it when hctl find works ok !!! */
       
   365     snd_ctl_elem_value_set_id(control, id);
       
   366 
       
   367     snd_ctl_close(handle);
       
   368     handle = NULL;
       
   369 
       
   370     snd_hctl_t *hctl;
       
   371     snd_hctl_elem_t *elem;
       
   372     if ((err = snd_hctl_open(&hctl, card.toAscii(), 0)) < 0) {
       
   373         return 0;
       
   374     }
       
   375     if ((err = snd_hctl_load(hctl)) < 0) {
       
   376         return 0;
       
   377     }
       
   378     elem = snd_hctl_find_elem(hctl, id);
       
   379     if (elem)
       
   380         volume = vol(elem);
       
   381 
       
   382     snd_hctl_close(hctl);
       
   383 
       
   384     return (volume/63.0) * 100;
       
   385 }
       
   386 
       
   387 void V4LRadioControl::setVolume(int volume)
       
   388 {
       
   389 
       
   390     int vol = (volume / 100.0) * 63; // 63 is a headphone max setting
       
   391     callAmixer("Line DAC Playback Volume", QString().setNum(vol)+QString(",")+QString().setNum(vol));
       
   392 }
       
   393 
       
   394 bool V4LRadioControl::isMuted() const
       
   395 {
       
   396     return muted;
       
   397 }
       
   398 
       
   399 void V4LRadioControl::setMuted(bool muted)
       
   400 {
       
   401     struct v4l2_control vctrl;
       
   402     vctrl.id = V4L2_CID_AUDIO_MUTE;
       
   403     vctrl.value = muted ? 1 : 0;
       
   404     ioctl(fd, VIDIOC_S_CTRL, &vctrl);
       
   405 }
       
   406 
       
   407 void V4LRadioControl::setupHeadPhone()
       
   408 {
       
   409     QMap<QString, QString> settings;
       
   410 
       
   411     settings["Jack Function"] = "Headset";
       
   412     settings["Left DAC_L1 Mixer HP Switch"] = "off";
       
   413     settings["Right DAC_R1 Mixer HP Switch"] = "off";
       
   414     settings["Line DAC Playback Switch"] = "on";
       
   415     settings["Line DAC Playback Volume"] = "63,63"; // Volume is set to 100%
       
   416     settings["HPCOM DAC Playback Switch"] = "off";
       
   417     settings["Left DAC_L1 Mixer HP Switch"] = "off";
       
   418     settings["Left DAC_L1 Mixer Line Switch"] = "on";
       
   419     settings["Right DAC_R1 Mixer HP Switch"] = "off";
       
   420     settings["Right DAC_R1 Mixer Line Switch"] = "on";
       
   421     settings["Speaker Function"] = "Off";
       
   422 
       
   423     settings["Input Select"] = "ADC";
       
   424     settings["Left PGA Mixer Line1L Switch"] = "off";
       
   425     settings["Right PGA Mixer Line1L Switch"] = "off";
       
   426     settings["Right PGA Mixer Line1R Switch"] = "off";
       
   427     settings["PGA Capture Volume"] = "0,0";
       
   428 
       
   429     settings["PGA Capture Switch"] = "on";
       
   430 
       
   431     settings["Left PGA Mixer Line2L Switch"] = "on";
       
   432     settings["Right PGA Mixer Line2R Switch"] = "on";
       
   433 
       
   434     QMapIterator<QString, QString> i(settings);
       
   435     while (i.hasNext()) {
       
   436         i.next();
       
   437         callAmixer(i.key(), i.value());
       
   438     }
       
   439 }
       
   440 
       
   441 void V4LRadioControl::callAmixer(const QString& target, const QString& value)
       
   442 {
       
   443     int err;
       
   444     long tmp;
       
   445     unsigned int count;
       
   446     static snd_ctl_t *handle = NULL;
       
   447     QString card("hw:0");
       
   448     snd_ctl_elem_info_t *info;
       
   449     snd_ctl_elem_id_t *id;
       
   450     snd_ctl_elem_value_t *control;
       
   451     snd_ctl_elem_type_t type;
       
   452 
       
   453     snd_ctl_elem_info_alloca(&info);
       
   454     snd_ctl_elem_id_alloca(&id);
       
   455     snd_ctl_elem_value_alloca(&control);
       
   456     snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER);	/* MIXER */
       
   457 
       
   458     // in amixer parse func
       
   459     // char target[64];
       
   460     // e.g. PGA CAPTure Switch
       
   461     snd_ctl_elem_id_set_name(id, target.toAscii());
       
   462 
       
   463     if (handle == NULL && (err = snd_ctl_open(&handle, card.toAscii(), 0)) < 0)
       
   464     {
       
   465         return;
       
   466     }
       
   467 
       
   468     snd_ctl_elem_info_set_id(info, id);
       
   469     if ((err = snd_ctl_elem_info(handle, info)) < 0)
       
   470     {
       
   471         snd_ctl_close(handle);
       
   472         handle = NULL;
       
   473         return;
       
   474     }
       
   475 
       
   476     snd_ctl_elem_info_get_id(info, id);	/* FIXME: Remove it when hctl find works ok !!! */
       
   477     type = snd_ctl_elem_info_get_type(info);
       
   478     count = snd_ctl_elem_info_get_count(info);
       
   479 
       
   480     snd_ctl_elem_value_set_id(control, id);
       
   481 
       
   482     tmp = 0;
       
   483     for (int idx = 0; idx < count && idx < 128; idx++)
       
   484     {
       
   485         switch (type)
       
   486         {
       
   487             case SND_CTL_ELEM_TYPE_BOOLEAN:
       
   488                 qDebug() << "SND_CTL_ELEM_TYPE_BOOLEAN" << SND_CTL_ELEM_TYPE_BOOLEAN;
       
   489                 if ((value == "on") ||(value == "1"))
       
   490                 {
       
   491                     tmp = 1;
       
   492                 }
       
   493                 snd_ctl_elem_value_set_boolean(control, idx, tmp);
       
   494                 break;
       
   495             case SND_CTL_ELEM_TYPE_ENUMERATED:
       
   496                 tmp = getEnumItemIndex(handle, info, value);
       
   497                 snd_ctl_elem_value_set_enumerated(control, idx, tmp);
       
   498                 break;
       
   499             case SND_CTL_ELEM_TYPE_INTEGER:
       
   500                 qDebug() << "SND_CTL_ELEM_TYPE_INTEGER" << SND_CTL_ELEM_TYPE_INTEGER;
       
   501                 tmp = atoi(value.toAscii());
       
   502                 if (tmp <  snd_ctl_elem_info_get_min(info))
       
   503                     tmp = snd_ctl_elem_info_get_min(info);
       
   504                 else if (tmp > snd_ctl_elem_info_get_max(info))
       
   505                     tmp = snd_ctl_elem_info_get_max(info);
       
   506                 snd_ctl_elem_value_set_integer(control, idx, tmp);
       
   507                 break;
       
   508             default:
       
   509                 break;
       
   510 
       
   511         }
       
   512     }
       
   513 
       
   514     if ((err = snd_ctl_elem_write(handle, control)) < 0) {
       
   515         snd_ctl_close(handle);
       
   516         handle = NULL;
       
   517         return;
       
   518     }
       
   519 
       
   520     snd_ctl_close(handle);
       
   521     handle = NULL;
       
   522 }
       
   523 
       
   524 
       
   525 int V4LRadioControl::getEnumItemIndex(snd_ctl_t *handle, snd_ctl_elem_info_t *info,
       
   526        const QString &value)
       
   527 {
       
   528     int items, i;
       
   529 
       
   530     items = snd_ctl_elem_info_get_items(info);
       
   531     if (items <= 0)
       
   532         return -1;
       
   533 
       
   534     for (i = 0; i < items; i++)
       
   535     {
       
   536         snd_ctl_elem_info_set_item(info, i);
       
   537         if (snd_ctl_elem_info(handle, info) < 0)
       
   538             return -1;
       
   539         QString name = snd_ctl_elem_info_get_item_name(info);
       
   540         if(name == value)
       
   541         {
       
   542             return i;
       
   543         }
       
   544     }
       
   545     return -1;
       
   546 }
       
   547 
       
   548 bool V4LRadioControl::isSearching() const
       
   549 {
       
   550     return scanning;
       
   551 }
       
   552 
       
   553 void V4LRadioControl::cancelSearch()
       
   554 {
       
   555     scanning = false;
       
   556 }
       
   557 
       
   558 void V4LRadioControl::searchForward()
       
   559 {
       
   560     // Scan up
       
   561     if(scanning) {
       
   562         scanning = false;
       
   563         return;
       
   564     }
       
   565     scanning = true;
       
   566     forward  = true;
       
   567 }
       
   568 
       
   569 void V4LRadioControl::searchBackward()
       
   570 {
       
   571     // Scan down
       
   572     if(scanning) {
       
   573         scanning = false;
       
   574         return;
       
   575     }
       
   576     scanning = true;
       
   577     forward  = false;
       
   578 }
       
   579 
       
   580 void V4LRadioControl::start()
       
   581 {
       
   582 }
       
   583 
       
   584 void V4LRadioControl::stop()
       
   585 {
       
   586 }
       
   587 
       
   588 QRadioTuner::Error V4LRadioControl::error() const
       
   589 {
       
   590     if(m_error)
       
   591         return QRadioTuner::OpenError;
       
   592 
       
   593     return QRadioTuner::NoError;
       
   594 }
       
   595 
       
   596 QString V4LRadioControl::errorString() const
       
   597 {
       
   598     return QString();
       
   599 }
       
   600 
       
   601 void V4LRadioControl::search()
       
   602 {
       
   603     int signal = signalStrength();
       
   604     if(sig != signal) {
       
   605         sig = signal;
       
   606         emit signalStrengthChanged(sig);
       
   607     }
       
   608 
       
   609     if(!scanning) return;
       
   610 
       
   611     if (signal > 25) {
       
   612         cancelSearch();
       
   613         return;
       
   614     }
       
   615 
       
   616     if(forward) {
       
   617         setFrequency(currentFreq+step);
       
   618     } else {
       
   619         setFrequency(currentFreq-step);
       
   620     }
       
   621     emit signalStrengthChanged(signalStrength());
       
   622 }
       
   623 
       
   624 bool V4LRadioControl::initRadio()
       
   625 {
       
   626     v4l2_tuner tuner;
       
   627     v4l2_frequency freq;
       
   628     v4l2_capability cap;
       
   629 
       
   630     low = false;
       
   631     available = false;
       
   632     freqMin = freqMax = currentFreq = 0;
       
   633 
       
   634     fd = ::open("/dev/radio1", O_RDWR);
       
   635 
       
   636     if(fd != -1) {
       
   637         // Capabilites
       
   638         memset(&cap, 0, sizeof(cap));
       
   639         if(::ioctl(fd, VIDIOC_QUERYCAP, &cap ) >= 0) {
       
   640             if(((cap.capabilities & V4L2_CAP_RADIO) == 0) && ((cap.capabilities & V4L2_CAP_AUDIO) == 0))
       
   641                 available = true;
       
   642         }
       
   643 
       
   644         tuner.index = 0;
       
   645 
       
   646         if (ioctl(fd, VIDIOC_G_TUNER, &tuner) < 0) {
       
   647             return false;
       
   648         }
       
   649 
       
   650         if (tuner.type != V4L2_TUNER_RADIO)
       
   651             return false;
       
   652 
       
   653         if ((tuner.capability & V4L2_TUNER_CAP_LOW) != 0) {
       
   654             // Units are 1/16th of a kHz.
       
   655             low = true;
       
   656         }
       
   657 
       
   658         if(low) {
       
   659             freqMin = tuner.rangelow * 62.5;
       
   660             freqMax = tuner.rangehigh * 62.5;
       
   661         } else {
       
   662             freqMin = tuner.rangelow * 62500;
       
   663             freqMax = tuner.rangehigh * 62500;
       
   664         }
       
   665 
       
   666         // frequency
       
   667         memset(&freq, 0, sizeof(freq));
       
   668 
       
   669         if(::ioctl(fd, VIDIOC_G_FREQUENCY, &freq) >= 0) {
       
   670             if (((int)freq.frequency) != -1) {    // -1 means not set.
       
   671                 if(low)
       
   672                     currentFreq = freq.frequency * 62.5;
       
   673                 else
       
   674                     currentFreq = freq.frequency * 62500;
       
   675             }
       
   676         }
       
   677 
       
   678         // stereo
       
   679         bool stereo = false;
       
   680         memset(&tuner, 0, sizeof(tuner));
       
   681         if (ioctl(fd, VIDIOC_G_TUNER, &tuner) >= 0) {
       
   682             if((tuner.rxsubchans & V4L2_TUNER_SUB_STEREO) != 0)
       
   683                 stereo = true;
       
   684         }
       
   685 
       
   686         return true;
       
   687     }
       
   688 
       
   689     m_error = true;
       
   690     emit error();
       
   691 
       
   692     return false;
       
   693 }