AudioMixer.h 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  4. * You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. #ifndef MOZILLA_AUDIOMIXER_H_
  6. #define MOZILLA_AUDIOMIXER_H_
  7. #include "AudioSampleFormat.h"
  8. #include "nsTArray.h"
  9. #include "mozilla/PodOperations.h"
  10. #include "mozilla/LinkedList.h"
  11. #include "AudioStream.h"
  12. namespace mozilla {
  13. struct MixerCallbackReceiver {
  14. virtual void MixerCallback(AudioDataValue* aMixedBuffer,
  15. AudioSampleFormat aFormat,
  16. uint32_t aChannels,
  17. uint32_t aFrames,
  18. uint32_t aSampleRate) = 0;
  19. };
  20. /**
  21. * This class mixes multiple streams of audio together to output a single audio
  22. * stream.
  23. *
  24. * AudioMixer::Mix is to be called repeatedly with buffers that have the same
  25. * length, sample rate, sample format and channel count. This class works with
  26. * interleaved and plannar buffers, but the buffer mixed must be of the same
  27. * type during a mixing cycle.
  28. *
  29. * When all the tracks have been mixed, calling FinishMixing will call back with
  30. * a buffer containing the mixed audio data.
  31. *
  32. * This class is not thread safe.
  33. */
  34. class AudioMixer
  35. {
  36. public:
  37. AudioMixer()
  38. : mFrames(0),
  39. mChannels(0),
  40. mSampleRate(0)
  41. { }
  42. ~AudioMixer()
  43. {
  44. MixerCallback* cb;
  45. while ((cb = mCallbacks.popFirst())) {
  46. delete cb;
  47. }
  48. }
  49. void StartMixing()
  50. {
  51. mSampleRate = mChannels = mFrames = 0;
  52. }
  53. /* Get the data from the mixer. This is supposed to be called when all the
  54. * tracks have been mixed in. The caller should not hold onto the data. */
  55. void FinishMixing() {
  56. MOZ_ASSERT(mChannels && mFrames && mSampleRate, "Mix not called for this cycle?");
  57. for (MixerCallback* cb = mCallbacks.getFirst();
  58. cb != nullptr; cb = cb->getNext()) {
  59. cb->mReceiver->MixerCallback(mMixedAudio.Elements(),
  60. AudioSampleTypeToFormat<AudioDataValue>::Format,
  61. mChannels,
  62. mFrames,
  63. mSampleRate);
  64. }
  65. PodZero(mMixedAudio.Elements(), mMixedAudio.Length());
  66. mSampleRate = mChannels = mFrames = 0;
  67. }
  68. /* Add a buffer to the mix. */
  69. void Mix(AudioDataValue* aSamples,
  70. uint32_t aChannels,
  71. uint32_t aFrames,
  72. uint32_t aSampleRate) {
  73. if (!mFrames && !mChannels) {
  74. mFrames = aFrames;
  75. mChannels = aChannels;
  76. mSampleRate = aSampleRate;
  77. EnsureCapacityAndSilence();
  78. }
  79. MOZ_ASSERT(aFrames == mFrames);
  80. MOZ_ASSERT(aChannels == mChannels);
  81. MOZ_ASSERT(aSampleRate == mSampleRate);
  82. for (uint32_t i = 0; i < aFrames * aChannels; i++) {
  83. mMixedAudio[i] += aSamples[i];
  84. }
  85. }
  86. void AddCallback(MixerCallbackReceiver* aReceiver) {
  87. mCallbacks.insertBack(new MixerCallback(aReceiver));
  88. }
  89. bool FindCallback(MixerCallbackReceiver* aReceiver) {
  90. for (MixerCallback* cb = mCallbacks.getFirst();
  91. cb != nullptr; cb = cb->getNext()) {
  92. if (cb->mReceiver == aReceiver) {
  93. return true;
  94. }
  95. }
  96. return false;
  97. }
  98. bool RemoveCallback(MixerCallbackReceiver* aReceiver) {
  99. for (MixerCallback* cb = mCallbacks.getFirst();
  100. cb != nullptr; cb = cb->getNext()) {
  101. if (cb->mReceiver == aReceiver) {
  102. cb->remove();
  103. delete cb;
  104. return true;
  105. }
  106. }
  107. return false;
  108. }
  109. private:
  110. void EnsureCapacityAndSilence() {
  111. if (mFrames * mChannels > mMixedAudio.Length()) {
  112. mMixedAudio.SetLength(mFrames* mChannels);
  113. }
  114. PodZero(mMixedAudio.Elements(), mMixedAudio.Length());
  115. }
  116. class MixerCallback : public LinkedListElement<MixerCallback>
  117. {
  118. public:
  119. explicit MixerCallback(MixerCallbackReceiver* aReceiver)
  120. : mReceiver(aReceiver)
  121. { }
  122. MixerCallbackReceiver* mReceiver;
  123. };
  124. /* Function that is called when the mixing is done. */
  125. LinkedList<MixerCallback> mCallbacks;
  126. /* Number of frames for this mixing block. */
  127. uint32_t mFrames;
  128. /* Number of channels for this mixing block. */
  129. uint32_t mChannels;
  130. /* Sample rate the of the mixed data. */
  131. uint32_t mSampleRate;
  132. /* Buffer containing the mixed audio data. */
  133. nsTArray<AudioDataValue> mMixedAudio;
  134. };
  135. } // namespace mozilla
  136. #endif // MOZILLA_AUDIOMIXER_H_