summaryrefslogtreecommitdiff
path: root/src/codecs/ogg.cpp
diff options
context:
space:
mode:
authorjacqueline <me@jacqueline.id.au>2023-08-09 11:22:08 +1000
committerjacqueline <me@jacqueline.id.au>2023-08-09 11:22:08 +1000
commit578c3737f8c07e543b90f964da0e89db1c18bb9a (patch)
tree9463cef1108936bd25c76d17e5f0ea26a6412a36 /src/codecs/ogg.cpp
parentf277bd5d0c6fdb9e2c125a2a6cc32675f87056cf (diff)
downloadtangara-fw-578c3737f8c07e543b90f964da0e89db1c18bb9a.tar.gz
Add vorbis support whilst we're here
Diffstat (limited to 'src/codecs/ogg.cpp')
-rw-r--r--src/codecs/ogg.cpp109
1 files changed, 109 insertions, 0 deletions
diff --git a/src/codecs/ogg.cpp b/src/codecs/ogg.cpp
index e69de29b..2b332a12 100644
--- a/src/codecs/ogg.cpp
+++ b/src/codecs/ogg.cpp
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2023 jacqueline <me@jacqueline.id.au>
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+#include "ogg.hpp"
+#include <cstring>
+
+#include "esp_log.h"
+#include "ogg/ogg.h"
+
+namespace codecs {
+
+static constexpr char kTag[] = "ogg";
+
+OggContainer::OggContainer()
+ : sync_(),
+ stream_(),
+ page_(),
+ packet_(),
+ has_stream_(false),
+ has_packet_(false) {
+ ogg_sync_init(&sync_);
+ ogg_sync_pageout(&sync_, &page_);
+}
+
+OggContainer::~OggContainer() {
+ ogg_sync_clear(&sync_);
+ if (has_stream_) {
+ ogg_stream_clear(&stream_);
+ }
+}
+
+auto OggContainer::AddBytes(cpp::span<const std::byte> in) -> bool {
+ ESP_LOGI(kTag, "adding %u bytes to buffer", in.size());
+ char* buf = ogg_sync_buffer(&sync_, in.size());
+ if (buf == NULL) {
+ ESP_LOGE(kTag, "failed to allocate sync buffer");
+ return false;
+ }
+ std::memcpy(buf, in.data(), in.size());
+ if (ogg_sync_wrote(&sync_, in.size()) < 0) {
+ ESP_LOGE(kTag, "failed to write to sync buffer");
+ return false;
+ }
+ return AdvancePage() && AdvancePacket();
+}
+
+auto OggContainer::HasPacket() -> bool {
+ return has_packet_;
+}
+
+auto OggContainer::Next() -> bool {
+ if (AdvancePacket()) {
+ return true;
+ }
+ if (AdvancePage() && AdvancePacket()) {
+ return true;
+ }
+ return false;
+}
+
+auto OggContainer::Current() -> cpp::span<uint8_t> {
+ if (!has_packet_) {
+ return {};
+ }
+ ESP_LOGI(kTag, "getting packet, location %p size %li", packet_.packet,
+ packet_.bytes);
+ return {packet_.packet, static_cast<size_t>(packet_.bytes)};
+}
+
+auto OggContainer::AdvancePage() -> bool {
+ int err;
+ if ((err = ogg_sync_pageout(&sync_, &page_)) != 1) {
+ ESP_LOGE(kTag, "failed to assemble page, res %i", err);
+ return false;
+ }
+ if (!has_stream_) {
+ int serialno = ogg_page_serialno(&page_);
+ ESP_LOGI(kTag, "beginning ogg stream, serial number %i", serialno);
+ if ((err = ogg_stream_init(&stream_, serialno) < 0)) {
+ ESP_LOGE(kTag, "failed to init stream page, res %i", err);
+ return false;
+ }
+ has_stream_ = true;
+ }
+ if (ogg_stream_pagein(&stream_, &page_) < 0) {
+ ESP_LOGE(kTag, "failed to read in page");
+ return false;
+ }
+ return true;
+}
+
+auto OggContainer::AdvancePacket() -> bool {
+ has_packet_ = false;
+ int res;
+ while ((res = ogg_stream_packetout(&stream_, &packet_)) == -1) {
+ // Retry until we sync, or run out of data.
+ ESP_LOGW(kTag, "trying to sync stream...");
+ }
+ has_packet_ = res;
+ if (!has_packet_) {
+ ESP_LOGE(kTag, "failed to read out packet");
+ }
+ return has_packet_;
+}
+
+} // namespace codecs \ No newline at end of file