qtmobility/src/multimedia/audio/qaudiodeviceinfo_alsa_p.cpp
changeset 14 6fbed849b4f4
equal deleted inserted replaced
11:06b8e2af4411 14:6fbed849b4f4
       
     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 //
       
    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 QString QAudioDeviceInfoInternal::deviceName() const
       
   103 {
       
   104     return device;
       
   105 }
       
   106 
       
   107 QStringList QAudioDeviceInfoInternal::supportedCodecs()
       
   108 {
       
   109     updateLists();
       
   110     return codecz;
       
   111 }
       
   112 
       
   113 QList<int> QAudioDeviceInfoInternal::supportedSampleRates()
       
   114 {
       
   115     updateLists();
       
   116     return freqz;
       
   117 }
       
   118 
       
   119 QList<int> QAudioDeviceInfoInternal::supportedChannelCounts()
       
   120 {
       
   121     updateLists();
       
   122     return channelz;
       
   123 }
       
   124 
       
   125 QList<int> QAudioDeviceInfoInternal::supportedSampleSizes()
       
   126 {
       
   127     updateLists();
       
   128     return sizez;
       
   129 }
       
   130 
       
   131 QList<QAudioFormat::Endian> QAudioDeviceInfoInternal::supportedByteOrders()
       
   132 {
       
   133     updateLists();
       
   134     return byteOrderz;
       
   135 }
       
   136 
       
   137 QList<QAudioFormat::SampleType> QAudioDeviceInfoInternal::supportedSampleTypes()
       
   138 {
       
   139     updateLists();
       
   140     return typez;
       
   141 }
       
   142 
       
   143 bool QAudioDeviceInfoInternal::open()
       
   144 {
       
   145     int err = 0;
       
   146     QString dev = device;
       
   147     QList<QByteArray> devices = availableDevices(mode);
       
   148 
       
   149     if(dev.compare(QLatin1String("default")) == 0) {
       
   150 #if(SND_LIB_MAJOR == 1 && SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR >= 14)
       
   151         dev = QLatin1String(devices.first().constData());
       
   152 #else
       
   153         dev = QLatin1String("hw:0,0");
       
   154 #endif
       
   155     } else {
       
   156 #if(SND_LIB_MAJOR == 1 && SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR >= 14)
       
   157         dev = device;
       
   158 #else
       
   159         int idx = 0;
       
   160         char *name;
       
   161 
       
   162         QString shortName = device.mid(device.indexOf(QLatin1String("="),0)+1);
       
   163 
       
   164 	while(snd_card_get_name(idx,&name) == 0) {
       
   165             if(dev.contains(QLatin1String(name)))
       
   166                 break;
       
   167             idx++;
       
   168 	}
       
   169         dev = QString(QLatin1String("hw:%1,0")).arg(idx);
       
   170 #endif
       
   171     }
       
   172     if(mode == QAudio::AudioOutput) {
       
   173         err=snd_pcm_open( &handle,dev.toLocal8Bit().constData(),SND_PCM_STREAM_PLAYBACK,0);
       
   174     } else {
       
   175         err=snd_pcm_open( &handle,dev.toLocal8Bit().constData(),SND_PCM_STREAM_CAPTURE,0);
       
   176     }
       
   177     if(err < 0) {
       
   178         handle = 0;
       
   179         return false;
       
   180     }
       
   181     return true;
       
   182 }
       
   183 
       
   184 void QAudioDeviceInfoInternal::close()
       
   185 {
       
   186     if(handle)
       
   187         snd_pcm_close(handle);
       
   188     handle = 0;
       
   189 }
       
   190 
       
   191 bool QAudioDeviceInfoInternal::testSettings(const QAudioFormat& format) const
       
   192 {
       
   193     // Set nearest to closest settings that do work.
       
   194     // See if what is in settings will work (return value).
       
   195     int err = 0;
       
   196     snd_pcm_t* handle;
       
   197     snd_pcm_hw_params_t *params;
       
   198     QString dev = device;
       
   199 
       
   200     QList<QByteArray> devices = QAudioDeviceInfoInternal::availableDevices(QAudio::AudioOutput);
       
   201 
       
   202     if(dev.compare(QLatin1String("default")) == 0) {
       
   203 #if(SND_LIB_MAJOR == 1 && SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR >= 14)
       
   204         dev = QLatin1String(devices.first().constData());
       
   205 #else
       
   206         dev = QLatin1String("hw:0,0");
       
   207 #endif
       
   208     } else {
       
   209 #if(SND_LIB_MAJOR == 1 && SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR >= 14)
       
   210         dev = device;
       
   211 #else
       
   212         int idx = 0;
       
   213         char *name;
       
   214 
       
   215         QString shortName = device.mid(device.indexOf(QLatin1String("="),0)+1);
       
   216 
       
   217         while(snd_card_get_name(idx,&name) == 0) {
       
   218             if(shortName.compare(QLatin1String(name)) == 0)
       
   219                 break;
       
   220             idx++;
       
   221         }
       
   222         dev = QString(QLatin1String("hw:%1,0")).arg(idx);
       
   223 #endif
       
   224     }
       
   225     if(mode == QAudio::AudioOutput) {
       
   226         err=snd_pcm_open( &handle,dev.toLocal8Bit().constData(),SND_PCM_STREAM_PLAYBACK,0);
       
   227     } else {
       
   228         err=snd_pcm_open( &handle,dev.toLocal8Bit().constData(),SND_PCM_STREAM_CAPTURE,0);
       
   229     }
       
   230     if(err < 0) {
       
   231         handle = 0;
       
   232         return false;
       
   233     }
       
   234 
       
   235     bool testChannel = false;
       
   236     bool testCodec = false;
       
   237     bool testFreq = false;
       
   238     bool testType = false;
       
   239     bool testSize = false;
       
   240 
       
   241     int  dir = 0;
       
   242 
       
   243     snd_pcm_nonblock( handle, 0 );
       
   244     snd_pcm_hw_params_alloca( &params );
       
   245     snd_pcm_hw_params_any( handle, params );
       
   246 
       
   247     // set the values!
       
   248     snd_pcm_hw_params_set_channels(handle,params,format.channels());
       
   249     snd_pcm_hw_params_set_rate(handle,params,format.frequency(),dir);
       
   250     switch(format.sampleSize()) {
       
   251         case 8:
       
   252             if(format.sampleType() == QAudioFormat::SignedInt)
       
   253                 snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S8);
       
   254             else if(format.sampleType() == QAudioFormat::UnSignedInt)
       
   255                 snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U8);
       
   256             break;
       
   257         case 16:
       
   258             if(format.sampleType() == QAudioFormat::SignedInt) {
       
   259                 if(format.byteOrder() == QAudioFormat::LittleEndian)
       
   260                     snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S16_LE);
       
   261                 else if(format.byteOrder() == QAudioFormat::BigEndian)
       
   262                     snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S16_BE);
       
   263             } else if(format.sampleType() == QAudioFormat::UnSignedInt) {
       
   264                 if(format.byteOrder() == QAudioFormat::LittleEndian)
       
   265                     snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U16_LE);
       
   266                 else if(format.byteOrder() == QAudioFormat::BigEndian)
       
   267                     snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U16_BE);
       
   268             }
       
   269             break;
       
   270         case 32:
       
   271             if(format.sampleType() == QAudioFormat::SignedInt) {
       
   272                 if(format.byteOrder() == QAudioFormat::LittleEndian)
       
   273                     snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S32_LE);
       
   274                 else if(format.byteOrder() == QAudioFormat::BigEndian)
       
   275                     snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S32_BE);
       
   276             } else if(format.sampleType() == QAudioFormat::UnSignedInt) {
       
   277                 if(format.byteOrder() == QAudioFormat::LittleEndian)
       
   278                     snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U32_LE);
       
   279                 else if(format.byteOrder() == QAudioFormat::BigEndian)
       
   280                     snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U32_BE);
       
   281             }
       
   282     }
       
   283 
       
   284     // For now, just accept only audio/pcm codec
       
   285     if(!format.codec().startsWith(QLatin1String("audio/pcm"))) {
       
   286         err=-1;
       
   287     } else
       
   288         testCodec = true;
       
   289 
       
   290     if(err>=0 && format.channels() != -1) {
       
   291         err = snd_pcm_hw_params_test_channels(handle,params,format.channels());
       
   292         if(err>=0)
       
   293             err = snd_pcm_hw_params_set_channels(handle,params,format.channels());
       
   294         if(err>=0)
       
   295             testChannel = true;
       
   296     }
       
   297 
       
   298     if(err>=0 && format.frequency() != -1) {
       
   299         err = snd_pcm_hw_params_test_rate(handle,params,format.frequency(),0);
       
   300         if(err>=0)
       
   301             err = snd_pcm_hw_params_set_rate(handle,params,format.frequency(),dir);
       
   302         if(err>=0)
       
   303             testFreq = true;
       
   304     }
       
   305 
       
   306     if((err>=0 && format.sampleSize() != -1) &&
       
   307             (format.sampleType() != QAudioFormat::Unknown)) {
       
   308         switch(format.sampleSize()) {
       
   309             case 8:
       
   310                 if(format.sampleType() == QAudioFormat::SignedInt)
       
   311                     err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S8);
       
   312                 else if(format.sampleType() == QAudioFormat::UnSignedInt)
       
   313                     err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U8);
       
   314                 break;
       
   315             case 16:
       
   316                 if(format.sampleType() == QAudioFormat::SignedInt) {
       
   317                     if(format.byteOrder() == QAudioFormat::LittleEndian)
       
   318                         err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S16_LE);
       
   319                     else if(format.byteOrder() == QAudioFormat::BigEndian)
       
   320                         err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S16_BE);
       
   321                 } else if(format.sampleType() == QAudioFormat::UnSignedInt) {
       
   322                     if(format.byteOrder() == QAudioFormat::LittleEndian)
       
   323                         err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U16_LE);
       
   324                     else if(format.byteOrder() == QAudioFormat::BigEndian)
       
   325                         err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U16_BE);
       
   326                 }
       
   327                 break;
       
   328             case 32:
       
   329                 if(format.sampleType() == QAudioFormat::SignedInt) {
       
   330                     if(format.byteOrder() == QAudioFormat::LittleEndian)
       
   331                         err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S32_LE);
       
   332                     else if(format.byteOrder() == QAudioFormat::BigEndian)
       
   333                         err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S32_BE);
       
   334                 } else if(format.sampleType() == QAudioFormat::UnSignedInt) {
       
   335                     if(format.byteOrder() == QAudioFormat::LittleEndian)
       
   336                         err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U32_LE);
       
   337                     else if(format.byteOrder() == QAudioFormat::BigEndian)
       
   338                         err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U32_BE);
       
   339                 }
       
   340         }
       
   341         if(err>=0) {
       
   342             testSize = true;
       
   343             testType = true;
       
   344         }
       
   345     }
       
   346     if(err>=0)
       
   347         err = snd_pcm_hw_params(handle, params);
       
   348 
       
   349     if(err == 0) {
       
   350         // settings work
       
   351         // close()
       
   352         if(handle)
       
   353             snd_pcm_close(handle);
       
   354         return true;
       
   355     }
       
   356     if(handle)
       
   357         snd_pcm_close(handle);
       
   358 
       
   359     return false;
       
   360 }
       
   361 
       
   362 void QAudioDeviceInfoInternal::updateLists()
       
   363 {
       
   364     // redo all lists based on current settings
       
   365     freqz.clear();
       
   366     channelz.clear();
       
   367     sizez.clear();
       
   368     byteOrderz.clear();
       
   369     typez.clear();
       
   370     codecz.clear();
       
   371 
       
   372     if(!handle)
       
   373         open();
       
   374 
       
   375     if(!handle)
       
   376         return;
       
   377 
       
   378     for(int i=0; i<(int)MAX_SAMPLE_RATES; i++) {
       
   379         //if(snd_pcm_hw_params_test_rate(handle, params, SAMPLE_RATES[i], dir) == 0)
       
   380         freqz.append(SAMPLE_RATES[i]);
       
   381     }
       
   382     channelz.append(1);
       
   383     channelz.append(2);
       
   384     sizez.append(8);
       
   385     sizez.append(16);
       
   386     sizez.append(32);
       
   387     byteOrderz.append(QAudioFormat::LittleEndian);
       
   388     byteOrderz.append(QAudioFormat::BigEndian);
       
   389     typez.append(QAudioFormat::SignedInt);
       
   390     typez.append(QAudioFormat::UnSignedInt);
       
   391     typez.append(QAudioFormat::Float);
       
   392     codecz.append(QLatin1String("audio/pcm"));
       
   393     close();
       
   394 }
       
   395 
       
   396 QList<QByteArray> QAudioDeviceInfoInternal::availableDevices(QAudio::Mode mode)
       
   397 {
       
   398     QList<QByteArray> allDevices;
       
   399     QList<QByteArray> devices;
       
   400     QByteArray filter;
       
   401 
       
   402 #if(SND_LIB_MAJOR == 1 && SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR >= 14)
       
   403     // Create a list of all current audio devices that support mode
       
   404     void **hints, **n;
       
   405     char *name, *descr, *io;
       
   406 
       
   407     if(snd_device_name_hint(-1, "pcm", &hints) < 0) {
       
   408         qWarning() << "no alsa devices available";
       
   409         return devices;
       
   410     }
       
   411     n = hints;
       
   412 
       
   413     if(mode == QAudio::AudioInput) {
       
   414         filter = "Input";
       
   415     } else {
       
   416         filter = "Output";
       
   417     }
       
   418 
       
   419     while (*n != NULL) {
       
   420         name = snd_device_name_get_hint(*n, "NAME");
       
   421         descr = snd_device_name_get_hint(*n, "DESC");
       
   422         io = snd_device_name_get_hint(*n, "IOID");
       
   423         if((name != NULL) && (descr != NULL) && ((io == NULL) || (io == filter))) {
       
   424             QString deviceName = QLatin1String(name);
       
   425             QString deviceDescription = QLatin1String(descr);
       
   426             allDevices.append(deviceName.toLocal8Bit().constData());
       
   427             if(deviceDescription.contains(QLatin1String("Default Audio Device")))
       
   428                 devices.append(deviceName.toLocal8Bit().constData());
       
   429         }
       
   430         if(name != NULL)
       
   431             free(name);
       
   432         if(descr != NULL)
       
   433             free(descr);
       
   434         if(io != NULL)
       
   435             free(io);
       
   436         ++n;
       
   437     }
       
   438     snd_device_name_free_hint(hints);
       
   439 
       
   440     if(devices.size() > 0) {
       
   441         devices.append("default");
       
   442     }
       
   443 #else
       
   444     int idx = 0;
       
   445     char* name;
       
   446 
       
   447     while(snd_card_get_name(idx,&name) == 0) {
       
   448         devices.append(name);
       
   449         idx++;
       
   450     }
       
   451     if (idx > 0)
       
   452         devices.append("default");
       
   453 #endif
       
   454     if (devices.size() == 0 && allDevices.size() > 0)
       
   455         return allDevices;
       
   456 
       
   457     return devices;
       
   458 }
       
   459 
       
   460 QByteArray QAudioDeviceInfoInternal::defaultInputDevice()
       
   461 {
       
   462     QList<QByteArray> devices = availableDevices(QAudio::AudioInput);
       
   463     if(devices.size() == 0)
       
   464         return QByteArray();
       
   465 
       
   466     return devices.first();
       
   467 }
       
   468 
       
   469 QByteArray QAudioDeviceInfoInternal::defaultOutputDevice()
       
   470 {
       
   471     QList<QByteArray> devices = availableDevices(QAudio::AudioOutput);
       
   472     if(devices.size() == 0)
       
   473         return QByteArray();
       
   474 
       
   475     return devices.first();
       
   476 }
       
   477 
       
   478 QT_END_NAMESPACE