summaryrefslogtreecommitdiff
path: root/src/tangara/audio/stream_cues.cpp
blob: 6a9a76747bec1c83e528266f09984b565bc0cedb (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
57
58
59
60
61
62
63
64
65
66
67
/*
 * Copyright 2024 jacqueline <me@jacqueline.id.au>
 *
 * SPDX-License-Identifier: GPL-3.0-only
 */

#include "audio/stream_cues.hpp"

#include <cstdint>
#include <memory>

namespace audio {

StreamCues::StreamCues() : now_(0) {}

auto StreamCues::update(uint32_t sample) -> void {
  if (sample < now_) {
    // The current time must have overflowed. Deal with any cues between now_
    // and UINT32_MAX, then proceed as normal.
    while (!upcoming_.empty() && upcoming_.front().start_at > now_) {
      current_ = upcoming_.front();
      upcoming_.pop_front();
    }
  }
  now_ = sample;

  // Advance the current queue until we've caught up.
  while (!upcoming_.empty() && upcoming_.front().start_at <= now_) {
    current_ = upcoming_.front();
    upcoming_.pop_front();
  }
}

auto StreamCues::addCue(std::shared_ptr<TrackInfo> track, uint32_t sample)
    -> void {
  if (sample == now_) {
    current_ = {track, now_};
  } else {
    upcoming_.push_back(Cue{
        .track = track,
        .start_at = sample,
    });
  }
}

auto StreamCues::current() -> std::pair<std::shared_ptr<TrackInfo>, uint32_t> {
  if (!current_) {
    return {};
  }

  uint32_t duration;
  if (now_ < current_->start_at) {
    // now_ overflowed since this track started.
    duration = now_ + (UINT32_MAX - current_->start_at);
  } else {
    duration = now_ - current_->start_at;
  }

  return {current_->track, duration};
}

auto StreamCues::hasStream() -> bool {
  // 'current_' might be tracking how long we've been playing nothing for.
  return (current_ && current_->track) || !upcoming_.empty();
}

}  // namespace audio