Qt 4.8
qsoundqss_qws.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
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 Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/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 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include "qsoundqss_qws.h"
43 
44 #ifndef QT_NO_SOUND
45 #include <qbytearray.h>
46 #include <qlist.h>
47 #include <qsocketnotifier.h>
48 #include <qfile.h>
49 #include <qfileinfo.h>
50 #include <qstringlist.h>
51 #include <qevent.h>
52 #include <qalgorithms.h>
53 #include <qtimer.h>
54 #include <qpointer.h>
55 #include <qendian.h>
56 #include <private/qcore_unix_p.h> // overrides QT_OPEN
57 
58 #include <unistd.h>
59 #include <stdlib.h>
60 #include <fcntl.h>
61 #include <errno.h>
62 #include <time.h>
63 #include <sys/types.h>
64 #include <sys/stat.h>
65 #include <sys/ioctl.h>
66 #include <sys/soundcard.h>
67 
68 #include <qdebug.h>
69 
70 #include <qvfbhdr.h>
71 
72 extern int errno;
73 
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];
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
106 #else
107 static const int sound_stereo=0;
108 #endif
109 #ifdef QT_QWS_SOUND_16BIT
111 #else
112 static const bool sound_16bit=false;
113 #endif
114 
115 #ifndef QT_NO_QWS_SOUNDSERVER
117  Q_OBJECT
118 
119 public:
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);
151  int left, right;
152  bool priExist;
153  static int lastId;
154  static int nextId() { return ++lastId; }
156 };
157 
159 
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 
172 {
173  if (priExist)
174  playPriorityOnly(false);
176  if (socket)
177  socket->deleteLater();
178 }
179 
181 {
182  int pos = in.indexOf(QLatin1Char(' '));
183  QString ret;
184  if (pos > 0) {
185  ret = in.left(pos);
186  in = in.mid(pos+1);
187  } else {
188  ret = in;
189  in = QString::null;
190  }
191  return ret;
192 }
193 
194 static int getNumTok(QString &in)
195 {
196  return getStringTok(in).toInt();
197 }
198 
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 
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 
256 {
257  if (gid == mCurrentID)
258  sendClientMessage(QLatin1String("SOUNDCOMPLETED ")
259  + QString::number(sid) + QLatin1Char('\n'));
260 }
261 
263 {
264  if (gid == mCurrentID)
265  sendClientMessage(QLatin1String("DEVICEREADY ")
266  + QString::number(sid) + QLatin1Char('\n'));
267 }
268 
269 void QWSSoundServerClient::sendDeviceError(int gid, int sid, int err)
270 {
271  if (gid == mCurrentID)
272  sendClientMessage(QLatin1String("DEVICEERROR ")
273  + QString::number(sid) + QLatin1Char(' ')
274  + QString::number(err) + QLatin1Char('\n'));
275 }
276 #endif
277 
278 static const int maxVolume = 100;
279 static const int runinLength = 2*sound_buffer_size;
281 public:
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 
297  }
298 
299  int groupId() const { return mWid; }
300  int soundId() const { return mSid; }
301 
303  // inteded to provide even audio return from mute/pause/dead samples.
304  //sampleRunin = runinLength; // or more?
305  }
306 
307 
308  void setVolume(int lv, int rv) {
309  leftVolume = qMin(maxVolume, qMax(0, lv));
310  rightVolume = qMin(maxVolume, qMax(0, rv));
311  }
312 
313  void setMute(bool m) { mMuted = m; }
314  bool muted() { return mMuted; }
315 
316  void setPriority(bool p) {
317  if (p != isPriority) {
318  isPriority = p; // currently meaningless.
319  }
320  }
321 
322 
323  static void setPlayPriorityOnly(bool p)
324  {
325  if (p)
326  priorityExists++;
327  else
328  priorityExists--;
329 
330  if (priorityExists < 0)
331  qDebug("QSS: got more priority offs than ons");
332  }
333 
334  // return -1 for file broken, give up.
335  // else return sampels ready for playing.
336  // argument is max samples server is looking for,
337  // in terms of current device status.
338  virtual int readySamples(int) = 0;
339 
340  int getSample(int off, int bps) {
341 
342  //
343  // 16-bit audio data is converted to native endian so that it can be scaled
344  // Yes, this is ugly on a BigEndian machine
345  // Perhaps it shouldn't be scaled at all
346  //
347  return (bps == 1) ? (data[out+off] - 128) * 128 : qToLittleEndian(((short*)data)[(out/2)+off]);
348  }
349 
350  int add(int* mixl, int* mixr, int count)
351  {
352  int bytesPerSample = chunkdata.wBitsPerSample >> 3;
353 
354  if ( mMuted ) {
355  sampleRunin -= qMin(sampleRunin,count);
356  while (count && (dev != -1)) {
357  if (out >= *max) {
358  // switch buffers
359  out = 0;
360  if (data == data1 && max2 != 0) {
361  data = data2;
362  max = &max2;
363  max1 = 0;
364  } else if (data == data2 && max1 != 0) {
365  data = data1;
366  max = &max1;
367  max2 = 0;
368  } else {
369  qDebug("QSS Read Error: both buffers empty");
370  return 0;
371  }
372  }
373  samples_due += sound_speed;
374  while (count && samples_due >= chunkdata.samplesPerSec) {
375  samples_due -= chunkdata.samplesPerSec;
376  count--;
377  }
378  out += bytesPerSample * chunkdata.channels;
379  }
380  return count;
381  }
382 
383  // This shouldn't be the case
384  if ( !mixl || !mixr )
385  return 0;
386 
387  int lVolNum = leftVolume, lVolDen = maxVolume;
388  int rVolNum = rightVolume, rVolDen = maxVolume;
389  if (priorityExists > 0 && !isPriority) {
390  lVolNum = 0; // later, make this gradually fade in and out.
391  lVolDen = 5;
392  rVolNum = 0;
393  rVolDen = 5;
394  }
395 
396  while (count && (dev != -1)) {
397  if (out >= *max) {
398  // switch buffers
399  out = 0;
400  if (data == data1 && max2 != 0) {
401  data = data2;
402  max = &max2;
403  max1 = 0;
404  } else if (data == data2 && max1 != 0) {
405  data = data1;
406  max = &max1;
407  max2 = 0;
408  } else {
409  qDebug("QSS Read Error: both buffers empty");
410  return 0;
411  }
412  }
413  samples_due += sound_speed;
414  if (count && samples_due >= chunkdata.samplesPerSec) {
415  int l = getSample(0,bytesPerSample)*lVolNum/lVolDen;
416  int r = (chunkdata.channels == 2) ? getSample(1,bytesPerSample)*rVolNum/rVolDen : l;
417  if (!sound_stereo && chunkdata.channels == 2)
418  l += r;
419  if (sampleRunin) {
420  while (sampleRunin && count && samples_due >= chunkdata.samplesPerSec) {
421  mixl++;
422  if (sound_stereo)
423  mixr++;
424  samples_due -= chunkdata.samplesPerSec;
425  sampleRunin--;
426  count--;
427  }
428  }
429  while (count && samples_due >= chunkdata.samplesPerSec) {
430  *mixl++ += l;
431  if (sound_stereo)
432  *mixr++ += r;
433  samples_due -= chunkdata.samplesPerSec;
434  count--;
435  }
436  }
437 
438  // optimize out manipulation of sample if downsampling and we skip it
439  out += bytesPerSample * chunkdata.channels;
440  }
441 
442  return count;
443  }
444 
445  virtual bool finished() const = 0;
446 
447  bool equal(int wid, int sid)
448  {
449  return (wid == mWid && sid == mSid);
450  }
451 
452 protected:
453 
454  char * prepareBuffer( int &size)
455  {
456  // keep reading as long as there is 50 % or more room in off buffer.
457  if (data == data1 && (max2<<1 < sound_buffer_size)) {
458  size=sound_buffer_size - max2;
459  return (char *)data2;
460  } else if (data == data2 && (max1<<1 < sound_buffer_size)) {
461  size=sound_buffer_size - max1;
462  return (char *)data1;
463  } else {
464  size = 0;
465  return 0;
466  }
467  }
468 
469  void updateBuffer(int read)
470  {
471  // always reads to off buffer.
472  if (read >= 0) {
473  if (data == data2) {
474  max1 = read;
475  } else {
476  max2 = read;
477  }
478  }
479  }
480 
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 {
497  } chunkdata;
498  int dev;
500 private:
501  int mWid;
502  int mSid;
506  static int priorityExists;
507  int *max;
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;
513  bool mMuted;
514 };
515 
517 
519 public:
520  QWSSoundServerBucket(int d, int wid, int sid)
521  : QWSSoundServerProvider(wid, sid)
522  {
523  dev = d;
524  wavedata_remaining = -1;
525  mFinishedRead = false;
526  mInsufficientSamples = false;
527  }
529  {
530  //dev->close();
531  ::close(dev);
532  }
533  bool finished() const
534  {
535  //return !max;
536  return mInsufficientSamples && mFinishedRead ;
537  }
538  int readySamples(int)
539  {
540  int size;
541  char *dest = prepareBuffer(size);
542  // may want to change this to something like
543  // if (data == data1 && max2<<1 < sound_buffer_size
544  // ||
545  // data == data2 && max1<<1 < sound_buffer_size)
546  // so will keep filling off buffer while there is +50% space left
547  if (size > 0 && dest != 0) {
548  while ( wavedata_remaining < 0 ) {
549  //max = 0;
550  wavedata_remaining = -1;
551  // Keep reading chunks...
552  const int n = sizeof(chunk)-sizeof(chunk.data);
553  int nr = ::read(dev, (void*)&chunk,n);
554  if ( nr != n ) {
555  // XXX check error? or don't we care?
556  wavedata_remaining = 0;
557  mFinishedRead = true;
558  } else if ( qstrncmp(chunk.id,"data",4) == 0 ) {
559  wavedata_remaining = qToLittleEndian( chunk.size );
560 
561  //out = max = sound_buffer_size;
562 
563  } else if ( qstrncmp(chunk.id,"RIFF",4) == 0 ) {
564  char d[4];
565  if ( read(dev, d, 4) != 4 ) {
566  // XXX check error? or don't we care?
567  //qDebug("couldn't read riff");
568  mInsufficientSamples = true;
569  mFinishedRead = true;
570  return 0;
571  } else if ( qstrncmp(d,"WAVE",4) != 0 ) {
572  // skip
573  if ( chunk.size > 1000000000 || lseek(dev,chunk.size-4, SEEK_CUR) == -1 ) {
574  //qDebug("oversized wav chunk");
575  mFinishedRead = true;
576  }
577  }
578  } else if ( qstrncmp(chunk.id,"fmt ",4) == 0 ) {
579  if ( ::read(dev,(char*)&chunkdata,sizeof(chunkdata)) != sizeof(chunkdata) ) {
580  // XXX check error? or don't we care?
581  //qDebug("couldn't ready chunkdata");
582  mFinishedRead = true;
583  }
584 
585 #define WAVE_FORMAT_PCM 1
586  else
587  {
588  /*
589  ** Endian Fix the chuck data
590  */
591  chunkdata.formatTag = qToLittleEndian( chunkdata.formatTag );
592  chunkdata.channels = qToLittleEndian( chunkdata.channels );
593  chunkdata.samplesPerSec = qToLittleEndian( chunkdata.samplesPerSec );
594  chunkdata.avgBytesPerSec = qToLittleEndian( chunkdata.avgBytesPerSec );
595  chunkdata.blockAlign = qToLittleEndian( chunkdata.blockAlign );
596  chunkdata.wBitsPerSample = qToLittleEndian( chunkdata.wBitsPerSample );
597  if ( chunkdata.formatTag != WAVE_FORMAT_PCM ) {
598  qWarning("WAV file: UNSUPPORTED FORMAT %d",chunkdata.formatTag);
599  mFinishedRead = true;
600  }
601  }
602  } else {
603  // ignored chunk
604  if ( chunk.size > 1000000000 || lseek(dev, chunk.size, SEEK_CUR) == -1) {
605  //qDebug("chunk size too big");
606  mFinishedRead = true;
607  }
608  }
609  }
610  // this looks wrong.
611  if (wavedata_remaining <= 0) {
612  mFinishedRead = true;
613  }
614 
615  }
616  // may want to change this to something like
617  // if (data == data1 && max2<<1 < sound_buffer_size
618  // ||
619  // data == data2 && max1<<1 < sound_buffer_size)
620  // so will keep filling off buffer while there is +50% space left
621 
622  if (wavedata_remaining) {
623  if (size > 0 && dest != 0) {
624  int read = ::read(dev, dest, qMin(size, wavedata_remaining));
625  // XXX check error? or don't we care?
626  wavedata_remaining -= read;
627  updateBuffer(read);
628  if (read <= 0) // data unexpectidly ended
629  mFinishedRead = true;
630  }
631  }
632  int possible = devSamples();
633  if (possible == 0)
634  mInsufficientSamples = true;
635  return possible;
636  }
637 
638 protected:
643 };
644 
646 public:
647  QWSSoundServerStream(int d,int c, int f, int b,
648  int wid, int sid)
649  : QWSSoundServerProvider(wid, sid)
650  {
651  chunkdata.channels = c;
652  chunkdata.samplesPerSec = f;
653  chunkdata.wBitsPerSample = b;
654  dev = d;
655  //fcntl( dev, F_SETFL, O_NONBLOCK );
656  lasttime = 0;
657  }
658 
660  {
661  if (dev != -1) {
662  ::close(dev);
663  dev = -1;
664  }
665  }
666 
667  bool finished() const
668  {
669  return (dev == -1);
670  }
671 
672 
673  int readySamples(int)
674  {
675  int size;
676  char *dest = prepareBuffer(size);
677  if (size > 0 && dest != 0 && dev != -1) {
678 
679  int read = ::read(dev, dest, size);
680  if (read < 0) {
681  switch(errno) {
682  case EAGAIN:
683  case EINTR:
684  // means read may yet succeed on the next attempt
685  break;
686  default:
687  // unexpected error, fail.
688  ::close(dev);
689  dev = -1;
690  }
691  } else if (read == 0) {
692  // 0 means writer has closed dev and/or
693  // file is at end.
694  ::close(dev);
695  dev = -1;
696  } else {
697  updateBuffer(read);
698  }
699  }
700  int possible = devSamples();
701  if (possible == 0)
702  startSampleRunin();
703  return possible;
704  }
705 
706 protected:
708 };
709 
710 #ifndef QT_NO_QWS_SOUNDSERVER
711 QWSSoundServerSocket::QWSSoundServerSocket(QObject *parent) :
713 {
714  connect(this, SIGNAL(newConnection()), this, SLOT(newConnection()));
715 }
716 
717 
718 #ifdef QT3_SUPPORT
719 QWSSoundServerSocket::QWSSoundServerSocket(QObject *parent, const char *name) :
721 {
722  if (name)
723  setObjectName(QString::fromAscii(name));
724  connect(this, SIGNAL(newConnection()), this, SLOT(newConnection()));
725 }
726 #endif
727 
728 void QWSSoundServerSocket::newConnection()
729 {
730  while (QWS_SOCK_BASE *sock = nextPendingConnection()) {
731  QWSSoundServerClient* client = new QWSSoundServerClient(sock,this);
732 
733  connect(client, SIGNAL(play(int,int,QString)),
734  this, SIGNAL(playFile(int,int,QString)));
735  connect(client, SIGNAL(play(int,int,QString,int,int)),
736  this, SIGNAL(playFile(int,int,QString,int,int)));
737  connect(client, SIGNAL(playRaw(int,int,QString,int,int,int,int)),
738  this, SIGNAL(playRawFile(int,int,QString,int,int,int,int)));
739 
740  connect(client, SIGNAL(pause(int,int)),
741  this, SIGNAL(pauseFile(int,int)));
742  connect(client, SIGNAL(stop(int,int)),
743  this, SIGNAL(stopFile(int,int)));
744  connect(client, SIGNAL(playPriorityOnly(bool)),
745  this, SIGNAL(playPriorityOnly(bool)));
746  connect(client, SIGNAL(stopAll(int)),
747  this, SIGNAL(stopAll(int)));
748  connect(client, SIGNAL(resume(int,int)),
749  this, SIGNAL(resumeFile(int,int)));
750 
751  connect(client, SIGNAL(setSilent(bool)),
752  this, SIGNAL(setSilent(bool)));
753 
754  connect(client, SIGNAL(setMute(int,int,bool)),
755  this, SIGNAL(setMute(int,int,bool)));
756  connect(client, SIGNAL(setVolume(int,int,int,int)),
757  this, SIGNAL(setVolume(int,int,int,int)));
758 
759  connect(this, SIGNAL(soundFileCompleted(int,int)),
760  client, SLOT(sendSoundCompleted(int,int)));
761  connect(this, SIGNAL(deviceReady(int,int)),
762  client, SLOT(sendDeviceReady(int,int)));
763  connect(this, SIGNAL(deviceError(int,int,int)),
764  client, SLOT(sendDeviceError(int,int,int)));
765  }
766 }
767 
768 #endif
769 
771  Q_OBJECT
772 
773 public:
774  QWSSoundServerPrivate(QObject* parent=0, const char* name=0) :
775  QObject(parent)
776  {
777  timerId = 0;
778  if (name)
779  setObjectName(QString::fromAscii(name));
780 #ifndef QT_NO_QWS_SOUNDSERVER
781  server = new QWSSoundServerSocket(this);
782 
783  connect(server, SIGNAL(playFile(int,int,QString)),
784  this, SLOT(playFile(int,int,QString)));
785  connect(server, SIGNAL(playFile(int,int,QString,int,int)),
786  this, SLOT(playFile(int,int,QString,int,int)));
787  connect(server, SIGNAL(playRawFile(int,int,QString,int,int,int,int)),
788  this, SLOT(playRawFile(int,int,QString,int,int,int,int)));
789 
790  connect(server, SIGNAL(pauseFile(int,int)),
791  this, SLOT(pauseFile(int,int)));
792  connect(server, SIGNAL(stopFile(int,int)),
793  this, SLOT(stopFile(int,int)));
794  connect(server, SIGNAL(stopAll(int)),
795  this, SLOT(stopAll(int)));
796  connect(server, SIGNAL(playPriorityOnly(bool)),
797  this, SLOT(playPriorityOnly(bool)));
798  connect(server, SIGNAL(resumeFile(int,int)),
799  this, SLOT(resumeFile(int,int)));
800 
801  connect( server, SIGNAL(setSilent(bool)),
802  this, SLOT(setSilent(bool)));
803 
804  connect(server, SIGNAL(setMute(int,int,bool)),
805  this, SLOT(setMute(int,int,bool)));
806  connect(server, SIGNAL(setVolume(int,int,int,int)),
807  this, SLOT(setVolume(int,int,int,int)));
808 
809  connect(this, SIGNAL(soundFileCompleted(int,int)),
810  server, SIGNAL(soundFileCompleted(int,int)));
811  connect(this, SIGNAL(deviceReady(int,int)),
812  server, SIGNAL(deviceReady(int,int)));
813  connect(this, SIGNAL(deviceError(int,int,int)),
814  server, SIGNAL(deviceError(int,int,int)));
815 
816 #endif
817  silent = false;
818  fd = -1;
819  unwritten = 0;
820  can_GETOSPACE = true;
821  }
822 
824  {
825  qDeleteAll(active);
826  qDeleteAll(inactive);
827  }
828 
829 signals:
830  void soundFileCompleted(int, int);
831  void deviceReady(int, int);
832  void deviceError(int, int, int);
833 
834 public slots:
835  void playRawFile(int wid, int sid, const QString &filename, int freq, int channels, int bitspersample, int flags);
836  void playFile(int wid, int sid, const QString& filename);
837  void playFile(int wid, int sid, const QString& filename, int v, int flags);
838  void checkPresetVolumes(int wid, int sid, QWSSoundServerProvider *p);
839  void pauseFile(int wid, int sid);
840  void resumeFile(int wid, int sid);
841  void stopFile(int wid, int sid);
842  void stopAll(int wid);
843  void setVolume(int wid, int sid, int lv, int rv);
844  void setMute(int wid, int sid, bool m);
845  void playPriorityOnly(bool p);
846  void sendCompletedSignals();
847  void feedDevice(int fd);
848  void setSilent( bool enabled );
849 
850 protected:
851  void timerEvent(QTimerEvent* event);
852 
853 private:
854  int openFile(int wid, int sid, const QString& filename);
855  bool openDevice();
856  void closeDevice()
857  {
858  if (fd >= 0) {
859  ::close(fd);
860  fd = -1;
861  }
862  }
863 
866  struct PresetVolume {
867  int wid;
868  int sid;
869  int left;
870  int right;
871  bool mute;
872  };
874  struct CompletedInfo {
875  CompletedInfo( ) : groupId( 0 ), soundId( 0 ) { }
876  CompletedInfo( int _groupId, int _soundId ) : groupId( _groupId ), soundId( _soundId ) { }
877  int groupId;
878  int soundId;
879  };
881 
882  bool silent;
883 
884  int fd;
886  int timerId;
887  char* cursor;
890 #ifndef QT_NO_QWS_SOUNDSERVER
891  QWSSoundServerSocket *server;
892 #endif
893 };
894 
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 
912 {
913  // qDebug("QSS timer event");
914  if( event->timerId() == timerId ) {
915  if (fd >= 0)
916  feedDevice(fd);
917  if (fd < 0) {
918  killTimer(timerId);
919  timerId = 0;
920  }
921  }
922 }
923 
924 void QWSSoundServerPrivate::playRawFile(int wid, int sid, const QString &filename,
925  int freq, int channels, int bitspersample, int flags)
926 {
927 #ifdef QT_NO_QWS_SOUNDSERVER
928  Q_UNUSED(flags);
929 #endif
930  int f = openFile(wid, sid, filename);
931  if ( f ) {
932  QWSSoundServerStream *b = new QWSSoundServerStream(f, channels, freq, bitspersample, wid, sid);
933  // check preset volumes.
934  checkPresetVolumes(wid, sid, b);
935 #ifndef QT_NO_QWS_SOUNDSERVER
936  b->setPriority((flags & QWSSoundClient::Priority) == QWSSoundClient::Priority);
937 #endif
938  active.append(b);
939  emit deviceReady(wid, sid);
940  }
941 }
942 
943 void QWSSoundServerPrivate::playFile(int wid, int sid, const QString& filename)
944 {
945  int f = openFile(wid, sid, filename);
946  if ( f ) {
947  QWSSoundServerProvider *b = new QWSSoundServerBucket(f, wid, sid);
948  checkPresetVolumes(wid, sid, b);
949  active.append( b );
950  emit deviceReady(wid, sid);
951  }
952 }
953 
954 void QWSSoundServerPrivate::playFile(int wid, int sid, const QString& filename,
955  int v, int flags)
956 {
957 #ifdef QT_NO_QWS_SOUNDSERVER
958  Q_UNUSED(flags);
959 #endif
960  int f = openFile(wid, sid, filename);
961  if ( f ) {
962  QWSSoundServerProvider *b = new QWSSoundServerBucket(f, wid, sid);
963  checkPresetVolumes(wid, sid, b);
964  b->setVolume(v, v);
965 #ifndef QT_NO_QWS_SOUNDSERVER
966  b->setPriority((flags & QWSSoundClient::Priority) == QWSSoundClient::Priority);
967 #endif
968  active.append(b);
969  emit deviceReady(wid, sid);
970  }
971 }
972 
974 {
975  QList<PresetVolume>::Iterator it = volumes.begin();
976  while (it != volumes.end()) {
977  PresetVolume v = *it;
978  if (v.wid == wid && v.sid == sid) {
979  p->setVolume(v.left, v.right);
980  p->setMute(v.mute);
981  it = volumes.erase(it);
982  return;
983  } else {
984  ++it;
985  }
986  }
987 }
988 
989 void QWSSoundServerPrivate::pauseFile(int wid, int sid)
990 {
991  QWSSoundServerProvider *bucket;
992  for (int i = 0; i < active.size(); ++i ) {
993  bucket = active.at(i);
994  if (bucket->equal(wid, sid)) {
995  // found bucket....
996  active.removeAt(i);
997  inactive.append(bucket);
998  return;
999  }
1000  }
1001 }
1002 
1004 {
1005  QWSSoundServerProvider *bucket;
1006  for (int i = 0; i < inactive.size(); ++i ) {
1007  bucket = inactive.at(i);
1008  if (bucket->equal(wid, sid)) {
1009  // found bucket....
1010  inactive.removeAt(i);
1011  active.append(bucket);
1012  return;
1013  }
1014  }
1015 }
1016 
1017 void QWSSoundServerPrivate::stopFile(int wid, int sid)
1018 {
1019  QWSSoundServerProvider *bucket;
1020  for (int i = 0; i < active.size(); ++i ) {
1021  bucket = active.at(i);
1022  if (bucket->equal(wid, sid)) {
1023  active.removeAt(i);
1024  delete bucket;
1025  return;
1026  }
1027  }
1028  for (int i = 0; i < inactive.size(); ++i ) {
1029  bucket = inactive.at(i);
1030  if (bucket->equal(wid, sid)) {
1031  inactive.removeAt(i);
1032  delete bucket;
1033  return;
1034  }
1035  }
1036 }
1037 
1039 {
1040  QWSSoundServerProvider *bucket;
1041  if (!active.isEmpty()) {
1043  while (it != active.end()) {
1044  bucket = *it;
1045  if (bucket->groupId() == wid) {
1046  it = active.erase(it);
1047  delete bucket;
1048  } else {
1049  ++it;
1050  }
1051  }
1052  }
1053  if (!inactive.isEmpty()) {
1054  QList<QWSSoundServerProvider*>::Iterator it = inactive.begin();
1055  while (it != inactive.end()) {
1056  bucket = *it;
1057  if (bucket->groupId() == wid) {
1058  it = inactive.erase(it);
1059  delete bucket;
1060  } else {
1061  ++it;
1062  }
1063  }
1064  }
1065 }
1066 
1067 void QWSSoundServerPrivate::setVolume(int wid, int sid, int lv, int rv)
1068 {
1069  QWSSoundServerProvider *bucket;
1070  for( int i = 0; i < active.size(); ++i ) {
1071  bucket = active.at(i);
1072  if (bucket->equal(wid, sid)) {
1073  bucket->setVolume(lv,rv);
1074  return;
1075  }
1076  }
1077  // If gotten here, then it means wid/sid wasn't set up yet.
1078  // first find and remove current preset volumes, then add this one.
1079  QList<PresetVolume>::Iterator it = volumes.begin();
1080  while (it != volumes.end()) {
1081  PresetVolume v = *it;
1082  if (v.wid == wid && v.sid == sid)
1083  it = volumes.erase(it);
1084  else
1085  ++it;
1086  }
1087  // and then add this volume
1088  PresetVolume nv;
1089  nv.wid = wid;
1090  nv.sid = sid;
1091  nv.left = lv;
1092  nv.right = rv;
1093  nv.mute = false;
1094  volumes.append(nv);
1095 }
1096 
1097 void QWSSoundServerPrivate::setMute(int wid, int sid, bool m)
1098 {
1099  QWSSoundServerProvider *bucket;
1100  for( int i = 0; i < active.size(); ++i ) {
1101  bucket = active.at(i);
1102  if (bucket->equal(wid, sid)) {
1103  bucket->setMute(m);
1104  return;
1105  }
1106  }
1107  // if gotten here then setting is being applied before item
1108  // is created.
1109  QList<PresetVolume>::Iterator it = volumes.begin();
1110  while (it != volumes.end()) {
1111  PresetVolume v = *it;
1112  if (v.wid == wid && v.sid == sid) {
1113  (*it).mute = m;
1114  return;
1115  }
1116  }
1117  if (m) {
1118  PresetVolume nv;
1119  nv.wid = wid;
1120  nv.sid = sid;
1121  nv.left = maxVolume>>1;
1122  nv.right = maxVolume>>1;
1123  nv.mute = true;
1124  volumes.append(nv);
1125  }
1126 }
1127 
1129 {
1131 }
1132 
1134 {
1135  while( !completed.isEmpty() ) {
1136  emit soundFileCompleted( (*completed.begin()).groupId,
1137  (*completed.begin()).soundId );
1138  completed.erase( completed.begin() );
1139  }
1140 }
1141 
1142 
1143 int QWSSoundServerPrivate::openFile(int wid, int sid, const QString& filename)
1144 {
1145  stopFile(wid, sid); // close and re-open.
1146  int f = QT_OPEN(QFile::encodeName(filename), O_RDONLY|O_NONBLOCK);
1147  if (f == -1) {
1148  // XXX check ferror, check reason.
1149  qDebug("Failed opening \"%s\"",filename.toLatin1().data());
1150 #ifndef QT_NO_QWS_SOUNDSERVER
1151  emit deviceError(wid, sid, (int)QWSSoundClient::ErrOpeningFile );
1152 #endif
1153  } else if ( openDevice() ) {
1154  return f;
1155  }
1156 #ifndef QT_NO_QWS_SOUNDSERVER
1157  emit deviceError(wid, sid, (int)QWSSoundClient::ErrOpeningAudioDevice );
1158 #endif
1159  return 0;
1160 }
1161 
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 
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;
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 
1340  while (it != active.end()) {
1341  bucket = *it;
1342  if (bucket->finished()) {
1343  completed.append(CompletedInfo(bucket->groupId(), bucket->soundId()));
1344  it = active.erase(it);
1345  delete bucket;
1346  } else {
1347  ++it;
1348  }
1349  }
1350 }
1351 
1352 
1353 QWSSoundServer::QWSSoundServer(QObject* parent) :
1354  QObject(parent)
1355 {
1356  d = new QWSSoundServerPrivate(this);
1357 
1358  connect( d, SIGNAL(soundFileCompleted(int,int)),
1359  this, SLOT(translateSoundCompleted(int,int)) );
1360 }
1361 
1362 void QWSSoundServer::playFile( int sid, const QString& filename )
1363 {
1364  //wid == 0, as it is the server initiating rather than a client
1365  // if wid was passable, would accidently collide with server
1366  // sockect's wids.
1367  d->playFile(0, sid, filename);
1368 }
1369 
1370 void QWSSoundServer::pauseFile( int sid )
1371 {
1372  d->pauseFile(0, sid);
1373 }
1374 
1375 void QWSSoundServer::stopFile( int sid )
1376 {
1377  d->stopFile(0, sid);
1378 }
1379 
1380 void QWSSoundServer::resumeFile( int sid )
1381 {
1382  d->resumeFile(0, sid);
1383 }
1384 
1385 QWSSoundServer::~QWSSoundServer()
1386 {
1387  d->stopAll(0);
1388 }
1389 
1390 void QWSSoundServer::translateSoundCompleted( int, int sid )
1391 {
1392  emit soundCompleted( sid );
1393 }
1394 
1395 #ifndef QT_NO_QWS_SOUNDSERVER
1396 QWSSoundClient::QWSSoundClient(QObject* parent) :
1397  QWSSocket(parent)
1398 {
1399  connectToLocalFile(QT_VFB_SOUND_PIPE(qws_display_id));
1400  QObject::connect(this,SIGNAL(readyRead()),
1401  this,SLOT(tryReadCommand()));
1402  if( state() == QWS_SOCK_BASE::ConnectedState ) QTimer::singleShot(1, this, SIGNAL(connected()));
1403  else QTimer::singleShot(1, this, SLOT(emitConnectionRefused()));
1404 }
1405 
1406 QWSSoundClient::~QWSSoundClient( )
1407 {
1408  flush();
1409 }
1410 
1411 void QWSSoundClient::reconnect()
1412 {
1413  connectToLocalFile(QT_VFB_SOUND_PIPE(qws_display_id));
1414  if( state() == QWS_SOCK_BASE::ConnectedState ) emit connected();
1416 }
1417 
1418 void QWSSoundClient::sendServerMessage(QString msg)
1419 {
1420 #ifndef QT_NO_TEXTCODEC
1421  QByteArray u = msg.toUtf8();
1422 #else
1423  QByteArray u = msg.toLatin1();
1424 #endif
1425  write(u.data(), u.length());
1426  flush();
1427 }
1428 
1429 void QWSSoundClient::play( int id, const QString& filename )
1430 {
1431  QFileInfo fi(filename);
1432  sendServerMessage(QLatin1String("PLAY ")
1433  + QString::number(id) + QLatin1Char(' ')
1434  + fi.absoluteFilePath() + QLatin1Char('\n'));
1435 }
1436 
1437 void QWSSoundClient::play( int id, const QString& filename, int volume, int flags)
1438 {
1439  QFileInfo fi(filename);
1440  sendServerMessage(QLatin1String("PLAYEXTEND ")
1441  + QString::number(id) + QLatin1Char(' ')
1442  + QString::number(volume) + QLatin1Char(' ')
1443  + QString::number(flags) + QLatin1Char(' ')
1444  + fi.absoluteFilePath() + QLatin1Char('\n'));
1445 }
1446 
1447 void QWSSoundClient::pause( int id )
1448 {
1449  sendServerMessage(QLatin1String("PAUSE ")
1450  + QString::number(id) + QLatin1Char('\n'));
1451 }
1452 
1453 void QWSSoundClient::stop( int id )
1454 {
1455  sendServerMessage(QLatin1String("STOP ")
1456  + QString::number(id) + QLatin1Char('\n'));
1457 }
1458 
1459 void QWSSoundClient::resume( int id )
1460 {
1461  sendServerMessage(QLatin1String("RESUME ")
1462  + QString::number(id) + QLatin1Char('\n'));
1463 }
1464 
1465 void QWSSoundClient::playRaw( int id, const QString& filename,
1466  int freq, int chs, int bitspersample, int flags)
1467 {
1468  QFileInfo fi(filename);
1469  sendServerMessage(QLatin1String("PLAYRAW ")
1470  + QString::number(id) + QLatin1Char(' ')
1471  + QString::number(chs) + QLatin1Char(' ')
1472  + QString::number(freq) + QLatin1Char(' ')
1473  + QString::number(bitspersample) + QLatin1Char(' ')
1474  + QString::number(flags) + QLatin1Char(' ')
1475  + fi.absoluteFilePath() + QLatin1Char('\n'));
1476 }
1477 
1478 void QWSSoundClient::setMute( int id, bool m )
1479 {
1480  sendServerMessage(QLatin1String(m ? "MUTE " : "UNMUTE ")
1481  + QString::number(id) + QLatin1Char('\n'));
1482 }
1483 
1484 void QWSSoundClient::setVolume( int id, int leftVol, int rightVol )
1485 {
1486  sendServerMessage(QLatin1String("SETVOLUME ")
1487  + QString::number(id) + QLatin1Char(' ')
1488  + QString::number(leftVol) + QLatin1Char(' ')
1489  + QString::number(rightVol) + QLatin1Char('\n'));
1490 }
1491 
1492 void QWSSoundClient::playPriorityOnly( bool pri )
1493 {
1494  sendServerMessage(QLatin1String("PRIORITYONLY ")
1495  + QString::number(pri ? 1 : 0) + QLatin1Char('\n'));
1496 }
1497 
1498 void QWSSoundClient::setSilent( bool enable )
1499 {
1500  sendServerMessage(QLatin1String("SILENT ")
1501  + QString::number( enable ? 1 : 0 ) + QLatin1Char('\n'));
1502 }
1503 
1504 void QWSSoundClient::tryReadCommand()
1505 {
1506  while ( canReadLine() ) {
1507  QString l = QString::fromAscii(readLine());
1508  l.truncate(l.length()-1); // chomp
1509  QStringList token = l.split(QLatin1Char(' '));
1510  if (token[0] == QLatin1String("SOUNDCOMPLETED")) {
1511  emit soundCompleted(token[1].toInt());
1512  } else if (token[0] == QLatin1String("DEVICEREADY")) {
1513  emit deviceReady(token[1].toInt());
1514  } else if (token[0] == QLatin1String("DEVICEERROR")) {
1515  emit deviceError(token[1].toInt(),(DeviceErrors)token[2].toInt());
1516  }
1517  }
1518 }
1519 
1520 void QWSSoundClient::emitConnectionRefused()
1521 {
1523 }
1524 #endif
1525 
1527 
1528 #include "qsoundqss_qws.moc"
1529 
1530 #endif // QT_NO_SOUND
static QString number(int, int base=10)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition: qstring.cpp:6448
quint32 size
static QString getStringTok(QString &in)
double d
Definition: qnumeric_p.h:62
void updateBuffer(int read)
void playRaw(int, int, const QString &, int, int, int, int)
static int sound_stereo
static mach_timebase_info_data_t info
unsigned char c[8]
Definition: qnumeric_p.h:62
QWSSoundServerStream(int d, int c, int f, int b, int wid, int sid)
void pause(int, int)
Q_DECL_CONSTEXPR const T & qMin(const T &a, const T &b)
Definition: qglobal.h:1215
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
CompletedInfo(int _groupId, int _soundId)
int qint32
Definition: qglobal.h:937
EventRef event
static QString fromAscii(const char *, int size=-1)
Returns a QString initialized with the first size characters from the string str. ...
Definition: qstring.cpp:4276
void timerEvent(QTimerEvent *event)
This event handler can be reimplemented in a subclass to receive timer events for the object...
char * data()
Returns a pointer to the data stored in the byte array.
Definition: qbytearray.h:429
void playFile(int wid, int sid, const QString &filename)
int toInt(bool *ok=0, int base=10) const
Returns the string converted to an int using base base, which is 10 by default and must be between 2 ...
Definition: qstring.cpp:6090
QWSSoundServerClient(QWS_SOCK_BASE *s, QObject *parent)
#define it(className, varName)
QByteArray toUtf8() const Q_REQUIRED_RESULT
Returns a UTF-8 representation of the string as a QByteArray.
Definition: qstring.cpp:4074
#define error(msg)
The QByteArray class provides an array of bytes.
Definition: qbytearray.h:135
static int sound_speed
int length() const
Returns the number of characters in this string.
Definition: qstring.h:696
#define SLOT(a)
Definition: qobjectdefs.h:226
void resumeFile(int wid, int sid)
#define O_RDONLY
void setVolume(int lv, int rv)
QWSSoundServerPrivate(QObject *parent=0, const char *name=0)
QString absoluteFilePath() const
Returns an absolute path including the file name.
Definition: qfileinfo.cpp:534
QLatin1String(DBUS_INTERFACE_DBUS))) Q_GLOBAL_STATIC_WITH_ARGS(QString
quint16 u
static char * zeroMem
The QString class provides a Unicode character string.
Definition: qstring.h:83
void checkPresetVolumes(int wid, int sid, QWSSoundServerProvider *p)
The QObject class is the base class of all Qt objects.
Definition: qobject.h:111
QPointer< QWS_SOCK_BASE > socket
void setMute(int, int, bool)
Q_CORE_EXPORT QTextStream & right(QTextStream &s)
Q_DECL_CONSTEXPR const T & qMax(const T &a, const T &b)
Definition: qglobal.h:1217
void sendDeviceReady(int, int)
void setVolume(int wid, int sid, int lv, int rv)
char * prepareBuffer(int &size)
Q_CORE_EXPORT void qDebug(const char *,...)
static void setPlayPriorityOnly(bool p)
#define SIGNAL(a)
Definition: qobjectdefs.h:227
virtual bool finished() const =0
unsigned char uchar
Definition: qglobal.h:994
int getSample(int off, int bps)
void append(const T &t)
Inserts value at the end of the list.
Definition: qlist.h:507
void sendDeviceError(int, int, int)
static const int sound_fragment_size
void sendClientMessage(QString msg)
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
#define QT_QWS_SOUND_STEREO
static QIntfbScreen * connected
QList< QWSSoundServerProvider * > inactive
int add(int *mixl, int *mixr, int count)
void truncate(int pos)
Truncates the string at the given position index.
Definition: qstring.cpp:4603
void setSilent(bool enabled)
unsigned long time_t
QString left(int n) const Q_REQUIRED_RESULT
Returns a substring that contains the n leftmost characters of the string.
Definition: qstring.cpp:3664
static bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
Creates a connection of the given type from the signal in the sender object to the method in the rece...
Definition: qobject.cpp:2580
#define calloc(a, b)
virtual int readySamples(int)=0
void playPriorityOnly(bool p)
void pauseFile(int wid, int sid)
const char * name
char data[4]
const T & at(int i) const
Returns the item at index position i in the list.
Definition: qlist.h:468
#define emit
Definition: qobjectdefs.h:76
The QStringList class provides a list of strings.
Definition: qstringlist.h:66
short qint16
Definition: qglobal.h:935
QList< PresetVolume > volumes
static int toInt(const QByteArray &str)
Definition: generator.cpp:167
Q_CORE_EXPORT void qWarning(const char *,...)
int timerId() const
Returns the unique timer identifier, which is the same identifier as returned from QObject::startTime...
Definition: qcoreevent.h:346
static const int runinLength
int qws_display_id
static const char * data(const QByteArray &arr)
int indexOf(QChar c, int from=0, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Definition: qstring.cpp:2838
QWSSoundServerBucket(int d, int wid, int sid)
QByteArray toLatin1() const Q_REQUIRED_RESULT
Returns a Latin-1 representation of the string as a QByteArray.
Definition: qstring.cpp:3993
#define Q_OBJECT
Definition: qobjectdefs.h:157
static int getNumTok(QString &in)
The QList::iterator class provides an STL-style non-const iterator for QList and QQueue.
Definition: qlist.h:181
int length() const
Same as size().
Definition: qbytearray.h:356
QString mid(int position, int n=-1) const Q_REQUIRED_RESULT
Returns a string that contains n characters of this string, starting at the specified position index...
Definition: qstring.cpp:3706
static QAuServer & server()
Definition: qsound.cpp:79
int fcntl(int, int,...)
void playPriorityOnly(bool)
#define QT_OPEN
Definition: qcore_unix_p.h:186
The QTimerEvent class contains parameters that describe a timer event.
Definition: qcoreevent.h:341
#define QWS_SOCK_BASE
Definition: qwsutils_qws.h:54
int openFile(int wid, int sid, const QString &filename)
QList< QWSSoundServerProvider * > active
#define WAVE_FORMAT_PCM
void stop(int, int)
void play(int, int, const QString &)
QObject * parent() const
Returns a pointer to the parent object.
Definition: qobject.h:273
bool singleShot
This static function calls a slot after a given time interval.
Definition: qtimer.h:59
void setVolume(int, int, int, int)
unsigned int quint32
Definition: qglobal.h:938
int size() const
Returns the number of items in the list.
Definition: qlist.h:137
void sendSoundCompleted(int, int)
QList< CompletedInfo > completed
int qstrncmp(const char *str1, const char *str2, uint len)
Definition: qbytearray.h:101
QFactoryLoader * l
QWSSoundServerSocket * server
static const int maxVolume
static bool sound_16bit
void stopFile(int wid, int sid)
QWSSoundServerProvider(int w, int s)
void setMute(int wid, int sid, bool m)
Q_CORE_EXPORT QTextStream & flush(QTextStream &s)
#define QT_QWS_SOUND_16BIT
void resume(int, int)
static QByteArray encodeName(const QString &fileName)
By default, this function converts fileName to the local 8-bit encoding determined by the user&#39;s loca...
Definition: qfile.cpp:528
int errno
QStringList split(const QString &sep, SplitBehavior behavior=KeepEmptyParts, Qt::CaseSensitivity cs=Qt::CaseSensitive) const Q_REQUIRED_RESULT
Splits the string into substrings wherever sep occurs, and returns the list of those strings...
Definition: qstring.cpp:6526
bool equal(int wid, int sid)
static const Null null
Definition: qstring.h:502
#define slots
Definition: qobjectdefs.h:68
#define QT_VFB_SOUND_PIPE(DISPLAY)
Definition: qvfbhdr.h:82
The QFileInfo class provides system-independent file information.
Definition: qfileinfo.h:60
#define signals
Definition: qobjectdefs.h:69
Q_CORE_EXPORT QTextStream & left(QTextStream &s)
#define Q_UNUSED(x)
Indicates to the compiler that the parameter with the specified name is not used in the body of a fun...
Definition: qglobal.h:1729
Q_OUTOFLINE_TEMPLATE void qDeleteAll(ForwardIterator begin, ForwardIterator end)
Definition: qalgorithms.h:319
#define O_RDWR
T qToLittleEndian(T source)
Definition: qendian.h:341
void deleteLater()
Schedules this object for deletion.
Definition: qobject.cpp:2145
The QLatin1Char class provides an 8-bit ASCII/Latin-1 character.
Definition: qchar.h:55
#define O_WRONLY
#define enabled
static const int sound_buffer_size
void playRawFile(int wid, int sid, const QString &filename, int freq, int channels, int bitspersample, int flags)
The QList class is a template class that provides lists.
Definition: qdatastream.h:62