Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[video_player_videohole] Implement message queue for native license request #646

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions packages/video_player_videohole/tizen/project_def.prop
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ type = staticLib
profile = common-5.5

# Source files
USER_SRCS += src/*.cc
USER_SRCS += src/*.cc src/drm/*.cc

# User defines
USER_DEFS =
Expand All @@ -15,6 +15,6 @@ USER_CPP_DEFS = FLUTTER_PLUGIN_IMPL
USER_CPP_UNDEFS =

# User includes
USER_INC_DIRS = inc src
USER_INC_DIRS = inc src src/drm
USER_INC_FILES =
USER_CPP_INC_FILES =
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Copyright 2023 Samsung Electronics Co., Ltd. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef FLUTTER_PLUGIN_DRM_LICENSE_REQUEST_H_
#define FLUTTER_PLUGIN_DRM_LICENSE_REQUEST_H_

#include <functional>
#include <memory>
#include <string>
#include <vector>

using OnLicenseRequestDone = std::function<void(
const std::string& session_id, const std::vector<uint8_t>& response_data)>;

struct DataForLicenseProcess {
DataForLicenseProcess(void* session_id, void* message, int message_length)
: session_id(static_cast<char*>(session_id)),
message(static_cast<char*>(message), message_length) {}
std::string session_id;
std::string message;
};
class DrmLicenseRequest {
public:
explicit DrmLicenseRequest(
OnLicenseRequestDone on_license_request_done_callback)
: on_license_request_done_callback_(on_license_request_done_callback) {}
virtual ~DrmLicenseRequest() {}
virtual void RequestLicense(void* session_id, int message_type, void* message,
int message_length) = 0;
void OnLicenseResponse(const std::string& session_id,
const std::vector<uint8_t>& response_data) {
if (on_license_request_done_callback_) {
on_license_request_done_callback_(session_id, response_data);
}
}

protected:
OnLicenseRequestDone on_license_request_done_callback_ = nullptr;
};
#endif // FLUTTER_PLUGIN_DRM_LICENSE_REQUEST_H_
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
// Copyright 2023 Samsung Electronics Co., Ltd. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "drm_license_request_channel.h"

#include <flutter/method_result_functions.h>
#include <flutter/standard_method_codec.h>

#include <utility>

#include "log.h"

DrmLicenseRequestChannel::DrmLicenseRequestChannel(
flutter::BinaryMessenger *binary_messenger,
OnLicenseRequestDone on_license_request_done_callback)
: DrmLicenseRequest(on_license_request_done_callback),
request_license_channel_(
std::make_unique<flutter::MethodChannel<flutter::EncodableValue>>(
binary_messenger, "dev.flutter.videoplayer.drm",
&flutter::StandardMethodCodec::GetInstance())) {
license_request_pipe_ = ecore_pipe_add(
[](void *data, void *buffer, unsigned int nbyte) -> void {
auto *self = static_cast<DrmLicenseRequestChannel *>(data);
self->ExecuteRequest();
},
this);
}

void DrmLicenseRequestChannel::RequestLicense(void *session_id,
int message_type, void *message,
int message_length) {
DataForLicenseProcess process_message(session_id, message, message_length);
PushLicenseRequest(process_message);
}

void DrmLicenseRequestChannel::ExecuteRequest() {
std::lock_guard<std::mutex> lock(queue_mutex_);
while (!license_request_queue_.empty()) {
DataForLicenseProcess data = license_request_queue_.front();
RequestLicense(data.session_id, data.message);
license_request_queue_.pop();
}
}

void DrmLicenseRequestChannel::PushLicenseRequest(
const DataForLicenseProcess &data) {
std::lock_guard<std::mutex> lock(queue_mutex_);
license_request_queue_.push(data);
ecore_pipe_write(license_request_pipe_, nullptr, 0);
}

void DrmLicenseRequestChannel::RequestLicense(const std::string &session_id,
const std::string &message) {
LOG_INFO("[DrmLicenseRequestChannel] Start request license.");

if (request_license_channel_ == nullptr) {
LOG_ERROR("[DrmLicenseRequestChannel] request license channel is null.");
return;
}

std::vector<uint8_t> message_vec(message.begin(), message.end());
flutter::EncodableMap args_map = {
{flutter::EncodableValue("message"),
flutter::EncodableValue(message_vec)},
};
auto result_handler =
std::make_unique<flutter::MethodResultFunctions<flutter::EncodableValue>>(

[session_id, this](const flutter::EncodableValue *success_value) {
std::vector<uint8_t> response;
if (std::holds_alternative<std::vector<uint8_t>>(*success_value)) {
response = std::get<std::vector<uint8_t>>(*success_value);
} else {
LOG_ERROR("[DrmLicenseRequestChannel] Fail to get response.");
return;
}
LOG_INFO("[DrmLicenseRequestChannel] Response length : %d",
response.size());
OnLicenseResponse(session_id, response);
},
nullptr, nullptr);
request_license_channel_->InvokeMethod(
"requestLicense",
std::make_unique<flutter::EncodableValue>(
flutter::EncodableValue(args_map)),
std::move(result_handler));
}

DrmLicenseRequestChannel::~DrmLicenseRequestChannel() {
if (license_request_pipe_) {
ecore_pipe_del(license_request_pipe_);
license_request_pipe_ = nullptr;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Copyright 2023 Samsung Electronics Co., Ltd. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef FLUTTER_PLUGIN_DRM_LICENSE_REQUEST_CHANNEL_H_
#define FLUTTER_PLUGIN_DRM_LICENSE_REQUEST_CHANNEL_H_

#include <Ecore.h>
#include <flutter/method_channel.h>

#include <memory>
#include <mutex>
#include <queue>
#include <string>
#include <vector>

#include "drm_license_request.h"

class DrmLicenseRequestChannel : public DrmLicenseRequest {
public:
explicit DrmLicenseRequestChannel(
flutter::BinaryMessenger *binary_messenger,
OnLicenseRequestDone on_license_request_done_callback);
void RequestLicense(void *session_id, int message_type, void *message,
int message_length) override;
~DrmLicenseRequestChannel();

private:
void ExecuteRequest();
void PushLicenseRequest(const DataForLicenseProcess &data);
void RequestLicense(const std::string &session_id,
const std::string &message);
std::unique_ptr<flutter::MethodChannel<flutter::EncodableValue>>
request_license_channel_;
std::mutex queue_mutex_;
Ecore_Pipe *license_request_pipe_ = nullptr;
std::queue<DataForLicenseProcess> license_request_queue_;
};
#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
// Copyright 2023 Samsung Electronics Co., Ltd. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "drm_license_request_native.h"

#include <string>
#include <vector>

#include "drm_license_helper.h"
#include "log.h"

constexpr int kMessageQuit = -1;
constexpr int kMessageRequestLicense = 0;

struct Message {
Eina_Thread_Queue_Msg head;
int event;
DataForLicenseProcess* data_for_request = nullptr;
};

LicenseResponsePipe::LicenseResponsePipe(
OnLicenseRequestDone on_license_request_done_callback)
: on_license_request_done_callback_(on_license_request_done_callback) {
license_response_pipe_ = ecore_pipe_add(
[](void* data, void* buffer, unsigned int nbyte) -> void {
auto* self = static_cast<LicenseResponsePipe*>(data);
self->ExecuteResponse();
},
this);
}

void LicenseResponsePipe::ExecuteResponse() {
std::lock_guard<std::mutex> lock(queue_mutex_);
while (!license_response_queue_.empty()) {
if (on_license_request_done_callback_) {
auto response_data = license_response_queue_.front();
on_license_request_done_callback_(response_data.first,
response_data.second);
}
license_response_queue_.pop();
}
}

void LicenseResponsePipe::PushLicenseResponse(
const std::string& session_id, const std::vector<uint8_t>& response_data) {
std::lock_guard<std::mutex> lock(queue_mutex_);
license_response_queue_.push(std::make_pair(session_id, response_data));
ecore_pipe_write(license_response_pipe_, nullptr, 0);
}

LicenseResponsePipe::~LicenseResponsePipe() {
if (license_response_pipe_) {
ecore_pipe_del(license_response_pipe_);
license_response_pipe_ = nullptr;
}
}

DrmLicenseRequestNative::DrmLicenseRequestNative(
int drm_type, const std::string& license_server_url,
OnLicenseRequestDone on_license_request_done_callback)
: DrmLicenseRequest(on_license_request_done_callback),
drm_type_(drm_type),
license_server_url_(license_server_url) {
license_response_pipe_ = std::make_shared<LicenseResponsePipe>(
[this](const std::string& session_id,
const std::vector<uint8_t>& response_data) {
OnLicenseResponse(session_id, response_data);
});
license_request_thread_ = ecore_thread_feedback_run(RunLoop, nullptr, nullptr,
nullptr, this, EINA_TRUE);
}

void DrmLicenseRequestNative::RequestLicense(void* session_id, int message_type,
void* message,
int message_length) {
if (!license_request_thread_ || ecore_thread_check(license_request_thread_)) {
LOG_ERROR("Invalid license request thread.");
return;
}

if (!license_request_queue_) {
LOG_ERROR("Invalid license request thread queue.");
return;
}

void* ref;
Message* request_message = static_cast<Message*>(
eina_thread_queue_send(license_request_queue_, sizeof(Message), &ref));
request_message->event = kMessageRequestLicense;
request_message->data_for_request =
new DataForLicenseProcess(session_id, message, message_length);
eina_thread_queue_send_done(license_request_queue_, ref);
}

void DrmLicenseRequestNative::StopMessageQueue() {
if (!license_request_thread_ || ecore_thread_check(license_request_thread_)) {
LOG_ERROR("Invalid license request thread.");
return;
}

if (!license_request_queue_) {
LOG_ERROR("Invalid license request thread queue.");
return;
}

void* ref;
Message* message = static_cast<Message*>(
eina_thread_queue_send(license_request_queue_, sizeof(Message), &ref));
message->event = kMessageQuit;
eina_thread_queue_send_done(license_request_queue_, ref);
}

void DrmLicenseRequestNative::RunLoop(void* data, Ecore_Thread* thread) {
Eina_Thread_Queue* license_request_queue = eina_thread_queue_new();
if (!license_request_queue) {
LOG_ERROR("Invalid license request thread queue.");
ecore_thread_cancel(thread);
return;
}
auto* self = static_cast<DrmLicenseRequestNative*>(data);
self->license_request_queue_ = license_request_queue;
std::weak_ptr<LicenseResponsePipe> weak_pipe = self->license_response_pipe_;
std::string license_server_url = self->license_server_url_;
int drm_type = self->drm_type_;
while (!ecore_thread_check(thread)) {
void* ref;
Message* message = static_cast<Message*>(
eina_thread_queue_wait(license_request_queue, &ref));
if (message->event == kMessageQuit) {
LOG_DEBUG("Receive kMessageQuit message");
eina_thread_queue_wait_done(license_request_queue, ref);
break;
}
if (message->data_for_request == nullptr) {
LOG_ERROR("data_for_request is null");
continue;
}
std::string challenge = message->data_for_request->message;
std::string session_id = message->data_for_request->session_id;
delete message->data_for_request;
eina_thread_queue_wait_done(license_request_queue, ref);
// Get license via the license server.
unsigned char* response_data = nullptr;
unsigned long response_len = 0;
std::vector<uint8_t> response;
DRM_RESULT ret = DrmLicenseHelper::DoTransactionTZ(
license_server_url.c_str(), challenge.c_str(), challenge.size(),
&response_data, &response_len,
static_cast<DrmLicenseHelper::DrmType>(drm_type), nullptr, nullptr);

if (DRM_SUCCESS != ret || nullptr == response_data || 0 == response_len) {
LOG_ERROR("Fail to get respone by license server url.");
continue;
}
LOG_INFO("Response length : %lu", response_len);
if (weak_pipe.expired()) {
LOG_DEBUG("weak_pipe expired");
free(response_data);
break;
}
auto response_vec =
std::vector<uint8_t>(response_data, response_data + response_len);
weak_pipe.lock()->PushLicenseResponse(session_id, response_vec);
free(response_data);
}
if (license_request_queue) {
eina_thread_queue_free(license_request_queue);
}
}

DrmLicenseRequestNative::~DrmLicenseRequestNative() {
StopMessageQueue();
if (license_request_thread_) {
ecore_thread_cancel(license_request_thread_);
license_request_thread_ = nullptr;
}
}
Loading