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