src/gui/embedded/qsoundqss_qws.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
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 QtGui 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 #include "qsoundqss_qws.h"
       
    43 
       
    44 #ifndef QT_NO_SOUND
       
    45 #include <qbytearray.h>
       
    46 #include <qlist.h>
       
    47 #include <qsocketnotifier.h>
       
    48 #include <qfile.h>
       
    49 #include <qfileinfo.h>
       
    50 #include <qstringlist.h>
       
    51 #include <qevent.h>
       
    52 #include <qalgorithms.h>
       
    53 #include <qtimer.h>
       
    54 #include <qpointer.h>
       
    55 #include <qendian.h>
       
    56 #include <private/qcore_unix_p.h> // overrides QT_OPEN
       
    57 
       
    58 #include <unistd.h>
       
    59 #include <stdlib.h>
       
    60 #include <fcntl.h>
       
    61 #include <errno.h>
       
    62 #include <time.h>
       
    63 #include <sys/types.h>
       
    64 #include <sys/stat.h>
       
    65 #include <sys/ioctl.h>
       
    66 #include <sys/soundcard.h>
       
    67 
       
    68 #include <qdebug.h>
       
    69 
       
    70 #include <qvfbhdr.h>
       
    71 
       
    72 extern int errno;
       
    73 
       
    74 QT_BEGIN_NAMESPACE
       
    75 
       
    76 #define QT_QWS_SOUND_16BIT 1 // or 0, or undefined for always 0
       
    77 #define QT_QWS_SOUND_STEREO 1 // or 0, or undefined for always 0
       
    78 
       
    79 // Zaurus SL5000D doesn't seem to return any error if setting to 44000 and it fails,
       
    80 // however 44100 works, 44100 is more common that 44000.
       
    81 static int sound_speed = 44100;
       
    82 #ifndef QT_NO_QWS_SOUNDSERVER
       
    83 extern int qws_display_id;
       
    84 #endif
       
    85 
       
    86 static char *zeroMem = 0;
       
    87 
       
    88 struct QRiffChunk {
       
    89     char id[4];
       
    90     quint32 size;
       
    91     char data[4/*size*/];
       
    92 };
       
    93 
       
    94 #if defined(QT_QWS_IPAQ)
       
    95 static const int sound_fragment_size = 12;
       
    96 #else
       
    97 static const int sound_fragment_size = 12;
       
    98 #endif
       
    99 static const int sound_buffer_size = 1 << sound_fragment_size;
       
   100 // nb. there will be an sound startup delay of
       
   101 //        2^sound_fragment_size / sound_speed seconds.
       
   102 // (eg. sound_fragment_size==12, sound_speed==44000 means 0.093s delay)
       
   103 
       
   104 #ifdef QT_QWS_SOUND_STEREO
       
   105 static int sound_stereo=QT_QWS_SOUND_STEREO;
       
   106 #else
       
   107 static const int sound_stereo=0;
       
   108 #endif
       
   109 #ifdef QT_QWS_SOUND_16BIT
       
   110 static bool sound_16bit=QT_QWS_SOUND_16BIT;
       
   111 #else
       
   112 static const bool sound_16bit=false;
       
   113 #endif
       
   114 
       
   115 #ifndef QT_NO_QWS_SOUNDSERVER
       
   116 class QWSSoundServerClient : public QObject {
       
   117     Q_OBJECT
       
   118 
       
   119 public:
       
   120     QWSSoundServerClient(QWS_SOCK_BASE *s, QObject* parent);
       
   121     ~QWSSoundServerClient();
       
   122 
       
   123 public slots:
       
   124     void sendSoundCompleted(int, int);
       
   125     void sendDeviceReady(int, int);
       
   126     void sendDeviceError(int, int, int);
       
   127 
       
   128 signals:
       
   129     void play(int, int, const QString&);
       
   130     void play(int, int, const QString&, int, int);
       
   131     void playRaw(int, int, const QString&, int, int, int, int);
       
   132 
       
   133     void pause(int, int);
       
   134     void stop(int, int);
       
   135     void resume(int, int);
       
   136     void setVolume(int, int, int, int);
       
   137     void setMute(int, int, bool);
       
   138 
       
   139     void stopAll(int);
       
   140 
       
   141     void playPriorityOnly(bool);
       
   142 
       
   143     void setSilent( bool );
       
   144 
       
   145 private slots:
       
   146     void tryReadCommand();
       
   147 
       
   148 private:
       
   149     void sendClientMessage(QString msg);
       
   150     int mCurrentID;
       
   151     int left, right;
       
   152     bool priExist;
       
   153     static int lastId;
       
   154     static int nextId() { return ++lastId; }
       
   155     QPointer<QWS_SOCK_BASE> socket;
       
   156 };
       
   157 
       
   158 int QWSSoundServerClient::lastId = 0;
       
   159 
       
   160 QWSSoundServerClient::QWSSoundServerClient(QWS_SOCK_BASE *s, QObject* parent) :
       
   161     QObject( parent )
       
   162 {
       
   163     socket = s;
       
   164     priExist = false;
       
   165     mCurrentID = nextId();
       
   166     connect(socket,SIGNAL(readyRead()),
       
   167         this,SLOT(tryReadCommand()));
       
   168     connect(socket, SIGNAL(disconnected()), this, SLOT(deleteLater()));
       
   169 }
       
   170 
       
   171 QWSSoundServerClient::~QWSSoundServerClient()
       
   172 {
       
   173     if (priExist)
       
   174 	playPriorityOnly(false);
       
   175     emit stopAll(mCurrentID);
       
   176     if (socket)
       
   177         socket->deleteLater();
       
   178 }
       
   179 
       
   180 static QString getStringTok(QString &in)
       
   181 {
       
   182     int pos = in.indexOf(QLatin1Char(' '));
       
   183     QString ret;
       
   184     if (pos > 0) {
       
   185 	ret = in.left(pos);
       
   186 	in = in.mid(pos+1);
       
   187     } else {
       
   188 	ret = in;
       
   189 	in = QString::null;
       
   190     }
       
   191     return ret;
       
   192 }
       
   193 
       
   194 static int getNumTok(QString &in)
       
   195 {
       
   196     return getStringTok(in).toInt();
       
   197 }
       
   198 
       
   199 void QWSSoundServerClient::tryReadCommand()
       
   200 {
       
   201     while ( socket->canReadLine() ) {
       
   202 	QString l = QString::fromAscii(socket->readLine());
       
   203 	l.truncate(l.length()-1); // chomp
       
   204 	QString functionName = getStringTok(l);
       
   205 	int soundid = getNumTok(l);
       
   206 	if (functionName == QLatin1String("PLAY")) {
       
   207 	    emit play(mCurrentID, soundid, l);
       
   208 	} else if (functionName == QLatin1String("PLAYEXTEND")) {
       
   209 	    int volume = getNumTok(l);
       
   210 	    int flags = getNumTok(l);
       
   211 	    emit play(mCurrentID, soundid, l, volume, flags);
       
   212 	} else if (functionName == QLatin1String("PLAYRAW")) {
       
   213 	    int chs = getNumTok(l);
       
   214 	    int freq = getNumTok(l);
       
   215 	    int bitspersample = getNumTok(l);
       
   216 	    int flags = getNumTok(l);
       
   217 	    emit playRaw(mCurrentID, soundid, l, freq, chs, bitspersample, flags);
       
   218 	} else if (functionName == QLatin1String("PAUSE")) {
       
   219 	    emit pause(mCurrentID, soundid);
       
   220 	} else if (functionName == QLatin1String("STOP")) {
       
   221 	    emit stop(mCurrentID, soundid);
       
   222 	} else if (functionName == QLatin1String("RESUME")) {
       
   223 	    emit resume(mCurrentID, soundid);
       
   224 	} else if (functionName == QLatin1String("SETVOLUME")) {
       
   225 	    int left = getNumTok(l);
       
   226 	    int right = getNumTok(l);
       
   227 	    emit setVolume(mCurrentID, soundid, left, right);
       
   228 	} else if (functionName == QLatin1String("MUTE")) {
       
   229 	    emit setMute(mCurrentID, soundid, true);
       
   230 	} else if (functionName == QLatin1String("UNMUTE")) {
       
   231 	    emit setMute(mCurrentID, soundid, false);
       
   232 	} else if (functionName == QLatin1String("PRIORITYONLY")) {
       
   233 	    bool sPri = soundid != 0;
       
   234 	    if (sPri != priExist) {
       
   235 		priExist = sPri;
       
   236 		emit playPriorityOnly(sPri);
       
   237 	    }
       
   238 	} else if(functionName == QLatin1String("SILENT")) {
       
   239 	    emit setSilent( soundid != 0 );
       
   240 	}
       
   241     }
       
   242 }
       
   243 
       
   244 void QWSSoundServerClient::sendClientMessage(QString msg)
       
   245 {
       
   246 #ifndef QT_NO_TEXTCODEC
       
   247     QByteArray u = msg.toUtf8();
       
   248 #else
       
   249     QByteArray u = msg.toLatin1();
       
   250 #endif
       
   251     socket->write(u.data(), u.length());
       
   252     socket->flush();
       
   253 }
       
   254 
       
   255 void QWSSoundServerClient::sendSoundCompleted(int gid, int sid)
       
   256 {
       
   257     if (gid == mCurrentID)
       
   258         sendClientMessage(QLatin1String("SOUNDCOMPLETED ")
       
   259                           + QString::number(sid) + QLatin1Char('\n'));
       
   260 }
       
   261 
       
   262 void QWSSoundServerClient::sendDeviceReady(int gid, int sid)
       
   263 {
       
   264     if (gid == mCurrentID)
       
   265         sendClientMessage(QLatin1String("DEVICEREADY ")
       
   266                           + QString::number(sid) + QLatin1Char('\n'));
       
   267 }
       
   268 
       
   269 void QWSSoundServerClient::sendDeviceError(int gid, int sid, int err)
       
   270 {
       
   271     if (gid == mCurrentID)
       
   272         sendClientMessage(QLatin1String("DEVICEERROR ")
       
   273                           + QString::number(sid) + QLatin1Char(' ')
       
   274                           + QString::number(err) + QLatin1Char('\n'));
       
   275 }
       
   276 #endif
       
   277 
       
   278 static const int maxVolume = 100;
       
   279 static const int runinLength = 2*sound_buffer_size;
       
   280 class QWSSoundServerProvider {
       
   281 public:
       
   282     QWSSoundServerProvider(int w, int s)
       
   283 	: mWid(w), mSid(s), mMuted(false)
       
   284     {
       
   285 	leftVolume = maxVolume>>1;
       
   286 	rightVolume = maxVolume>>1;
       
   287 	isPriority = false;
       
   288         samples_due = 0;
       
   289 	max1 = max2 = out = 0;//= sound_buffer_size;
       
   290 	data = data1;
       
   291 	max = &max1;
       
   292 	sampleRunin = 0;
       
   293 	dev = -1;
       
   294     }
       
   295 
       
   296     virtual ~QWSSoundServerProvider() {
       
   297     }
       
   298 
       
   299     int groupId() const { return mWid; }
       
   300     int soundId() const { return mSid; }
       
   301 
       
   302     void startSampleRunin() {
       
   303 	// inteded to provide even audio return from mute/pause/dead samples.
       
   304 	//sampleRunin = runinLength; // or more?
       
   305     }
       
   306 
       
   307 
       
   308     void setVolume(int lv, int rv) {
       
   309 	leftVolume = qMin(maxVolume, qMax(0, lv));
       
   310 	rightVolume = qMin(maxVolume, qMax(0, rv));
       
   311     }
       
   312 
       
   313     void setMute(bool m) { mMuted = m; }
       
   314     bool muted() { return mMuted; }
       
   315 
       
   316     void setPriority(bool p) {
       
   317 	if (p != isPriority) {
       
   318 	    isPriority = p; // currently meaningless.
       
   319 	}
       
   320     }
       
   321 
       
   322 
       
   323     static void setPlayPriorityOnly(bool p)
       
   324     {
       
   325 	if (p)
       
   326 	    priorityExists++;
       
   327 	else
       
   328 	    priorityExists--;
       
   329 
       
   330 	if (priorityExists < 0)
       
   331 	    qDebug("QSS: got more priority offs than ons");
       
   332     }
       
   333 
       
   334     // return -1 for file broken, give up.
       
   335     // else return sampels ready for playing.
       
   336     // argument is max samples server is looking for,
       
   337     // in terms of current device status.
       
   338     virtual int readySamples(int) = 0;
       
   339 
       
   340     int getSample(int off, int bps) {
       
   341 
       
   342         //
       
   343         //  16-bit audio data is converted to native endian so that it can be scaled
       
   344         //  Yes, this is ugly on a BigEndian machine
       
   345         //  Perhaps it shouldn't be scaled at all
       
   346         //
       
   347         return (bps == 1) ? (data[out+off] - 128) * 128 : qToLittleEndian(((short*)data)[(out/2)+off]);
       
   348     }
       
   349 
       
   350     int add(int* mixl, int* mixr, int count)
       
   351     {
       
   352         int bytesPerSample = chunkdata.wBitsPerSample >> 3;
       
   353 
       
   354         if ( mMuted ) {
       
   355             sampleRunin -= qMin(sampleRunin,count);
       
   356             while (count && (dev != -1)) {
       
   357                 if (out >= *max) {
       
   358                     // switch buffers
       
   359                     out = 0;
       
   360                     if (data == data1 && max2 != 0) {
       
   361                         data = data2;
       
   362                         max = &max2;
       
   363                         max1 = 0;
       
   364                     } else if (data == data2 && max1 != 0) {
       
   365                         data = data1;
       
   366                         max = &max1;
       
   367                         max2 = 0;
       
   368                     } else {
       
   369                         qDebug("QSS Read Error: both buffers empty");
       
   370                         return 0;
       
   371                     }
       
   372                 }
       
   373                 samples_due += sound_speed;
       
   374                 while (count && samples_due >= chunkdata.samplesPerSec) {
       
   375                     samples_due -= chunkdata.samplesPerSec;
       
   376                     count--;
       
   377                 }
       
   378                 out += bytesPerSample * chunkdata.channels;
       
   379             }
       
   380             return count;
       
   381         }
       
   382 
       
   383         // This shouldn't be the case
       
   384         if ( !mixl || !mixr )
       
   385             return 0;
       
   386 
       
   387         int lVolNum = leftVolume, lVolDen = maxVolume;
       
   388         int rVolNum = rightVolume, rVolDen = maxVolume;
       
   389         if (priorityExists > 0 && !isPriority) {
       
   390             lVolNum = 0; // later, make this gradually fade in and out.
       
   391             lVolDen = 5;
       
   392             rVolNum = 0;
       
   393             rVolDen = 5;
       
   394         }
       
   395 
       
   396         while (count && (dev != -1)) {
       
   397             if (out >= *max) {
       
   398                 // switch buffers
       
   399                 out = 0;
       
   400                 if (data == data1 && max2 != 0) {
       
   401                     data = data2;
       
   402                     max = &max2;
       
   403                     max1 = 0;
       
   404                 } else if (data == data2 && max1 != 0) {
       
   405                     data = data1;
       
   406                     max = &max1;
       
   407                     max2 = 0;
       
   408                 } else {
       
   409                     qDebug("QSS Read Error: both buffers empty");
       
   410                     return 0;
       
   411                 }
       
   412             }
       
   413             samples_due += sound_speed;
       
   414             if (count && samples_due >= chunkdata.samplesPerSec) {
       
   415                 int l = getSample(0,bytesPerSample)*lVolNum/lVolDen;
       
   416                 int r = (chunkdata.channels == 2) ? getSample(1,bytesPerSample)*rVolNum/rVolDen : l;
       
   417                 if (!sound_stereo && chunkdata.channels == 2)
       
   418                     l += r;
       
   419 		if (sampleRunin) {
       
   420                     while (sampleRunin && count && samples_due >= chunkdata.samplesPerSec) {
       
   421                         mixl++;
       
   422                         if (sound_stereo)
       
   423                             mixr++;
       
   424                         samples_due -= chunkdata.samplesPerSec;
       
   425 		        sampleRunin--;
       
   426                         count--;
       
   427                     }
       
   428                 }
       
   429                 while (count && samples_due >= chunkdata.samplesPerSec) {
       
   430                     *mixl++ += l;
       
   431                     if (sound_stereo)
       
   432                         *mixr++ += r;
       
   433                     samples_due -= chunkdata.samplesPerSec;
       
   434                     count--;
       
   435                 }
       
   436             }
       
   437 
       
   438             // optimize out manipulation of sample if downsampling and we skip it
       
   439             out += bytesPerSample * chunkdata.channels;
       
   440         }
       
   441 
       
   442         return count;
       
   443     }
       
   444 
       
   445     virtual bool finished() const = 0;
       
   446 
       
   447     bool equal(int wid, int sid)
       
   448     {
       
   449 	return (wid == mWid && sid == mSid);
       
   450     }
       
   451 
       
   452 protected:
       
   453 
       
   454     char * prepareBuffer( int &size)
       
   455     {
       
   456 	// keep reading as long as there is 50 % or more room in off buffer.
       
   457 	if (data == data1 && (max2<<1 < sound_buffer_size)) {
       
   458 	    size=sound_buffer_size - max2;
       
   459 	    return (char *)data2;
       
   460 	} else if (data == data2 && (max1<<1 < sound_buffer_size)) {
       
   461 	    size=sound_buffer_size - max1;
       
   462 	    return (char *)data1;
       
   463 	} else {
       
   464 	    size = 0;
       
   465 	    return 0;
       
   466 	}
       
   467     }
       
   468 
       
   469     void updateBuffer(int read)
       
   470     {
       
   471 	// always reads to off buffer.
       
   472 	if (read >= 0) {
       
   473 	    if (data == data2) {
       
   474 		max1 = read;
       
   475 	    } else {
       
   476 		max2 = read;
       
   477 	    }
       
   478 	}
       
   479     }
       
   480 
       
   481     int devSamples()
       
   482     {
       
   483 	int possible = (((max1+max2-out) / ((chunkdata.wBitsPerSample>>3)*chunkdata.channels))
       
   484 		*sound_speed)/chunkdata.samplesPerSec;
       
   485 
       
   486 	return possible;
       
   487     }
       
   488 
       
   489 
       
   490     struct {
       
   491         qint16 formatTag;
       
   492         qint16 channels;
       
   493         qint32 samplesPerSec;
       
   494         qint32 avgBytesPerSec;
       
   495         qint16 blockAlign;
       
   496         qint16 wBitsPerSample;
       
   497     } chunkdata;
       
   498     int dev;
       
   499     int samples_due;
       
   500 private:
       
   501     int mWid;
       
   502     int mSid;
       
   503     int leftVolume;
       
   504     int rightVolume;
       
   505     bool isPriority;
       
   506     static int priorityExists;
       
   507     int *max;
       
   508     uchar *data;
       
   509     uchar data1[sound_buffer_size+4]; // +4 to handle badly aligned input data
       
   510     uchar data2[sound_buffer_size+4]; // +4 to handle badly aligned input data
       
   511     int out, max1, max2;
       
   512     int sampleRunin;
       
   513     bool mMuted;
       
   514 };
       
   515 
       
   516 int QWSSoundServerProvider::priorityExists = 0;
       
   517 
       
   518 class QWSSoundServerBucket : public QWSSoundServerProvider {
       
   519 public:
       
   520     QWSSoundServerBucket(int d, int wid, int sid)
       
   521 	: QWSSoundServerProvider(wid, sid)
       
   522     {
       
   523 	dev = d;
       
   524 	wavedata_remaining = -1;
       
   525 	mFinishedRead = false;
       
   526 	mInsufficientSamples = false;
       
   527     }
       
   528     ~QWSSoundServerBucket()
       
   529     {
       
   530 	//dev->close();
       
   531 	::close(dev);
       
   532     }
       
   533     bool finished() const
       
   534     {
       
   535 	//return !max;
       
   536 	return mInsufficientSamples && mFinishedRead ;
       
   537     }
       
   538     int readySamples(int)
       
   539     {
       
   540 	int size;
       
   541 	char *dest = prepareBuffer(size);
       
   542 	// may want to change this to something like
       
   543 	// if (data == data1 && max2<<1 < sound_buffer_size
       
   544 	//	||
       
   545 	//	data == data2 && max1<<1 < sound_buffer_size)
       
   546 	// so will keep filling off buffer while there is +50% space left
       
   547 	if (size > 0 && dest != 0) {
       
   548 	    while ( wavedata_remaining < 0 ) {
       
   549 		//max = 0;
       
   550 		wavedata_remaining = -1;
       
   551 		// Keep reading chunks...
       
   552 		const int n = sizeof(chunk)-sizeof(chunk.data);
       
   553 		int nr = ::read(dev, (void*)&chunk,n);
       
   554 		if ( nr != n ) {
       
   555 		    // XXX check error? or don't we care?
       
   556 		    wavedata_remaining = 0;
       
   557 		    mFinishedRead = true;
       
   558 		} else if ( qstrncmp(chunk.id,"data",4) == 0 ) {
       
   559 		    wavedata_remaining = qToLittleEndian( chunk.size );
       
   560 
       
   561 		    //out = max = sound_buffer_size;
       
   562 
       
   563 		} else if ( qstrncmp(chunk.id,"RIFF",4) == 0 ) {
       
   564 		    char d[4];
       
   565 		    if ( read(dev, d, 4) != 4 ) {
       
   566 			// XXX check error? or don't we care?
       
   567 			//qDebug("couldn't read riff");
       
   568 			mInsufficientSamples = true;
       
   569 			mFinishedRead = true;
       
   570 			return 0;
       
   571 		    } else if ( qstrncmp(d,"WAVE",4) != 0 ) {
       
   572 			// skip
       
   573 			if ( chunk.size > 1000000000 || lseek(dev,chunk.size-4, SEEK_CUR) == -1 ) {
       
   574 			    //qDebug("oversized wav chunk");
       
   575 			    mFinishedRead = true;
       
   576 			}
       
   577 		    }
       
   578 		} else if ( qstrncmp(chunk.id,"fmt ",4) == 0 ) {
       
   579 		    if ( ::read(dev,(char*)&chunkdata,sizeof(chunkdata)) != sizeof(chunkdata) ) {
       
   580 			// XXX check error? or don't we care?
       
   581 			//qDebug("couldn't ready chunkdata");
       
   582 			mFinishedRead = true;
       
   583 		    }
       
   584 
       
   585 #define WAVE_FORMAT_PCM 1
       
   586 		    else
       
   587             {
       
   588                 /*
       
   589                 **  Endian Fix the chuck data
       
   590                 */
       
   591                 chunkdata.formatTag         = qToLittleEndian( chunkdata.formatTag );
       
   592                 chunkdata.channels          = qToLittleEndian( chunkdata.channels );
       
   593                 chunkdata.samplesPerSec     = qToLittleEndian( chunkdata.samplesPerSec );
       
   594                 chunkdata.avgBytesPerSec    = qToLittleEndian( chunkdata.avgBytesPerSec );
       
   595                 chunkdata.blockAlign        = qToLittleEndian( chunkdata.blockAlign );
       
   596                 chunkdata.wBitsPerSample    = qToLittleEndian( chunkdata.wBitsPerSample );
       
   597                 if ( chunkdata.formatTag != WAVE_FORMAT_PCM ) {
       
   598                     qWarning("WAV file: UNSUPPORTED FORMAT %d",chunkdata.formatTag);
       
   599                     mFinishedRead = true;
       
   600                 }
       
   601 		    }
       
   602 		} else {
       
   603 		    // ignored chunk
       
   604 		    if ( chunk.size > 1000000000 || lseek(dev, chunk.size, SEEK_CUR) == -1) {
       
   605 			//qDebug("chunk size too big");
       
   606 			mFinishedRead = true;
       
   607 		    }
       
   608 		}
       
   609 	    }
       
   610 	    // this looks wrong.
       
   611 	    if (wavedata_remaining <= 0) {
       
   612 		mFinishedRead = true;
       
   613 	    }
       
   614 
       
   615 	}
       
   616 	// may want to change this to something like
       
   617 	// if (data == data1 && max2<<1 < sound_buffer_size
       
   618 	//	||
       
   619 	//	data == data2 && max1<<1 < sound_buffer_size)
       
   620 	// so will keep filling off buffer while there is +50% space left
       
   621 
       
   622 	if (wavedata_remaining) {
       
   623 	    if (size > 0 && dest != 0) {
       
   624 		int read = ::read(dev, dest, qMin(size, wavedata_remaining));
       
   625 		// XXX check error? or don't we care?
       
   626 		wavedata_remaining -= read;
       
   627 		updateBuffer(read);
       
   628 		if (read <= 0) // data unexpectidly ended
       
   629 		    mFinishedRead = true;
       
   630 	    }
       
   631 	}
       
   632 	int possible = devSamples();
       
   633 	if (possible == 0)
       
   634 	    mInsufficientSamples = true;
       
   635 	return possible;
       
   636     }
       
   637 
       
   638 protected:
       
   639     QRiffChunk chunk;
       
   640     int wavedata_remaining;
       
   641     bool mFinishedRead;
       
   642     bool mInsufficientSamples;
       
   643 };
       
   644 
       
   645 class QWSSoundServerStream : public QWSSoundServerProvider {
       
   646 public:
       
   647     QWSSoundServerStream(int d,int c, int f, int b,
       
   648 	    int wid, int sid)
       
   649 	: QWSSoundServerProvider(wid, sid)
       
   650     {
       
   651 	chunkdata.channels = c;
       
   652 	chunkdata.samplesPerSec = f;
       
   653 	chunkdata.wBitsPerSample = b;
       
   654 	dev = d;
       
   655 	//fcntl( dev, F_SETFL, O_NONBLOCK );
       
   656 	lasttime = 0;
       
   657     }
       
   658 
       
   659     ~QWSSoundServerStream()
       
   660     {
       
   661 	if (dev != -1) {
       
   662 	    ::close(dev);
       
   663 	    dev = -1;
       
   664 	}
       
   665     }
       
   666 
       
   667     bool finished() const
       
   668     {
       
   669 	return (dev == -1);
       
   670     }
       
   671 
       
   672 
       
   673     int readySamples(int)
       
   674     {
       
   675 	int size;
       
   676 	char *dest = prepareBuffer(size);
       
   677 	if (size > 0 && dest != 0 && dev != -1) {
       
   678 
       
   679 	    int read = ::read(dev, dest, size);
       
   680 	    if (read < 0) {
       
   681 		switch(errno) {
       
   682 		    case EAGAIN:
       
   683 		    case EINTR:
       
   684 			// means read may yet succeed on the next attempt
       
   685 			break;
       
   686 		    default:
       
   687 			// unexpected error, fail.
       
   688 			::close(dev);
       
   689 			dev = -1;
       
   690 		}
       
   691 	    } else if (read == 0) {
       
   692 		// 0 means writer has closed dev and/or
       
   693 		// file is at end.
       
   694 		::close(dev);
       
   695 		dev = -1;
       
   696 	    } else {
       
   697 		updateBuffer(read);
       
   698 	    }
       
   699 	}
       
   700 	int possible = devSamples();
       
   701 	if (possible == 0)
       
   702 	    startSampleRunin();
       
   703 	return possible;
       
   704     }
       
   705 
       
   706 protected:
       
   707     time_t lasttime;
       
   708 };
       
   709 
       
   710 #ifndef QT_NO_QWS_SOUNDSERVER
       
   711 QWSSoundServerSocket::QWSSoundServerSocket(QObject *parent) :
       
   712     QWSServerSocket(QT_VFB_SOUND_PIPE(qws_display_id), parent)
       
   713 {
       
   714     connect(this, SIGNAL(newConnection()), this, SLOT(newConnection()));
       
   715 }
       
   716 
       
   717 
       
   718 #ifdef QT3_SUPPORT
       
   719 QWSSoundServerSocket::QWSSoundServerSocket(QObject *parent, const char *name) :
       
   720     QWSServerSocket(QT_VFB_SOUND_PIPE(qws_display_id), parent)
       
   721 {
       
   722     if (name)
       
   723         setObjectName(QString::fromAscii(name));
       
   724     connect(this, SIGNAL(newConnection()), this, SLOT(newConnection()));
       
   725 }
       
   726 #endif
       
   727 
       
   728 void QWSSoundServerSocket::newConnection()
       
   729 {
       
   730     while (QWS_SOCK_BASE *sock = nextPendingConnection()) {
       
   731         QWSSoundServerClient* client = new QWSSoundServerClient(sock,this);
       
   732 
       
   733         connect(client, SIGNAL(play(int,int,QString)),
       
   734                 this, SIGNAL(playFile(int,int,QString)));
       
   735         connect(client, SIGNAL(play(int,int,QString,int,int)),
       
   736                 this, SIGNAL(playFile(int,int,QString,int,int)));
       
   737         connect(client, SIGNAL(playRaw(int,int,QString,int,int,int,int)),
       
   738                 this, SIGNAL(playRawFile(int,int,QString,int,int,int,int)));
       
   739 
       
   740         connect(client, SIGNAL(pause(int,int)),
       
   741                 this, SIGNAL(pauseFile(int,int)));
       
   742         connect(client, SIGNAL(stop(int,int)),
       
   743                 this, SIGNAL(stopFile(int,int)));
       
   744         connect(client, SIGNAL(playPriorityOnly(bool)),
       
   745                 this, SIGNAL(playPriorityOnly(bool)));
       
   746         connect(client, SIGNAL(stopAll(int)),
       
   747                 this, SIGNAL(stopAll(int)));
       
   748         connect(client, SIGNAL(resume(int,int)),
       
   749                 this, SIGNAL(resumeFile(int,int)));
       
   750 
       
   751         connect(client, SIGNAL(setSilent(bool)),
       
   752                 this, SIGNAL(setSilent(bool)));
       
   753 
       
   754         connect(client, SIGNAL(setMute(int,int,bool)),
       
   755                 this, SIGNAL(setMute(int,int,bool)));
       
   756         connect(client, SIGNAL(setVolume(int,int,int,int)),
       
   757                 this, SIGNAL(setVolume(int,int,int,int)));
       
   758 
       
   759         connect(this, SIGNAL(soundFileCompleted(int,int)),
       
   760                 client, SLOT(sendSoundCompleted(int,int)));
       
   761         connect(this, SIGNAL(deviceReady(int,int)),
       
   762                 client, SLOT(sendDeviceReady(int,int)));
       
   763         connect(this, SIGNAL(deviceError(int,int,int)),
       
   764                 client, SLOT(sendDeviceError(int,int,int)));
       
   765     }
       
   766 }
       
   767 
       
   768 #endif
       
   769 
       
   770 class QWSSoundServerPrivate : public QObject {
       
   771     Q_OBJECT
       
   772 
       
   773 public:
       
   774     QWSSoundServerPrivate(QObject* parent=0, const char* name=0) :
       
   775         QObject(parent)
       
   776     {
       
   777 	timerId = 0;
       
   778         if (name)
       
   779             setObjectName(QString::fromAscii(name));
       
   780 #ifndef QT_NO_QWS_SOUNDSERVER
       
   781         server = new QWSSoundServerSocket(this);
       
   782 
       
   783 	connect(server, SIGNAL(playFile(int,int,QString)),
       
   784 		this, SLOT(playFile(int,int,QString)));
       
   785 	connect(server, SIGNAL(playFile(int,int,QString,int,int)),
       
   786 		this, SLOT(playFile(int,int,QString,int,int)));
       
   787 	connect(server, SIGNAL(playRawFile(int,int,QString,int,int,int,int)),
       
   788 		this, SLOT(playRawFile(int,int,QString,int,int,int,int)));
       
   789 
       
   790 	connect(server, SIGNAL(pauseFile(int,int)),
       
   791 		this, SLOT(pauseFile(int,int)));
       
   792 	connect(server, SIGNAL(stopFile(int,int)),
       
   793 		this, SLOT(stopFile(int,int)));
       
   794 	connect(server, SIGNAL(stopAll(int)),
       
   795 		this, SLOT(stopAll(int)));
       
   796 	connect(server, SIGNAL(playPriorityOnly(bool)),
       
   797 		this, SLOT(playPriorityOnly(bool)));
       
   798 	connect(server, SIGNAL(resumeFile(int,int)),
       
   799 		this, SLOT(resumeFile(int,int)));
       
   800 
       
   801         connect( server, SIGNAL(setSilent(bool)),
       
   802                 this, SLOT(setSilent(bool)));
       
   803 
       
   804         connect(server, SIGNAL(setMute(int,int,bool)),
       
   805                 this, SLOT(setMute(int,int,bool)));
       
   806 	connect(server, SIGNAL(setVolume(int,int,int,int)),
       
   807 		this, SLOT(setVolume(int,int,int,int)));
       
   808 
       
   809 	connect(this, SIGNAL(soundFileCompleted(int,int)),
       
   810 		server, SIGNAL(soundFileCompleted(int,int)));
       
   811 	connect(this, SIGNAL(deviceReady(int,int)),
       
   812 		server, SIGNAL(deviceReady(int,int)));
       
   813 	connect(this, SIGNAL(deviceError(int,int,int)),
       
   814 		server, SIGNAL(deviceError(int,int,int)));
       
   815 
       
   816 #endif
       
   817         silent = false;
       
   818         fd = -1;
       
   819         unwritten = 0;
       
   820         can_GETOSPACE = true;
       
   821     }
       
   822 
       
   823     ~QWSSoundServerPrivate()
       
   824     {
       
   825         qDeleteAll(active);
       
   826         qDeleteAll(inactive);
       
   827     }
       
   828 
       
   829 signals:
       
   830     void soundFileCompleted(int, int);
       
   831     void deviceReady(int, int);
       
   832     void deviceError(int, int, int);
       
   833 
       
   834 public slots:
       
   835     void playRawFile(int wid, int sid, const QString &filename, int freq, int channels, int bitspersample, int flags);
       
   836     void playFile(int wid, int sid, const QString& filename);
       
   837     void playFile(int wid, int sid, const QString& filename, int v, int flags);
       
   838     void checkPresetVolumes(int wid, int sid, QWSSoundServerProvider *p);
       
   839     void pauseFile(int wid, int sid);
       
   840     void resumeFile(int wid, int sid);
       
   841     void stopFile(int wid, int sid);
       
   842     void stopAll(int wid);
       
   843     void setVolume(int wid, int sid, int lv, int rv);
       
   844     void setMute(int wid, int sid, bool m);
       
   845     void playPriorityOnly(bool p);
       
   846     void sendCompletedSignals();
       
   847     void feedDevice(int fd);
       
   848     void setSilent( bool enabled );
       
   849 
       
   850 protected:
       
   851     void timerEvent(QTimerEvent* event);
       
   852 
       
   853 private:
       
   854     int openFile(int wid, int sid, const QString& filename);
       
   855     bool openDevice();
       
   856     void closeDevice()
       
   857     {
       
   858         if (fd >= 0) {
       
   859             ::close(fd);
       
   860             fd = -1;
       
   861         }
       
   862     }
       
   863 
       
   864     QList<QWSSoundServerProvider*> active;
       
   865     QList<QWSSoundServerProvider*> inactive;
       
   866     struct PresetVolume {
       
   867 	int wid;
       
   868 	int sid;
       
   869 	int left;
       
   870 	int right;
       
   871 	bool mute;
       
   872     };
       
   873     QList<PresetVolume> volumes;
       
   874     struct CompletedInfo {
       
   875 	CompletedInfo( ) : groupId( 0 ), soundId( 0 ) { }
       
   876 	CompletedInfo( int _groupId, int _soundId ) : groupId( _groupId ), soundId( _soundId ) { }
       
   877 	int groupId;
       
   878 	int soundId;
       
   879     };
       
   880     QList<CompletedInfo> completed;
       
   881 
       
   882     bool silent;
       
   883 
       
   884     int fd;
       
   885     int unwritten;
       
   886     int timerId;
       
   887     char* cursor;
       
   888     short data[sound_buffer_size*2];
       
   889     bool can_GETOSPACE;
       
   890 #ifndef QT_NO_QWS_SOUNDSERVER
       
   891     QWSSoundServerSocket *server;
       
   892 #endif
       
   893 };
       
   894 
       
   895 void QWSSoundServerPrivate::setSilent( bool enabled )
       
   896 {
       
   897     // Close output device
       
   898     closeDevice();
       
   899     if( !unwritten && !active.count() ) {
       
   900         sendCompletedSignals();
       
   901     }
       
   902     // Stop processing audio
       
   903     killTimer( timerId );
       
   904     silent = enabled;
       
   905     // If audio remaining, open output device and continue processing
       
   906     if( unwritten || active.count() ) {
       
   907         openDevice();
       
   908     }
       
   909 }
       
   910 
       
   911 void QWSSoundServerPrivate::timerEvent(QTimerEvent* event)
       
   912 {
       
   913     // qDebug("QSS timer event");
       
   914     if( event->timerId() == timerId ) {
       
   915         if (fd >= 0)
       
   916             feedDevice(fd);
       
   917         if (fd < 0) {
       
   918             killTimer(timerId);
       
   919             timerId = 0;
       
   920         }
       
   921     }
       
   922 }
       
   923 
       
   924 void QWSSoundServerPrivate::playRawFile(int wid, int sid, const QString &filename,
       
   925                                         int freq, int channels, int bitspersample, int flags)
       
   926 {
       
   927 #ifdef QT_NO_QWS_SOUNDSERVER
       
   928     Q_UNUSED(flags);
       
   929 #endif
       
   930     int f = openFile(wid, sid, filename);
       
   931     if ( f ) {
       
   932         QWSSoundServerStream *b = new QWSSoundServerStream(f, channels, freq, bitspersample, wid, sid);
       
   933         // check preset volumes.
       
   934         checkPresetVolumes(wid, sid, b);
       
   935 #ifndef QT_NO_QWS_SOUNDSERVER
       
   936         b->setPriority((flags & QWSSoundClient::Priority) == QWSSoundClient::Priority);
       
   937 #endif
       
   938         active.append(b);
       
   939         emit deviceReady(wid, sid);
       
   940     }
       
   941 }
       
   942 
       
   943 void QWSSoundServerPrivate::playFile(int wid, int sid, const QString& filename)
       
   944 {
       
   945     int f = openFile(wid, sid, filename);
       
   946     if ( f ) {
       
   947         QWSSoundServerProvider *b = new QWSSoundServerBucket(f, wid, sid);
       
   948         checkPresetVolumes(wid, sid, b);
       
   949         active.append( b );
       
   950         emit deviceReady(wid, sid);
       
   951     }
       
   952 }
       
   953 
       
   954 void QWSSoundServerPrivate::playFile(int wid, int sid, const QString& filename,
       
   955                                      int v, int flags)
       
   956 {
       
   957 #ifdef QT_NO_QWS_SOUNDSERVER
       
   958     Q_UNUSED(flags);
       
   959 #endif
       
   960     int f = openFile(wid, sid, filename);
       
   961     if ( f ) {
       
   962         QWSSoundServerProvider *b = new QWSSoundServerBucket(f, wid, sid);
       
   963         checkPresetVolumes(wid, sid, b);
       
   964         b->setVolume(v, v);
       
   965 #ifndef QT_NO_QWS_SOUNDSERVER
       
   966         b->setPriority((flags & QWSSoundClient::Priority) == QWSSoundClient::Priority);
       
   967 #endif
       
   968         active.append(b);
       
   969         emit deviceReady(wid, sid);
       
   970     }
       
   971 }
       
   972 
       
   973 void QWSSoundServerPrivate::checkPresetVolumes(int wid, int sid, QWSSoundServerProvider *p)
       
   974 {
       
   975     QList<PresetVolume>::Iterator it = volumes.begin();
       
   976     while (it != volumes.end()) {
       
   977         PresetVolume v = *it;
       
   978         if (v.wid == wid && v.sid == sid) {
       
   979             p->setVolume(v.left, v.right);
       
   980             p->setMute(v.mute);
       
   981             it = volumes.erase(it);
       
   982             return;
       
   983         } else {
       
   984             ++it;
       
   985         }
       
   986     }
       
   987 }
       
   988 
       
   989 void QWSSoundServerPrivate::pauseFile(int wid, int sid)
       
   990 {
       
   991     QWSSoundServerProvider *bucket;
       
   992     for (int i = 0; i < active.size(); ++i ) {
       
   993         bucket = active.at(i);
       
   994         if (bucket->equal(wid, sid)) {
       
   995             // found bucket....
       
   996             active.removeAt(i);
       
   997             inactive.append(bucket);
       
   998             return;
       
   999         }
       
  1000     }
       
  1001 }
       
  1002 
       
  1003 void QWSSoundServerPrivate::resumeFile(int wid, int sid)
       
  1004 {
       
  1005     QWSSoundServerProvider *bucket;
       
  1006     for (int i = 0; i < inactive.size(); ++i ) {
       
  1007         bucket = inactive.at(i);
       
  1008         if (bucket->equal(wid, sid)) {
       
  1009             // found bucket....
       
  1010             inactive.removeAt(i);
       
  1011             active.append(bucket);
       
  1012             return;
       
  1013         }
       
  1014     }
       
  1015 }
       
  1016 
       
  1017 void QWSSoundServerPrivate::stopFile(int wid, int sid)
       
  1018 {
       
  1019     QWSSoundServerProvider *bucket;
       
  1020     for (int i = 0; i < active.size(); ++i ) {
       
  1021         bucket = active.at(i);
       
  1022         if (bucket->equal(wid, sid)) {
       
  1023             active.removeAt(i);
       
  1024             delete bucket;
       
  1025             return;
       
  1026         }
       
  1027     }
       
  1028     for (int i = 0; i < inactive.size(); ++i ) {
       
  1029         bucket = inactive.at(i);
       
  1030         if (bucket->equal(wid, sid)) {
       
  1031             inactive.removeAt(i);
       
  1032             delete bucket;
       
  1033             return;
       
  1034         }
       
  1035     }
       
  1036 }
       
  1037 
       
  1038 void QWSSoundServerPrivate::stopAll(int wid)
       
  1039 {
       
  1040     QWSSoundServerProvider *bucket;
       
  1041     if (!active.isEmpty()) {
       
  1042         QList<QWSSoundServerProvider*>::Iterator it = active.begin();
       
  1043         while (it != active.end()) {
       
  1044             bucket = *it;
       
  1045             if (bucket->groupId() == wid) {
       
  1046                 it = active.erase(it);
       
  1047                 delete bucket;
       
  1048             } else {
       
  1049                 ++it;
       
  1050             }
       
  1051         }
       
  1052     }
       
  1053     if (!inactive.isEmpty()) {
       
  1054         QList<QWSSoundServerProvider*>::Iterator it = inactive.begin();
       
  1055         while (it != inactive.end()) {
       
  1056             bucket = *it;
       
  1057             if (bucket->groupId() == wid) {
       
  1058                 it = inactive.erase(it);
       
  1059                 delete bucket;
       
  1060             } else {
       
  1061                 ++it;
       
  1062             }
       
  1063         }
       
  1064     }
       
  1065 }
       
  1066 
       
  1067 void QWSSoundServerPrivate::setVolume(int wid, int sid, int lv, int rv)
       
  1068 {
       
  1069     QWSSoundServerProvider *bucket;
       
  1070     for( int i = 0; i < active.size(); ++i ) {
       
  1071         bucket = active.at(i);
       
  1072         if (bucket->equal(wid, sid)) {
       
  1073             bucket->setVolume(lv,rv);
       
  1074             return;
       
  1075         }
       
  1076     }
       
  1077     // If gotten here, then it means wid/sid wasn't set up yet.
       
  1078     // first find and remove current preset volumes, then add this one.
       
  1079     QList<PresetVolume>::Iterator it = volumes.begin();
       
  1080     while (it != volumes.end()) {
       
  1081         PresetVolume v = *it;
       
  1082         if (v.wid == wid && v.sid == sid)
       
  1083             it = volumes.erase(it);
       
  1084         else
       
  1085             ++it;
       
  1086     }
       
  1087     // and then add this volume
       
  1088     PresetVolume nv;
       
  1089     nv.wid = wid;
       
  1090     nv.sid = sid;
       
  1091     nv.left = lv;
       
  1092     nv.right = rv;
       
  1093     nv.mute = false;
       
  1094     volumes.append(nv);
       
  1095 }
       
  1096 
       
  1097 void QWSSoundServerPrivate::setMute(int wid, int sid, bool m)
       
  1098 {
       
  1099     QWSSoundServerProvider *bucket;
       
  1100     for( int i = 0; i < active.size(); ++i ) {
       
  1101         bucket = active.at(i);
       
  1102         if (bucket->equal(wid, sid)) {
       
  1103             bucket->setMute(m);
       
  1104             return;
       
  1105         }
       
  1106     }
       
  1107     // if gotten here then setting is being applied before item
       
  1108     // is created.
       
  1109     QList<PresetVolume>::Iterator it = volumes.begin();
       
  1110     while (it != volumes.end()) {
       
  1111         PresetVolume v = *it;
       
  1112         if (v.wid == wid && v.sid == sid) {
       
  1113             (*it).mute = m;
       
  1114             return;
       
  1115         }
       
  1116     }
       
  1117     if (m) {
       
  1118         PresetVolume nv;
       
  1119         nv.wid = wid;
       
  1120         nv.sid = sid;
       
  1121         nv.left = maxVolume>>1;
       
  1122         nv.right = maxVolume>>1;
       
  1123         nv.mute = true;
       
  1124         volumes.append(nv);
       
  1125     }
       
  1126 }
       
  1127 
       
  1128 void QWSSoundServerPrivate::playPriorityOnly(bool p)
       
  1129 {
       
  1130     QWSSoundServerProvider::setPlayPriorityOnly(p);
       
  1131 }
       
  1132 
       
  1133 void QWSSoundServerPrivate::sendCompletedSignals()
       
  1134 {
       
  1135     while( !completed.isEmpty() ) {
       
  1136         emit soundFileCompleted( (*completed.begin()).groupId,
       
  1137             (*completed.begin()).soundId );
       
  1138             completed.erase( completed.begin() );
       
  1139     }
       
  1140 }
       
  1141 
       
  1142 
       
  1143 int QWSSoundServerPrivate::openFile(int wid, int sid, const QString& filename)
       
  1144 {
       
  1145     stopFile(wid, sid); // close and re-open.
       
  1146     int f = QT_OPEN(QFile::encodeName(filename), O_RDONLY|O_NONBLOCK);
       
  1147     if (f == -1) {
       
  1148         // XXX check ferror, check reason.
       
  1149         qDebug("Failed opening \"%s\"",filename.toLatin1().data());
       
  1150 #ifndef QT_NO_QWS_SOUNDSERVER
       
  1151         emit deviceError(wid, sid, (int)QWSSoundClient::ErrOpeningFile );
       
  1152 #endif
       
  1153     } else if ( openDevice() ) {
       
  1154         return f;
       
  1155     }
       
  1156 #ifndef QT_NO_QWS_SOUNDSERVER
       
  1157     emit deviceError(wid, sid, (int)QWSSoundClient::ErrOpeningAudioDevice );
       
  1158 #endif
       
  1159     return 0;
       
  1160 }
       
  1161 
       
  1162 bool QWSSoundServerPrivate::openDevice()
       
  1163 {
       
  1164         if (fd < 0) {
       
  1165             if( silent ) {
       
  1166                 fd = QT_OPEN( "/dev/null", O_WRONLY );
       
  1167                 // Emulate write to audio device
       
  1168                 int delay = 1000*(sound_buffer_size>>(sound_stereo+sound_16bit))/sound_speed/2;
       
  1169                 timerId = startTimer(delay);
       
  1170 
       
  1171                 return true;
       
  1172             }
       
  1173             //
       
  1174             // Don't block open right away.
       
  1175             //
       
  1176             bool openOkay = false;
       
  1177             if ((fd = QT_OPEN("/dev/dsp", O_WRONLY|O_NONBLOCK)) != -1) {
       
  1178                 int flags = fcntl(fd, F_GETFL);
       
  1179                 flags &= ~O_NONBLOCK;
       
  1180 		openOkay = (fcntl(fd, F_SETFL, flags) == 0);
       
  1181 	    }
       
  1182             if (!openOkay) {
       
  1183 	        qDebug("Failed opening audio device");
       
  1184 		return false;
       
  1185             }
       
  1186 
       
  1187             // Setup soundcard at 16 bit mono
       
  1188             int v;
       
  1189 	    //v=0x00010000+sound_fragment_size;
       
  1190 	    // um the media player did this instead.
       
  1191 	    v=0x10000 * 4 + sound_fragment_size;
       
  1192             if (ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &v))
       
  1193                 qWarning("Could not set fragments to %08x",v);
       
  1194 #ifdef QT_QWS_SOUND_16BIT
       
  1195             //
       
  1196             //  Use native endian
       
  1197             //  Since we have manipulated the data volume the data
       
  1198             //  is now in native format, even though its stored
       
  1199             //  as little endian in the WAV file
       
  1200             //
       
  1201             v=AFMT_S16_NE; if (ioctl(fd, SNDCTL_DSP_SETFMT, &v))
       
  1202                 qWarning("Could not set format %d",v);
       
  1203             if (AFMT_S16_NE != v)
       
  1204                 qDebug("Want format %d got %d", AFMT_S16_LE, v);
       
  1205 #else
       
  1206             v=AFMT_U8; if (ioctl(fd, SNDCTL_DSP_SETFMT, &v))
       
  1207                 qWarning("Could not set format %d",v);
       
  1208             if (AFMT_U8 != v)
       
  1209                 qDebug("Want format %d got %d", AFMT_U8, v);
       
  1210 #endif
       
  1211             v=sound_stereo; if (ioctl(fd, SNDCTL_DSP_STEREO, &v))
       
  1212                 qWarning("Could not set stereo %d",v);
       
  1213             if (sound_stereo != v)
       
  1214                 qDebug("Want stereo %d got %d", sound_stereo, v);
       
  1215 #ifdef QT_QWS_SOUND_STEREO
       
  1216             sound_stereo=v;
       
  1217 #endif
       
  1218             v=sound_speed; if (ioctl(fd, SNDCTL_DSP_SPEED, &sound_speed))
       
  1219                 qWarning("Could not set speed %d",v);
       
  1220             if (v != sound_speed)
       
  1221                 qDebug("Want speed %d got %d", v, sound_speed);
       
  1222 
       
  1223             int delay = 1000*(sound_buffer_size>>(sound_stereo+sound_16bit))
       
  1224                                     /sound_speed/2;
       
  1225 	    // qDebug("QSS delay: %d", delay);
       
  1226             timerId = startTimer(delay);
       
  1227 
       
  1228 	    //
       
  1229 	    // Check system volume
       
  1230 	    //
       
  1231 	    int mixerHandle = QT_OPEN( "/dev/mixer", O_RDWR|O_NONBLOCK );
       
  1232 	    if ( mixerHandle >= 0 ) {
       
  1233 		int volume;
       
  1234 		ioctl( mixerHandle, MIXER_READ(0), &volume );
       
  1235 		close( mixerHandle );
       
  1236 		if ( volume < 1<<(sound_stereo+sound_16bit) )
       
  1237 		    qDebug("Want sound at %d got %d",
       
  1238 			    1<<(sound_stereo+sound_16bit), volume);
       
  1239 	    } else
       
  1240 		qDebug( "get volume of audio device failed" );
       
  1241 
       
  1242         }
       
  1243         return true;
       
  1244 }
       
  1245 
       
  1246 void  QWSSoundServerPrivate::feedDevice(int fd)
       
  1247 {
       
  1248     if ( !unwritten && active.size() == 0 ) {
       
  1249         closeDevice();
       
  1250         sendCompletedSignals();
       
  1251         return;
       
  1252     } else {
       
  1253         sendCompletedSignals();
       
  1254     }
       
  1255 
       
  1256     QWSSoundServerProvider* bucket;
       
  1257 
       
  1258     // find out how much audio is possible
       
  1259     int available = sound_buffer_size;
       
  1260     QList<QWSSoundServerProvider*> running;
       
  1261     for (int i = 0; i < active.size(); ++i) {
       
  1262         bucket = active.at(i);
       
  1263         int ready = bucket->readySamples(available);
       
  1264         if (ready > 0) {
       
  1265             available = qMin(available, ready);
       
  1266             running.append(bucket);
       
  1267         }
       
  1268     }
       
  1269 
       
  1270     audio_buf_info info;
       
  1271     if (can_GETOSPACE && ioctl(fd,SNDCTL_DSP_GETOSPACE,&info)) {
       
  1272         can_GETOSPACE = false;
       
  1273         fcntl(fd, F_SETFL, O_NONBLOCK);
       
  1274     }
       
  1275     if (!can_GETOSPACE)
       
  1276         info.fragments = 4; // #### configurable?
       
  1277     if (info.fragments > 0) {
       
  1278         if (!unwritten) {
       
  1279             int left[sound_buffer_size];
       
  1280             memset(left,0,available*sizeof(int));
       
  1281             int right[sound_buffer_size];
       
  1282             if ( sound_stereo )
       
  1283                 memset(right,0,available*sizeof(int));
       
  1284 
       
  1285             if (running.size() > 0) {
       
  1286             // should do volume mod here in regards to each bucket to avoid flattened/bad peaks.
       
  1287                 for (int i = 0; i < running.size(); ++i ) {
       
  1288                     bucket = running.at(i);
       
  1289                     int unused = bucket->add(left,right,available);
       
  1290                     if (unused > 0) {
       
  1291                         // this error is quite serious, as
       
  1292                         // it will really screw up mixing.
       
  1293                         qDebug("provider lied about samples ready");
       
  1294                     }
       
  1295                 }
       
  1296                 if ( sound_16bit ) {
       
  1297                     short *d = (short*)data;
       
  1298                     for (int i=0; i<available; i++) {
       
  1299                         *d++ = (short)qMax(qMin(left[i],32767),-32768);
       
  1300                         if ( sound_stereo )
       
  1301                             *d++ = (short)qMax(qMin(right[i],32767),-32768);
       
  1302                     }
       
  1303                 } else {
       
  1304                     signed char *d = (signed char *)data;
       
  1305                     for (int i=0; i<available; i++) {
       
  1306                         *d++ = (signed char)qMax(qMin(left[i]/256,127),-128)+128;
       
  1307                         if ( sound_stereo )
       
  1308                             *d++ = (signed char)qMax(qMin(right[i]/256,127),-128)+128;
       
  1309                     }
       
  1310                 }
       
  1311                 unwritten = available*(sound_16bit+1)*(sound_stereo+1);
       
  1312                 cursor = (char*)data;
       
  1313             }
       
  1314         }
       
  1315         // sound open, but nothing written.  Should clear the buffer.
       
  1316 
       
  1317         int w;
       
  1318         if (unwritten) {
       
  1319             w = ::write(fd,cursor,unwritten);
       
  1320 
       
  1321             if (w < 0) {
       
  1322                 if (can_GETOSPACE)
       
  1323                     return;
       
  1324                 w = 0;
       
  1325             }
       
  1326 
       
  1327             cursor += w;
       
  1328             unwritten -= w;
       
  1329         } else {
       
  1330             // write some zeros to clear the buffer?
       
  1331             if (!zeroMem)
       
  1332                 zeroMem = (char *)calloc(sound_buffer_size, sizeof(char));
       
  1333             w = ::write(fd, zeroMem, sound_buffer_size);
       
  1334             if (w < 0)
       
  1335                 w = 0;
       
  1336         }
       
  1337     }
       
  1338 
       
  1339     QList<QWSSoundServerProvider*>::Iterator it = active.begin();
       
  1340     while (it != active.end()) {
       
  1341         bucket = *it;
       
  1342         if (bucket->finished()) {
       
  1343             completed.append(CompletedInfo(bucket->groupId(), bucket->soundId()));
       
  1344             it = active.erase(it);
       
  1345             delete bucket;
       
  1346         } else {
       
  1347             ++it;
       
  1348         }
       
  1349     }
       
  1350 }
       
  1351 
       
  1352 
       
  1353 QWSSoundServer::QWSSoundServer(QObject* parent) :
       
  1354     QObject(parent)
       
  1355 {
       
  1356     d = new QWSSoundServerPrivate(this);
       
  1357 
       
  1358     connect( d, SIGNAL(soundFileCompleted(int,int)),
       
  1359         this, SLOT(translateSoundCompleted(int,int)) );
       
  1360 }
       
  1361 
       
  1362 void QWSSoundServer::playFile( int sid, const QString& filename )
       
  1363 {
       
  1364     //wid == 0, as it is the server initiating rather than a client
       
  1365     // if wid was passable, would accidently collide with server
       
  1366     // sockect's wids.
       
  1367     d->playFile(0, sid, filename);
       
  1368 }
       
  1369 
       
  1370 void QWSSoundServer::pauseFile( int sid )
       
  1371 {
       
  1372     d->pauseFile(0, sid);
       
  1373 }
       
  1374 
       
  1375 void QWSSoundServer::stopFile( int sid )
       
  1376 {
       
  1377     d->stopFile(0, sid);
       
  1378 }
       
  1379 
       
  1380 void QWSSoundServer::resumeFile( int sid )
       
  1381 {
       
  1382     d->resumeFile(0, sid);
       
  1383 }
       
  1384 
       
  1385 QWSSoundServer::~QWSSoundServer()
       
  1386 {
       
  1387     d->stopAll(0);
       
  1388 }
       
  1389 
       
  1390 void QWSSoundServer::translateSoundCompleted( int, int sid )
       
  1391 {
       
  1392     emit soundCompleted( sid );
       
  1393 }
       
  1394 
       
  1395 #ifndef QT_NO_QWS_SOUNDSERVER
       
  1396 QWSSoundClient::QWSSoundClient(QObject* parent) :
       
  1397     QWSSocket(parent)
       
  1398 {
       
  1399     connectToLocalFile(QT_VFB_SOUND_PIPE(qws_display_id));
       
  1400     QObject::connect(this,SIGNAL(readyRead()),
       
  1401 	this,SLOT(tryReadCommand()));
       
  1402     if( state() == QWS_SOCK_BASE::ConnectedState ) QTimer::singleShot(1, this, SIGNAL(connected()));
       
  1403     else QTimer::singleShot(1, this, SLOT(emitConnectionRefused()));
       
  1404 }
       
  1405 
       
  1406 QWSSoundClient::~QWSSoundClient( )
       
  1407 {
       
  1408     flush();
       
  1409 }
       
  1410 
       
  1411 void QWSSoundClient::reconnect()
       
  1412 {
       
  1413     connectToLocalFile(QT_VFB_SOUND_PIPE(qws_display_id));
       
  1414     if( state() == QWS_SOCK_BASE::ConnectedState ) emit connected();
       
  1415     else emit error( QTcpSocket::ConnectionRefusedError );
       
  1416 }
       
  1417 
       
  1418 void QWSSoundClient::sendServerMessage(QString msg)
       
  1419 {
       
  1420 #ifndef QT_NO_TEXTCODEC
       
  1421     QByteArray u = msg.toUtf8();
       
  1422 #else
       
  1423     QByteArray u = msg.toLatin1();
       
  1424 #endif
       
  1425     write(u.data(), u.length());
       
  1426     flush();
       
  1427 }
       
  1428 
       
  1429 void QWSSoundClient::play( int id, const QString& filename )
       
  1430 {
       
  1431     QFileInfo fi(filename);
       
  1432     sendServerMessage(QLatin1String("PLAY ")
       
  1433                       + QString::number(id) + QLatin1Char(' ')
       
  1434                       + fi.absoluteFilePath() + QLatin1Char('\n'));
       
  1435 }
       
  1436 
       
  1437 void QWSSoundClient::play( int id, const QString& filename, int volume, int flags)
       
  1438 {
       
  1439     QFileInfo fi(filename);
       
  1440     sendServerMessage(QLatin1String("PLAYEXTEND ")
       
  1441         + QString::number(id) + QLatin1Char(' ')
       
  1442         + QString::number(volume) + QLatin1Char(' ')
       
  1443         + QString::number(flags) + QLatin1Char(' ')
       
  1444         + fi.absoluteFilePath() + QLatin1Char('\n'));
       
  1445 }
       
  1446 
       
  1447 void QWSSoundClient::pause( int id )
       
  1448 {
       
  1449     sendServerMessage(QLatin1String("PAUSE ")
       
  1450         + QString::number(id) + QLatin1Char('\n'));
       
  1451 }
       
  1452 
       
  1453 void QWSSoundClient::stop( int id )
       
  1454 {
       
  1455     sendServerMessage(QLatin1String("STOP ")
       
  1456         + QString::number(id) + QLatin1Char('\n'));
       
  1457 }
       
  1458 
       
  1459 void QWSSoundClient::resume( int id )
       
  1460 {
       
  1461     sendServerMessage(QLatin1String("RESUME ")
       
  1462         + QString::number(id) + QLatin1Char('\n'));
       
  1463 }
       
  1464 
       
  1465 void QWSSoundClient::playRaw( int id, const QString& filename,
       
  1466 	int freq, int chs, int bitspersample, int flags)
       
  1467 {
       
  1468     QFileInfo fi(filename);
       
  1469     sendServerMessage(QLatin1String("PLAYRAW ")
       
  1470         + QString::number(id) + QLatin1Char(' ')
       
  1471         + QString::number(chs) + QLatin1Char(' ')
       
  1472         + QString::number(freq) + QLatin1Char(' ')
       
  1473         + QString::number(bitspersample) + QLatin1Char(' ')
       
  1474         + QString::number(flags) + QLatin1Char(' ')
       
  1475         + fi.absoluteFilePath() + QLatin1Char('\n'));
       
  1476 }
       
  1477 
       
  1478 void QWSSoundClient::setMute( int id, bool m )
       
  1479 {
       
  1480     sendServerMessage(QLatin1String(m ? "MUTE " : "UNMUTE ")
       
  1481         + QString::number(id) + QLatin1Char('\n'));
       
  1482 }
       
  1483 
       
  1484 void QWSSoundClient::setVolume( int id, int leftVol, int rightVol )
       
  1485 {
       
  1486     sendServerMessage(QLatin1String("SETVOLUME ")
       
  1487         + QString::number(id) + QLatin1Char(' ')
       
  1488         + QString::number(leftVol) + QLatin1Char(' ')
       
  1489         + QString::number(rightVol) + QLatin1Char('\n'));
       
  1490 }
       
  1491 
       
  1492 void QWSSoundClient::playPriorityOnly( bool pri )
       
  1493 {
       
  1494     sendServerMessage(QLatin1String("PRIORITYONLY ")
       
  1495         + QString::number(pri ? 1 : 0) + QLatin1Char('\n'));
       
  1496 }
       
  1497 
       
  1498 void QWSSoundClient::setSilent( bool enable )
       
  1499 {
       
  1500     sendServerMessage(QLatin1String("SILENT ")
       
  1501             + QString::number( enable ? 1 : 0 ) + QLatin1Char('\n'));
       
  1502 }
       
  1503 
       
  1504 void QWSSoundClient::tryReadCommand()
       
  1505 {
       
  1506     while ( canReadLine() ) {
       
  1507 	QString l = QString::fromAscii(readLine());
       
  1508 	l.truncate(l.length()-1); // chomp
       
  1509 	QStringList token = l.split(QLatin1Char(' '));
       
  1510 	if (token[0] == QLatin1String("SOUNDCOMPLETED")) {
       
  1511 	    emit soundCompleted(token[1].toInt());
       
  1512 	} else if (token[0] == QLatin1String("DEVICEREADY")) {
       
  1513             emit deviceReady(token[1].toInt());
       
  1514 	} else if (token[0] == QLatin1String("DEVICEERROR")) {
       
  1515             emit deviceError(token[1].toInt(),(DeviceErrors)token[2].toInt());
       
  1516 	}
       
  1517     }
       
  1518 }
       
  1519 
       
  1520 void QWSSoundClient::emitConnectionRefused()
       
  1521 {
       
  1522     emit error( QTcpSocket::ConnectionRefusedError );
       
  1523 }
       
  1524 #endif
       
  1525 
       
  1526 QT_END_NAMESPACE
       
  1527 
       
  1528 #include "qsoundqss_qws.moc"
       
  1529 
       
  1530 #endif        // QT_NO_SOUND