Add Deezer support
This commit is contained in:
487
src/engine/deezerengine.cpp
Normal file
487
src/engine/deezerengine.cpp
Normal file
@@ -0,0 +1,487 @@
|
||||
/*
|
||||
* Strawberry Music Player
|
||||
* Copyright 2018, Jonas Kvinge <jonas@jkvinge.net>
|
||||
*
|
||||
* Strawberry is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Strawberry is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <deezer/deezer-connect.h>
|
||||
#include <deezer/deezer-player.h>
|
||||
|
||||
#include <QtGlobal>
|
||||
#include <QCoreApplication>
|
||||
#include <QStandardPaths>
|
||||
#include <QByteArray>
|
||||
#include <QString>
|
||||
#include <QUrl>
|
||||
#include <QDateTime>
|
||||
|
||||
#include "core/timeconstants.h"
|
||||
#include "core/taskmanager.h"
|
||||
#include "core/logging.h"
|
||||
#include "engine_fwd.h"
|
||||
#include "enginebase.h"
|
||||
#include "enginetype.h"
|
||||
#include "deezerengine.h"
|
||||
#include "deezer/deezerservice.h"
|
||||
#include "settings/deezersettingspage.h"
|
||||
|
||||
DeezerEngine::DeezerEngine(TaskManager *task_manager)
|
||||
: EngineBase(),
|
||||
state_(Engine::Empty),
|
||||
position_(0) {
|
||||
|
||||
type_ = Engine::Deezer;
|
||||
ReloadSettings();
|
||||
|
||||
}
|
||||
|
||||
DeezerEngine::~DeezerEngine() {
|
||||
|
||||
if (player_) {
|
||||
dz_object_release((dz_object_handle) player_);
|
||||
player_ = nullptr;
|
||||
}
|
||||
|
||||
if (connect_) {
|
||||
dz_object_release((dz_object_handle) connect_);
|
||||
connect_ = nullptr;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool DeezerEngine::Init() {
|
||||
|
||||
qLog(Debug) << "Deezer native SDK Version:" << dz_connect_get_build_id();
|
||||
|
||||
struct dz_connect_configuration config;
|
||||
memset(&config, 0, sizeof(struct dz_connect_configuration));
|
||||
config.app_id = QString::number(DeezerService::kAppID).toUtf8();
|
||||
config.product_id = QCoreApplication::applicationName().toUtf8();
|
||||
config.product_build_id = QCoreApplication::applicationVersion().toUtf8().constData();
|
||||
config.user_profile_path = QStandardPaths::writableLocation(QStandardPaths::CacheLocation).toUtf8().constData();
|
||||
config.connect_event_cb = ConnectEventCallback;
|
||||
|
||||
connect_ = dz_connect_new(&config);
|
||||
if (!connect_) {
|
||||
qLog(Error) << "Deezer: Failed to create connect.";
|
||||
return false;
|
||||
}
|
||||
|
||||
qLog(Debug) << "Device ID:" << dz_connect_get_device_id(connect_);
|
||||
|
||||
dz_error_t dzerr(DZ_ERROR_NO_ERROR);
|
||||
|
||||
dzerr = dz_connect_debug_log_disable(connect_);
|
||||
if (dzerr != DZ_ERROR_NO_ERROR) {
|
||||
qLog(Error) << "Deezer: Failed to disable debug log.";
|
||||
return false;
|
||||
}
|
||||
|
||||
dzerr = dz_connect_activate(connect_, this);
|
||||
if (dzerr != DZ_ERROR_NO_ERROR) {
|
||||
qLog(Error) << "Deezer: Failed to activate connect.";
|
||||
return false;
|
||||
}
|
||||
|
||||
dz_connect_cache_path_set(connect_, nullptr, nullptr, QStandardPaths::writableLocation(QStandardPaths::CacheLocation).toUtf8().constData());
|
||||
|
||||
player_ = dz_player_new(connect_);
|
||||
if (!player_) {
|
||||
qLog(Error) << "Deezer: Failed to create player.";
|
||||
return false;
|
||||
}
|
||||
|
||||
dzerr = dz_player_activate(player_, this);
|
||||
if (dzerr != DZ_ERROR_NO_ERROR) {
|
||||
qLog(Error) << "Deezer: Failed to activate player.";
|
||||
return false;
|
||||
}
|
||||
|
||||
dzerr = dz_player_set_event_cb(player_, PlayerEventCallback);
|
||||
if (dzerr != DZ_ERROR_NO_ERROR) {
|
||||
qLog(Error) << "Deezer: Failed to set event callback.";
|
||||
return false;
|
||||
}
|
||||
|
||||
dzerr = dz_player_set_metadata_cb(player_, PlayerMetaDataCallback);
|
||||
if (dzerr != DZ_ERROR_NO_ERROR) {
|
||||
qLog(Error) << "Deezer: Failed to set metadata callback.";
|
||||
return false;
|
||||
}
|
||||
|
||||
dzerr = dz_player_set_render_progress_cb(player_, PlayerProgressCallback, 1000);
|
||||
if (dzerr != DZ_ERROR_NO_ERROR) {
|
||||
qLog(Error) << "Deezer: Failed to set progress callback.";
|
||||
return false;
|
||||
}
|
||||
|
||||
dzerr = dz_player_set_crossfading_duration(player_, nullptr, nullptr, 3000);
|
||||
if (dzerr != DZ_ERROR_NO_ERROR) {
|
||||
qLog(Error) << "Deezer: Failed to set crossfade duration.";
|
||||
return false;
|
||||
}
|
||||
|
||||
dzerr = dz_connect_offline_mode(connect_, nullptr, nullptr, false);
|
||||
if (dzerr != DZ_ERROR_NO_ERROR) {
|
||||
qLog(Error) << "Deezer: Failed to set offline mode.";
|
||||
return false;
|
||||
}
|
||||
|
||||
LoadAccessToken();
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
bool DeezerEngine::Initialised() const {
|
||||
|
||||
if (connect_ && player_) return true;
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
void DeezerEngine::LoadAccessToken() {
|
||||
|
||||
QSettings s;
|
||||
s.beginGroup(DeezerSettingsPage::kSettingsGroup);
|
||||
if (!s.contains("access_token") || !s.contains("expiry_time")) return;
|
||||
access_token_ = s.value("access_token").toString();
|
||||
expiry_time_ = s.value("expiry_time").toDateTime();
|
||||
s.endGroup();
|
||||
|
||||
dz_error_t dzerr = dz_connect_set_access_token(connect_, nullptr, nullptr, access_token_.toUtf8().constData());
|
||||
if (dzerr != DZ_ERROR_NO_ERROR) {
|
||||
qLog(Error) << "Deezer: Failed to set access token.";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool DeezerEngine::Load(const QUrl &media_url, const QUrl &original_url, Engine::TrackChangeFlags change, bool force_stop_at_end, quint64 beginning_nanosec, qint64 end_nanosec) {
|
||||
|
||||
if (!Initialised()) return false;
|
||||
|
||||
Engine::Base::Load(media_url, original_url, change, force_stop_at_end, beginning_nanosec, end_nanosec);
|
||||
dz_error_t dzerr = dz_player_load(player_, nullptr, nullptr, media_url.toString().toUtf8().constData());
|
||||
if (dzerr != DZ_ERROR_NO_ERROR) return false;
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
bool DeezerEngine::Play(quint64 offset_nanosec) {
|
||||
|
||||
if (!Initialised()) return false;
|
||||
|
||||
dz_error_t dzerr(DZ_ERROR_NO_ERROR);
|
||||
if (state() == Engine::Paused) dzerr = dz_player_resume(player_, nullptr, nullptr);
|
||||
else dzerr = dz_player_play(player_, nullptr, nullptr, DZ_PLAYER_PLAY_CMD_START_TRACKLIST, DZ_INDEX_IN_QUEUELIST_CURRENT);
|
||||
if (dzerr != DZ_ERROR_NO_ERROR) return false;
|
||||
|
||||
Seek(offset_nanosec);
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
void DeezerEngine::Stop(bool stop_after) {
|
||||
|
||||
if (!Initialised()) return;
|
||||
|
||||
dz_error_t dzerr = dz_player_stop(player_, nullptr, nullptr);
|
||||
if (dzerr != DZ_ERROR_NO_ERROR) return;
|
||||
|
||||
state_ = Engine::Empty;
|
||||
emit TrackEnded();
|
||||
|
||||
}
|
||||
|
||||
void DeezerEngine::Pause() {
|
||||
|
||||
if (!Initialised()) return;
|
||||
|
||||
dz_error_t dzerr = dz_player_pause(player_, nullptr, nullptr);
|
||||
if (dzerr != DZ_ERROR_NO_ERROR) return;
|
||||
|
||||
}
|
||||
|
||||
void DeezerEngine::Unpause() {
|
||||
|
||||
if (!Initialised()) return;
|
||||
dz_error_t dzerr = dz_player_resume(player_, nullptr, nullptr);
|
||||
if (dzerr != DZ_ERROR_NO_ERROR) return;
|
||||
|
||||
}
|
||||
|
||||
void DeezerEngine::Seek(quint64 offset_nanosec) {
|
||||
|
||||
if (!Initialised()) return;
|
||||
|
||||
int offset = (offset_nanosec / kNsecPerMsec);
|
||||
|
||||
uint len = (length_nanosec() / kNsecPerMsec);
|
||||
if (len == 0) return;
|
||||
|
||||
float pos = float(offset) / len;
|
||||
|
||||
dz_error_t dzerr = dz_player_seek(player_, nullptr, nullptr, pos);
|
||||
if (dzerr != DZ_ERROR_NO_ERROR) return;
|
||||
|
||||
}
|
||||
|
||||
void DeezerEngine::SetVolumeSW(uint percent) {
|
||||
|
||||
if (!Initialised()) return;
|
||||
|
||||
dz_error_t dzerr = dz_player_set_output_volume(player_, nullptr, nullptr, percent);
|
||||
if (dzerr != DZ_ERROR_NO_ERROR) qLog(Error) << "Deezer: Failed to set volume.";
|
||||
|
||||
}
|
||||
|
||||
qint64 DeezerEngine::position_nanosec() const {
|
||||
|
||||
if (state() == Engine::Empty) return 0;
|
||||
const qint64 result = (position_ * kNsecPerUsec);
|
||||
return qint64(qMax(0ll, result));
|
||||
|
||||
}
|
||||
|
||||
qint64 DeezerEngine::length_nanosec() const {
|
||||
|
||||
if (state() == Engine::Empty) return 0;
|
||||
|
||||
const qint64 result = (end_nanosec_ - beginning_nanosec_);
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
EngineBase::OutputDetailsList DeezerEngine::GetOutputsList() const {
|
||||
OutputDetailsList ret;
|
||||
OutputDetails output;
|
||||
output.name = "default";
|
||||
output.description = "Default";
|
||||
output.iconname = "soundcard";
|
||||
ret << output;
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool DeezerEngine::ValidOutput(const QString &output) {
|
||||
return(true);
|
||||
}
|
||||
|
||||
bool DeezerEngine::CustomDeviceSupport(const QString &output) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DeezerEngine::ALSADeviceSupport(const QString &output) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DeezerEngine::CanDecode(const QUrl &url) {
|
||||
if (url.scheme() == "dzmedia") return true;
|
||||
else return false;
|
||||
}
|
||||
|
||||
void DeezerEngine::ConnectEventCallback(dz_connect_handle handle, dz_connect_event_handle event, void *delegate) {
|
||||
|
||||
dz_connect_event_t type = dz_connect_event_get_type(event);
|
||||
//DeezerEngine *engine = reinterpret_cast<DeezerEngine*>(delegate);
|
||||
|
||||
switch (type) {
|
||||
case DZ_CONNECT_EVENT_USER_OFFLINE_AVAILABLE:
|
||||
qLog(Debug) << "CONNECT_EVENT USER_OFFLINE_AVAILABLE";
|
||||
break;
|
||||
|
||||
case DZ_CONNECT_EVENT_USER_ACCESS_TOKEN_OK: {
|
||||
const char* szAccessToken;
|
||||
szAccessToken = dz_connect_event_get_access_token(event);
|
||||
qLog(Debug) << "CONNECT_EVENT USER_ACCESS_TOKEN_OK Access_token :" << szAccessToken;
|
||||
}
|
||||
break;
|
||||
|
||||
case DZ_CONNECT_EVENT_USER_ACCESS_TOKEN_FAILED:
|
||||
qLog(Debug) << "CONNECT_EVENT USER_ACCESS_TOKEN_FAILED";
|
||||
break;
|
||||
|
||||
case DZ_CONNECT_EVENT_USER_LOGIN_OK:
|
||||
qLog(Debug) << "Deezer CONNECT_EVENT USER_LOGIN_OK";
|
||||
break;
|
||||
|
||||
case DZ_CONNECT_EVENT_USER_NEW_OPTIONS:
|
||||
qLog(Debug) << "Deezer: CONNECT_EVENT USER_NEW_OPTIONS";
|
||||
break;
|
||||
|
||||
case DZ_CONNECT_EVENT_USER_LOGIN_FAIL_NETWORK_ERROR:
|
||||
qLog(Debug) << "Deezer: CONNECT_EVENT USER_LOGIN_FAIL_NETWORK_ERROR";
|
||||
break;
|
||||
|
||||
case DZ_CONNECT_EVENT_USER_LOGIN_FAIL_BAD_CREDENTIALS:
|
||||
qLog(Debug) << "Deezer: CONNECT_EVENT USER_LOGIN_FAIL_BAD_CREDENTIALS";
|
||||
break;
|
||||
|
||||
case DZ_CONNECT_EVENT_USER_LOGIN_FAIL_USER_INFO:
|
||||
qLog(Debug) << "Deezer: CONNECT_EVENT USER_LOGIN_FAIL_USER_INFO";
|
||||
break;
|
||||
|
||||
case DZ_CONNECT_EVENT_USER_LOGIN_FAIL_OFFLINE_MODE:
|
||||
qLog(Debug) << "Deezer: CONNECT_EVENT USER_LOGIN_FAIL_OFFLINE_MODE";
|
||||
break;
|
||||
|
||||
case DZ_CONNECT_EVENT_ADVERTISEMENT_START:
|
||||
qLog(Debug) << "Deezer: CONNECT_EVENTADVERTISEMENT_START";
|
||||
break;
|
||||
|
||||
case DZ_CONNECT_EVENT_ADVERTISEMENT_STOP:
|
||||
qLog(Debug) << "Deezer: CONNECT_EVENTADVERTISEMENT_STOP";
|
||||
break;
|
||||
|
||||
case DZ_CONNECT_EVENT_UNKNOWN:
|
||||
default:
|
||||
qLog(Debug) << "Deezer: CONNECT_EVENTUNKNOWN or default (type =" << type;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void DeezerEngine::PlayerEventCallback(dz_player_handle handle, dz_player_event_handle event, void *supervisor) {
|
||||
|
||||
DeezerEngine *engine = reinterpret_cast<DeezerEngine*>(supervisor);
|
||||
dz_streaming_mode_t streaming_mode;
|
||||
dz_index_in_queuelist idx;
|
||||
dz_player_event_t type = dz_player_event_get_type(event);
|
||||
|
||||
if (!dz_player_event_get_queuelist_context(event, &streaming_mode, &idx)) {
|
||||
streaming_mode = DZ_STREAMING_MODE_ONDEMAND;
|
||||
idx = DZ_INDEX_IN_QUEUELIST_INVALID;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
|
||||
case DZ_PLAYER_EVENT_LIMITATION_FORCED_PAUSE:
|
||||
qLog(Debug) << "Deezer: PLAYER_EVENT_LIMITATION_FORCED_PAUSE";
|
||||
break;
|
||||
|
||||
case DZ_PLAYER_EVENT_QUEUELIST_LOADED:
|
||||
qLog(Debug) << "Deezer: PLAYER_EVENT_QUEUELIST_LOADED";
|
||||
break;
|
||||
|
||||
case DZ_PLAYER_EVENT_QUEUELIST_NO_RIGHT:
|
||||
qLog(Debug) << "Deezer: PLAYER_EVENT_QUEUELIST_NO_RIGHT";
|
||||
break;
|
||||
|
||||
case DZ_PLAYER_EVENT_QUEUELIST_NEED_NATURAL_NEXT:
|
||||
qLog(Debug) << "Deezer: PLAYER_EVENT_QUEUELIST_NEED_NATURAL_NEXT";
|
||||
break;
|
||||
|
||||
case DZ_PLAYER_EVENT_QUEUELIST_TRACK_NOT_AVAILABLE_OFFLINE:
|
||||
qLog(Debug) << "Deezer: PLAYER_EVENT_QUEUELIST_TRACK_NOT_AVAILABLE_OFFLINE";
|
||||
engine->state_ = Engine::Error;
|
||||
emit engine->StateChanged(engine->state_);
|
||||
emit engine->Error("Track not available offline.");
|
||||
break;
|
||||
|
||||
case DZ_PLAYER_EVENT_QUEUELIST_TRACK_RIGHTS_AFTER_AUDIOADS:
|
||||
qLog(Debug) << "Deezer: PLAYER_EVENT_QUEUELIST_TRACK_RIGHTS_AFTER_AUDIOADS";
|
||||
break;
|
||||
|
||||
case DZ_PLAYER_EVENT_QUEUELIST_SKIP_NO_RIGHT:
|
||||
qLog(Debug) << "Deezer: PLAYER_EVENT_QUEUELIST_SKIP_NO_RIGHT";
|
||||
break;
|
||||
|
||||
case DZ_PLAYER_EVENT_QUEUELIST_TRACK_SELECTED:
|
||||
break;
|
||||
|
||||
case DZ_PLAYER_EVENT_MEDIASTREAM_DATA_READY:
|
||||
qLog(Debug) << "Deezer: PLAYER_EVENT_MEDIASTREAM_DATA_READY";
|
||||
break;
|
||||
|
||||
case DZ_PLAYER_EVENT_MEDIASTREAM_DATA_READY_AFTER_SEEK:
|
||||
qLog(Debug) << "Deezer: PLAYER_EVENT_MEDIASTREAM_DATA_READY_AFTER_SEEK";
|
||||
break;
|
||||
|
||||
case DZ_PLAYER_EVENT_RENDER_TRACK_START_FAILURE:
|
||||
qLog(Debug) << "Deezer: PLAYER_EVENT_RENDER_TRACK_START_FAILURE";
|
||||
engine->state_ = Engine::Error;
|
||||
emit engine->StateChanged(engine->state_);
|
||||
emit engine->Error("Track start failure.");
|
||||
break;
|
||||
|
||||
case DZ_PLAYER_EVENT_RENDER_TRACK_START:
|
||||
qLog(Debug) << "Deezer: PLAYER_EVENT_RENDER_TRACK_START";
|
||||
engine->state_ = Engine::Playing;
|
||||
engine->position_ = 0;
|
||||
emit engine->StateChanged(engine->state_);
|
||||
break;
|
||||
|
||||
case DZ_PLAYER_EVENT_RENDER_TRACK_END:
|
||||
qLog(Debug) << "Deezer: PLAYER_EVENT_RENDER_TRACK_END";
|
||||
engine->state_ = Engine::Idle;
|
||||
engine->position_ = 0;
|
||||
emit engine->TrackEnded();
|
||||
break;
|
||||
|
||||
case DZ_PLAYER_EVENT_RENDER_TRACK_PAUSED:
|
||||
qLog(Debug) << "Deezer: PLAYER_EVENT_RENDER_TRACK_PAUSED";
|
||||
engine->state_ = Engine::Paused;
|
||||
emit engine->StateChanged(engine->state_);
|
||||
break;
|
||||
|
||||
case DZ_PLAYER_EVENT_RENDER_TRACK_UNDERFLOW:
|
||||
qLog(Debug) << "Deezer: PLAYER_EVENT_RENDER_TRACK_UNDERFLOW";
|
||||
break;
|
||||
|
||||
case DZ_PLAYER_EVENT_RENDER_TRACK_RESUMED:
|
||||
qLog(Debug) << "Deezer: PLAYER_EVENT_RENDER_TRACK_RESUMED";
|
||||
engine->state_ = Engine::Playing;
|
||||
emit engine->StateChanged(engine->state_);
|
||||
break;
|
||||
|
||||
case DZ_PLAYER_EVENT_RENDER_TRACK_SEEKING:
|
||||
qLog(Debug) << "Deezer: PLAYER_EVENT_RENDER_TRACK_SEEKING";
|
||||
break;
|
||||
|
||||
case DZ_PLAYER_EVENT_RENDER_TRACK_REMOVED:
|
||||
qLog(Debug) << "Deezer: PLAYER_EVENT_RENDER_TRACK_REMOVED";
|
||||
engine->state_ = Engine::Empty;
|
||||
engine->position_ = 0;
|
||||
emit engine->TrackEnded();
|
||||
break;
|
||||
|
||||
case DZ_PLAYER_EVENT_UNKNOWN:
|
||||
default:
|
||||
qLog(Error) << "Deezer: Unknown player event" << type;
|
||||
break;
|
||||
}
|
||||
//emit engine->StateChanged(engine->state_);
|
||||
|
||||
}
|
||||
|
||||
void DeezerEngine::PlayerProgressCallback(dz_player_handle handle, dz_useconds_t progress, void *userdata) {
|
||||
DeezerEngine *engine = reinterpret_cast<DeezerEngine*>(userdata);
|
||||
engine->position_ = progress;
|
||||
}
|
||||
|
||||
void DeezerEngine::PlayerMetaDataCallback(dz_player_handle handle, dz_track_metadata_handle metadata, void *userdata) {
|
||||
//DeezerEngine *engine = reinterpret_cast<DeezerEngine*>(userdata);
|
||||
}
|
||||
88
src/engine/deezerengine.h
Normal file
88
src/engine/deezerengine.h
Normal file
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Strawberry Music Player
|
||||
* Copyright 2018, Jonas Kvinge <jonas@jkvinge.net>
|
||||
*
|
||||
* Strawberry is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Strawberry is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Strawberry. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef DEEZERENGINE_H
|
||||
#define DEEZERENGINE_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <deezer/deezer-connect.h>
|
||||
#include <deezer/deezer-player.h>
|
||||
|
||||
#include <QtGlobal>
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QUrl>
|
||||
#include <QDateTime>
|
||||
|
||||
#include "engine_fwd.h"
|
||||
#include "enginebase.h"
|
||||
|
||||
class TaskManager;
|
||||
|
||||
class DeezerEngine : public Engine::Base {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
DeezerEngine(TaskManager *task_manager);
|
||||
~DeezerEngine();
|
||||
|
||||
bool Init();
|
||||
Engine::State state() const { return state_; }
|
||||
bool Load(const QUrl &media_url, const QUrl &original_url, Engine::TrackChangeFlags change, bool force_stop_at_end, quint64 beginning_nanosec, qint64 end_nanosec);
|
||||
bool Play(quint64 offset_nanosec);
|
||||
void Stop(bool stop_after = false);
|
||||
void Pause();
|
||||
void Unpause();
|
||||
void Seek(quint64 offset_nanosec);
|
||||
protected:
|
||||
void SetVolumeSW(uint percent);
|
||||
public:
|
||||
virtual qint64 position_nanosec() const;
|
||||
virtual qint64 length_nanosec() const;
|
||||
|
||||
OutputDetailsList GetOutputsList() const;
|
||||
bool ValidOutput(const QString &output);
|
||||
QString DefaultOutput() { return ""; }
|
||||
bool CustomDeviceSupport(const QString &output);
|
||||
bool ALSADeviceSupport(const QString &output);
|
||||
|
||||
private:
|
||||
Engine::State state_;
|
||||
dz_connect_handle connect_;
|
||||
dz_player_handle player_;
|
||||
QString access_token_;
|
||||
QDateTime expiry_time_;
|
||||
qint64 position_;
|
||||
|
||||
bool Initialised() const;
|
||||
bool CanDecode(const QUrl &url);
|
||||
|
||||
static void ConnectEventCallback(dz_connect_handle handle, dz_connect_event_handle event, void *delegate);
|
||||
static void PlayerEventCallback(dz_player_handle handle, dz_player_event_handle event, void *supervisor);
|
||||
static void PlayerMetaDataCallback(dz_player_handle handle, dz_track_metadata_handle metadata, void *userdata);
|
||||
static void PlayerProgressCallback(dz_player_handle handle, dz_useconds_t progress, void *userdata);
|
||||
|
||||
public slots:
|
||||
void LoadAccessToken();
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -147,8 +147,7 @@ signals:
|
||||
void MetaData(const Engine::SimpleMetaBundle&);
|
||||
|
||||
// Signals that the engine's state has changed (a stream was stopped for example).
|
||||
// Always use the state from event, because it's not guaranteed that immediate
|
||||
// subsequent call to state() won't return a stale value.
|
||||
// Always use the state from event, because it's not guaranteed that immediate subsequent call to state() won't return a stale value.
|
||||
void StateChanged(Engine::State);
|
||||
|
||||
protected:
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/*
|
||||
* Strawberry Music Player
|
||||
* This file was part of Clementine.
|
||||
* Copyright 2014, David Sansome <me@davidsansome.com>
|
||||
* Copyright 2014, Jonas Kvinge <jonas@jkvinge.net>
|
||||
*
|
||||
* Strawberry is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/*
|
||||
* Strawberry Music Player
|
||||
* This file was part of Clementine.
|
||||
* Copyright 2014, David Sansome <me@davidsansome.com>
|
||||
* Copyright 2014, Jonas Kvinge <jonas@jkvinge.net>
|
||||
*
|
||||
* Strawberry is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -28,19 +28,21 @@ namespace Engine {
|
||||
|
||||
Engine::EngineType EngineTypeFromName(QString enginename) {
|
||||
QString lower = enginename.toLower();
|
||||
if (lower == "xine") return Engine::Xine;
|
||||
else if (lower == "gstreamer") return Engine::GStreamer;
|
||||
else if (lower == "phonon") return Engine::Phonon;
|
||||
else if (lower == "vlc") return Engine::VLC;
|
||||
else return Engine::None;
|
||||
if (lower == "gstreamer") return Engine::GStreamer;
|
||||
else if (lower == "xine") return Engine::Xine;
|
||||
else if (lower == "vlc") return Engine::VLC;
|
||||
else if (lower == "phonon") return Engine::Phonon;
|
||||
else if (lower == "deezer") return Engine::Deezer;
|
||||
else return Engine::None;
|
||||
}
|
||||
|
||||
QString EngineName(Engine::EngineType enginetype) {
|
||||
switch (enginetype) {
|
||||
case Engine::Xine: return QString("xine");
|
||||
case Engine::GStreamer: return QString("gstreamer");
|
||||
case Engine::Phonon: return QString("phonon");
|
||||
case Engine::Xine: return QString("xine");
|
||||
case Engine::VLC: return QString("vlc");
|
||||
case Engine::Phonon: return QString("phonon");
|
||||
case Engine::Deezer: return QString("deezer");
|
||||
case Engine::None:
|
||||
default: return QString("None");
|
||||
}
|
||||
@@ -48,10 +50,11 @@ QString EngineName(Engine::EngineType enginetype) {
|
||||
|
||||
QString EngineDescription(Engine::EngineType enginetype) {
|
||||
switch (enginetype) {
|
||||
case Engine::Xine: return QString("Xine");
|
||||
case Engine::GStreamer: return QString("GStreamer");
|
||||
case Engine::Phonon: return QString("Phonon");
|
||||
case Engine::Xine: return QString("Xine");
|
||||
case Engine::VLC: return QString("VLC");
|
||||
case Engine::Phonon: return QString("Phonon");
|
||||
case Engine::Deezer: return QString("Deezer");
|
||||
case Engine::None:
|
||||
default: return QString("None");
|
||||
|
||||
|
||||
@@ -32,7 +32,8 @@ enum EngineType {
|
||||
GStreamer,
|
||||
VLC,
|
||||
Xine,
|
||||
Phonon
|
||||
Phonon,
|
||||
Deezer
|
||||
};
|
||||
|
||||
Engine::EngineType EngineTypeFromName(QString enginename);
|
||||
|
||||
Reference in New Issue
Block a user