Веб-сайт самохостера Lotigara

summaryrefslogtreecommitdiff
path: root/source/core
diff options
context:
space:
mode:
Diffstat (limited to 'source/core')
-rw-r--r--source/core/CMakeLists.txt4
-rw-r--r--source/core/StarAudio.cpp191
-rw-r--r--source/core/StarBuffer.cpp13
-rw-r--r--source/core/StarBuffer.hpp4
-rw-r--r--source/core/StarCompression.cpp12
-rw-r--r--source/core/StarCompression.hpp2
-rw-r--r--source/core/StarFile.cpp11
-rw-r--r--source/core/StarFile.hpp2
-rw-r--r--source/core/StarIODevice.hpp3
-rw-r--r--source/core/StarIODeviceCallbacks.cpp39
-rw-r--r--source/core/StarIODeviceCallbacks.hpp37
11 files changed, 238 insertions, 80 deletions
diff --git a/source/core/CMakeLists.txt b/source/core/CMakeLists.txt
index 3d00baf..63f86cf 100644
--- a/source/core/CMakeLists.txt
+++ b/source/core/CMakeLists.txt
@@ -10,6 +10,7 @@ SET (star_core_HEADERS
StarAssetPath.hpp
StarAtomicSharedPtr.hpp
StarAudio.hpp
+ StarIODeviceCallbacks.hpp
StarBTree.hpp
StarBTreeDatabase.hpp
StarBiMap.hpp
@@ -141,6 +142,7 @@ SET (star_core_SOURCES
StarBuffer.cpp
StarByteArray.cpp
StarColor.cpp
+ StarIODeviceCallbacks.cpp
StarCompression.cpp
StarCurve25519.cpp
StarDataStream.cpp
@@ -235,4 +237,4 @@ IF(STAR_USE_JEMALLOC AND JEMALLOC_IS_PREFIXED)
SET_SOURCE_FILES_PROPERTIES(StarMemory.cpp PROPERTIES
COMPILE_DEFINITIONS STAR_JEMALLOC_IS_PREFIXED
)
-ENDIF() \ No newline at end of file
+ENDIF()
diff --git a/source/core/StarAudio.cpp b/source/core/StarAudio.cpp
index a1f2e62..1b7e78e 100644
--- a/source/core/StarAudio.cpp
+++ b/source/core/StarAudio.cpp
@@ -6,10 +6,13 @@
#include "StarAudio.hpp"
#include "StarBuffer.hpp"
+#include "StarIODeviceCallbacks.hpp"
#include "StarFile.hpp"
#include "StarFormat.hpp"
#include "StarLogging.hpp"
#include "StarDataStreamDevices.hpp"
+#include "StarSha256.hpp"
+#include "StarEncode.hpp"
namespace Star {
@@ -35,9 +38,10 @@ float amplitudeToPerceptual(float amp, float normalizedMax, float range, float b
namespace {
struct WaveData {
- ByteArrayPtr byteArray;
+ IODevicePtr device;
unsigned channels;
unsigned sampleRate;
+ size_t dataSize; // get the data size from the header to avoid id3 tag
};
template <typename T>
@@ -141,59 +145,59 @@ namespace {
device->size(), wavDataSize + wavDataOffset));
}
- ByteArrayPtr pcmData = make_shared<ByteArray>();
- pcmData->resize(wavDataSize);
-
- // Copy across data and perform and endianess conversion if needed
- device->readFull(pcmData->ptr(), pcmData->size());
- for (size_t i = 0; i < pcmData->size() / 2; ++i)
- fromByteOrder(ByteOrder::LittleEndian, pcmData->ptr() + i * 2, 2);
-
- return WaveData{std::move(pcmData), wavChannels, wavSampleRate};
+ // Return the original device positioned at the PCM data
+ // Note: This means the caller owns handling endianness conversion
+ device->seek(wavDataOffset);
+
+ return WaveData{device, wavChannels, wavSampleRate, wavDataSize};
}
}
class CompressedAudioImpl {
public:
- static size_t readFunc(void* ptr, size_t size, size_t nmemb, void* datasource) {
- return static_cast<ExternalBuffer*>(datasource)->read((char*)ptr, size * nmemb) / size;
- }
- static int seekFunc(void* datasource, ogg_int64_t offset, int whence) {
- static_cast<ExternalBuffer*>(datasource)->seek(offset, (IOSeek)whence);
- return 0;
- };
+ CompressedAudioImpl(CompressedAudioImpl const& impl)
+ : m_audioData(impl.m_audioData->clone()) // Clone instead of sharing
+ , m_deviceCallbacks(m_audioData) // Pass reference to cloned data
+ , m_vorbisInfo(nullptr) {
+ setupCallbacks();
- static long int tellFunc(void* datasource) {
- return (long int)static_cast<ExternalBuffer*>(datasource)->pos();
- };
+ // Make sure data stream is ready to be read
+ m_audioData->open(IOMode::Read);
+ m_audioData->seek(0);
+
+ // Add error checking to see what's happening with the clone
+ if (!m_audioData->isOpen())
+ throw AudioException("Failed to open cloned audio device");
- CompressedAudioImpl(CompressedAudioImpl const& impl) {
- m_audioData = impl.m_audioData;
- m_memoryFile.reset(m_audioData->ptr(), m_audioData->size());
- m_vorbisInfo = nullptr;
+ auto size = m_audioData->size();
+ if (size <= 0)
+ throw AudioException("Cloned audio device has no data");
}
- CompressedAudioImpl(IODevicePtr audioData) {
- audioData->open(IOMode::Read);
- audioData->seek(0);
- m_audioData = make_shared<ByteArray>(audioData->readBytes((size_t)audioData->size()));
- m_memoryFile.reset(m_audioData->ptr(), m_audioData->size());
- m_vorbisInfo = nullptr;
+ CompressedAudioImpl(IODevicePtr audioData)
+ : m_audioData(audioData->clone()) // Clone instead of taking ownership
+ , m_deviceCallbacks(m_audioData) // Pass reference
+ , m_vorbisInfo(nullptr) {
+ setupCallbacks();
+ m_audioData->open(IOMode::Read);
+ m_audioData->seek(0);
}
~CompressedAudioImpl() {
ov_clear(&m_vorbisFile);
}
- bool open() {
- m_callbacks.read_func = readFunc;
- m_callbacks.seek_func = seekFunc;
- m_callbacks.tell_func = tellFunc;
- m_callbacks.close_func = NULL;
+ void setupCallbacks() {
+ m_deviceCallbacks.setupOggCallbacks(m_callbacks);
+ }
- if (ov_open_callbacks(&m_memoryFile, &m_vorbisFile, NULL, 0, m_callbacks) < 0)
+ bool open() {
+ int result = ov_open_callbacks(&m_deviceCallbacks, &m_vorbisFile, NULL, 0, m_callbacks);
+ if (result < 0) {
+ Logger::error("Failed to open ogg stream: error code {}", result);
return false;
+ }
m_vorbisInfo = ov_info(&m_vorbisFile, -1);
return true;
@@ -252,14 +256,14 @@ public:
} while (read == OV_HOLE);
if (read < 0)
throw AudioException::format("Error in Audio::read ({})", read);
-
+
// read in bytes, returning number of int16_t samples.
return read / 2;
}
-
+
private:
- ByteArrayConstPtr m_audioData;
- ExternalBuffer m_memoryFile;
+ IODevicePtr m_audioData;
+ IODeviceCallbacks m_deviceCallbacks;
ov_callbacks m_callbacks;
OggVorbis_File m_vorbisFile;
vorbis_info* m_vorbisInfo;
@@ -267,41 +271,49 @@ private:
class UncompressedAudioImpl {
public:
- UncompressedAudioImpl(UncompressedAudioImpl const& impl) {
- m_channels = impl.m_channels;
- m_sampleRate = impl.m_sampleRate;
- m_audioData = impl.m_audioData;
- m_memoryFile.reset(m_audioData->ptr(), m_audioData->size());
- }
-
+ UncompressedAudioImpl(UncompressedAudioImpl const& impl)
+ : m_device(impl.m_device->clone())
+ , m_channels(impl.m_channels)
+ , m_sampleRate(impl.m_sampleRate)
+ , m_dataSize(impl.m_dataSize)
+ , m_dataStart(impl.m_dataStart)
+
+ {
+ StreamOffset initialPos = m_device->pos(); // Store initial position
+ if (!m_device->isOpen())
+ m_device->open(IOMode::Read);
+ m_device->seek(initialPos); // Restore position after open
+ }
+
UncompressedAudioImpl(CompressedAudioImpl& impl) {
m_channels = impl.channels();
m_sampleRate = impl.sampleRate();
+ // Create a memory buffer to store decompressed data
+ auto memDevice = make_shared<Buffer>();
+
int16_t buffer[1024];
- Buffer uncompressBuffer;
while (true) {
size_t ramt = impl.readPartial(buffer, 1024);
-
- if (ramt == 0) {
- // End of stream reached
+ if (ramt == 0)
break;
- } else {
- uncompressBuffer.writeFull((char*)buffer, ramt * 2);
- }
+ memDevice->writeFull((char*)buffer, ramt * 2);
}
- m_audioData = make_shared<ByteArray>(uncompressBuffer.takeData());
- m_memoryFile.reset(m_audioData->ptr(), m_audioData->size());
+ m_device = memDevice;
}
- UncompressedAudioImpl(ByteArrayConstPtr data, unsigned channels, unsigned sampleRate) {
- m_channels = channels;
- m_sampleRate = sampleRate;
- m_audioData = std::move(data);
- m_memoryFile.reset(m_audioData->ptr(), m_audioData->size());
+ UncompressedAudioImpl(IODevicePtr device, unsigned channels, unsigned sampleRate, size_t dataSize)
+ : m_device(std::move(device))
+ , m_channels(channels)
+ , m_sampleRate(sampleRate)
+ , m_dataSize(dataSize)
+ , m_dataStart((size_t)m_device->pos()) // Store current position as data start
+ {
+ if (!m_device->isOpen())
+ m_device->open(IOMode::Read);
}
-
+
bool open() {
return true;
}
@@ -319,7 +331,7 @@ public:
}
uint64_t totalSamples() {
- return m_memoryFile.dataSize() / 2 / m_channels;
+ return m_device->size() / 2 / m_channels;
}
void seekTime(double time) {
@@ -327,7 +339,7 @@ public:
}
void seekSample(uint64_t pos) {
- m_memoryFile.seek(pos * 2 * m_channels);
+ m_device->seek(pos * 2 * m_channels);
}
double currentTime() {
@@ -335,20 +347,41 @@ public:
}
uint64_t currentSample() {
- return m_memoryFile.pos() / 2 / m_channels;
+ return m_device->pos() / 2 / m_channels;
}
+
size_t readPartial(int16_t* buffer, size_t bufferSize) {
if (bufferSize != NPos)
bufferSize = bufferSize * 2;
- return m_memoryFile.read((char*)buffer, bufferSize) / 2;
+
+ // Calculate remaining valid data
+ size_t currentPos = m_device->pos() - m_dataStart;
+ size_t remainingBytes = m_dataSize - currentPos;
+
+ // Limit read to remaining valid data
+ if (bufferSize > remainingBytes)
+ bufferSize = remainingBytes;
+
+ if (bufferSize == 0)
+ return 0;
+
+ size_t bytesRead = m_device->read((char*)buffer, bufferSize);
+
+ // Handle endianness conversion
+ for (size_t i = 0; i < bytesRead / 2; ++i)
+ fromByteOrder(ByteOrder::LittleEndian, ((char*)buffer) + i * 2, 2);
+
+ return bytesRead / 2;
+
}
private:
+ IODevicePtr m_device;
unsigned m_channels;
unsigned m_sampleRate;
- ByteArrayConstPtr m_audioData;
- ExternalBuffer m_memoryFile;
+ size_t m_dataSize;
+ size_t m_dataStart;
};
Audio::Audio(IODevicePtr device, String name) {
@@ -358,7 +391,7 @@ Audio::Audio(IODevicePtr device, String name) {
if (isUncompressed(device)) {
WaveData data = parseWav(device);
- m_uncompressed = make_shared<UncompressedAudioImpl>(std::move(data.byteArray), data.channels, data.sampleRate);
+ m_uncompressed = make_shared<UncompressedAudioImpl>(std::move(data.device), data.channels, data.sampleRate, data.dataSize);
} else {
m_compressed = make_shared<CompressedAudioImpl>(device);
if (!m_compressed->open())
@@ -375,16 +408,16 @@ Audio::Audio(Audio&& audio) {
}
Audio& Audio::operator=(Audio const& audio) {
- if (audio.m_uncompressed) {
- m_uncompressed = make_shared<UncompressedAudioImpl>(*audio.m_uncompressed);
- m_uncompressed->open();
- } else {
- m_compressed = make_shared<CompressedAudioImpl>(*audio.m_compressed);
- m_compressed->open();
- }
-
- seekSample(audio.currentSample());
- return *this;
+ if (audio.m_uncompressed) {
+ m_uncompressed = make_shared<UncompressedAudioImpl>(*audio.m_uncompressed);
+ m_uncompressed->open();
+ } else {
+ m_compressed = make_shared<CompressedAudioImpl>(*audio.m_compressed);
+ if (!m_compressed->open()) // Check the return value
+ throw AudioException("Failed to open compressed audio stream during copy");
+ seekSample(audio.currentSample()); // Only seek after successful open
+ }
+ return *this;
}
Audio& Audio::operator=(Audio&& audio) {
diff --git a/source/core/StarBuffer.cpp b/source/core/StarBuffer.cpp
index 5b5b2e4..e8184e3 100644
--- a/source/core/StarBuffer.cpp
+++ b/source/core/StarBuffer.cpp
@@ -2,6 +2,7 @@
#include "StarMathCommon.hpp"
#include "StarIODevice.hpp"
#include "StarFormat.hpp"
+#include "StarLogging.hpp"
namespace Star {
@@ -273,6 +274,18 @@ void ExternalBuffer::reset(char const* externalData, size_t len) {
m_size = len;
}
+IODevicePtr Buffer::clone() {
+ auto cloned = make_shared<Buffer>(*this);
+ // Reset position to 0 while preserving mode and data
+ cloned->seek(0);
+ return cloned;
+}
+
+IODevicePtr ExternalBuffer::clone() {
+ Logger::info("Cloning ExternalBuffer from position {}");
+ return make_shared<ExternalBuffer>(*this);
+}
+
size_t ExternalBuffer::doRead(size_t pos, char* data, size_t len) {
if (len == 0)
return 0;
diff --git a/source/core/StarBuffer.hpp b/source/core/StarBuffer.hpp
index 0f9864a..4870b53 100644
--- a/source/core/StarBuffer.hpp
+++ b/source/core/StarBuffer.hpp
@@ -34,6 +34,8 @@ public:
String deviceName() const override;
StreamOffset size() override;
+
+ IODevicePtr clone() override;
ByteArray& data();
ByteArray const& data() const;
@@ -95,6 +97,8 @@ public:
String deviceName() const override;
StreamOffset size() override;
+
+ IODevicePtr clone() override;
// Returns a pointer to the beginning of the Buffer.
char const* ptr() const;
diff --git a/source/core/StarCompression.cpp b/source/core/StarCompression.cpp
index 58b43ef..d99745c 100644
--- a/source/core/StarCompression.cpp
+++ b/source/core/StarCompression.cpp
@@ -233,4 +233,16 @@ void CompressedFile::close() {
setMode(IOMode::Closed);
}
+IODevicePtr CompressedFile::clone() {
+ auto cloned = make_shared<CompressedFile>(m_filename);
+ cloned->setCompression(m_compression);
+ if (isOpen()) {
+ // Open with same mode
+ cloned->open(mode());
+ // Seek to same position
+ cloned->seek(pos());
+ }
+ return cloned;
+}
+
}
diff --git a/source/core/StarCompression.hpp b/source/core/StarCompression.hpp
index 3322662..5ffe791 100644
--- a/source/core/StarCompression.hpp
+++ b/source/core/StarCompression.hpp
@@ -49,6 +49,8 @@ public:
void sync() override;
void close() override;
+ IODevicePtr clone() override;
+
private:
String m_filename;
void* m_file;
diff --git a/source/core/StarFile.cpp b/source/core/StarFile.cpp
index 9153960..75813b4 100644
--- a/source/core/StarFile.cpp
+++ b/source/core/StarFile.cpp
@@ -243,4 +243,15 @@ String File::deviceName() const {
return m_filename;
}
+IODevicePtr File::clone() {
+ auto cloned = make_shared<File>(m_filename);
+ if (isOpen()) {
+ // Open with same mode
+ cloned->open(mode());
+ // Seek to same position
+ cloned->seek(pos());
+ }
+ return cloned;
+}
+
}
diff --git a/source/core/StarFile.hpp b/source/core/StarFile.hpp
index fb489ab..36c8390 100644
--- a/source/core/StarFile.hpp
+++ b/source/core/StarFile.hpp
@@ -127,6 +127,8 @@ public:
String deviceName() const override;
+ IODevicePtr clone() override;
+
private:
static void* fopen(char const* filename, IOMode mode);
static void fseek(void* file, StreamOffset offset, IOSeek seek);
diff --git a/source/core/StarIODevice.hpp b/source/core/StarIODevice.hpp
index b375e81..7bc2a04 100644
--- a/source/core/StarIODevice.hpp
+++ b/source/core/StarIODevice.hpp
@@ -70,6 +70,9 @@ public:
// Default implementation is a no-op
virtual void sync();
+ // Returns a clone of this device with the same mode
+ virtual IODevicePtr clone() = 0;
+
// Default implementation just prints address of generic IODevice
virtual String deviceName() const;
diff --git a/source/core/StarIODeviceCallbacks.cpp b/source/core/StarIODeviceCallbacks.cpp
new file mode 100644
index 0000000..ca8b692
--- /dev/null
+++ b/source/core/StarIODeviceCallbacks.cpp
@@ -0,0 +1,39 @@
+#include "StarIODeviceCallbacks.hpp"
+#include "vorbis/vorbisfile.h"
+
+namespace Star {
+
+IODeviceCallbacks::IODeviceCallbacks(IODevicePtr device)
+ : m_device(std::move(device)) {
+ if (!m_device->isOpen())
+ m_device->open(IOMode::Read);
+}
+
+IODevicePtr const& IODeviceCallbacks::device() const {
+ return m_device;
+}
+
+size_t IODeviceCallbacks::readFunc(void* ptr, size_t size, size_t nmemb, void* datasource) {
+ auto* callbacks = static_cast<IODeviceCallbacks*>(datasource);
+ return callbacks->m_device->read((char*)ptr, size * nmemb) / size;
+}
+
+int IODeviceCallbacks::seekFunc(void* datasource, ogg_int64_t offset, int whence) {
+ auto* callbacks = static_cast<IODeviceCallbacks*>(datasource);
+ callbacks->m_device->seek(offset, (IOSeek)whence);
+ return 0;
+}
+
+long int IODeviceCallbacks::tellFunc(void* datasource) {
+ auto* callbacks = static_cast<IODeviceCallbacks*>(datasource);
+ return (long int)callbacks->m_device->pos();
+}
+
+void IODeviceCallbacks::setupOggCallbacks(ov_callbacks& callbacks) {
+ callbacks.read_func = readFunc;
+ callbacks.seek_func = seekFunc;
+ callbacks.tell_func = tellFunc;
+ callbacks.close_func = nullptr;
+}
+
+} \ No newline at end of file
diff --git a/source/core/StarIODeviceCallbacks.hpp b/source/core/StarIODeviceCallbacks.hpp
new file mode 100644
index 0000000..8e2f9ed
--- /dev/null
+++ b/source/core/StarIODeviceCallbacks.hpp
@@ -0,0 +1,37 @@
+#pragma once
+
+#include "StarIODevice.hpp"
+#include "vorbis/codec.h"
+#include "vorbis/vorbisfile.h"
+
+namespace Star {
+
+// Provides callbacks for interfacing IODevice with ogg vorbis callbacks
+class IODeviceCallbacks {
+public:
+ explicit IODeviceCallbacks(IODevicePtr device);
+
+ // No copying
+ IODeviceCallbacks(IODeviceCallbacks const&) = delete;
+ IODeviceCallbacks& operator=(IODeviceCallbacks const&) = delete;
+
+ // Moving is ok
+ IODeviceCallbacks(IODeviceCallbacks&&) = default;
+ IODeviceCallbacks& operator=(IODeviceCallbacks&&) = default;
+
+ // Get the underlying device
+ IODevicePtr const& device() const;
+
+ // Callback functions for Ogg Vorbis
+ static size_t readFunc(void* ptr, size_t size, size_t nmemb, void* datasource);
+ static int seekFunc(void* datasource, ogg_int64_t offset, int whence);
+ static long int tellFunc(void* datasource);
+
+ // Sets up callbacks for Ogg Vorbis
+ void setupOggCallbacks(ov_callbacks& callbacks);
+
+private:
+ IODevicePtr m_device;
+};
+
+}