src/multimedia/audio/qaudiodeviceinfo_alsa_p.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     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 QtMultimedia module of the Qt Toolkit.
       
     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 //
       
    43 //  W A R N I N G
       
    44 //  -------------
       
    45 //
       
    46 // This file is not part of the Qt API.  It exists for the convenience
       
    47 // of other Qt classes.  This header file may change from version to
       
    48 // version without notice, or even be removed.
       
    49 //
       
    50 // We mean it.
       
    51 //
       
    52 
       
    53 #include "qaudiodeviceinfo_alsa_p.h"
       
    54 
       
    55 #include <alsa/version.h>
       
    56 
       
    57 QT_BEGIN_NAMESPACE
       
    58 
       
    59 QAudioDeviceInfoInternal::QAudioDeviceInfoInternal(QByteArray dev, QAudio::Mode mode)
       
    60 {
       
    61     handle = 0;
       
    62 
       
    63     device = QLatin1String(dev);
       
    64     this->mode = mode;
       
    65 }
       
    66 
       
    67 QAudioDeviceInfoInternal::~QAudioDeviceInfoInternal()
       
    68 {
       
    69     close();
       
    70 }
       
    71 
       
    72 bool QAudioDeviceInfoInternal::isFormatSupported(const QAudioFormat& format) const
       
    73 {
       
    74     return testSettings(format);
       
    75 }
       
    76 
       
    77 QAudioFormat QAudioDeviceInfoInternal::preferredFormat() const
       
    78 {
       
    79     QAudioFormat nearest;
       
    80     if(mode == QAudio::AudioOutput) {
       
    81         nearest.setFrequency(44100);
       
    82         nearest.setChannels(2);
       
    83         nearest.setByteOrder(QAudioFormat::LittleEndian);
       
    84         nearest.setSampleType(QAudioFormat::SignedInt);
       
    85         nearest.setSampleSize(16);
       
    86         nearest.setCodec(QLatin1String("audio/pcm"));
       
    87     } else {
       
    88         nearest.setFrequency(8000);
       
    89         nearest.setChannels(1);
       
    90         nearest.setSampleType(QAudioFormat::UnSignedInt);
       
    91         nearest.setSampleSize(8);
       
    92         nearest.setCodec(QLatin1String("audio/pcm"));
       
    93         if(!testSettings(nearest)) {
       
    94             nearest.setChannels(2);
       
    95             nearest.setSampleSize(16);
       
    96             nearest.setSampleType(QAudioFormat::SignedInt);
       
    97         }
       
    98     }
       
    99     return nearest;
       
   100 }
       
   101 
       
   102 QAudioFormat QAudioDeviceInfoInternal::nearestFormat(const QAudioFormat& format) const
       
   103 {
       
   104     if(testSettings(format))
       
   105         return format;
       
   106     else
       
   107         return preferredFormat();
       
   108 }
       
   109 
       
   110 QString QAudioDeviceInfoInternal::deviceName() const
       
   111 {
       
   112     return device;
       
   113 }
       
   114 
       
   115 QStringList QAudioDeviceInfoInternal::codecList()
       
   116 {
       
   117     updateLists();
       
   118     return codecz;
       
   119 }
       
   120 
       
   121 QList<int> QAudioDeviceInfoInternal::frequencyList()
       
   122 {
       
   123     updateLists();
       
   124     return freqz;
       
   125 }
       
   126 
       
   127 QList<int> QAudioDeviceInfoInternal::channelsList()
       
   128 {
       
   129     updateLists();
       
   130     return channelz;
       
   131 }
       
   132 
       
   133 QList<int> QAudioDeviceInfoInternal::sampleSizeList()
       
   134 {
       
   135     updateLists();
       
   136     return sizez;
       
   137 }
       
   138 
       
   139 QList<QAudioFormat::Endian> QAudioDeviceInfoInternal::byteOrderList()
       
   140 {
       
   141     updateLists();
       
   142     return byteOrderz;
       
   143 }
       
   144 
       
   145 QList<QAudioFormat::SampleType> QAudioDeviceInfoInternal::sampleTypeList()
       
   146 {
       
   147     updateLists();
       
   148     return typez;
       
   149 }
       
   150 
       
   151 bool QAudioDeviceInfoInternal::open()
       
   152 {
       
   153     int err = 0;
       
   154     QString dev = device;
       
   155     if(!dev.contains(QLatin1String("default"))) {
       
   156 #if(SND_LIB_MAJOR == 1 && SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR >= 14)
       
   157          dev = QString(QLatin1String("default:CARD=%1")).arg(dev);
       
   158 #else
       
   159         int idx = 0;
       
   160         char *name;
       
   161 
       
   162 	while(snd_card_get_name(idx,&name) == 0) {
       
   163             if(dev.contains(QLatin1String(name)))
       
   164                 break;
       
   165             idx++;
       
   166 	}
       
   167         dev = QString(QLatin1String("hw:%1,0")).arg(idx);
       
   168 #endif
       
   169     }
       
   170     if(mode == QAudio::AudioOutput) {
       
   171         err=snd_pcm_open( &handle,dev.toLocal8Bit().constData(),SND_PCM_STREAM_PLAYBACK,0);
       
   172     } else {
       
   173         err=snd_pcm_open( &handle,dev.toLocal8Bit().constData(),SND_PCM_STREAM_CAPTURE,0);
       
   174     }
       
   175     if(err < 0) {
       
   176         handle = 0;
       
   177         return false;
       
   178     }
       
   179     return true;
       
   180 }
       
   181 
       
   182 void QAudioDeviceInfoInternal::close()
       
   183 {
       
   184     if(handle)
       
   185         snd_pcm_close(handle);
       
   186     handle = 0;
       
   187 }
       
   188 
       
   189 bool QAudioDeviceInfoInternal::testSettings(const QAudioFormat& format) const
       
   190 {
       
   191     // Set nearest to closest settings that do work.
       
   192     // See if what is in settings will work (return value).
       
   193     int err = 0;
       
   194     snd_pcm_t* handle;
       
   195     snd_pcm_hw_params_t *params;
       
   196     QString dev = device;
       
   197 
       
   198     // open()
       
   199     if(!dev.contains(QLatin1String("default"))) {
       
   200 #if(SND_LIB_MAJOR == 1 && SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR >= 14)
       
   201          dev = QString(QLatin1String("default:CARD=%1")).arg(dev);
       
   202 #else
       
   203         int idx = 0;
       
   204         char *name;
       
   205     
       
   206         while(snd_card_get_name(idx,&name) == 0) {
       
   207             if(dev.contains(QLatin1String(name)))
       
   208                 break;
       
   209             idx++;
       
   210         }
       
   211         dev = QString(QLatin1String("hw:%1,0")).arg(idx);
       
   212 #endif
       
   213     }
       
   214     if(mode == QAudio::AudioOutput) {
       
   215         err=snd_pcm_open( &handle,dev.toLocal8Bit().constData(),SND_PCM_STREAM_PLAYBACK,0);
       
   216     } else {
       
   217         err=snd_pcm_open( &handle,dev.toLocal8Bit().constData(),SND_PCM_STREAM_CAPTURE,0);
       
   218     }
       
   219     if(err < 0) {
       
   220         handle = 0;
       
   221         return false;
       
   222     }
       
   223 
       
   224     bool testChannel = false;
       
   225     bool testCodec = false;
       
   226     bool testFreq = false;
       
   227     bool testType = false;
       
   228     bool testSize = false;
       
   229 
       
   230     int  dir = 0;
       
   231 
       
   232     snd_pcm_nonblock( handle, 0 );
       
   233     snd_pcm_hw_params_alloca( &params );
       
   234     snd_pcm_hw_params_any( handle, params );
       
   235 
       
   236     // set the values!
       
   237     snd_pcm_hw_params_set_channels(handle,params,format.channels());
       
   238     snd_pcm_hw_params_set_rate(handle,params,format.frequency(),dir);
       
   239     switch(format.sampleSize()) {
       
   240         case 8:
       
   241             if(format.sampleType() == QAudioFormat::SignedInt)
       
   242                 snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S8);
       
   243             else if(format.sampleType() == QAudioFormat::UnSignedInt)
       
   244                 snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U8);
       
   245             break;
       
   246         case 16:
       
   247             if(format.sampleType() == QAudioFormat::SignedInt) {
       
   248                 if(format.byteOrder() == QAudioFormat::LittleEndian)
       
   249                     snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S16_LE);
       
   250                 else if(format.byteOrder() == QAudioFormat::BigEndian)
       
   251                     snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S16_BE);
       
   252             } else if(format.sampleType() == QAudioFormat::UnSignedInt) {
       
   253                 if(format.byteOrder() == QAudioFormat::LittleEndian)
       
   254                     snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U16_LE);
       
   255                 else if(format.byteOrder() == QAudioFormat::BigEndian)
       
   256                     snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U16_BE);
       
   257             }
       
   258             break;
       
   259         case 32:
       
   260             if(format.sampleType() == QAudioFormat::SignedInt) {
       
   261                 if(format.byteOrder() == QAudioFormat::LittleEndian)
       
   262                     snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S32_LE);
       
   263                 else if(format.byteOrder() == QAudioFormat::BigEndian)
       
   264                     snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S32_BE);
       
   265             } else if(format.sampleType() == QAudioFormat::UnSignedInt) {
       
   266                 if(format.byteOrder() == QAudioFormat::LittleEndian)
       
   267                     snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U32_LE);
       
   268                 else if(format.byteOrder() == QAudioFormat::BigEndian)
       
   269                     snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U32_BE);
       
   270             }
       
   271     }
       
   272 
       
   273     // For now, just accept only audio/pcm codec
       
   274     if(!format.codec().startsWith(QLatin1String("audio/pcm"))) {
       
   275         err=-1;
       
   276     } else
       
   277         testCodec = true;
       
   278 
       
   279     if(err>=0 && format.channels() != -1) {
       
   280         err = snd_pcm_hw_params_test_channels(handle,params,format.channels());
       
   281         if(err>=0)
       
   282             err = snd_pcm_hw_params_set_channels(handle,params,format.channels());
       
   283         if(err>=0)
       
   284             testChannel = true;
       
   285     }
       
   286 
       
   287     if(err>=0 && format.frequency() != -1) {
       
   288         err = snd_pcm_hw_params_test_rate(handle,params,format.frequency(),0);
       
   289         if(err>=0)
       
   290             err = snd_pcm_hw_params_set_rate(handle,params,format.frequency(),dir);
       
   291         if(err>=0)
       
   292             testFreq = true;
       
   293     }
       
   294 
       
   295     if((err>=0 && format.sampleSize() != -1) &&
       
   296             (format.sampleType() != QAudioFormat::Unknown)) {
       
   297         switch(format.sampleSize()) {
       
   298             case 8:
       
   299                 if(format.sampleType() == QAudioFormat::SignedInt)
       
   300                     err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S8);
       
   301                 else if(format.sampleType() == QAudioFormat::UnSignedInt)
       
   302                     err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U8);
       
   303                 break;
       
   304             case 16:
       
   305                 if(format.sampleType() == QAudioFormat::SignedInt) {
       
   306                     if(format.byteOrder() == QAudioFormat::LittleEndian)
       
   307                         err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S16_LE);
       
   308                     else if(format.byteOrder() == QAudioFormat::BigEndian)
       
   309                         err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S16_BE);
       
   310                 } else if(format.sampleType() == QAudioFormat::UnSignedInt) {
       
   311                     if(format.byteOrder() == QAudioFormat::LittleEndian)
       
   312                         err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U16_LE);
       
   313                     else if(format.byteOrder() == QAudioFormat::BigEndian)
       
   314                         err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U16_BE);
       
   315                 }
       
   316                 break;
       
   317             case 32:
       
   318                 if(format.sampleType() == QAudioFormat::SignedInt) {
       
   319                     if(format.byteOrder() == QAudioFormat::LittleEndian)
       
   320                         err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S32_LE);
       
   321                     else if(format.byteOrder() == QAudioFormat::BigEndian)
       
   322                         err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S32_BE);
       
   323                 } else if(format.sampleType() == QAudioFormat::UnSignedInt) {
       
   324                     if(format.byteOrder() == QAudioFormat::LittleEndian)
       
   325                         err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U32_LE);
       
   326                     else if(format.byteOrder() == QAudioFormat::BigEndian)
       
   327                         err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U32_BE);
       
   328                 }
       
   329         }
       
   330         if(err>=0) {
       
   331             testSize = true;
       
   332             testType = true;
       
   333         }
       
   334     }
       
   335     if(err>=0)
       
   336         err = snd_pcm_hw_params(handle, params);
       
   337 
       
   338     if(err == 0) {
       
   339         // settings work
       
   340         // close()
       
   341         if(handle)
       
   342             snd_pcm_close(handle);
       
   343         return true;
       
   344     }
       
   345     if(handle)
       
   346         snd_pcm_close(handle);
       
   347 
       
   348     return false;
       
   349 }
       
   350 
       
   351 void QAudioDeviceInfoInternal::updateLists()
       
   352 {
       
   353     // redo all lists based on current settings
       
   354     freqz.clear();
       
   355     channelz.clear();
       
   356     sizez.clear();
       
   357     byteOrderz.clear();
       
   358     typez.clear();
       
   359     codecz.clear();
       
   360 
       
   361     if(!handle)
       
   362         open();
       
   363 
       
   364     if(!handle)
       
   365         return;
       
   366 
       
   367     for(int i=0; i<(int)MAX_SAMPLE_RATES; i++) {
       
   368         //if(snd_pcm_hw_params_test_rate(handle, params, SAMPLE_RATES[i], dir) == 0)
       
   369         freqz.append(SAMPLE_RATES[i]);
       
   370     }
       
   371     channelz.append(1);
       
   372     channelz.append(2);
       
   373     sizez.append(8);
       
   374     sizez.append(16);
       
   375     sizez.append(32);
       
   376     byteOrderz.append(QAudioFormat::LittleEndian);
       
   377     byteOrderz.append(QAudioFormat::BigEndian);
       
   378     typez.append(QAudioFormat::SignedInt);
       
   379     typez.append(QAudioFormat::UnSignedInt);
       
   380     typez.append(QAudioFormat::Float);
       
   381     codecz.append(QLatin1String("audio/pcm"));
       
   382     close();
       
   383 }
       
   384 
       
   385 QList<QByteArray> QAudioDeviceInfoInternal::deviceList(QAudio::Mode mode)
       
   386 {
       
   387     QList<QByteArray> devices;
       
   388     QByteArray filter;
       
   389 #if(SND_LIB_MAJOR == 1 && SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR >= 14)
       
   390     // Create a list of all current audio devices that support mode
       
   391     void **hints, **n;
       
   392     char *name, *descr, *io;
       
   393 
       
   394     if(snd_device_name_hint(-1, "pcm", &hints) < 0) {
       
   395         qWarning() << "no alsa devices available";
       
   396         return devices;
       
   397     }
       
   398     n = hints;
       
   399 
       
   400     if(mode == QAudio::AudioInput) {
       
   401         filter = "Input";
       
   402     } else {
       
   403         filter = "Output";
       
   404     }
       
   405 
       
   406     while (*n != NULL) {
       
   407         name = snd_device_name_get_hint(*n, "NAME");
       
   408         descr = snd_device_name_get_hint(*n, "DESC");
       
   409         io = snd_device_name_get_hint(*n, "IOID");
       
   410         if((name != NULL) && (descr != NULL) && ((io == NULL) || (io == filter))) {
       
   411             QString str = QLatin1String(name);
       
   412 
       
   413             if(str.contains(QLatin1String("default"))) {
       
   414                 int pos = str.indexOf(QLatin1String("="),0);
       
   415                 devices.append(str.mid(pos+1).toLocal8Bit().constData());
       
   416             }
       
   417         }
       
   418         if(name != NULL)
       
   419             free(name);
       
   420         if(descr != NULL)
       
   421             free(descr);
       
   422         if(io != NULL)
       
   423             free(io);
       
   424         ++n;
       
   425     }
       
   426     snd_device_name_free_hint(hints);
       
   427 
       
   428     if(devices.size() > 0) {
       
   429         devices.append("default");
       
   430     }
       
   431 #else
       
   432     int idx = 0;
       
   433     char* name;
       
   434 
       
   435     while(snd_card_get_name(idx,&name) == 0) {
       
   436         devices.append(name);
       
   437         idx++;
       
   438     }
       
   439     if (idx > 0)
       
   440         devices.append("default");
       
   441 #endif
       
   442     return devices;
       
   443 }
       
   444 
       
   445 QByteArray QAudioDeviceInfoInternal::defaultInputDevice()
       
   446 {
       
   447     QList<QByteArray> devices = deviceList(QAudio::AudioInput);
       
   448     if(devices.size() == 0)
       
   449         return QByteArray();
       
   450 
       
   451     return QByteArray("default");
       
   452 }
       
   453 
       
   454 QByteArray QAudioDeviceInfoInternal::defaultOutputDevice()
       
   455 {
       
   456     QList<QByteArray> devices = deviceList(QAudio::AudioOutput);
       
   457     if(devices.size() == 0)
       
   458         return QByteArray();
       
   459 
       
   460     return QByteArray("default");
       
   461 }
       
   462 
       
   463 QT_END_NAMESPACE