343 lines
9.9 KiB
C++
343 lines
9.9 KiB
C++
/*
|
|
* Copyright (C) 2014-present Amlogic, Inc. All rights reserved.
|
|
*
|
|
* All information contained herein is Amlogic confidential.
|
|
*
|
|
* This software is provided to you pursuant to Software License Agreement
|
|
* (SLA) with Amlogic Inc ("Amlogic"). This software may be used
|
|
* only in accordance with the terms of this agreement.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification is strictly prohibited without prior written permission from
|
|
* Amlogic.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include <future>
|
|
#include <mutex>
|
|
#include <poll.h>
|
|
#include <thread>
|
|
#include <vector>
|
|
|
|
#include <systemd/sd-bus.h>
|
|
|
|
#include "dbus_defines.h"
|
|
|
|
#define LOG_MODULE_TAG "PQ"
|
|
#define LOG_CLASS_TAG "PqService"
|
|
|
|
#include "CPQLog.h"
|
|
#include "PqClient.h"
|
|
|
|
static sd_bus *gs_signal_bus = nullptr;
|
|
|
|
bool pqclient_preset_signal_bus(sd_bus *bus) {
|
|
if (nullptr == bus) {
|
|
LOGE("invalid parameter\n");
|
|
return false;
|
|
}
|
|
|
|
if (nullptr != gs_signal_bus) {
|
|
LOGE("signal bus already set\n");
|
|
return false;
|
|
}
|
|
|
|
gs_signal_bus = bus;
|
|
return true;
|
|
}
|
|
|
|
static int gs_method_call_pipe[2];
|
|
|
|
static std::vector<PqClient::PqClientIObserver *> mPqClientObserver;
|
|
static int SendEvent(CPqClientCb &cb_data) {
|
|
for (const auto &o : mPqClientObserver) {
|
|
if (o != nullptr) {
|
|
o->GetPqCbData(cb_data);
|
|
LOGD("send event for %p count PqClientObserver!\n", o);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int signalCallback(sd_bus_message *msg, void *userdata,
|
|
sd_bus_error *ret_error) {
|
|
const char *memb = sd_bus_message_get_member(msg);
|
|
if (strcmp(memb, PQ_SERVICE_SIGNAL_HDR_TYPE) == 0) {
|
|
PqClientCb::HdrTypeCb cb;
|
|
int r = sd_bus_message_read(msg, "i", &cb.mHdrType);
|
|
if (r < 0)
|
|
return r;
|
|
SendEvent(cb);
|
|
} else if (strcmp(memb, PQ_SERVICE_SIGNAL_ALLM_GAME_MODE) == 0) {
|
|
PqClientCb::AllmGameModeCb cb;
|
|
int r = sd_bus_message_read(msg, "i", &cb.mAllmGameMode);
|
|
if (r < 0)
|
|
return r;
|
|
SendEvent(cb);
|
|
} else if (strcmp(memb, PQ_SERVICE_SIGNAL_FILM_MAKER_MODE) == 0) {
|
|
PqClientCb::FilmMakerModeCb cb;
|
|
int r = sd_bus_message_read(msg, "i", &cb.mFilmMakerMode);
|
|
if (r < 0)
|
|
return r;
|
|
SendEvent(cb);
|
|
} else if (strcmp(memb, PQ_SERVICE_SIGNAL_REFRESH_RATE) == 0) {
|
|
PqClientCb::RefreshRateCb cb;
|
|
int r = sd_bus_message_read(msg, "i", &cb.mRefreshRate);
|
|
if (r < 0)
|
|
return r;
|
|
SendEvent(cb);
|
|
} else if (strcmp(memb, PQ_SERVICE_SIGNAL_PICTURE_MODE) == 0) {
|
|
PqClientCb::PqModeChangedCb cb;
|
|
int r = sd_bus_message_read(msg, "iiii", &cb.pq_mode_info.pq_mode, &cb.pq_mode_info.hdr_type,
|
|
&cb.pq_mode_info.input_src, &cb.pq_mode_info.low_latency);
|
|
if (r < 0)
|
|
return r;
|
|
SendEvent(cb);
|
|
} else if (strcmp(memb, PQ_SERVICE_SIGNAL_PICTURE_MODE_MANUAL) == 0) {
|
|
PqClientCb::PictureModeCb cb;
|
|
int r = sd_bus_message_read(msg, "i", &cb.mPictureMode);
|
|
if (r < 0)
|
|
return r;
|
|
SendEvent(cb);
|
|
} else {
|
|
LOGE("invalid signal received!\n");
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void bus_cleanup(sd_bus *bus, sd_event *event) {
|
|
if (event) {
|
|
sd_event_exit(event, 0);
|
|
sd_event_unref(event);
|
|
event = nullptr;
|
|
}
|
|
|
|
if (bus) {
|
|
sd_bus_unref(bus);
|
|
bus = nullptr;
|
|
}
|
|
}
|
|
|
|
using DeferCallbackHandler = std::function<void(sd_bus *, sd_event *)>;
|
|
|
|
struct defer_callback_data {
|
|
sd_bus *bus;
|
|
sd_event *event;
|
|
const DeferCallbackHandler *handler;
|
|
defer_callback_data(sd_bus *b, sd_event *e, const DeferCallbackHandler *h)
|
|
: bus(b), event(e), handler(h) {}
|
|
};
|
|
|
|
static int defer_callback(sd_event_source *, void *userdata) {
|
|
auto data = static_cast<defer_callback_data *>(userdata);
|
|
(*data->handler)(data->bus, data->event);
|
|
delete data;
|
|
return 0;
|
|
}
|
|
|
|
static void init_run_bus(DeferCallbackHandler callback) {
|
|
std::thread t([cb = std::move(callback)]() {
|
|
sd_bus *bus = nullptr;
|
|
sd_event *event = nullptr;
|
|
|
|
int r = sd_bus_default_system(&bus);
|
|
if (r < 0) {
|
|
LOGE("Failed to open system bus: %s\n", strerror(-r));
|
|
return;
|
|
}
|
|
|
|
r = sd_event_default(&event);
|
|
if (r < 0) {
|
|
LOGE("Failed to create event: %s\n", strerror(-r));
|
|
sd_bus_unref(bus);
|
|
return;
|
|
}
|
|
|
|
r = sd_bus_attach_event(bus, event, 0);
|
|
if (r < 0) {
|
|
LOGE("Failed to attach event: %s\n", strerror(-r));
|
|
sd_event_unref(event);
|
|
sd_bus_unref(bus);
|
|
return;
|
|
}
|
|
|
|
if (cb) {
|
|
// Add a defer event
|
|
r = sd_event_add_defer(event, nullptr, defer_callback,
|
|
new defer_callback_data(bus, event, &cb));
|
|
if (r < 0) {
|
|
LOGE("Failed to add defer event: %s\n", strerror(-r));
|
|
sd_event_unref(event);
|
|
sd_bus_unref(bus);
|
|
return;
|
|
}
|
|
}
|
|
sd_event_loop(event);
|
|
bus_cleanup(bus, event);
|
|
});
|
|
t.detach();
|
|
}
|
|
|
|
using onCallPrepareHandler = std::function<bool(sd_bus_message *)>;
|
|
using onCallDoneHandler = std::function<int(sd_bus_message *)>;
|
|
|
|
struct MethodCallRequest {
|
|
const char *method;
|
|
onCallPrepareHandler *callPrepare;
|
|
onCallDoneHandler *onCallDone;
|
|
MethodCallRequest()
|
|
: method(nullptr), callPrepare(nullptr), onCallDone(nullptr) {}
|
|
MethodCallRequest(const char *m, onCallPrepareHandler *cp,
|
|
onCallDoneHandler *ocd)
|
|
: method(m), callPrepare(cp), onCallDone(ocd) {}
|
|
};
|
|
|
|
static int on_call_done(sd_bus_message *m, void *userdata,
|
|
sd_bus_error *ret_error) {
|
|
auto handler = static_cast<onCallDoneHandler *>(userdata);
|
|
const sd_bus_error *err = sd_bus_message_get_error(m);
|
|
if (err) {
|
|
LOGE("Failed to call: %s, %s(%s)\n", strerror(-sd_bus_error_get_errno(err)),
|
|
err->name, err->message);
|
|
return (*handler)(nullptr);
|
|
}
|
|
return (*handler)(m);
|
|
}
|
|
|
|
static int method_call_handler(sd_event_source *, int fd, uint32_t /*revents*/,
|
|
void *userdata) {
|
|
sd_bus *bus = (sd_bus *)userdata;
|
|
MethodCallRequest req;
|
|
int len = read(fd, &req, sizeof(req));
|
|
if (len != sizeof(req)) {
|
|
LOGE("%d read, %d bytes expected\n", len, sizeof(req));
|
|
} else {
|
|
if (req.method == nullptr)
|
|
return 0;
|
|
|
|
sd_bus_message *msg = nullptr;
|
|
if (sd_bus_message_new_method_call(
|
|
bus, &msg, PQ_SERVICE_DBUS_SERVICE, PQ_SERVICE_DBUS_OBJECT,
|
|
PQ_SERVICE_DBUS_INTERFACE, req.method) < 0)
|
|
return 0;
|
|
|
|
if (req.callPrepare && !(*req.callPrepare)(msg)) {
|
|
sd_bus_message_unref(msg);
|
|
msg = nullptr;
|
|
return 0;
|
|
}
|
|
|
|
int r;
|
|
if ((r = sd_bus_call_async(bus, nullptr, msg, on_call_done, req.onCallDone,
|
|
0)) < 0) {
|
|
LOGE("Failed to async call: %s (%s)\n", req.method, strerror(-r));
|
|
(*req.onCallDone)(nullptr);
|
|
}
|
|
if (msg) {
|
|
sd_bus_message_unref(msg);
|
|
msg = nullptr;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static sd_bus_message *
|
|
call_method(const char *member, std::function<bool(sd_bus_message *)> packer) {
|
|
std::promise<sd_bus_message *> b;
|
|
std::future<sd_bus_message *> f = b.get_future();
|
|
onCallPrepareHandler prepare(
|
|
[=](sd_bus_message *msg) -> bool { return packer(msg); });
|
|
onCallDoneHandler done([&b](sd_bus_message *m) -> int {
|
|
sd_bus_message_ref(m);
|
|
b.set_value(m);
|
|
return 0;
|
|
});
|
|
MethodCallRequest req(member, packer ? &prepare : nullptr, &done);
|
|
if (write(gs_method_call_pipe[1], &req, sizeof(req)) != sizeof(req)) {
|
|
LOGE("Failed to write to pipe: %s\n", strerror(errno));
|
|
return nullptr;
|
|
}
|
|
sd_bus_message *msg = f.get();
|
|
return msg;
|
|
}
|
|
|
|
#include "dbus_client_api_impl.cpp"
|
|
|
|
PqClient::PqClient() {
|
|
init_pq_logging();
|
|
|
|
if (gs_signal_bus) {
|
|
int r = sd_bus_match_signal(
|
|
gs_signal_bus, nullptr, PQ_SERVICE_DBUS_SERVICE, PQ_SERVICE_DBUS_OBJECT,
|
|
PQ_SERVICE_DBUS_INTERFACE, nullptr, signalCallback, nullptr);
|
|
if (r < 0) {
|
|
LOGE("Failed to match signal: %s\n", strerror(-r));
|
|
}
|
|
} else {
|
|
init_run_bus([](sd_bus *bus, sd_event *) {
|
|
int r = sd_bus_match_signal(
|
|
bus, nullptr, PQ_SERVICE_DBUS_SERVICE, PQ_SERVICE_DBUS_OBJECT,
|
|
PQ_SERVICE_DBUS_INTERFACE, nullptr, signalCallback, nullptr);
|
|
if (r < 0) {
|
|
LOGE("Failed to match signal: %s\n", strerror(-r));
|
|
}
|
|
});
|
|
}
|
|
|
|
std::promise<bool> b;
|
|
std::future<bool> f = b.get_future();
|
|
init_run_bus([&](sd_bus *bus, sd_event *event) {
|
|
if (pipe(gs_method_call_pipe) < 0) {
|
|
LOGE("pipe() failed: %s\n", strerror(errno));
|
|
return;
|
|
}
|
|
sd_event_add_io(event, nullptr, gs_method_call_pipe[0], POLLIN,
|
|
method_call_handler, bus);
|
|
try {
|
|
b.set_value(true);
|
|
} catch (const std::future_error &e) {
|
|
LOGE("%s\n", e.what());
|
|
}
|
|
});
|
|
f.get();
|
|
}
|
|
|
|
PqClient::~PqClient() {
|
|
LOGD("%s: PqClient has been destructed.\n", __FUNCTION__);
|
|
}
|
|
|
|
int PqClient::RegisterObserverToPqClient(PqClientIObserver *observer) {
|
|
if (observer != nullptr) {
|
|
mPqClientObserver.emplace_back(observer);
|
|
LOGD("%s: mPqClientObserver[%p] has been register.\n", __FUNCTION__,
|
|
observer);
|
|
} else {
|
|
LOGD("%s: observer is NULL.\n", __FUNCTION__);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
PqClient *PqClient::GetInstance() {
|
|
static std::shared_ptr<PqClient> inst_;
|
|
if (inst_.get() == nullptr) {
|
|
inst_ = std::shared_ptr<PqClient>(new PqClient(),
|
|
[](PqClient *ptr) { delete ptr; });
|
|
}
|
|
|
|
return inst_.get();
|
|
}
|
|
|