src/multimedia/audio/qaudiodeviceinfo_alsa_p.cpp
changeset 0 876b1a06bc25
equal deleted inserted replaced
-1:000000000000 0:876b1a06bc25
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the Qt Mobility Components.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 //
       
    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     checkSurround();
       
    67 }
       
    68 
       
    69 QAudioDeviceInfoInternal::~QAudioDeviceInfoInternal()
       
    70 {
       
    71     close();
       
    72 }
       
    73 
       
    74 bool QAudioDeviceInfoInternal::isFormatSupported(const QAudioFormat& format) const
       
    75 {
       
    76     return testSettings(format);
       
    77 }
       
    78 
       
    79 QAudioFormat QAudioDeviceInfoInternal::preferredFormat() const
       
    80 {
       
    81     QAudioFormat nearest;
       
    82     if(mode == QAudio::AudioOutput) {
       
    83         nearest.setFrequency(44100);
       
    84         nearest.setChannels(2);
       
    85         nearest.setByteOrder(QAudioFormat::LittleEndian);
       
    86         nearest.setSampleType(QAudioFormat::SignedInt);
       
    87         nearest.setSampleSize(16);
       
    88         nearest.setCodec(QLatin1String("audio/pcm"));
       
    89     } else {
       
    90         nearest.setFrequency(8000);
       
    91         nearest.setChannels(1);
       
    92         nearest.setSampleType(QAudioFormat::UnSignedInt);
       
    93         nearest.setSampleSize(8);
       
    94         nearest.setCodec(QLatin1String("audio/pcm"));
       
    95         if(!testSettings(nearest)) {
       
    96             nearest.setChannels(2);
       
    97             nearest.setSampleSize(16);
       
    98             nearest.setSampleType(QAudioFormat::SignedInt);
       
    99         }
       
   100     }
       
   101     return nearest;
       
   102 }
       
   103 
       
   104 QString QAudioDeviceInfoInternal::deviceName() const
       
   105 {
       
   106     return device;
       
   107 }
       
   108 
       
   109 QStringList QAudioDeviceInfoInternal::supportedCodecs()
       
   110 {
       
   111     updateLists();
       
   112     return codecz;
       
   113 }
       
   114 
       
   115 QList<int> QAudioDeviceInfoInternal::supportedSampleRates()
       
   116 {
       
   117     updateLists();
       
   118     return freqz;
       
   119 }
       
   120 
       
   121 QList<int> QAudioDeviceInfoInternal::supportedChannelCounts()
       
   122 {
       
   123     updateLists();
       
   124     return channelz;
       
   125 }
       
   126 
       
   127 QList<int> QAudioDeviceInfoInternal::supportedSampleSizes()
       
   128 {
       
   129     updateLists();
       
   130     return sizez;
       
   131 }
       
   132 
       
   133 QList<QAudioFormat::Endian> QAudioDeviceInfoInternal::supportedByteOrders()
       
   134 {
       
   135     updateLists();
       
   136     return byteOrderz;
       
   137 }
       
   138 
       
   139 QList<QAudioFormat::SampleType> QAudioDeviceInfoInternal::supportedSampleTypes()
       
   140 {
       
   141     updateLists();
       
   142     return typez;
       
   143 }
       
   144 
       
   145 bool QAudioDeviceInfoInternal::open()
       
   146 {
       
   147     int err = 0;
       
   148     QString dev = device;
       
   149     QList<QByteArray> devices = availableDevices(mode);
       
   150 
       
   151     if(dev.compare(QLatin1String("default")) == 0) {
       
   152 #if(SND_LIB_MAJOR == 1 && SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR >= 14)
       
   153         if (devices.size() > 0)
       
   154             dev = QLatin1String(devices.first().constData());
       
   155         else
       
   156             return false;
       
   157 #else
       
   158         dev = QLatin1String("hw:0,0");
       
   159 #endif
       
   160     } else {
       
   161 #if(SND_LIB_MAJOR == 1 && SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR >= 14)
       
   162         dev = device;
       
   163 #else
       
   164         int idx = 0;
       
   165         char *name;
       
   166 
       
   167         QString shortName = device.mid(device.indexOf(QLatin1String("="),0)+1);
       
   168 
       
   169 	while(snd_card_get_name(idx,&name) == 0) {
       
   170             if(dev.contains(QLatin1String(name)))
       
   171                 break;
       
   172             idx++;
       
   173 	}
       
   174         dev = QString(QLatin1String("hw:%1,0")).arg(idx);
       
   175 #endif
       
   176     }
       
   177     if(mode == QAudio::AudioOutput) {
       
   178         err=snd_pcm_open( &handle,dev.toLocal8Bit().constData(),SND_PCM_STREAM_PLAYBACK,0);
       
   179     } else {
       
   180         err=snd_pcm_open( &handle,dev.toLocal8Bit().constData(),SND_PCM_STREAM_CAPTURE,0);
       
   181     }
       
   182     if(err < 0) {
       
   183         handle = 0;
       
   184         return false;
       
   185     }
       
   186     return true;
       
   187 }
       
   188 
       
   189 void QAudioDeviceInfoInternal::close()
       
   190 {
       
   191     if(handle)
       
   192         snd_pcm_close(handle);
       
   193     handle = 0;
       
   194 }
       
   195 
       
   196 bool QAudioDeviceInfoInternal::testSettings(const QAudioFormat& format) const
       
   197 {
       
   198     // Set nearest to closest settings that do work.
       
   199     // See if what is in settings will work (return value).
       
   200     int err = 0;
       
   201     snd_pcm_t* handle;
       
   202     snd_pcm_hw_params_t *params;
       
   203     QString dev = device;
       
   204 
       
   205     QList<QByteArray> devices = QAudioDeviceInfoInternal::availableDevices(QAudio::AudioOutput);
       
   206 
       
   207     if(dev.compare(QLatin1String("default")) == 0) {
       
   208 #if(SND_LIB_MAJOR == 1 && SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR >= 14)
       
   209         dev = QLatin1String(devices.first().constData());
       
   210 #else
       
   211         dev = QLatin1String("hw:0,0");
       
   212 #endif
       
   213     } else {
       
   214 #if(SND_LIB_MAJOR == 1 && SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR >= 14)
       
   215         dev = device;
       
   216 #else
       
   217         int idx = 0;
       
   218         char *name;
       
   219 
       
   220         QString shortName = device.mid(device.indexOf(QLatin1String("="),0)+1);
       
   221 
       
   222         while(snd_card_get_name(idx,&name) == 0) {
       
   223             if(shortName.compare(QLatin1String(name)) == 0)
       
   224                 break;
       
   225             idx++;
       
   226         }
       
   227         dev = QString(QLatin1String("hw:%1,0")).arg(idx);
       
   228 #endif
       
   229     }
       
   230     if(mode == QAudio::AudioOutput) {
       
   231         err=snd_pcm_open( &handle,dev.toLocal8Bit().constData(),SND_PCM_STREAM_PLAYBACK,0);
       
   232     } else {
       
   233         err=snd_pcm_open( &handle,dev.toLocal8Bit().constData(),SND_PCM_STREAM_CAPTURE,0);
       
   234     }
       
   235     if(err < 0) {
       
   236         handle = 0;
       
   237         return false;
       
   238     }
       
   239 
       
   240     bool testChannel = false;
       
   241     bool testCodec = false;
       
   242     bool testFreq = false;
       
   243     bool testType = false;
       
   244     bool testSize = false;
       
   245 
       
   246     int  dir = 0;
       
   247 
       
   248     snd_pcm_nonblock( handle, 0 );
       
   249     snd_pcm_hw_params_alloca( &params );
       
   250     snd_pcm_hw_params_any( handle, params );
       
   251 
       
   252     // set the values!
       
   253     snd_pcm_hw_params_set_channels(handle,params,format.channels());
       
   254     snd_pcm_hw_params_set_rate(handle,params,format.frequency(),dir);
       
   255     switch(format.sampleSize()) {
       
   256         case 8:
       
   257             if(format.sampleType() == QAudioFormat::SignedInt)
       
   258                 snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S8);
       
   259             else if(format.sampleType() == QAudioFormat::UnSignedInt)
       
   260                 snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U8);
       
   261             break;
       
   262         case 16:
       
   263             if(format.sampleType() == QAudioFormat::SignedInt) {
       
   264                 if(format.byteOrder() == QAudioFormat::LittleEndian)
       
   265                     snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S16_LE);
       
   266                 else if(format.byteOrder() == QAudioFormat::BigEndian)
       
   267                     snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S16_BE);
       
   268             } else if(format.sampleType() == QAudioFormat::UnSignedInt) {
       
   269                 if(format.byteOrder() == QAudioFormat::LittleEndian)
       
   270                     snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U16_LE);
       
   271                 else if(format.byteOrder() == QAudioFormat::BigEndian)
       
   272                     snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U16_BE);
       
   273             }
       
   274             break;
       
   275         case 32:
       
   276             if(format.sampleType() == QAudioFormat::SignedInt) {
       
   277                 if(format.byteOrder() == QAudioFormat::LittleEndian)
       
   278                     snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S32_LE);
       
   279                 else if(format.byteOrder() == QAudioFormat::BigEndian)
       
   280                     snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S32_BE);
       
   281             } else if(format.sampleType() == QAudioFormat::UnSignedInt) {
       
   282                 if(format.byteOrder() == QAudioFormat::LittleEndian)
       
   283                     snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U32_LE);
       
   284                 else if(format.byteOrder() == QAudioFormat::BigEndian)
       
   285                     snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U32_BE);
       
   286             }
       
   287     }
       
   288 
       
   289     // For now, just accept only audio/pcm codec
       
   290     if(!format.codec().startsWith(QLatin1String("audio/pcm"))) {
       
   291         err=-1;
       
   292     } else
       
   293         testCodec = true;
       
   294 
       
   295     if(err>=0 && format.channels() != -1) {
       
   296         err = snd_pcm_hw_params_test_channels(handle,params,format.channels());
       
   297         if(err>=0)
       
   298             err = snd_pcm_hw_params_set_channels(handle,params,format.channels());
       
   299         if(err>=0)
       
   300             testChannel = true;
       
   301     }
       
   302 
       
   303     if(err>=0 && format.frequency() != -1) {
       
   304         err = snd_pcm_hw_params_test_rate(handle,params,format.frequency(),0);
       
   305         if(err>=0)
       
   306             err = snd_pcm_hw_params_set_rate(handle,params,format.frequency(),dir);
       
   307         if(err>=0)
       
   308             testFreq = true;
       
   309     }
       
   310 
       
   311     if((err>=0 && format.sampleSize() != -1) &&
       
   312             (format.sampleType() != QAudioFormat::Unknown)) {
       
   313         switch(format.sampleSize()) {
       
   314             case 8:
       
   315                 if(format.sampleType() == QAudioFormat::SignedInt)
       
   316                     err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S8);
       
   317                 else if(format.sampleType() == QAudioFormat::UnSignedInt)
       
   318                     err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U8);
       
   319                 break;
       
   320             case 16:
       
   321                 if(format.sampleType() == QAudioFormat::SignedInt) {
       
   322                     if(format.byteOrder() == QAudioFormat::LittleEndian)
       
   323                         err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S16_LE);
       
   324                     else if(format.byteOrder() == QAudioFormat::BigEndian)
       
   325                         err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S16_BE);
       
   326                 } else if(format.sampleType() == QAudioFormat::UnSignedInt) {
       
   327                     if(format.byteOrder() == QAudioFormat::LittleEndian)
       
   328                         err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U16_LE);
       
   329                     else if(format.byteOrder() == QAudioFormat::BigEndian)
       
   330                         err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U16_BE);
       
   331                 }
       
   332                 break;
       
   333             case 32:
       
   334                 if(format.sampleType() == QAudioFormat::SignedInt) {
       
   335                     if(format.byteOrder() == QAudioFormat::LittleEndian)
       
   336                         err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S32_LE);
       
   337                     else if(format.byteOrder() == QAudioFormat::BigEndian)
       
   338                         err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S32_BE);
       
   339                 } else if(format.sampleType() == QAudioFormat::UnSignedInt) {
       
   340                     if(format.byteOrder() == QAudioFormat::LittleEndian)
       
   341                         err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U32_LE);
       
   342                     else if(format.byteOrder() == QAudioFormat::BigEndian)
       
   343                         err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U32_BE);
       
   344                 }
       
   345         }
       
   346         if(err>=0) {
       
   347             testSize = true;
       
   348             testType = true;
       
   349         }
       
   350     }
       
   351     if(err>=0)
       
   352         err = snd_pcm_hw_params(handle, params);
       
   353 
       
   354     if(err == 0) {
       
   355         // settings work
       
   356         // close()
       
   357         if(handle)
       
   358             snd_pcm_close(handle);
       
   359         return true;
       
   360     }
       
   361     if(handle)
       
   362         snd_pcm_close(handle);
       
   363 
       
   364     return false;
       
   365 }
       
   366 
       
   367 void QAudioDeviceInfoInternal::updateLists()
       
   368 {
       
   369     // redo all lists based on current settings
       
   370     freqz.clear();
       
   371     channelz.clear();
       
   372     sizez.clear();
       
   373     byteOrderz.clear();
       
   374     typez.clear();
       
   375     codecz.clear();
       
   376 
       
   377     if(!handle)
       
   378         open();
       
   379 
       
   380     if(!handle)
       
   381         return;
       
   382 
       
   383     for(int i=0; i<(int)MAX_SAMPLE_RATES; i++) {
       
   384         //if(snd_pcm_hw_params_test_rate(handle, params, SAMPLE_RATES[i], dir) == 0)
       
   385         freqz.append(SAMPLE_RATES[i]);
       
   386     }
       
   387     channelz.append(1);
       
   388     channelz.append(2);
       
   389     if (surround40) channelz.append(4);
       
   390     if (surround51) channelz.append(6);
       
   391     if (surround71) channelz.append(8);
       
   392     sizez.append(8);
       
   393     sizez.append(16);
       
   394     sizez.append(32);
       
   395     byteOrderz.append(QAudioFormat::LittleEndian);
       
   396     byteOrderz.append(QAudioFormat::BigEndian);
       
   397     typez.append(QAudioFormat::SignedInt);
       
   398     typez.append(QAudioFormat::UnSignedInt);
       
   399     typez.append(QAudioFormat::Float);
       
   400     codecz.append(QLatin1String("audio/pcm"));
       
   401     close();
       
   402 }
       
   403 
       
   404 QList<QByteArray> QAudioDeviceInfoInternal::availableDevices(QAudio::Mode mode)
       
   405 {
       
   406     QList<QByteArray> allDevices;
       
   407     QList<QByteArray> devices;
       
   408     QByteArray filter;
       
   409 
       
   410 #if(SND_LIB_MAJOR == 1 && SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR >= 14)
       
   411     // Create a list of all current audio devices that support mode
       
   412     void **hints, **n;
       
   413     char *name, *descr, *io;
       
   414 
       
   415     if(snd_device_name_hint(-1, "pcm", &hints) < 0) {
       
   416         qWarning() << "no alsa devices available";
       
   417         return devices;
       
   418     }
       
   419     n = hints;
       
   420 
       
   421     if(mode == QAudio::AudioInput) {
       
   422         filter = "Input";
       
   423     } else {
       
   424         filter = "Output";
       
   425     }
       
   426 
       
   427     while (*n != NULL) {
       
   428         name = snd_device_name_get_hint(*n, "NAME");
       
   429         descr = snd_device_name_get_hint(*n, "DESC");
       
   430         io = snd_device_name_get_hint(*n, "IOID");
       
   431         if((name != NULL) && (descr != NULL) && ((io == NULL) || (io == filter))) {
       
   432             QString deviceName = QLatin1String(name);
       
   433             QString deviceDescription = QLatin1String(descr);
       
   434             allDevices.append(deviceName.toLocal8Bit().constData());
       
   435             if(deviceDescription.contains(QLatin1String("Default Audio Device")))
       
   436                 devices.append(deviceName.toLocal8Bit().constData());
       
   437         }
       
   438         if(name != NULL)
       
   439             free(name);
       
   440         if(descr != NULL)
       
   441             free(descr);
       
   442         if(io != NULL)
       
   443             free(io);
       
   444         ++n;
       
   445     }
       
   446     snd_device_name_free_hint(hints);
       
   447 
       
   448     if(devices.size() > 0) {
       
   449         devices.append("default");
       
   450     }
       
   451 #else
       
   452     int idx = 0;
       
   453     char* name;
       
   454 
       
   455     while(snd_card_get_name(idx,&name) == 0) {
       
   456         devices.append(name);
       
   457         idx++;
       
   458     }
       
   459     if (idx > 0)
       
   460         devices.append("default");
       
   461 #endif
       
   462 #if (!defined(Q_WS_MAEMO_5) && !defined(Q_WS_MAEMO_6))
       
   463     if (devices.size() == 0 && allDevices.size() > 0)
       
   464         return allDevices;
       
   465 #endif
       
   466 
       
   467     return devices;
       
   468 }
       
   469 
       
   470 QByteArray QAudioDeviceInfoInternal::defaultInputDevice()
       
   471 {
       
   472     QList<QByteArray> devices = availableDevices(QAudio::AudioInput);
       
   473     if(devices.size() == 0)
       
   474         return QByteArray();
       
   475 
       
   476     return devices.first();
       
   477 }
       
   478 
       
   479 QByteArray QAudioDeviceInfoInternal::defaultOutputDevice()
       
   480 {
       
   481     QList<QByteArray> devices = availableDevices(QAudio::AudioOutput);
       
   482     if(devices.size() == 0)
       
   483         return QByteArray();
       
   484 
       
   485     return devices.first();
       
   486 }
       
   487 
       
   488 void QAudioDeviceInfoInternal::checkSurround()
       
   489 {
       
   490     QList<QByteArray> devices;
       
   491     surround40 = false;
       
   492     surround51 = false;
       
   493     surround71 = false;
       
   494 
       
   495     void **hints, **n;
       
   496     char *name, *descr, *io;
       
   497 
       
   498     if(snd_device_name_hint(-1, "pcm", &hints) < 0)
       
   499         return;
       
   500 
       
   501     n = hints;
       
   502 
       
   503     while (*n != NULL) {
       
   504         name = snd_device_name_get_hint(*n, "NAME");
       
   505         descr = snd_device_name_get_hint(*n, "DESC");
       
   506         io = snd_device_name_get_hint(*n, "IOID");
       
   507         if((name != NULL) && (descr != NULL)) {
       
   508             QString deviceName = QLatin1String(name);
       
   509             if (mode == QAudio::AudioOutput) {
       
   510                 if(deviceName.contains(QLatin1String("surround40")))
       
   511                     surround40 = true;
       
   512                 if(deviceName.contains(QLatin1String("surround51")))
       
   513                     surround51 = true;
       
   514                 if(deviceName.contains(QLatin1String("surround71")))
       
   515                     surround71 = true;
       
   516             }
       
   517         }
       
   518         if(name != NULL)
       
   519             free(name);
       
   520         if(descr != NULL)
       
   521             free(descr);
       
   522         if(io != NULL)
       
   523             free(io);
       
   524         ++n;
       
   525     }
       
   526     snd_device_name_free_hint(hints);
       
   527 }
       
   528 
       
   529 QT_END_NAMESPACE