qtmobility/plugins/multimedia/v4l/radio/v4lradiocontrol.cpp
changeset 1 2b40d63a9c3d
child 4 90517678cc4f
equal deleted inserted replaced
0:cfcbf08528c4 1:2b40d63a9c3d
       
     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.h"
       
    43 #include "v4lradioservice.h"
       
    44 
       
    45 #include <QtCore/qdebug.h>
       
    46 
       
    47 #include <fcntl.h>
       
    48 
       
    49 #include <sys/ioctl.h>
       
    50 #include "linux/videodev2.h"
       
    51 
       
    52 #include <sys/soundcard.h>
       
    53 #include <stdio.h>
       
    54 #include <sys/types.h>
       
    55 #include <sys/ioctl.h>
       
    56 #include <fcntl.h>
       
    57 #include <unistd.h>
       
    58 
       
    59 V4LRadioControl::V4LRadioControl(QObject *parent)
       
    60     :QRadioTunerControl(parent)
       
    61 {
       
    62     fd = -1;
       
    63     initRadio();
       
    64     muted = false;
       
    65     stereo = false;
       
    66     m_error = false;
       
    67     sig = 0;
       
    68     currentBand = QRadioTuner::FM;
       
    69     step = 100000;
       
    70     scanning = false;
       
    71     playTime.restart();
       
    72     timer = new QTimer(this);
       
    73     timer->setInterval(200);
       
    74     connect(timer,SIGNAL(timeout()),this,SLOT(search()));
       
    75     timer->start();
       
    76 }
       
    77 
       
    78 V4LRadioControl::~V4LRadioControl()
       
    79 {
       
    80     timer->stop();
       
    81 
       
    82     if(fd > 0)
       
    83         ::close(fd);
       
    84 }
       
    85 
       
    86 bool V4LRadioControl::isAvailable() const
       
    87 {
       
    88     return available;
       
    89 }
       
    90 
       
    91 QtMedia::AvailabilityError V4LRadioControl::availabilityError() const
       
    92 {
       
    93     if (fd > 0)
       
    94         return QtMedia::NoError;
       
    95     else
       
    96         return QtMedia::ResourceError;
       
    97 }
       
    98 
       
    99 QRadioTuner::State V4LRadioControl::state() const
       
   100 {
       
   101     return fd > 0 ? QRadioTuner::ActiveState : QRadioTuner::StoppedState;
       
   102 }
       
   103 
       
   104 QRadioTuner::Band V4LRadioControl::band() const
       
   105 {
       
   106     return currentBand;
       
   107 }
       
   108 
       
   109 bool V4LRadioControl::isBandSupported(QRadioTuner::Band b) const
       
   110 {
       
   111     QRadioTuner::Band bnd = (QRadioTuner::Band)b;
       
   112     switch(bnd) {
       
   113         case QRadioTuner::FM:
       
   114             if(freqMin <= 87500000 && freqMax >= 108000000)
       
   115                 return true;
       
   116             break;
       
   117         case QRadioTuner::LW:
       
   118             if(freqMin <= 148500 && freqMax >= 283500)
       
   119                 return true;
       
   120         case QRadioTuner::AM:
       
   121             if(freqMin <= 520000 && freqMax >= 1610000)
       
   122                 return true;
       
   123         default:
       
   124             if(freqMin <= 1711000 && freqMax >= 30000000)
       
   125                 return true;
       
   126     }
       
   127 
       
   128     return false;
       
   129 }
       
   130 
       
   131 void V4LRadioControl::setBand(QRadioTuner::Band b)
       
   132 {
       
   133     if(freqMin <= 87500000 && freqMax >= 108000000 && b == QRadioTuner::FM) {
       
   134         // FM 87.5 to 108.0 MHz, except Japan 76-90 MHz
       
   135         currentBand =  (QRadioTuner::Band)b;
       
   136         step = 100000; // 100kHz steps
       
   137         emit bandChanged(currentBand);
       
   138 
       
   139     } else if(freqMin <= 148500 && freqMax >= 283500 && b == QRadioTuner::LW) {
       
   140         // LW 148.5 to 283.5 kHz, 9kHz channel spacing (Europe, Africa, Asia)
       
   141         currentBand =  (QRadioTuner::Band)b;
       
   142         step = 1000; // 1kHz steps
       
   143         emit bandChanged(currentBand);
       
   144 
       
   145     } else if(freqMin <= 520000 && freqMax >= 1610000 && b == QRadioTuner::AM) {
       
   146         // AM 520 to 1610 kHz, 9 or 10kHz channel spacing, extended 1610 to 1710 kHz
       
   147         currentBand =  (QRadioTuner::Band)b;
       
   148         step = 1000; // 1kHz steps
       
   149         emit bandChanged(currentBand);
       
   150 
       
   151     } else if(freqMin <= 1711000 && freqMax >= 30000000 && b == QRadioTuner::SW) {
       
   152         // SW 1.711 to 30.0 MHz, divided into 15 bands. 5kHz channel spacing
       
   153         currentBand =  (QRadioTuner::Band)b;
       
   154         step = 500; // 500Hz steps
       
   155         emit bandChanged(currentBand);
       
   156     }
       
   157     playTime.restart();
       
   158 }
       
   159 
       
   160 int V4LRadioControl::frequency() const
       
   161 {
       
   162     return currentFreq;
       
   163 }
       
   164 
       
   165 int V4LRadioControl::frequencyStep(QRadioTuner::Band b) const
       
   166 {
       
   167     int step = 0;
       
   168 
       
   169     if(b == QRadioTuner::FM)
       
   170         step = 100000; // 100kHz steps
       
   171     else if(b == QRadioTuner::LW)
       
   172         step = 1000; // 1kHz steps
       
   173     else if(b == QRadioTuner::AM)
       
   174         step = 1000; // 1kHz steps
       
   175     else if(b == QRadioTuner::SW)
       
   176         step = 500; // 500Hz steps
       
   177 
       
   178     return step;
       
   179 }
       
   180 
       
   181 QPair<int,int> V4LRadioControl::frequencyRange(QRadioTuner::Band b) const
       
   182 {
       
   183     if(b == QRadioTuner::AM)
       
   184         return qMakePair<int,int>(520000,1710000);
       
   185     else if(b == QRadioTuner::FM)
       
   186         return qMakePair<int,int>(87500000,108000000);
       
   187     else if(b == QRadioTuner::SW)
       
   188         return qMakePair<int,int>(1711111,30000000);
       
   189     else if(b == QRadioTuner::LW)
       
   190         return qMakePair<int,int>(148500,283500);
       
   191 
       
   192     return qMakePair<int,int>(0,0);
       
   193 }
       
   194 
       
   195 void V4LRadioControl::setFrequency(int frequency)
       
   196 {
       
   197     qint64 f = frequency;
       
   198 
       
   199     v4l2_frequency freq;
       
   200 
       
   201     if(frequency < freqMin)
       
   202         f = freqMax;
       
   203     if(frequency > freqMax)
       
   204         f = freqMin;
       
   205 
       
   206     if(fd > 0) {
       
   207         memset( &freq, 0, sizeof( freq ) );
       
   208         // Use the first tuner
       
   209         freq.tuner = 0;
       
   210         if ( ioctl( fd, VIDIOC_G_FREQUENCY, &freq ) >= 0 ) {
       
   211             if(low) {
       
   212                 // For low, freq in units of 62.5Hz, so convert from Hz to units.
       
   213                 freq.frequency = (int)(f/62.5);
       
   214             } else {
       
   215                 // For high, freq in units of 62.5kHz, so convert from Hz to units.
       
   216                 freq.frequency = (int)(f/62500);
       
   217             }
       
   218             ioctl( fd, VIDIOC_S_FREQUENCY, &freq );
       
   219             currentFreq = f;
       
   220             playTime.restart();
       
   221             emit frequencyChanged(currentFreq);
       
   222         }
       
   223     }
       
   224     playTime.restart();
       
   225 }
       
   226 
       
   227 bool V4LRadioControl::isStereo() const
       
   228 {
       
   229     return stereo;
       
   230 }
       
   231 
       
   232 QRadioTuner::StereoMode V4LRadioControl::stereoMode() const
       
   233 {
       
   234     return QRadioTuner::Auto;
       
   235 }
       
   236 
       
   237 void V4LRadioControl::setStereoMode(QRadioTuner::StereoMode mode)
       
   238 {
       
   239     bool stereo = true;
       
   240 
       
   241     if(mode == QRadioTuner::ForceMono)
       
   242         stereo = false;
       
   243 
       
   244     v4l2_tuner tuner;
       
   245 
       
   246     memset( &tuner, 0, sizeof( tuner ) );
       
   247 
       
   248     if ( ioctl( fd, VIDIOC_G_TUNER, &tuner ) >= 0 ) {
       
   249         if(stereo)
       
   250             tuner.audmode = V4L2_TUNER_MODE_STEREO;
       
   251         else
       
   252             tuner.audmode = V4L2_TUNER_MODE_MONO;
       
   253 
       
   254         if ( ioctl( fd, VIDIOC_S_TUNER, &tuner ) >= 0 ) {
       
   255             emit stereoStatusChanged(stereo);
       
   256         }
       
   257     }
       
   258 }
       
   259 
       
   260 int V4LRadioControl::signalStrength() const
       
   261 {
       
   262     v4l2_tuner tuner;
       
   263 
       
   264     // Return the first tuner founds signal strength.
       
   265     for ( int index = 0; index < tuners; ++index ) {
       
   266         memset( &tuner, 0, sizeof( tuner ) );
       
   267         tuner.index = index;
       
   268         if ( ioctl( fd, VIDIOC_G_TUNER, &tuner ) < 0 )
       
   269             continue;
       
   270         if ( tuner.type != V4L2_TUNER_RADIO )
       
   271             continue;
       
   272         // percentage signal strength
       
   273         return tuner.signal*100/65535;
       
   274     }
       
   275 
       
   276     return 0;
       
   277 }
       
   278 
       
   279 int V4LRadioControl::volume() const
       
   280 {
       
   281     v4l2_queryctrl queryctrl;
       
   282 
       
   283     if(fd > 0) {
       
   284         memset( &queryctrl, 0, sizeof( queryctrl ) );
       
   285         queryctrl.id = V4L2_CID_AUDIO_VOLUME;
       
   286         if ( ioctl( fd, VIDIOC_QUERYCTRL, &queryctrl ) >= 0 ) {
       
   287             if(queryctrl.maximum == 0) {
       
   288                 return vol;
       
   289             } else {
       
   290                 // percentage volume returned
       
   291                 return queryctrl.default_value*100/queryctrl.maximum;
       
   292             }
       
   293         }
       
   294     }
       
   295     return 0;
       
   296 }
       
   297 
       
   298 void V4LRadioControl::setVolume(int volume)
       
   299 {
       
   300     v4l2_queryctrl queryctrl;
       
   301 
       
   302     if(fd > 0) {
       
   303         memset( &queryctrl, 0, sizeof( queryctrl ) );
       
   304         queryctrl.id = V4L2_CID_AUDIO_VOLUME;
       
   305         if ( ioctl( fd, VIDIOC_QUERYCTRL, &queryctrl ) >= 0 ) {
       
   306             v4l2_control control;
       
   307 
       
   308             if(queryctrl.maximum > 0) {
       
   309                 memset( &control, 0, sizeof( control ) );
       
   310                 control.id = V4L2_CID_AUDIO_VOLUME;
       
   311                 control.value = volume*queryctrl.maximum/100;
       
   312                 ioctl( fd, VIDIOC_S_CTRL, &control );
       
   313             } else {
       
   314                 setVol(volume);
       
   315             }
       
   316             emit volumeChanged(volume);
       
   317         }
       
   318     }
       
   319 }
       
   320 
       
   321 bool V4LRadioControl::isMuted() const
       
   322 {
       
   323     return muted;
       
   324 }
       
   325 
       
   326 void V4LRadioControl::setMuted(bool muted)
       
   327 {
       
   328     v4l2_queryctrl queryctrl;
       
   329 
       
   330     if(fd > 0) {
       
   331         memset( &queryctrl, 0, sizeof( queryctrl ) );
       
   332         queryctrl.id = V4L2_CID_AUDIO_MUTE;
       
   333         if ( ioctl( fd, VIDIOC_QUERYCTRL, &queryctrl ) >= 0 ) {
       
   334             v4l2_control control;
       
   335             memset( &control, 0, sizeof( control ) );
       
   336             control.id = V4L2_CID_AUDIO_MUTE;
       
   337             control.value = (muted ? queryctrl.maximum : queryctrl.minimum );
       
   338             ioctl( fd, VIDIOC_S_CTRL, &control );
       
   339             this->muted = muted;
       
   340             emit mutedChanged(muted);
       
   341         }
       
   342     }
       
   343 }
       
   344 
       
   345 bool V4LRadioControl::isSearching() const
       
   346 {
       
   347     //TODO
       
   348     return false;
       
   349 }
       
   350 
       
   351 void V4LRadioControl::cancelSearch()
       
   352 {
       
   353     //TODO
       
   354 }
       
   355 
       
   356 void V4LRadioControl::searchForward()
       
   357 {
       
   358     // Scan up
       
   359     if(scanning) {
       
   360         scanning = false;
       
   361         return;
       
   362     }
       
   363     scanning = true;
       
   364     forward  = true;
       
   365 }
       
   366 
       
   367 void V4LRadioControl::searchBackward()
       
   368 {
       
   369     // Scan down
       
   370     if(scanning) {
       
   371         scanning = false;
       
   372         return;
       
   373     }
       
   374     scanning = true;
       
   375     forward  = false;
       
   376     timer->start();
       
   377 }
       
   378 
       
   379 void V4LRadioControl::start()
       
   380 {
       
   381 }
       
   382 
       
   383 void V4LRadioControl::stop()
       
   384 {
       
   385 }
       
   386 
       
   387 QRadioTuner::Error V4LRadioControl::error() const
       
   388 {
       
   389     if(m_error)
       
   390         return QRadioTuner::OpenError;
       
   391 
       
   392     return QRadioTuner::NoError;
       
   393 }
       
   394 
       
   395 QString V4LRadioControl::errorString() const
       
   396 {
       
   397     return QString();
       
   398 }
       
   399 
       
   400 void V4LRadioControl::search()
       
   401 {
       
   402     int signal = signalStrength();
       
   403     if(sig != signal) {
       
   404         sig = signal;
       
   405         emit signalStrengthChanged(sig);
       
   406     }
       
   407 
       
   408     if(!scanning) return;
       
   409 
       
   410     if(forward) {
       
   411         setFrequency(currentFreq+step);
       
   412     } else {
       
   413         setFrequency(currentFreq-step);
       
   414     }
       
   415     emit signalStrengthChanged(signalStrength());
       
   416 }
       
   417 
       
   418 bool V4LRadioControl::initRadio()
       
   419 {
       
   420     v4l2_tuner tuner;
       
   421     v4l2_input input;
       
   422     v4l2_frequency freq;
       
   423     v4l2_capability cap;
       
   424 
       
   425     low = false;
       
   426     available = false;
       
   427     freqMin = freqMax = currentFreq = 0;
       
   428 
       
   429     fd = ::open("/dev/radio", O_RDWR);
       
   430 
       
   431     if(fd != -1) {
       
   432         // Capabilites
       
   433         memset( &cap, 0, sizeof( cap ) );
       
   434         if(::ioctl(fd, VIDIOC_QUERYCAP, &cap ) >= 0) {
       
   435             if(((cap.capabilities & V4L2_CAP_RADIO) == 0) && ((cap.capabilities & V4L2_CAP_AUDIO) == 0))
       
   436                 available = true;
       
   437         }
       
   438 
       
   439         // Tuners
       
   440         memset( &input, 0, sizeof( input ) );
       
   441         tuners = 0;
       
   442         for ( ;; ) {
       
   443             memset( &input, 0, sizeof( input ) );
       
   444             input.index = tuners;
       
   445             if ( ioctl( fd, VIDIOC_ENUMINPUT, &input ) < 0 )
       
   446                 break;
       
   447             ++tuners;
       
   448         }
       
   449 
       
   450         // Freq bands
       
   451         for ( int index = 0; index < tuners; ++index ) {
       
   452             memset( &tuner, 0, sizeof( tuner ) );
       
   453             tuner.index = index;
       
   454             if ( ioctl( fd, VIDIOC_G_TUNER, &tuner ) < 0 )
       
   455                 continue;
       
   456             if ( tuner.type != V4L2_TUNER_RADIO )
       
   457                 continue;
       
   458             if ( ( tuner.capability & V4L2_TUNER_CAP_LOW ) != 0 ) {
       
   459                 // Units are 1/16th of a kHz.
       
   460                 low = true;
       
   461             }
       
   462             if(low) {
       
   463                 freqMin = tuner.rangelow * 62.5;
       
   464                 freqMax = tuner.rangehigh * 62.5;
       
   465             } else {
       
   466                 freqMin = tuner.rangelow * 62500;
       
   467                 freqMax = tuner.rangehigh * 62500;
       
   468             }
       
   469         }
       
   470 
       
   471         // frequency
       
   472         memset( &freq, 0, sizeof( freq ) );
       
   473         if(::ioctl(fd, VIDIOC_G_FREQUENCY, &freq ) >= 0) {
       
   474             if ( ((int)freq.frequency) != -1 ) {    // -1 means not set.
       
   475                 if(low)
       
   476                     currentFreq = freq.frequency * 62.5;
       
   477                 else
       
   478                     currentFreq = freq.frequency * 62500;
       
   479             }
       
   480         }
       
   481 
       
   482         qWarning()<<"min="<<freqMin<<", max="<<freqMax<<", current="<<currentFreq;
       
   483 
       
   484         // stereo
       
   485         bool stereo = false;
       
   486         memset( &tuner, 0, sizeof( tuner ) );
       
   487         if ( ioctl( fd, VIDIOC_G_TUNER, &tuner ) >= 0 ) {
       
   488             if((tuner.rxsubchans & V4L2_TUNER_SUB_STEREO) != 0)
       
   489                 stereo = true;
       
   490         }
       
   491 
       
   492         vol = getVol();
       
   493 
       
   494         return true;
       
   495     }
       
   496     m_error = true;
       
   497     emit error();
       
   498 
       
   499     return false;
       
   500 }
       
   501 
       
   502 void V4LRadioControl::setVol(int v)
       
   503 {
       
   504     int fd = ::open( "/dev/mixer", O_RDWR, 0 );
       
   505     if ( fd < 0 )
       
   506         return;
       
   507     int volume = v;
       
   508     if ( volume < 0 )
       
   509         volume = 0;
       
   510     else if ( volume > 100 )
       
   511         volume = 100;
       
   512     vol = volume;
       
   513     volume += volume << 8;
       
   514     ::ioctl( fd, MIXER_WRITE(SOUND_MIXER_VOLUME), &volume );
       
   515     ::close( fd );
       
   516 }
       
   517 
       
   518 int V4LRadioControl::getVol()
       
   519 {
       
   520     int fd = ::open( "/dev/mixer", O_RDWR, 0 );
       
   521     if ( fd >= 0 ) {
       
   522         int volume = 0;
       
   523         ::ioctl( fd, MIXER_READ(SOUND_MIXER_VOLUME), &volume );
       
   524         int left = ( volume & 0xFF );
       
   525         int right = ( ( volume >> 8 ) & 0xFF );
       
   526         if ( left > right )
       
   527             vol = left;
       
   528         else
       
   529             vol = right;
       
   530         ::close( fd );
       
   531         return vol;
       
   532     }
       
   533     return 0;
       
   534 }
       
   535