src/multimedia/audio/qaudiooutput_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 <QtCore/qcoreapplication.h>
       
    54 #include "qaudiooutput_alsa_p.h"
       
    55 
       
    56 QT_BEGIN_NAMESPACE
       
    57 
       
    58 //#define DEBUG_AUDIO 1
       
    59 
       
    60 static const int minimumIntervalTime = 50;
       
    61 
       
    62 QAudioOutputPrivate::QAudioOutputPrivate(const QByteArray &device, const QAudioFormat& audioFormat):
       
    63     settings(audioFormat)
       
    64 {
       
    65     bytesAvailable = 0;
       
    66     handle = 0;
       
    67     ahandler = 0;
       
    68     access = SND_PCM_ACCESS_RW_INTERLEAVED;
       
    69     pcmformat = SND_PCM_FORMAT_S16;
       
    70     buffer_frames = 0;
       
    71     period_frames = 0;
       
    72     buffer_size = 0;
       
    73     period_size = 0;
       
    74     buffer_time = 100000;
       
    75     period_time = 20000;
       
    76     totalTimeValue = 0;
       
    77     intervalTime = 1000;
       
    78     audioBuffer = 0;
       
    79     errorState = QAudio::NoError;
       
    80     deviceState = QAudio::StopState;
       
    81     audioSource = 0;
       
    82     pullMode = true;
       
    83     resuming = false;
       
    84     opened = false;
       
    85 
       
    86     QStringList list1 = QString(QLatin1String(device)).split(QLatin1String(":"));
       
    87     m_device = QByteArray(list1.at(0).toLocal8Bit().constData());
       
    88 
       
    89     timer = new QTimer(this);
       
    90     connect(timer,SIGNAL(timeout()),SLOT(userFeed()));
       
    91 }
       
    92 
       
    93 QAudioOutputPrivate::~QAudioOutputPrivate()
       
    94 {
       
    95     close();
       
    96     disconnect(timer, SIGNAL(timeout()));
       
    97     QCoreApplication::processEvents();
       
    98     delete timer;
       
    99 }
       
   100 
       
   101 QAudio::Error QAudioOutputPrivate::error() const
       
   102 {
       
   103     return errorState;
       
   104 }
       
   105 
       
   106 QAudio::State QAudioOutputPrivate::state() const
       
   107 {
       
   108     return deviceState;
       
   109 }
       
   110 
       
   111 void QAudioOutputPrivate::async_callback(snd_async_handler_t *ahandler)
       
   112 {
       
   113     QAudioOutputPrivate* audioOut;
       
   114 
       
   115     audioOut = static_cast<QAudioOutputPrivate*>
       
   116         (snd_async_handler_get_callback_private(ahandler));
       
   117 
       
   118     if((audioOut->deviceState==QAudio::ActiveState)||(audioOut->resuming))
       
   119         audioOut->feedback();
       
   120 }
       
   121 
       
   122 int QAudioOutputPrivate::xrun_recovery(int err)
       
   123 {
       
   124     int  count = 0;
       
   125     bool reset = false;
       
   126 
       
   127     if(err == -EPIPE) {
       
   128         errorState = QAudio::UnderrunError;
       
   129         err = snd_pcm_prepare(handle);
       
   130         if(err < 0)
       
   131             reset = true;
       
   132 
       
   133     } else if((err == -ESTRPIPE)||(err == -EIO)) {
       
   134         errorState = QAudio::IOError;
       
   135         while((err = snd_pcm_resume(handle)) == -EAGAIN){
       
   136             usleep(100);
       
   137             count++;
       
   138             if(count > 5) {
       
   139                 reset = true;
       
   140                 break;
       
   141             }
       
   142         }
       
   143         if(err < 0) {
       
   144             err = snd_pcm_prepare(handle);
       
   145             if(err < 0)
       
   146                 reset = true;
       
   147         }
       
   148     }
       
   149     if(reset) {
       
   150         close();
       
   151         open();
       
   152         snd_pcm_prepare(handle);
       
   153         return 0;
       
   154     }
       
   155     return err;
       
   156 }
       
   157 
       
   158 int QAudioOutputPrivate::setFormat()
       
   159 {
       
   160     snd_pcm_format_t pcmformat = SND_PCM_FORMAT_S16;
       
   161 
       
   162     if(settings.sampleSize() == 8) {
       
   163         pcmformat = SND_PCM_FORMAT_U8;
       
   164 
       
   165     } else if(settings.sampleSize() == 16) {
       
   166         if(settings.sampleType() == QAudioFormat::SignedInt) {
       
   167             if(settings.byteOrder() == QAudioFormat::LittleEndian)
       
   168                 pcmformat = SND_PCM_FORMAT_S16_LE;
       
   169             else
       
   170                 pcmformat = SND_PCM_FORMAT_S16_BE;
       
   171         } else if(settings.sampleType() == QAudioFormat::UnSignedInt) {
       
   172             if(settings.byteOrder() == QAudioFormat::LittleEndian)
       
   173                 pcmformat = SND_PCM_FORMAT_U16_LE;
       
   174             else
       
   175                 pcmformat = SND_PCM_FORMAT_U16_BE;
       
   176         }
       
   177     } else if(settings.sampleSize() == 24) {
       
   178         if(settings.sampleType() == QAudioFormat::SignedInt) {
       
   179             if(settings.byteOrder() == QAudioFormat::LittleEndian)
       
   180                 pcmformat = SND_PCM_FORMAT_S24_LE;
       
   181             else
       
   182                 pcmformat = SND_PCM_FORMAT_S24_BE;
       
   183         } else if(settings.sampleType() == QAudioFormat::UnSignedInt) {
       
   184             if(settings.byteOrder() == QAudioFormat::LittleEndian)
       
   185                 pcmformat = SND_PCM_FORMAT_U24_LE;
       
   186             else
       
   187                 pcmformat = SND_PCM_FORMAT_U24_BE;
       
   188         }
       
   189     } else if(settings.sampleSize() == 32) {
       
   190         if(settings.sampleType() == QAudioFormat::SignedInt) {
       
   191             if(settings.byteOrder() == QAudioFormat::LittleEndian)
       
   192                 pcmformat = SND_PCM_FORMAT_S32_LE;
       
   193             else
       
   194                 pcmformat = SND_PCM_FORMAT_S32_BE;
       
   195         } else if(settings.sampleType() == QAudioFormat::UnSignedInt) {
       
   196             if(settings.byteOrder() == QAudioFormat::LittleEndian)
       
   197                 pcmformat = SND_PCM_FORMAT_U32_LE;
       
   198             else
       
   199                 pcmformat = SND_PCM_FORMAT_U32_BE;
       
   200         } else if(settings.sampleType() == QAudioFormat::Float) {
       
   201             if(settings.byteOrder() == QAudioFormat::LittleEndian)
       
   202                 pcmformat = SND_PCM_FORMAT_FLOAT_LE;
       
   203             else
       
   204                 pcmformat = SND_PCM_FORMAT_FLOAT_BE;
       
   205         }
       
   206     } else if(settings.sampleSize() == 64) {
       
   207         if(settings.byteOrder() == QAudioFormat::LittleEndian)
       
   208             pcmformat = SND_PCM_FORMAT_FLOAT64_LE;
       
   209         else
       
   210             pcmformat = SND_PCM_FORMAT_FLOAT64_BE;
       
   211     }
       
   212 
       
   213     return snd_pcm_hw_params_set_format( handle, hwparams, pcmformat);
       
   214 }
       
   215 
       
   216 QIODevice* QAudioOutputPrivate::start(QIODevice* device)
       
   217 {
       
   218     if(deviceState != QAudio::StopState)
       
   219         deviceState = QAudio::StopState;
       
   220 
       
   221     errorState = QAudio::NoError;
       
   222 
       
   223     // Handle change of mode
       
   224     if(audioSource && pullMode && !device) {
       
   225         // pull -> push
       
   226         close();
       
   227         audioSource = 0;
       
   228     } else if(audioSource && !pullMode && device) {
       
   229         // push -> pull
       
   230         close();
       
   231         delete audioSource;
       
   232         audioSource = 0;
       
   233     }
       
   234 
       
   235     if(device) {
       
   236         //set to pull mode
       
   237         pullMode = true;
       
   238         audioSource = device;
       
   239         deviceState = QAudio::ActiveState;
       
   240     } else {
       
   241         //set to push mode
       
   242         if(!audioSource) {
       
   243             audioSource = new OutputPrivate(this);
       
   244             audioSource->open(QIODevice::WriteOnly|QIODevice::Unbuffered);
       
   245         }
       
   246         pullMode = false;
       
   247         deviceState = QAudio::IdleState;
       
   248     }
       
   249 
       
   250     open();
       
   251 
       
   252     emit stateChanged(deviceState);
       
   253 
       
   254     return audioSource;
       
   255 }
       
   256 
       
   257 void QAudioOutputPrivate::stop()
       
   258 {
       
   259     if(deviceState == QAudio::StopState)
       
   260         return;
       
   261     deviceState = QAudio::StopState;
       
   262     close();
       
   263     emit stateChanged(deviceState);
       
   264 }
       
   265 
       
   266 bool QAudioOutputPrivate::open()
       
   267 {
       
   268     if(opened)
       
   269         return true;
       
   270 
       
   271 #ifdef DEBUG_AUDIO
       
   272     QTime now(QTime::currentTime());
       
   273     qDebug()<<now.second()<<"s "<<now.msec()<<"ms :open()";
       
   274 #endif
       
   275     timeStamp.restart();
       
   276     elapsedTimeOffset = 0;
       
   277 
       
   278     int dir;
       
   279     int err=-1;
       
   280     int count=0;
       
   281     unsigned int freakuency=settings.frequency();
       
   282 
       
   283     QString dev = QLatin1String(m_device.constData());
       
   284     if(!dev.contains(QLatin1String("default"))) {
       
   285 #if(SND_LIB_MAJOR == 1 && SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR >= 14) 
       
   286         dev = QString(QLatin1String("default:CARD=%1")).arg(QLatin1String(m_device.constData()));
       
   287 #else
       
   288         int idx = 0;
       
   289         char *name;
       
   290 
       
   291 	while(snd_card_get_name(idx,&name) == 0) {
       
   292             if(m_device.contains(name))
       
   293                 break;
       
   294             idx++;
       
   295 	}
       
   296         dev = QString(QLatin1String("hw:%1,0")).arg(idx);
       
   297 #endif
       
   298     }
       
   299     // Step 1: try and open the device
       
   300     while((count < 5) && (err < 0)) {
       
   301         err=snd_pcm_open(&handle,dev.toLocal8Bit().constData(),SND_PCM_STREAM_PLAYBACK,0);
       
   302         if(err < 0)
       
   303             count++;
       
   304     }
       
   305     if (( err < 0)||(handle == 0)) {
       
   306         errorState = QAudio::OpenError;
       
   307         deviceState = QAudio::StopState;
       
   308         return false;
       
   309     }
       
   310     snd_pcm_nonblock( handle, 0 );
       
   311 
       
   312     // Step 2: Set the desired HW parameters.
       
   313     snd_pcm_hw_params_alloca( &hwparams );
       
   314 
       
   315     bool fatal = false;
       
   316     QString errMessage;
       
   317     unsigned int chunks = 8;
       
   318 
       
   319     err = snd_pcm_hw_params_any( handle, hwparams );
       
   320     if ( err < 0 ) {
       
   321         fatal = true;
       
   322         errMessage = QString::fromLatin1("QAudioOutput: snd_pcm_hw_params_any: err = %1").arg(err);
       
   323     }
       
   324     if ( !fatal ) {
       
   325         err = snd_pcm_hw_params_set_rate_resample( handle, hwparams, 1 );
       
   326         if ( err < 0 ) {
       
   327             fatal = true;
       
   328             errMessage = QString::fromLatin1("QAudioOutput: snd_pcm_hw_params_set_rate_resample: err = %1").arg(err);
       
   329         }
       
   330     }
       
   331     if ( !fatal ) {
       
   332         err = snd_pcm_hw_params_set_access( handle, hwparams, access );
       
   333         if ( err < 0 ) {
       
   334             fatal = true;
       
   335             errMessage = QString::fromLatin1("QAudioOutput: snd_pcm_hw_params_set_access: err = %1").arg(err);
       
   336         }
       
   337     }
       
   338     if ( !fatal ) {
       
   339         err = setFormat();
       
   340         if ( err < 0 ) {
       
   341             fatal = true;
       
   342             errMessage = QString::fromLatin1("QAudioOutput: snd_pcm_hw_params_set_format: err = %1").arg(err);
       
   343         }
       
   344     }
       
   345     if ( !fatal ) {
       
   346         err = snd_pcm_hw_params_set_channels( handle, hwparams, (unsigned int)settings.channels() );
       
   347         if ( err < 0 ) {
       
   348             fatal = true;
       
   349             errMessage = QString::fromLatin1("QAudioOutput: snd_pcm_hw_params_set_channels: err = %1").arg(err);
       
   350         }
       
   351     }
       
   352     if ( !fatal ) {
       
   353         err = snd_pcm_hw_params_set_rate_near( handle, hwparams, &freakuency, 0 );
       
   354         if ( err < 0 ) {
       
   355             fatal = true;
       
   356             errMessage = QString::fromLatin1("QAudioOutput: snd_pcm_hw_params_set_rate_near: err = %1").arg(err);
       
   357         }
       
   358     }
       
   359     if ( !fatal ) {
       
   360         err = snd_pcm_hw_params_set_buffer_time_near(handle, hwparams, &buffer_time, &dir);
       
   361         if ( err < 0 ) {
       
   362             fatal = true;
       
   363                 errMessage = QString::fromLatin1("QAudioOutput: snd_pcm_hw_params_set_buffer_time_near: err = %1").arg(err);
       
   364         }
       
   365     }
       
   366     if ( !fatal ) {
       
   367         err = snd_pcm_hw_params_set_period_time_near(handle, hwparams, &period_time, &dir);
       
   368         if ( err < 0 ) {
       
   369             fatal = true;
       
   370             errMessage = QString::fromLatin1("QAudioOutput: snd_pcm_hw_params_set_period_time_near: err = %1").arg(err);
       
   371         }
       
   372     }
       
   373     if ( !fatal ) {
       
   374         err = snd_pcm_hw_params_set_periods_near(handle, hwparams, &chunks, &dir);
       
   375         if ( err < 0 ) {
       
   376             fatal = true;
       
   377             errMessage = QString::fromLatin1("QAudioOutput: snd_pcm_hw_params_set_periods_near: err = %1").arg(err);
       
   378         }
       
   379     }
       
   380     if ( !fatal ) {
       
   381         err = snd_pcm_hw_params(handle, hwparams);
       
   382         if ( err < 0 ) {
       
   383             fatal = true;
       
   384             errMessage = QString::fromLatin1("QAudioOutput: snd_pcm_hw_params: err = %1").arg(err);
       
   385         }
       
   386     }
       
   387     if( err < 0) {
       
   388         qWarning()<<errMessage;
       
   389         errorState = QAudio::OpenError;
       
   390         deviceState = QAudio::StopState;
       
   391         return false;
       
   392     }
       
   393     snd_pcm_hw_params_get_buffer_size(hwparams,&buffer_frames);
       
   394     buffer_size = snd_pcm_frames_to_bytes(handle,buffer_frames);
       
   395     snd_pcm_hw_params_get_period_size(hwparams,&period_frames, &dir);
       
   396     period_size = snd_pcm_frames_to_bytes(handle,period_frames);
       
   397     snd_pcm_hw_params_get_buffer_time(hwparams,&buffer_time, &dir);
       
   398     snd_pcm_hw_params_get_period_time(hwparams,&period_time, &dir);
       
   399 
       
   400     // Step 3: Set the desired SW parameters.
       
   401     snd_pcm_sw_params_t *swparams;
       
   402     snd_pcm_sw_params_alloca(&swparams);
       
   403     snd_pcm_sw_params_current(handle, swparams);
       
   404     snd_pcm_sw_params_set_start_threshold(handle,swparams,period_frames);
       
   405     snd_pcm_sw_params_set_stop_threshold(handle,swparams,buffer_frames);
       
   406     snd_pcm_sw_params_set_avail_min(handle, swparams,period_frames);
       
   407     snd_pcm_sw_params(handle, swparams);
       
   408 
       
   409     // Step 4: Prepare audio
       
   410     if(audioBuffer == 0)
       
   411         audioBuffer = new char[snd_pcm_frames_to_bytes(handle,buffer_frames)];
       
   412     snd_pcm_prepare( handle );
       
   413     snd_pcm_start(handle);
       
   414 
       
   415     // Step 5: Setup callback and timer fallback
       
   416     snd_async_add_pcm_handler(&ahandler, handle, async_callback, this);
       
   417     bytesAvailable = bytesFree();
       
   418 
       
   419     // Step 6: Start audio processing
       
   420     timer->start(period_time/1000);
       
   421 
       
   422     clockStamp.restart();
       
   423     timeStamp.restart();
       
   424     elapsedTimeOffset = 0;
       
   425     errorState  = QAudio::NoError;
       
   426     totalTimeValue = 0;
       
   427     opened = true;
       
   428 
       
   429     return true;
       
   430 }
       
   431 
       
   432 void QAudioOutputPrivate::close()
       
   433 {
       
   434     deviceState = QAudio::StopState;
       
   435     timer->stop();
       
   436 
       
   437     if ( handle ) {
       
   438         snd_pcm_drain( handle );
       
   439         snd_pcm_close( handle );
       
   440         handle = 0;
       
   441         delete [] audioBuffer;
       
   442         audioBuffer=0;
       
   443     }
       
   444     if(!pullMode && audioSource) {
       
   445         delete audioSource;
       
   446         audioSource = 0;
       
   447     }
       
   448     opened = false;
       
   449 }
       
   450 
       
   451 int QAudioOutputPrivate::bytesFree() const
       
   452 {
       
   453     if(resuming)
       
   454         return period_size;
       
   455 
       
   456     if(deviceState != QAudio::ActiveState && deviceState != QAudio::IdleState)
       
   457         return 0;
       
   458     int frames = snd_pcm_avail_update(handle);
       
   459     if((int)frames > (int)buffer_frames)
       
   460         frames = buffer_frames;
       
   461 
       
   462     return snd_pcm_frames_to_bytes(handle, frames);
       
   463 }
       
   464 
       
   465 qint64 QAudioOutputPrivate::write( const char *data, qint64 len )
       
   466 {
       
   467     // Write out some audio data
       
   468     if ( !handle )
       
   469         return 0;
       
   470 #ifdef DEBUG_AUDIO
       
   471     qDebug()<<"frames to write out = "<<
       
   472         snd_pcm_bytes_to_frames( handle, (int)len )<<" ("<<len<<") bytes";
       
   473 #endif
       
   474     int frames, err;
       
   475     int space = bytesFree();
       
   476     if(len < space) {
       
   477         // Just write it
       
   478         frames = snd_pcm_bytes_to_frames( handle, (int)len );
       
   479         err = snd_pcm_writei( handle, data, frames );
       
   480     } else {
       
   481         // Only write space worth
       
   482         frames = snd_pcm_bytes_to_frames( handle, (int)space );
       
   483         err = snd_pcm_writei( handle, data, frames );
       
   484     }
       
   485     if(err > 0) {
       
   486         totalTimeValue += err*1000000/settings.frequency();
       
   487         resuming = false;
       
   488         errorState = QAudio::NoError;
       
   489         deviceState = QAudio::ActiveState;
       
   490         return snd_pcm_frames_to_bytes( handle, err );
       
   491     } else
       
   492         err = xrun_recovery(err);
       
   493 
       
   494     if(err < 0) {
       
   495         close();
       
   496         errorState = QAudio::FatalError;
       
   497         deviceState = QAudio::StopState;
       
   498         emit stateChanged(deviceState);
       
   499     }
       
   500     return 0;
       
   501 }
       
   502 
       
   503 int QAudioOutputPrivate::periodSize() const
       
   504 {
       
   505     return period_size;
       
   506 }
       
   507 
       
   508 void QAudioOutputPrivate::setBufferSize(int value)
       
   509 {
       
   510     if(deviceState == QAudio::StopState)
       
   511         buffer_size = value;
       
   512 }
       
   513 
       
   514 int QAudioOutputPrivate::bufferSize() const
       
   515 {
       
   516     return buffer_size;
       
   517 }
       
   518 
       
   519 void QAudioOutputPrivate::setNotifyInterval(int ms)
       
   520 {
       
   521     if(ms >= minimumIntervalTime)
       
   522         intervalTime = ms;
       
   523     else
       
   524         intervalTime = minimumIntervalTime;
       
   525 }
       
   526 
       
   527 int QAudioOutputPrivate::notifyInterval() const
       
   528 {
       
   529     return intervalTime;
       
   530 }
       
   531 
       
   532 qint64 QAudioOutputPrivate::totalTime() const
       
   533 {
       
   534     return totalTimeValue;
       
   535 }
       
   536 
       
   537 void QAudioOutputPrivate::resume()
       
   538 {
       
   539     if(deviceState == QAudio::SuspendState) {
       
   540         int err = 0;
       
   541 
       
   542         if(handle) {
       
   543             err = snd_pcm_prepare( handle );
       
   544             if(err < 0)
       
   545                 xrun_recovery(err);
       
   546 
       
   547             err = snd_pcm_start(handle);
       
   548             if(err < 0)
       
   549                 xrun_recovery(err);
       
   550 
       
   551             bytesAvailable = (int)snd_pcm_frames_to_bytes(handle, buffer_frames);
       
   552         }
       
   553         resuming = true;
       
   554         if(pullMode)
       
   555             deviceState = QAudio::ActiveState;
       
   556         else
       
   557             deviceState = QAudio::IdleState;
       
   558 
       
   559         errorState = QAudio::NoError;
       
   560         timer->start(period_time/1000);
       
   561         emit stateChanged(deviceState);
       
   562     }
       
   563 }
       
   564 
       
   565 QAudioFormat QAudioOutputPrivate::format() const
       
   566 {
       
   567     return settings;
       
   568 }
       
   569 
       
   570 void QAudioOutputPrivate::suspend()
       
   571 {
       
   572     if(deviceState == QAudio::ActiveState || deviceState == QAudio::IdleState || resuming) {
       
   573         timer->stop();
       
   574         deviceState = QAudio::SuspendState;
       
   575         errorState = QAudio::NoError;
       
   576         emit stateChanged(deviceState);
       
   577     }
       
   578 }
       
   579 
       
   580 void QAudioOutputPrivate::userFeed()
       
   581 {
       
   582     if(deviceState == QAudio::StopState || deviceState == QAudio::SuspendState)
       
   583         return;
       
   584 #ifdef DEBUG_AUDIO
       
   585     QTime now(QTime::currentTime());
       
   586     qDebug()<<now.second()<<"s "<<now.msec()<<"ms :userFeed() OUT";
       
   587 #endif
       
   588     if(deviceState ==  QAudio::IdleState)
       
   589         bytesAvailable = bytesFree();
       
   590 
       
   591     deviceReady();
       
   592 }
       
   593 
       
   594 void QAudioOutputPrivate::feedback()
       
   595 {
       
   596     QMetaObject::invokeMethod(this, SLOT(updateAvailable()), Qt::QueuedConnection);
       
   597 }
       
   598 
       
   599 void QAudioOutputPrivate::updateAvailable()
       
   600 {
       
   601 #ifdef DEBUG_AUDIO
       
   602     QTime now(QTime::currentTime());
       
   603     qDebug()<<now.second()<<"s "<<now.msec()<<"ms :updateAvailable()";
       
   604 #endif
       
   605     bytesAvailable = bytesFree();
       
   606 }
       
   607 
       
   608 bool QAudioOutputPrivate::deviceReady()
       
   609 {
       
   610     if(pullMode) {
       
   611         int l = 0;
       
   612         int chunks = bytesAvailable/period_size;
       
   613         if(chunks==0) {
       
   614             bytesAvailable = bytesFree();
       
   615             return false;
       
   616         }
       
   617 #ifdef DEBUG_AUDIO
       
   618         qDebug()<<"deviceReady() avail="<<bytesAvailable<<" bytes, period size="<<period_size<<" bytes";
       
   619         qDebug()<<"deviceReady() no. of chunks that can fit ="<<chunks<<", chunks in bytes ="<<period_size*chunks;
       
   620 #endif
       
   621         int input = period_frames*chunks;
       
   622         if(input > (int)buffer_frames)
       
   623             input = buffer_frames;
       
   624         l = audioSource->read(audioBuffer,snd_pcm_frames_to_bytes(handle, input));
       
   625         if(l > 0) {
       
   626             // Got some data to output
       
   627             if(deviceState != QAudio::ActiveState)
       
   628                 return true;
       
   629             write(audioBuffer,l);
       
   630             bytesAvailable = bytesFree();
       
   631 
       
   632         } else if(l == 0) {
       
   633             // Did not get any data to output
       
   634             bytesAvailable = bytesFree();
       
   635             if(bytesAvailable > snd_pcm_frames_to_bytes(handle, buffer_frames-period_frames)) {
       
   636                 // Underrun
       
   637                 errorState = QAudio::UnderrunError;
       
   638                 deviceState = QAudio::IdleState;
       
   639                 emit stateChanged(deviceState);
       
   640             }
       
   641 
       
   642         } else if(l < 0) {
       
   643             close();
       
   644             errorState = QAudio::IOError;
       
   645             emit stateChanged(deviceState);
       
   646         }
       
   647     } else
       
   648         bytesAvailable = bytesFree();
       
   649 
       
   650     if(deviceState != QAudio::ActiveState)
       
   651         return true;
       
   652 
       
   653     if((timeStamp.elapsed() + elapsedTimeOffset) > intervalTime) {
       
   654         emit notify();
       
   655         elapsedTimeOffset = timeStamp.elapsed() + elapsedTimeOffset - intervalTime;
       
   656         timeStamp.restart();
       
   657     }
       
   658     return true;
       
   659 }
       
   660 
       
   661 qint64 QAudioOutputPrivate::clock() const
       
   662 {
       
   663     if(!handle)
       
   664         return 0;
       
   665 
       
   666     if (deviceState == QAudio::StopState)
       
   667         return 0;
       
   668 
       
   669 #if(SND_LIB_MAJOR == 1 && SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR >= 14) 
       
   670     snd_pcm_status_t* status;
       
   671     snd_pcm_status_alloca(&status);
       
   672 
       
   673     snd_timestamp_t t1,t2;
       
   674     if( snd_pcm_status(handle, status) >= 0) {
       
   675         snd_pcm_status_get_tstamp(status,&t1);
       
   676         snd_pcm_status_get_trigger_tstamp(status,&t2);
       
   677         t1.tv_sec-=t2.tv_sec;
       
   678 
       
   679         signed long l = (signed long)t1.tv_usec - (signed long)t2.tv_usec;
       
   680         if(l < 0) {
       
   681             t1.tv_sec--;
       
   682             l = -l;
       
   683             l %= 1000000;
       
   684         }
       
   685         return ((t1.tv_sec * 1000000)+l);
       
   686     } else
       
   687         return 0;
       
   688 #else
       
   689     return clockStamp.elapsed()*1000;
       
   690 #endif
       
   691     return 0;
       
   692 }
       
   693 
       
   694 void QAudioOutputPrivate::reset()
       
   695 {
       
   696     if(handle)
       
   697         snd_pcm_reset(handle);
       
   698 
       
   699     stop();
       
   700 }
       
   701 
       
   702 OutputPrivate::OutputPrivate(QAudioOutputPrivate* audio)
       
   703 {
       
   704     audioDevice = qobject_cast<QAudioOutputPrivate*>(audio);
       
   705 }
       
   706 
       
   707 OutputPrivate::~OutputPrivate() {}
       
   708 
       
   709 qint64 OutputPrivate::readData( char* data, qint64 len)
       
   710 {
       
   711     Q_UNUSED(data)
       
   712     Q_UNUSED(len)
       
   713 
       
   714     return 0;
       
   715 }
       
   716 
       
   717 qint64 OutputPrivate::writeData(const char* data, qint64 len)
       
   718 {
       
   719     int retry = 0;
       
   720     qint64 written = 0;
       
   721     if((audioDevice->deviceState == QAudio::ActiveState)
       
   722             ||(audioDevice->deviceState == QAudio::IdleState)) {
       
   723         while(written < len) {
       
   724             int chunk = audioDevice->write(data+written,(len-written));
       
   725             if(chunk <= 0)
       
   726                 retry++;
       
   727             written+=chunk;
       
   728             if(retry > 10)
       
   729                 return written;
       
   730         }
       
   731     }
       
   732     return written;
       
   733 
       
   734 }
       
   735 
       
   736 QT_END_NAMESPACE