1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file.  Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
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;
nextId()154     static int nextId() { return ++lastId; }
155     QPointer<QWS_SOCK_BASE> socket;
156 };
157 
158 int QWSSoundServerClient::lastId = 0;
159 
QWSSoundServerClient(QWS_SOCK_BASE * s,QObject * parent)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 
~QWSSoundServerClient()171 QWSSoundServerClient::~QWSSoundServerClient()
172 {
173     if (priExist)
174 	playPriorityOnly(false);
175     emit stopAll(mCurrentID);
176     if (socket)
177         socket->deleteLater();
178 }
179 
getStringTok(QString & in)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 
getNumTok(QString & in)194 static int getNumTok(QString &in)
195 {
196     return getStringTok(in).toInt();
197 }
198 
tryReadCommand()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 
sendClientMessage(QString msg)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 
sendSoundCompleted(int gid,int sid)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 
sendDeviceReady(int gid,int sid)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 
sendDeviceError(int gid,int sid,int err)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:
QWSSoundServerProvider(int w,int s)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 
~QWSSoundServerProvider()296     virtual ~QWSSoundServerProvider() {
297     }
298 
groupId() const299     int groupId() const { return mWid; }
soundId() const300     int soundId() const { return mSid; }
301 
startSampleRunin()302     void startSampleRunin() {
303 	// inteded to provide even audio return from mute/pause/dead samples.
304 	//sampleRunin = runinLength; // or more?
305     }
306 
307 
setVolume(int lv,int rv)308     void setVolume(int lv, int rv) {
309 	leftVolume = qMin(maxVolume, qMax(0, lv));
310 	rightVolume = qMin(maxVolume, qMax(0, rv));
311     }
312 
setMute(bool m)313     void setMute(bool m) { mMuted = m; }
muted()314     bool muted() { return mMuted; }
315 
setPriority(bool p)316     void setPriority(bool p) {
317 	if (p != isPriority) {
318 	    isPriority = p; // currently meaningless.
319 	}
320     }
321 
322 
setPlayPriorityOnly(bool p)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 
getSample(int off,int bps)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 
add(int * mixl,int * mixr,int count)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 
equal(int wid,int sid)447     bool equal(int wid, int sid)
448     {
449 	return (wid == mWid && sid == mSid);
450     }
451 
452 protected:
453 
prepareBuffer(int & size)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 
updateBuffer(int read)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 
devSamples()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:
QWSSoundServerBucket(int d,int wid,int sid)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     }
~QWSSoundServerBucket()528     ~QWSSoundServerBucket()
529     {
530 	//dev->close();
531 	::close(dev);
532     }
finished() const533     bool finished() const
534     {
535 	//return !max;
536 	return mInsufficientSamples && mFinishedRead ;
537     }
readySamples(int)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:
QWSSoundServerStream(int d,int c,int f,int b,int wid,int sid)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 
~QWSSoundServerStream()659     ~QWSSoundServerStream()
660     {
661 	if (dev != -1) {
662 	    ::close(dev);
663 	    dev = -1;
664 	}
665     }
666 
finished() const667     bool finished() const
668     {
669 	return (dev == -1);
670     }
671 
672 
readySamples(int)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
QWSSoundServerSocket(QObject * parent)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
QWSSoundServerSocket(QObject * parent,const char * name)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 
newConnection()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:
QWSSoundServerPrivate(QObject * parent=0,const char * name=0)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 
~QWSSoundServerPrivate()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();
closeDevice()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 {
CompletedInfoQWSSoundServerPrivate::CompletedInfo875 	CompletedInfo( ) : groupId( 0 ), soundId( 0 ) { }
CompletedInfoQWSSoundServerPrivate::CompletedInfo876 	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 
setSilent(bool enabled)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 
timerEvent(QTimerEvent * event)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 
playRawFile(int wid,int sid,const QString & filename,int freq,int channels,int bitspersample,int flags)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 
playFile(int wid,int sid,const QString & filename)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 
playFile(int wid,int sid,const QString & filename,int v,int flags)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 
checkPresetVolumes(int wid,int sid,QWSSoundServerProvider * p)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 
pauseFile(int wid,int sid)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 
resumeFile(int wid,int sid)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 
stopFile(int wid,int sid)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 
stopAll(int wid)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 
setVolume(int wid,int sid,int lv,int rv)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 
setMute(int wid,int sid,bool m)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 
playPriorityOnly(bool p)1128 void QWSSoundServerPrivate::playPriorityOnly(bool p)
1129 {
1130     QWSSoundServerProvider::setPlayPriorityOnly(p);
1131 }
1132 
sendCompletedSignals()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 
openFile(int wid,int sid,const QString & filename)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 
openDevice()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 
feedDevice(int fd)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 
QWSSoundServer(QObject * parent)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 
playFile(int sid,const QString & filename)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 
pauseFile(int sid)1370 void QWSSoundServer::pauseFile( int sid )
1371 {
1372     d->pauseFile(0, sid);
1373 }
1374 
stopFile(int sid)1375 void QWSSoundServer::stopFile( int sid )
1376 {
1377     d->stopFile(0, sid);
1378 }
1379 
resumeFile(int sid)1380 void QWSSoundServer::resumeFile( int sid )
1381 {
1382     d->resumeFile(0, sid);
1383 }
1384 
~QWSSoundServer()1385 QWSSoundServer::~QWSSoundServer()
1386 {
1387     d->stopAll(0);
1388 }
1389 
translateSoundCompleted(int,int sid)1390 void QWSSoundServer::translateSoundCompleted( int, int sid )
1391 {
1392     emit soundCompleted( sid );
1393 }
1394 
1395 #ifndef QT_NO_QWS_SOUNDSERVER
QWSSoundClient(QObject * parent)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 
~QWSSoundClient()1406 QWSSoundClient::~QWSSoundClient( )
1407 {
1408     flush();
1409 }
1410 
reconnect()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 
sendServerMessage(QString msg)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 
play(int id,const QString & filename)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 
play(int id,const QString & filename,int volume,int flags)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 
pause(int id)1447 void QWSSoundClient::pause( int id )
1448 {
1449     sendServerMessage(QLatin1String("PAUSE ")
1450         + QString::number(id) + QLatin1Char('\n'));
1451 }
1452 
stop(int id)1453 void QWSSoundClient::stop( int id )
1454 {
1455     sendServerMessage(QLatin1String("STOP ")
1456         + QString::number(id) + QLatin1Char('\n'));
1457 }
1458 
resume(int id)1459 void QWSSoundClient::resume( int id )
1460 {
1461     sendServerMessage(QLatin1String("RESUME ")
1462         + QString::number(id) + QLatin1Char('\n'));
1463 }
1464 
playRaw(int id,const QString & filename,int freq,int chs,int bitspersample,int flags)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 
setMute(int id,bool m)1478 void QWSSoundClient::setMute( int id, bool m )
1479 {
1480     sendServerMessage(QLatin1String(m ? "MUTE " : "UNMUTE ")
1481         + QString::number(id) + QLatin1Char('\n'));
1482 }
1483 
setVolume(int id,int leftVol,int rightVol)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 
playPriorityOnly(bool pri)1492 void QWSSoundClient::playPriorityOnly( bool pri )
1493 {
1494     sendServerMessage(QLatin1String("PRIORITYONLY ")
1495         + QString::number(pri ? 1 : 0) + QLatin1Char('\n'));
1496 }
1497 
setSilent(bool enable)1498 void QWSSoundClient::setSilent( bool enable )
1499 {
1500     sendServerMessage(QLatin1String("SILENT ")
1501             + QString::number( enable ? 1 : 0 ) + QLatin1Char('\n'));
1502 }
1503 
tryReadCommand()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 
emitConnectionRefused()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
1531