GEAudioOut.cpp 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. /**
  2. * Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
  3. * All rights reserved.
  4. *
  5. * For the applicable distribution terms see the license.txt -file, included in
  6. * the distribution.
  7. */
  8. #include "GEAudioOut.h"
  9. #include <QAudioOutput>
  10. #include <QIODevice>
  11. #include <QString>
  12. #include <QtMultimedia/qaudio.h>
  13. #include <QtMultimedia/qaudiodeviceinfo.h>
  14. #include "trace.h" // For debug macros
  15. #if defined(QTGAMEENABLER_USE_VOLUME_HACK) && defined(Q_OS_SYMBIAN)
  16. #include <SoundDevice.h>
  17. #endif
  18. // Constants
  19. const int GEDefaultChannelCount(2);
  20. const QString GEDefaultAudioCodec("audio/pcm");
  21. const QAudioFormat::Endian GEByteOrder(QAudioFormat::LittleEndian);
  22. const QAudioFormat::SampleType GESampleType(QAudioFormat::SignedInt);
  23. const int GEThreadSleepTime(1); // Milliseconds
  24. using namespace GE;
  25. /*!
  26. \class Audioout
  27. \brief An object deploying QAudioOutput for sending the pre-mixed/processed
  28. audio data into an actual audio device.
  29. */
  30. /*!
  31. Constructor.
  32. */
  33. AudioOut::AudioOut(AudioSource *source, QObject *parent /* = 0 */)
  34. : QThread(parent),
  35. m_audioOutput(0),
  36. m_outTarget(0),
  37. m_source(source),
  38. m_sendBuffer(0),
  39. m_sendBufferSize(0),
  40. m_samplesMixed(0),
  41. m_threadState(NotRunning),
  42. m_usingThread(false)
  43. {
  44. QAudioFormat format;
  45. format.setFrequency(AUDIO_FREQUENCY);
  46. format.setChannels(GEDefaultChannelCount);
  47. format.setSampleSize(AUDIO_SAMPLE_BITS);
  48. format.setCodec(GEDefaultAudioCodec);
  49. format.setByteOrder(GEByteOrder);
  50. format.setSampleType(GESampleType);
  51. QAudioDeviceInfo info(QAudioDeviceInfo::defaultOutputDevice());
  52. if (!info.isFormatSupported(format))
  53. format = info.nearestFormat(format);
  54. m_audioOutput = new QAudioOutput(info, format);
  55. #if defined(Q_WS_MAEMO_5) || defined(Q_WS_MAEMO_6)
  56. m_sendBufferSize = 4096 * 4;
  57. #else
  58. m_audioOutput->setBufferSize(4096 * 4);
  59. #endif
  60. m_outTarget = m_audioOutput->start();
  61. #if defined(Q_WS_MAEMO_5) || defined(Q_WS_MAEMO_6)
  62. m_audioOutput->setBufferSize(4096 * 16);
  63. m_sendBufferSize = 4096 * 8;
  64. #else
  65. m_audioOutput->setBufferSize(4096 * 4);
  66. m_sendBufferSize = 4096 * 2;
  67. #endif
  68. DEBUG_INFO("Buffer size: " << m_audioOutput->bufferSize());
  69. m_sendBuffer = new AUDIO_SAMPLE_TYPE[m_sendBufferSize];
  70. #ifndef Q_OS_SYMBIAN
  71. m_usingThread = true;
  72. start();
  73. #else
  74. #if defined(QTGAMEENABLER_USE_VOLUME_HACK) && defined(Q_OS_SYMBIAN)
  75. DEBUG_INFO("WARNING: Using the volume hack!");
  76. //m_audioOutput->setNotifyInterval(0);
  77. //connect(m_audioOutput, SIGNAL(notify()), this, SLOT(audioNotify()));
  78. // This really ugly hack is used as the last resort. This allows us to
  79. // adjust the application volume in Symbian. The CMMFDevSound object lies
  80. // deep inside the QAudioOutput in Symbian implementation and it has the
  81. // needed functions. So, we get the needed object accessing it directly
  82. // from memory.
  83. unsigned int *pointer_to_abstract_audio =
  84. (unsigned int*)((unsigned char*)m_audioOutput + 8);
  85. unsigned int *dev_sound_wrapper =
  86. (unsigned int*)(*pointer_to_abstract_audio) + 13;
  87. unsigned int *temp = ((unsigned int*)(*dev_sound_wrapper) + 6);
  88. CMMFDevSound *devSound = (CMMFDevSound*)(*temp);
  89. devSound->SetVolume(devSound->MaxVolume() * 6 / 10);
  90. #endif
  91. #endif // ifndef Q_OS_SYMBIAN - else
  92. }
  93. /*!
  94. Destructor.
  95. */
  96. AudioOut::~AudioOut()
  97. {
  98. if (m_threadState == DoRun) {
  99. // Set the thread to exit run().
  100. m_threadState = DoExit;
  101. }
  102. if (QThread::isRunning() == false) {
  103. m_threadState = NotRunning;
  104. }
  105. while (m_threadState != NotRunning) {
  106. // Wait until the thread is finished.
  107. msleep(50);
  108. }
  109. m_audioOutput->stop();
  110. delete m_audioOutput;
  111. delete [] m_sendBuffer;
  112. }
  113. /*!
  114. For internal notification solution.
  115. */
  116. void AudioOut::audioNotify()
  117. {
  118. tick();
  119. }
  120. /*!
  121. TODO: Document what this method actually does and why it is needed.
  122. Call this method manually only if you are not using a thread (with Symbian).
  123. Note: When using Qt GameEnabler, the GameWindow instance owning this AudioOut
  124. instance will handle calling this method and you should not try to call this
  125. explicitly.
  126. */
  127. void AudioOut::tick()
  128. {
  129. // Fill data to the buffer as much as there is free space available.
  130. int samplesToWrite(m_audioOutput->bytesFree() /
  131. (GEDefaultChannelCount * AUDIO_SAMPLE_BITS / 8));
  132. samplesToWrite *= 2;
  133. if (samplesToWrite <= 0)
  134. return;
  135. if (samplesToWrite > m_sendBufferSize)
  136. samplesToWrite = m_sendBufferSize;
  137. int mixedSamples = m_source->pullAudio(m_sendBuffer, samplesToWrite);
  138. m_outTarget->write((char*)m_sendBuffer, mixedSamples * 2);
  139. }
  140. /*!
  141. From QThread.
  142. Used only in threaded solutions.
  143. */
  144. void AudioOut::run()
  145. {
  146. DEBUG_INFO("Starting thread.");
  147. m_threadState = DoRun;
  148. if (!m_source) {
  149. DEBUG_INFO("No audio source, exiting the thread!");
  150. m_threadState = NotRunning;
  151. return;
  152. }
  153. while (m_threadState == DoRun) {
  154. tick();
  155. msleep(GEThreadSleepTime);
  156. }
  157. DEBUG_INFO("Exiting thread.");
  158. m_threadState = NotRunning;
  159. }