summaryrefslogtreecommitdiff
path: root/src/audio/audio_element.cpp
blob: cef5463101c7a916b5b7aec51fe3ef20bf5a5eb2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include "audio_element.hpp"
#include <memory>

namespace audio {

IAudioElement::IAudioElement()
    : input_events_(xQueueCreate(kEventQueueSize, sizeof(void*))),
      output_events_(nullptr),
      buffered_output_() {}

IAudioElement::~IAudioElement() {
  // Ensure we don't leak any memory from events leftover in the queue.
  while (uxQueueSpacesAvailable(input_events_) < kEventQueueSize) {
    StreamEvent* event;
    if (xQueueReceive(input_events_, &event, 0)) {
      free(event);
    } else {
      break;
    }
  }
  // Technically there's a race here if someone is still adding to the queue,
  // but hopefully the whole pipeline is stopped if an element is being
  // destroyed.
  vQueueDelete(input_events_);
}

auto IAudioElement::SendOrBufferEvent(std::unique_ptr<StreamEvent> event)
    -> bool {
  if (!buffered_output_.empty()) {
    // To ensure we send data in order, don't try to send if we've already
    // failed to send something.
    buffered_output_.push_back(std::move(event));
    return false;
  }
  StreamEvent* raw_event = event.release();
  if (!xQueueSend(output_events_, &raw_event, 0)) {
    event.reset(raw_event);
    buffered_output_.push_back(std::move(event));
    return false;
  }
  return true;
}

auto IAudioElement::FlushBufferedOutput() -> bool {
  while (!buffered_output_.empty()) {
    StreamEvent* raw_event = buffered_output_.front().release();
    buffered_output_.pop_front();
    if (!xQueueSend(output_events_, &raw_event, 0)) {
      buffered_output_.emplace_front(raw_event);
      return false;
    }
  }
  return true;
}

}  // namespace audio