| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172 | 
							- #pragma once
 
- #include <atomic>
 
- #include <cmath>
 
- #include <functional>
 
- #include <iostream>
 
- #include <memory>
 
- #include <mutex>
 
- #include "BellUtils.h"
 
- #include "CircularBuffer.h"
 
- #include "StreamInfo.h"
 
- #include "WrappedSemaphore.h"
 
- #ifdef _WIN32
 
- #define __attribute__(X)
 
- #endif
 
- typedef std::function<void(std::string)> shutdownEventHandler;
 
- namespace bell {
 
- class CentralAudioBuffer {
 
-  private:
 
-   std::mutex accessMutex;
 
-   std::atomic<bool> isLocked = false;
 
-   std::mutex dataAccessMutex;
 
-  public:
 
-   static const size_t PCM_CHUNK_SIZE = 4096;
 
-   std::unique_ptr<bell::WrappedSemaphore> chunkReady;
 
-   // Audio marker for track change detection, and DSP autoconfig
 
-   struct AudioChunk {
 
-     // Timeval
 
-     int32_t sec;
 
-     int32_t usec;
 
-     // Unique track hash, used for track change detection
 
-     size_t trackHash;
 
-     // Audio format
 
-     uint32_t sampleRate;
 
-     uint8_t channels;
 
-     uint8_t bitWidth;
 
-     // PCM data size
 
-     size_t pcmSize;
 
-     // PCM data
 
-     uint8_t pcmData[PCM_CHUNK_SIZE];
 
-   } __attribute__((packed));
 
-   CentralAudioBuffer(size_t chunks) {
 
-     audioBuffer = std::make_shared<CircularBuffer>(chunks * sizeof(AudioChunk));
 
-     chunkReady = std::make_unique<bell::WrappedSemaphore>(50);
 
-   }
 
-   std::shared_ptr<bell::CircularBuffer> audioBuffer;
 
-   uint32_t currentSampleRate = 44100;
 
-   /**
 
- 	 * Returns current sample rate
 
- 	 * @return sample rate
 
- 	 */
 
-   uint32_t getSampleRate() { return currentSampleRate; }
 
-   /**
 
- 	 * Clears input buffer, to be called for track change and such
 
- 	 */
 
-   void clearBuffer() {
 
-     std::scoped_lock lock(this->dataAccessMutex);
 
-     audioBuffer->emptyBuffer();
 
-     hasChunk = false;
 
-   }
 
-   void emptyCompletely() {
 
-     std::scoped_lock lock(this->dataAccessMutex);
 
-     audioBuffer->emptyBuffer();
 
-   }
 
-   bool hasAtLeast(size_t chunks) {
 
-     return this->audioBuffer->size() >= chunks * sizeof(AudioChunk);
 
-   }
 
-   /**
 
- 	 * Locks access to audio buffer. Call after starting playback
 
- 	 */
 
-   void lockAccess() {
 
-     if (!isLocked) {
 
-       clearBuffer();
 
-       this->accessMutex.lock();
 
-       isLocked = true;
 
-     }
 
-   }
 
-   /**
 
- 	 * Frees access to the audio buffer. Call during shutdown
 
- 	 */
 
-   void unlockAccess() {
 
-     if (isLocked) {
 
-       clearBuffer();
 
-       this->accessMutex.unlock();
 
-       isLocked = false;
 
-     }
 
-   }
 
-   AudioChunk currentChunk = {};
 
-   bool hasChunk = false;
 
-   AudioChunk lastReadChunk = {};
 
-   AudioChunk* readChunk() {
 
-     std::scoped_lock lock(this->dataAccessMutex);
 
-     if (audioBuffer->size() < sizeof(AudioChunk)) {
 
-       lastReadChunk.pcmSize = 0;
 
-       return nullptr;
 
-     }
 
-     audioBuffer->read((uint8_t*)&lastReadChunk, sizeof(AudioChunk));
 
-     currentSampleRate = static_cast<uint32_t>(lastReadChunk.sampleRate);
 
-     return &lastReadChunk;
 
-   }
 
-   size_t writePCM(const uint8_t* data, size_t dataSize, size_t hash,
 
-                   uint32_t sampleRate = 44100, uint8_t channels = 2,
 
-                   BitWidth bitWidth = BitWidth::BW_16, int32_t sec = 0,
 
-                   int32_t usec = 0) {
 
-     std::scoped_lock lock(this->dataAccessMutex);
 
-     if (hasChunk && (currentChunk.trackHash != hash ||
 
-                      currentChunk.pcmSize >= PCM_CHUNK_SIZE)) {
 
-       if ((audioBuffer->size() - audioBuffer->capacity()) <
 
-           sizeof(AudioChunk)) {
 
-         return 0;
 
-       }
 
-       // Track changed or buf full, return current chunk
 
-       hasChunk = false;
 
-       this->audioBuffer->write((uint8_t*)¤tChunk, sizeof(AudioChunk));
 
-       // this->chunkReady->give();
 
-     }
 
-     // New chunk requested, initialize
 
-     if (!hasChunk) {
 
-       currentChunk.trackHash = hash;
 
-       currentChunk.sampleRate = sampleRate;
 
-       currentChunk.channels = channels;
 
-       currentChunk.bitWidth = 16;
 
-       currentChunk.sec = sec;
 
-       currentChunk.usec = usec;
 
-       currentChunk.pcmSize = 0;
 
-       hasChunk = true;
 
-     }
 
-     // Calculate how much data we can write
 
-     size_t toWriteSize = dataSize;
 
-     if (currentChunk.pcmSize + toWriteSize > PCM_CHUNK_SIZE) {
 
-       toWriteSize = PCM_CHUNK_SIZE - currentChunk.pcmSize;
 
-     }
 
-     // Copy it over :)
 
-     memcpy(currentChunk.pcmData + currentChunk.pcmSize, data, toWriteSize);
 
-     currentChunk.pcmSize += toWriteSize;
 
-     return toWriteSize;
 
-   }
 
- };
 
- }  // namespace bell
 
 
  |