Barely working basic playback

This commit is contained in:
Blue 2018-12-17 20:15:58 +03:00 committed by Gitea
parent 2a4dce3616
commit 85a14b5101
19 changed files with 406 additions and 24 deletions

View file

@ -16,6 +16,7 @@ set(HEADERS
catalogue.h
button.h
file/file.h
file/audio.h
)
set(SOURCES
@ -28,6 +29,7 @@ set(SOURCES
catalogue.cpp
button.cpp
file/file.cpp
file/audio.cpp
)
add_library(wModel STATIC ${HEADERS} ${SOURCES})
@ -36,3 +38,4 @@ target_link_libraries(wModel Qt5::Core)
target_link_libraries(wModel wServerUtils)
target_link_libraries(wModel wType)
target_link_libraries(wModel wController)
target_link_libraries(wModel mad)

View file

@ -52,7 +52,7 @@ void M::Button::setEnabled(bool p_enabled)
enabled = p_enabled;
if (registered) {
W::Vocabulary* vc = new W::Vocabulary();
vc->insert(u"enable", new W::Boolean(enabled));
vc->insert(u"enabled", new W::Boolean(enabled));
broadcast(vc, W::Address{u"setEnabled"});
}
}

80
lib/wModel/file/audio.cpp Normal file
View file

@ -0,0 +1,80 @@
#include "audio.h"
#include <mad.h>
M::Audio::Audio(W::Blob* p_file, const W::Address& addr, QObject* parent):
File(p_file, addr, parent),
frames()
{
W::Handler* requestFrames = W::Handler::create(address + W::Address({u"requestFrames"}), this, &M::Audio::_h_requestFrames);
addHandler(requestFrames);
}
M::Audio::~Audio()
{}
M::Model::ModelType M::Audio::getType() const
{
return type;
}
void M::Audio::initAdditional(const W::String& p_mime)
{
File::initAdditional(p_mime); //TODO handle other than mp3 formats
mad_stream stream;
mad_header header;
mad_stream_init(&stream);
mad_header_init(&header);
mad_stream_buffer(&stream, file->uchar(), file->size());
uint64_t length = 0;
uint64_t tBits = 0;
while(stream.error != MAD_ERROR_BUFLEN) { //TODO handle other errors;
int success = mad_header_decode(&header, &stream);
if (success == 0) {
frames.emplace_back(stream.this_frame - stream.buffer, stream.next_frame - stream.this_frame);
length += header.duration.seconds * MAD_TIMER_RESOLUTION + header.duration.fraction;
tBits += header.bitrate;
}
}
additional.insert(u"duration", new W::Uint64(length / MAD_TIMER_RESOLUTION));
additional.insert(u"bitrate", new W::Uint64(tBits / frames.size()));
additional.insert(u"framesAmount", new W::Uint64(frames.size()));
}
void M::Audio::h_requestFrames(const W::Event& ev)
{
const W::Vocabulary& vc = static_cast<const W::Vocabulary&>(ev.getData());
const W::Uint64& index = static_cast<const W::Uint64&>(vc.at(u"index"));
const W::Uint64& amount = static_cast<const W::Uint64&>(vc.at(u"amount"));
W::Vocabulary* evc = new W::Vocabulary();
if (index + amount > frames.size()) {
evc->insert(u"result", new W::Uint64(1));
} else {
evc->insert(u"result", new W::Uint64(0));
uint64_t start = 0;
uint64_t size = 0;
bool first = true;
for (int i = 0; i < amount; ++i) {
const std::pair<uint64_t, uint64_t>& pair = frames[index + i];
if (first) {
start = pair.first;
first = false;
}
size += pair.second;
}
evc->insert(u"data", file->slice(start, size));
evc->insert(u"amount", new W::Uint64(amount));
}
response(evc, W::Address{u"responseFrames"}, ev);
}

36
lib/wModel/file/audio.h Normal file
View file

@ -0,0 +1,36 @@
#ifndef M_AUDIO_H
#define M_AUDIO_H
#include <wModel/file/file.h>
#include <wType/blob.h>
#include <deque>
namespace M {
/**
* @todo write docs
*/
class Audio : public File {
friend class File;
protected:
Audio(W::Blob* p_file, const W::Address& addr, QObject* parent = 0);
public:
~Audio();
M::Model::ModelType getType() const override;
static const M::Model::ModelType type = audio;
protected:
void initAdditional(const W::String& p_mime) override;
handler(requestFrames);
private:
std::deque<std::pair<uint64_t, uint64_t>> frames;
};
}
#endif // M_AUDIO_H

View file

@ -1,7 +1,13 @@
#include "file.h"
#include <iostream>
#include "audio.h"
QMimeDatabase M::File::mimeDB;
const std::map<QString, M::Model::ModelType> M::File::mimeMap = {
{"image/jpeg", M::Model::file},
{"audio/mpeg", M::Model::audio}
};
M::File::File(W::Blob* p_file, const W::Address& addr, QObject* parent):
M::Model(addr, parent),
@ -79,8 +85,24 @@ M::File * M::File::create(W::Blob* blob, const W::Address& addr, QObject* parent
M::File* out;
QMimeType mt = mimeDB.mimeTypeForData(blob->byteArray());
out = new File(blob, addr, parent);
out->initAdditional(W::String(mt.name().toStdString()));
const QString& mime = mt.name();
std::map<QString, M::Model::ModelType>::const_iterator itr = mimeMap.find(mime);
M::Model::ModelType modelType = M::Model::file;
if (itr != mimeMap.end()) {
modelType = itr->second;
}
switch (modelType) {
case Model::audio:
out = new Audio(blob, addr, parent);
break;
default:
out = new File(blob, addr, parent);
break;
}
out->initAdditional(W::String(mime.toStdString()));
return out;
}

View file

@ -38,6 +38,7 @@ namespace M {
W::Blob* file;
static QMimeDatabase mimeDB;
static const std::map<QString, M::Model::ModelType> mimeMap;
};
}

View file

@ -36,6 +36,7 @@ namespace M {
attributes = 50,
file,
resourceCache,
audio,
player = 107
};

View file

@ -144,3 +144,17 @@ const QByteArray & W::Blob::byteArray() const
return qDataView;
}
const unsigned char * W::Blob::uchar() const
{
return (unsigned char*) data;
}
W::Blob* W::Blob::slice(uint64_t start, uint64_t length) const
{
char* n_data = new char[length];
for (int i = 0; i < length; ++i) {
n_data[i] = data[start + i];
}
return new W::Blob(length, n_data);
}

View file

@ -22,6 +22,7 @@ namespace W
size_type size() const override;
objectType getType() const override;
Blob* slice(uint64_t start, uint64_t length = 0) const;
bool operator==(const W::Object & other) const override;
@ -33,6 +34,7 @@ namespace W
static const objectType type = blob;
const QByteArray& byteArray() const;
const unsigned char* uchar() const;
protected:
bool hasData;