| 1 | /**************************************************************************** | 
| 2 | ** | 
| 3 | ** Copyright (C) 2016 The Qt Company Ltd. | 
| 4 | ** Contact: https://www.qt.io/licensing/ | 
| 5 | ** | 
| 6 | ** This file is part 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 https://www.qt.io/terms-conditions. For further | 
| 15 | ** information use the contact form at https://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 3 as published by the Free Software | 
| 20 | ** Foundation and appearing in the file LICENSE.LGPL3 included in the | 
| 21 | ** packaging of this file. Please review the following information to | 
| 22 | ** ensure the GNU Lesser General Public License version 3 requirements | 
| 23 | ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. | 
| 24 | ** | 
| 25 | ** GNU General Public License Usage | 
| 26 | ** Alternatively, this file may be used under the terms of the GNU | 
| 27 | ** General Public License version 2.0 or (at your option) the GNU General | 
| 28 | ** Public license version 3 or any later version approved by the KDE Free | 
| 29 | ** Qt Foundation. The licenses are as published by the Free Software | 
| 30 | ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 | 
| 31 | ** included in the packaging of this file. Please review the following | 
| 32 | ** information to ensure the GNU General Public License requirements will | 
| 33 | ** be met: https://www.gnu.org/licenses/gpl-2.0.html and | 
| 34 | ** https://www.gnu.org/licenses/gpl-3.0.html. | 
| 35 | ** | 
| 36 | ** $QT_END_LICENSE$ | 
| 37 | ** | 
| 38 | ****************************************************************************/ | 
| 39 |  | 
| 40 |  | 
| 41 | #include "qaudio.h" | 
| 42 | #include "qaudiodeviceinfo.h" | 
| 43 | #include "qaudiosystem.h" | 
| 44 | #include "qaudiooutput.h" | 
| 45 |  | 
| 46 | #include "qaudiodevicefactory_p.h" | 
| 47 |  | 
| 48 |  | 
| 49 | QT_BEGIN_NAMESPACE | 
| 50 |  | 
| 51 | /*! | 
| 52 |     \class QAudioOutput | 
| 53 |     \brief The QAudioOutput class provides an interface for sending audio data to an audio output device. | 
| 54 |  | 
| 55 |     \inmodule QtMultimedia | 
| 56 |     \ingroup multimedia | 
| 57 |     \ingroup multimedia_audio | 
| 58 |  | 
| 59 |     You can construct an audio output with the system's | 
| 60 |     \l{QAudioDeviceInfo::defaultOutputDevice()}{default audio output | 
| 61 |     device}. It is also possible to create QAudioOutput with a | 
| 62 |     specific QAudioDeviceInfo. When you create the audio output, you | 
| 63 |     should also send in the QAudioFormat to be used for the playback | 
| 64 |     (see the QAudioFormat class description for details). | 
| 65 |  | 
| 66 |     To play a file: | 
| 67 |  | 
| 68 |     Starting to play an audio stream is simply a matter of calling | 
| 69 |     start() with a QIODevice. QAudioOutput will then fetch the data it | 
| 70 |     needs from the io device. So playing back an audio file is as | 
| 71 |     simple as: | 
| 72 |  | 
| 73 |     \snippet multimedia-snippets/audio.cpp Audio output class members | 
| 74 |  | 
| 75 |     \snippet multimedia-snippets/audio.cpp Audio output setup | 
| 76 |  | 
| 77 |     The file will start playing assuming that the audio system and | 
| 78 |     output device support it. If you run out of luck, check what's | 
| 79 |     up with the error() function. | 
| 80 |  | 
| 81 |     After the file has finished playing, we need to stop the device: | 
| 82 |  | 
| 83 |     \snippet multimedia-snippets/audio.cpp Audio output state changed | 
| 84 |  | 
| 85 |     At any given time, the QAudioOutput will be in one of four states: | 
| 86 |     active, suspended, stopped, or idle. These states are described | 
| 87 |     by the QAudio::State enum. | 
| 88 |     State changes are reported through the stateChanged() signal. You | 
| 89 |     can use this signal to, for instance, update the GUI of the | 
| 90 |     application; the mundane example here being changing the state of | 
| 91 |     a \c { play/pause } button. You request a state change directly | 
| 92 |     with suspend(), stop(), reset(), resume(), and start(). | 
| 93 |  | 
| 94 |     While the stream is playing, you can set a notify interval in | 
| 95 |     milliseconds with setNotifyInterval(). This interval specifies the | 
| 96 |     time between two emissions of the notify() signal. This is | 
| 97 |     relative to the position in the stream, i.e., if the QAudioOutput | 
| 98 |     is in the SuspendedState or the IdleState, the notify() signal is | 
| 99 |     not emitted. A typical use-case would be to update a | 
| 100 |     \l{QSlider}{slider} that allows seeking in the stream. | 
| 101 |     If you want the time since playback started regardless of which | 
| 102 |     states the audio output has been in, elapsedUSecs() is the function for you. | 
| 103 |  | 
| 104 |     If an error occurs, you can fetch the \l{QAudio::Error}{error | 
| 105 |     type} with the error() function. Please see the QAudio::Error enum | 
| 106 |     for a description of the possible errors that are reported.  When | 
| 107 |     an error is encountered, the state changes to QAudio::StoppedState. | 
| 108 |     You can check for errors by connecting to the stateChanged() | 
| 109 |     signal: | 
| 110 |  | 
| 111 |     \snippet multimedia-snippets/audio.cpp Audio output state changed | 
| 112 |  | 
| 113 |     \sa QAudioInput, QAudioDeviceInfo | 
| 114 | */ | 
| 115 |  | 
| 116 | /*! | 
| 117 |     Construct a new audio output and attach it to \a parent. | 
| 118 |     The default audio output device is used with the output | 
| 119 |     \a format parameters. | 
| 120 | */ | 
| 121 | QAudioOutput::QAudioOutput(const QAudioFormat &format, QObject *parent): | 
| 122 |     QObject(parent) | 
| 123 | { | 
| 124 |     d = QAudioDeviceFactory::createDefaultOutputDevice(format); | 
| 125 |     connect(asender: d, SIGNAL(notify()), SIGNAL(notify())); | 
| 126 |     connect(asender: d, SIGNAL(stateChanged(QAudio::State)), SIGNAL(stateChanged(QAudio::State))); | 
| 127 | } | 
| 128 |  | 
| 129 | /*! | 
| 130 |     Construct a new audio output and attach it to \a parent. | 
| 131 |     The device referenced by \a audioDevice is used with the output | 
| 132 |     \a format parameters. | 
| 133 | */ | 
| 134 | QAudioOutput::QAudioOutput(const QAudioDeviceInfo &audioDevice, const QAudioFormat &format, QObject *parent): | 
| 135 |     QObject(parent) | 
| 136 | { | 
| 137 |     d = QAudioDeviceFactory::createOutputDevice(device: audioDevice, format); | 
| 138 |     connect(asender: d, SIGNAL(notify()), SIGNAL(notify())); | 
| 139 |     connect(asender: d, SIGNAL(stateChanged(QAudio::State)), SIGNAL(stateChanged(QAudio::State))); | 
| 140 | } | 
| 141 |  | 
| 142 | /*! | 
| 143 |     Destroys this audio output. | 
| 144 |  | 
| 145 |     This will release any system resources used and free any buffers. | 
| 146 | */ | 
| 147 | QAudioOutput::~QAudioOutput() | 
| 148 | { | 
| 149 |     delete d; | 
| 150 | } | 
| 151 |  | 
| 152 | /*! | 
| 153 |     Returns the QAudioFormat being used. | 
| 154 |  | 
| 155 | */ | 
| 156 | QAudioFormat QAudioOutput::format() const | 
| 157 | { | 
| 158 |     return d->format(); | 
| 159 | } | 
| 160 |  | 
| 161 | /*! | 
| 162 |     Starts transferring audio data from the \a device to the system's audio output. | 
| 163 |     The \a device must have been opened in the \l{QIODevice::ReadOnly}{ReadOnly} or | 
| 164 |     \l{QIODevice::ReadWrite}{ReadWrite} modes. | 
| 165 |  | 
| 166 |     If the QAudioOutput is able to successfully output audio data, state() returns | 
| 167 |     QAudio::ActiveState, error() returns QAudio::NoError | 
| 168 |     and the stateChanged() signal is emitted. | 
| 169 |  | 
| 170 |     If a problem occurs during this process, error() returns QAudio::OpenError, | 
| 171 |     state() returns QAudio::StoppedState and the stateChanged() signal is emitted. | 
| 172 |  | 
| 173 |     \sa QIODevice | 
| 174 | */ | 
| 175 | void QAudioOutput::start(QIODevice* device) | 
| 176 | { | 
| 177 |     d->start(device); | 
| 178 | } | 
| 179 |  | 
| 180 | /*! | 
| 181 |     Returns a pointer to the internal QIODevice being used to transfer data to | 
| 182 |     the system's audio output. The device will already be open and | 
| 183 |     \l{QIODevice::write()}{write()} can write data directly to it. | 
| 184 |  | 
| 185 |     \note The pointer will become invalid after the stream is stopped or | 
| 186 |     if you start another stream. | 
| 187 |  | 
| 188 |     If the QAudioOutput is able to access the system's audio device, state() returns | 
| 189 |     QAudio::IdleState, error() returns QAudio::NoError | 
| 190 |     and the stateChanged() signal is emitted. | 
| 191 |  | 
| 192 |     If a problem occurs during this process, error() returns QAudio::OpenError, | 
| 193 |     state() returns QAudio::StoppedState and the stateChanged() signal is emitted. | 
| 194 |  | 
| 195 |     \sa QIODevice | 
| 196 | */ | 
| 197 | QIODevice* QAudioOutput::start() | 
| 198 | { | 
| 199 |     return d->start(); | 
| 200 | } | 
| 201 |  | 
| 202 | /*! | 
| 203 |     Stops the audio output, detaching from the system resource. | 
| 204 |  | 
| 205 |     Sets error() to QAudio::NoError, state() to QAudio::StoppedState and | 
| 206 |     emit stateChanged() signal. | 
| 207 | */ | 
| 208 | void QAudioOutput::stop() | 
| 209 | { | 
| 210 |     d->stop(); | 
| 211 | } | 
| 212 |  | 
| 213 | /*! | 
| 214 |     Drops all audio data in the buffers, resets buffers to zero. | 
| 215 |  | 
| 216 | */ | 
| 217 | void QAudioOutput::reset() | 
| 218 | { | 
| 219 |     d->reset(); | 
| 220 | } | 
| 221 |  | 
| 222 | /*! | 
| 223 |     Stops processing audio data, preserving buffered audio data. | 
| 224 |  | 
| 225 |     Sets error() to QAudio::NoError, state() to QAudio::SuspendedState and | 
| 226 |     emits stateChanged() signal. | 
| 227 | */ | 
| 228 | void QAudioOutput::suspend() | 
| 229 | { | 
| 230 |     d->suspend(); | 
| 231 | } | 
| 232 |  | 
| 233 | /*! | 
| 234 |     Resumes processing audio data after a suspend(). | 
| 235 |  | 
| 236 |     Sets error() to QAudio::NoError. | 
| 237 |     Sets state() to QAudio::ActiveState if you previously called start(QIODevice*). | 
| 238 |     Sets state() to QAudio::IdleState if you previously called start(). | 
| 239 |     emits stateChanged() signal. | 
| 240 | */ | 
| 241 | void QAudioOutput::resume() | 
| 242 | { | 
| 243 |      d->resume(); | 
| 244 | } | 
| 245 |  | 
| 246 | /*! | 
| 247 |     Returns the number of free bytes available in the audio buffer. | 
| 248 |  | 
| 249 |     \note The returned value is only valid while in QAudio::ActiveState or QAudio::IdleState | 
| 250 |     state, otherwise returns zero. | 
| 251 | */ | 
| 252 | int QAudioOutput::bytesFree() const | 
| 253 | { | 
| 254 |     return d->bytesFree(); | 
| 255 | } | 
| 256 |  | 
| 257 | /*! | 
| 258 |     Returns the period size in bytes. This is the amount of data required each period | 
| 259 |     to prevent buffer underrun, and to ensure uninterrupted playback. | 
| 260 |  | 
| 261 |     \note It is recommended to provide at least enough data for a full period with each | 
| 262 |     write operation. | 
| 263 | */ | 
| 264 | int QAudioOutput::periodSize() const | 
| 265 | { | 
| 266 |     return d->periodSize(); | 
| 267 | } | 
| 268 |  | 
| 269 | /*! | 
| 270 |     Sets the audio buffer size to \a value in bytes. | 
| 271 |  | 
| 272 |     \note This function can be called anytime before start().  Calls to this | 
| 273 |     are ignored after start(). It should not be assumed that the buffer size | 
| 274 |     set is the actual buffer size used - call bufferSize() anytime after start() | 
| 275 |     to return the actual buffer size being used. | 
| 276 | */ | 
| 277 | void QAudioOutput::setBufferSize(int value) | 
| 278 | { | 
| 279 |     d->setBufferSize(value); | 
| 280 | } | 
| 281 |  | 
| 282 | /*! | 
| 283 |     Returns the audio buffer size in bytes. | 
| 284 |  | 
| 285 |     If called before start(), returns platform default value. | 
| 286 |     If called before start() but setBufferSize() was called prior, returns value set by setBufferSize(). | 
| 287 |     If called after start(), returns the actual buffer size being used. This may not be what was set previously | 
| 288 |     by setBufferSize(). | 
| 289 |  | 
| 290 | */ | 
| 291 | int QAudioOutput::bufferSize() const | 
| 292 | { | 
| 293 |     return d->bufferSize(); | 
| 294 | } | 
| 295 |  | 
| 296 | /*! | 
| 297 |     Sets the interval for notify() signal to be emitted. | 
| 298 |     This is based on the \a ms of audio data processed, | 
| 299 |     not on wall clock time. | 
| 300 |     The minimum resolution of the timer is platform specific and values | 
| 301 |     should be checked with notifyInterval() to confirm the actual value | 
| 302 |     being used. | 
| 303 | */ | 
| 304 | void QAudioOutput::setNotifyInterval(int ms) | 
| 305 | { | 
| 306 |     d->setNotifyInterval(ms); | 
| 307 | } | 
| 308 |  | 
| 309 | /*! | 
| 310 |     Returns the notify interval in milliseconds. | 
| 311 | */ | 
| 312 | int QAudioOutput::notifyInterval() const | 
| 313 | { | 
| 314 |     return d->notifyInterval(); | 
| 315 | } | 
| 316 |  | 
| 317 | /*! | 
| 318 |     Returns the amount of audio data processed since start() | 
| 319 |     was called (in microseconds). | 
| 320 | */ | 
| 321 | qint64 QAudioOutput::processedUSecs() const | 
| 322 | { | 
| 323 |     return d->processedUSecs(); | 
| 324 | } | 
| 325 |  | 
| 326 | /*! | 
| 327 |     Returns the microseconds since start() was called, including time in Idle and | 
| 328 |     Suspend states. | 
| 329 | */ | 
| 330 | qint64 QAudioOutput::elapsedUSecs() const | 
| 331 | { | 
| 332 |     return d->elapsedUSecs(); | 
| 333 | } | 
| 334 |  | 
| 335 | /*! | 
| 336 |     Returns the error state. | 
| 337 | */ | 
| 338 | QAudio::Error QAudioOutput::error() const | 
| 339 | { | 
| 340 |     return d->error(); | 
| 341 | } | 
| 342 |  | 
| 343 | /*! | 
| 344 |     Returns the state of audio processing. | 
| 345 | */ | 
| 346 | QAudio::State QAudioOutput::state() const | 
| 347 | { | 
| 348 |     return d->state(); | 
| 349 | } | 
| 350 |  | 
| 351 | /*! | 
| 352 |     Sets the output volume to \a volume. | 
| 353 |  | 
| 354 |     The volume is scaled linearly from \c 0.0 (silence) to \c 1.0 (full volume). Values outside this | 
| 355 |     range will be clamped. | 
| 356 |  | 
| 357 |     The default volume is \c 1.0. | 
| 358 |  | 
| 359 |     Note: Adjustments to the volume will change the volume of this audio stream, not the global volume. | 
| 360 |  | 
| 361 |     UI volume controls should usually be scaled nonlinearly. For example, using a logarithmic scale | 
| 362 |     will produce linear changes in perceived loudness, which is what a user would normally expect | 
| 363 |     from a volume control. See QAudio::convertVolume() for more details. | 
| 364 | */ | 
| 365 | void QAudioOutput::setVolume(qreal volume) | 
| 366 | { | 
| 367 |     qreal v = qBound(min: qreal(0.0), val: volume, max: qreal(1.0)); | 
| 368 |     d->setVolume(v); | 
| 369 | } | 
| 370 |  | 
| 371 | /*! | 
| 372 |     Returns the volume between 0.0 and 1.0 inclusive. | 
| 373 | */ | 
| 374 | qreal QAudioOutput::volume() const | 
| 375 | { | 
| 376 |     return d->volume(); | 
| 377 | } | 
| 378 |  | 
| 379 | /*! | 
| 380 |     Returns the audio category of this audio stream. | 
| 381 |  | 
| 382 |     Some platforms can group audio streams into categories | 
| 383 |     and manage their volumes independently, or display them | 
| 384 |     in a system mixer control.  You can set this property to | 
| 385 |     allow the platform to distinguish the purpose of your streams. | 
| 386 |  | 
| 387 |     \sa setCategory() | 
| 388 | */ | 
| 389 | QString QAudioOutput::category() const | 
| 390 | { | 
| 391 |     return d->category(); | 
| 392 | } | 
| 393 |  | 
| 394 | /*! | 
| 395 |     Sets the audio category of this audio stream to \a category. | 
| 396 |  | 
| 397 |     Some platforms can group audio streams into categories | 
| 398 |     and manage their volumes independently, or display them | 
| 399 |     in a system mixer control.  You can set this property to | 
| 400 |     allow the platform to distinguish the purpose of your streams. | 
| 401 |  | 
| 402 |     Not all platforms support audio stream categorization.  In this | 
| 403 |     case, the function call will be ignored. | 
| 404 |  | 
| 405 |     Changing an audio output stream's category while it is opened | 
| 406 |     will not take effect until it is reopened. | 
| 407 |     \sa category() | 
| 408 | */ | 
| 409 | void QAudioOutput::setCategory(const QString &category) | 
| 410 | { | 
| 411 |     d->setCategory(category); | 
| 412 | } | 
| 413 |  | 
| 414 | /*! | 
| 415 |     \fn QAudioOutput::stateChanged(QAudio::State state) | 
| 416 |     This signal is emitted when the device \a state has changed. | 
| 417 |     This is the current state of the audio output. | 
| 418 | */ | 
| 419 |  | 
| 420 | /*! | 
| 421 |     \fn QAudioOutput::notify() | 
| 422 |     This signal is emitted when a certain interval of milliseconds | 
| 423 |     of audio data has been processed.  The interval is set by | 
| 424 |     setNotifyInterval(). | 
| 425 | */ | 
| 426 |  | 
| 427 | QT_END_NAMESPACE | 
| 428 |  | 
| 429 | #include "moc_qaudiooutput.cpp" | 
| 430 |  |