917 lines
25 KiB
C++
917 lines
25 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 "TV"
|
|
#define LOG_CLASS_TAG "TvClient"
|
|
|
|
#include "CTvLog.h"
|
|
|
|
#include "TvClient.h"
|
|
|
|
static sd_bus *gs_signal_bus = nullptr;
|
|
|
|
bool tvclient_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<TvClient::TvClientIObserver *> mTvClientObserver;
|
|
static int SendEvent(CTvEvent &event) {
|
|
for (const auto &o : mTvClientObserver) {
|
|
if (o != nullptr) {
|
|
o->onTvClientEvent(event);
|
|
LOGD("send event for %p count TvClientObserver!\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, TV_SERVICE_SIGNAL_SIGNAL_DETECTED) == 0) {
|
|
TvEvent::SignalDetectEvent e;
|
|
int r = sd_bus_message_read(msg, "iiiiiu", &e.mSourceInput, &e.mFmt,
|
|
&e.mTrans_fmt, &e.mStatus, &e.mDviFlag,
|
|
&e.mhdr_info);
|
|
if (r < 0)
|
|
return r;
|
|
SendEvent(e);
|
|
} else if (strcmp(memb, TV_SERVICE_SIGNAL_SOURCE_CONNECTED) == 0) {
|
|
TvEvent::SourceConnectEvent e;
|
|
int r = sd_bus_message_read(msg, "ii", &e.mSourceInput, &e.connectionState);
|
|
if (r < 0)
|
|
return r;
|
|
SendEvent(e);
|
|
} else if (strcmp(memb, TV_SERVICE_SIGNAL_DV_ALLM_CHANGED) == 0) {
|
|
TvEvent::SignalDvAllmEvent e;
|
|
int r = sd_bus_message_read(msg, "iii", &e.allm_mode, &e.it_content,
|
|
&e.cn_type);
|
|
if (r < 0)
|
|
return r;
|
|
SendEvent(e);
|
|
} else if (strcmp(memb, TV_SERVICE_SIGNAL_VRR_CHANGED) == 0) {
|
|
TvEvent::SignalVrrEvent e;
|
|
int r = sd_bus_message_read(msg, "i", &e.cur_vrr_status);
|
|
if (r < 0)
|
|
return r;
|
|
SendEvent(e);
|
|
} else if (strcmp(memb, TV_SERVICE_SIGNAL_QMS_CHANGED) == 0) {
|
|
TvEvent::QMSEvent e;
|
|
int r = sd_bus_message_read(msg, "iii", &e.qms_en, &e.qms_fps,
|
|
&e.qms_base_fps);
|
|
if (r < 0)
|
|
return r;
|
|
SendEvent(e);
|
|
} else if (strcmp(memb, TV_SERVICE_SIGNAL_PIP_SIGNAL_DETECTED) == 0) {
|
|
TvEvent::PipSignalDetectEvent e;
|
|
int r = sd_bus_message_read(msg, "iiiiiu", &e.mSourceInput, &e.mFmt,
|
|
&e.mTrans_fmt, &e.mStatus, &e.mDviFlag,
|
|
&e.mhdr_info);
|
|
if (r < 0)
|
|
return r;
|
|
SendEvent(e);
|
|
} 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([=]() {
|
|
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 (callback) {
|
|
// Add a defer event
|
|
r = sd_event_add_defer(event, nullptr, defer_callback,
|
|
new defer_callback_data(bus, event, &callback));
|
|
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, TV_SERVICE_DBUS_SERVICE, TV_SERVICE_DBUS_OBJECT,
|
|
TV_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;
|
|
}
|
|
|
|
#define _cleanup_(x) __attribute__((__cleanup__(x)))
|
|
#define _cleanup_bus_message_unref_ _cleanup_(sd_bus_message_unrefp)
|
|
|
|
int TvClient::StartTv(tv_source_input_t source) {
|
|
_cleanup_bus_message_unref_ sd_bus_message *m =
|
|
call_method("StartTv", [&](sd_bus_message *msg) -> bool {
|
|
int r = sd_bus_message_append(msg, "i", source);
|
|
if (r < 0) {
|
|
return false;
|
|
}
|
|
return true;
|
|
});
|
|
int result;
|
|
int r = sd_bus_message_read(m, "i", &result);
|
|
if (r < 0) {
|
|
return -1;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
int TvClient::StopTv(tv_source_input_t source) {
|
|
_cleanup_bus_message_unref_ sd_bus_message *m =
|
|
call_method("StopTv", [&](sd_bus_message *msg) -> bool {
|
|
int r = sd_bus_message_append(msg, "i", source);
|
|
if (r < 0) {
|
|
return false;
|
|
}
|
|
return true;
|
|
});
|
|
int result;
|
|
int r = sd_bus_message_read(m, "i", &result);
|
|
if (r < 0) {
|
|
return -1;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
int TvClient::SwitchSource(tv_source_input_t source) {
|
|
_cleanup_bus_message_unref_ sd_bus_message *m =
|
|
call_method("SwitchSource", [&](sd_bus_message *msg) -> bool {
|
|
int r = sd_bus_message_append(msg, "i", source);
|
|
if (r < 0) {
|
|
return false;
|
|
}
|
|
return true;
|
|
});
|
|
int result;
|
|
int r = sd_bus_message_read(m, "i", &result);
|
|
if (r < 0) {
|
|
return -1;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
tv_source_input_t TvClient::GetCurrentSource() {
|
|
_cleanup_bus_message_unref_ sd_bus_message *m =
|
|
call_method("GetCurrentSource", nullptr);
|
|
tv_source_input_t source;
|
|
int r = sd_bus_message_read(m, "i", &source);
|
|
if (r < 0) {
|
|
return SOURCE_INVALID;
|
|
}
|
|
return source;
|
|
}
|
|
|
|
int TvClient::SetVdinWorkMode(vdin_work_mode_t vdinWorkMode) {
|
|
_cleanup_bus_message_unref_ sd_bus_message *m =
|
|
call_method("SetVdinWorkMode", [&](sd_bus_message *msg) -> bool {
|
|
int r = sd_bus_message_append(msg, "i", vdinWorkMode);
|
|
if (r < 0) {
|
|
return false;
|
|
}
|
|
return true;
|
|
});
|
|
int result;
|
|
int r = sd_bus_message_read(m, "i", &result);
|
|
if (r < 0) {
|
|
return -1;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
int TvClient::SetEdidVersion(tv_source_input_t source, int edidVer) {
|
|
_cleanup_bus_message_unref_ sd_bus_message *m =
|
|
call_method("SetEdidVersion", [&](sd_bus_message *msg) -> bool {
|
|
int r = sd_bus_message_append(msg, "ii", source, edidVer);
|
|
if (r < 0) {
|
|
return false;
|
|
}
|
|
return true;
|
|
});
|
|
int result;
|
|
int r = sd_bus_message_read(m, "i", &result);
|
|
if (r < 0) {
|
|
return -1;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
int TvClient::GetEdidVersion(tv_source_input_t source) {
|
|
_cleanup_bus_message_unref_ sd_bus_message *m =
|
|
call_method("GetEdidVersion", [&](sd_bus_message *msg) -> bool {
|
|
int r = sd_bus_message_append(msg, "i", source);
|
|
if (r < 0) {
|
|
return false;
|
|
}
|
|
return true;
|
|
});
|
|
int result;
|
|
int r = sd_bus_message_read(m, "i", &result);
|
|
if (r < 0) {
|
|
return -1;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
int TvClient::SetEdidData(tv_source_input_t source, char *dataBuf) {
|
|
_cleanup_bus_message_unref_ sd_bus_message *m =
|
|
call_method("SetEdidData", [&](sd_bus_message *msg) -> bool {
|
|
int r = sd_bus_message_append_array(msg, 'y', dataBuf, 256);
|
|
if (r < 0) {
|
|
return false;
|
|
}
|
|
return true;
|
|
});
|
|
int result;
|
|
int r = sd_bus_message_read(m, "i", &result);
|
|
if (r < 0) {
|
|
return -1;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
int TvClient::GetEdidData(tv_source_input_t source, char *dataBuf) {
|
|
_cleanup_bus_message_unref_ sd_bus_message *m =
|
|
call_method("GetEdidData", [&](sd_bus_message *msg) -> bool {
|
|
int r = sd_bus_message_append(msg, "i", source);
|
|
if (r < 0) {
|
|
return false;
|
|
}
|
|
return true;
|
|
});
|
|
const void *ptr;
|
|
size_t size = 0;
|
|
int ret = 0;
|
|
int r = sd_bus_message_read(m, "i", &ret);
|
|
if (r < 0) {
|
|
return -1;
|
|
}
|
|
r = sd_bus_message_read_array(m, 'y', &ptr, &size);
|
|
if (r < 0) {
|
|
return -1;
|
|
}
|
|
memcpy(dataBuf, ptr, size > 256 ? 256 : size);
|
|
return ret;
|
|
}
|
|
|
|
int TvClient::GetHdmiSPDInfo(tv_source_input_t source, char *dataBuf,
|
|
size_t datalen) {
|
|
_cleanup_bus_message_unref_ sd_bus_message *m =
|
|
call_method("GetHdmiSPDInfo", [&](sd_bus_message *msg) -> bool {
|
|
int r = sd_bus_message_append(msg, "i", source);
|
|
if (r < 0) {
|
|
return false;
|
|
}
|
|
return true;
|
|
});
|
|
const void *ptr;
|
|
size_t size = 0;
|
|
int ret = 0;
|
|
int r = sd_bus_message_read(m, "i", &ret);
|
|
if (r < 0) {
|
|
return -1;
|
|
}
|
|
r = sd_bus_message_read_array(m, 'y', &ptr, &size);
|
|
if (r < 0) {
|
|
return -1;
|
|
}
|
|
memcpy(dataBuf, ptr, size > datalen ? datalen : size);
|
|
return ret;
|
|
}
|
|
|
|
int TvClient::GetCurrentSourceFrameHeight() {
|
|
_cleanup_bus_message_unref_ sd_bus_message *m =
|
|
call_method("GetCurrentSourceFrameHeight", nullptr);
|
|
int result;
|
|
int r = sd_bus_message_read(m, "i", &result);
|
|
if (r < 0) {
|
|
return -1;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
int TvClient::GetCurrentSourceFrameWidth() {
|
|
_cleanup_bus_message_unref_ sd_bus_message *m =
|
|
call_method("GetCurrentSourceFrameWidth", nullptr);
|
|
int result;
|
|
int r = sd_bus_message_read(m, "i", &result);
|
|
if (r < 0) {
|
|
return -1;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
int TvClient::GetCurrentSourceFrameFps() {
|
|
_cleanup_bus_message_unref_ sd_bus_message *m =
|
|
call_method("GetCurrentSourceFrameFps", nullptr);
|
|
int result;
|
|
int r = sd_bus_message_read(m, "i", &result);
|
|
if (r < 0) {
|
|
return -1;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
int TvClient::GetCurrentSourceColorDepth() {
|
|
_cleanup_bus_message_unref_ sd_bus_message *m =
|
|
call_method("GetCurrentSourceColorDepth", nullptr);
|
|
int result;
|
|
int r = sd_bus_message_read(m, "i", &result);
|
|
if (r < 0) {
|
|
return -1;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
tvin_aspect_ratio_t TvClient::GetCurrentSourceAspectRatio() {
|
|
_cleanup_bus_message_unref_ sd_bus_message *m =
|
|
call_method("GetCurrentSourceAspectRatio", nullptr);
|
|
int result;
|
|
int r = sd_bus_message_read(m, "i", &result);
|
|
if (r < 0) {
|
|
return (tvin_aspect_ratio_t)0;
|
|
}
|
|
return (tvin_aspect_ratio_t)result;
|
|
}
|
|
|
|
tvin_color_fmt_t TvClient::GetCurrentSourceColorFormat() {
|
|
_cleanup_bus_message_unref_ sd_bus_message *m =
|
|
call_method("GetCurrentSourceColorFormat", nullptr);
|
|
int result;
|
|
int r = sd_bus_message_read(m, "i", &result);
|
|
if (r < 0) {
|
|
return (tvin_color_fmt_t)0;
|
|
}
|
|
return (tvin_color_fmt_t)result;
|
|
}
|
|
|
|
int TvClient::SetCurrentSourceColorRange(tvin_color_range_t range_mode) {
|
|
_cleanup_bus_message_unref_ sd_bus_message *m = call_method(
|
|
"SetCurrentSourceColorRange", [&](sd_bus_message *msg) -> bool {
|
|
int r = sd_bus_message_append(msg, "i", range_mode);
|
|
if (r < 0) {
|
|
return false;
|
|
}
|
|
return true;
|
|
});
|
|
int result;
|
|
int r = sd_bus_message_read(m, "i", &result);
|
|
if (r < 0) {
|
|
return -1;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
tvin_color_range_t TvClient::GetCurrentSourceColorRange() {
|
|
_cleanup_bus_message_unref_ sd_bus_message *m =
|
|
call_method("GetCurrentSourceColorRange", nullptr);
|
|
int result;
|
|
int r = sd_bus_message_read(m, "i", &result);
|
|
if (r < 0) {
|
|
return (tvin_color_range_t)0;
|
|
}
|
|
return (tvin_color_range_t)result;
|
|
}
|
|
|
|
tvin_line_scan_mode_t TvClient::GetCurrentSourceLineScanMode() {
|
|
_cleanup_bus_message_unref_ sd_bus_message *m =
|
|
call_method("GetCurrentSourceLineScanMode", nullptr);
|
|
int result;
|
|
int r = sd_bus_message_read(m, "i", &result);
|
|
if (r < 0) {
|
|
return (tvin_line_scan_mode_t)0;
|
|
}
|
|
return (tvin_line_scan_mode_t)result;
|
|
}
|
|
|
|
int TvClient::GetSourceConnectStatus(tv_source_input_t source) {
|
|
_cleanup_bus_message_unref_ sd_bus_message *m =
|
|
call_method("GetSourceConnectStatus", [&](sd_bus_message *msg) -> bool {
|
|
int r = sd_bus_message_append(msg, "i", source);
|
|
if (r < 0) {
|
|
return false;
|
|
}
|
|
return true;
|
|
});
|
|
int result;
|
|
int r = sd_bus_message_read(m, "i", &result);
|
|
if (r < 0) {
|
|
return -1;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
int TvClient::SetEdidBoostOn(int bBoostOn) {
|
|
_cleanup_bus_message_unref_ sd_bus_message *m =
|
|
call_method("SetEdidBoostOn", [&](sd_bus_message *msg) -> bool {
|
|
int r = sd_bus_message_append(msg, "i", bBoostOn);
|
|
if (r < 0) {
|
|
return false;
|
|
}
|
|
return true;
|
|
});
|
|
int result;
|
|
int r = sd_bus_message_read(m, "i", &result);
|
|
if (r < 0) {
|
|
return -1;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
int TvClient::GetCurrentSourceAllmInfo(tvin_latency_s *info) {
|
|
_cleanup_bus_message_unref_ sd_bus_message *m =
|
|
call_method("GetCurrentSourceAllmInfo", nullptr);
|
|
int r = sd_bus_message_read(m, "yyiy", &info->allm_mode, &info->it_content,
|
|
&info->cn_type, &info->fmm_flag);
|
|
if (r < 0) {
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int TvClient::SetHdmiAllmEnabled(bool enable) {
|
|
_cleanup_bus_message_unref_ sd_bus_message *m =
|
|
call_method("SetHdmiAllmEnabled", [&](sd_bus_message *msg) -> bool {
|
|
int r = sd_bus_message_append(msg, "b", enable);
|
|
if (r < 0) {
|
|
return false;
|
|
}
|
|
return true;
|
|
});
|
|
int result;
|
|
int r = sd_bus_message_read(m, "i", &result);
|
|
if (r < 0) {
|
|
return -1;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
bool TvClient::GetHdmiAllmEnabled() {
|
|
_cleanup_bus_message_unref_ sd_bus_message *m =
|
|
call_method("GetHdmiAllmEnabled", nullptr);
|
|
int result;
|
|
int r = sd_bus_message_read(m, "b", &result);
|
|
if (r < 0) {
|
|
return false;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
bool TvClient::GetHdmiVrrSupport() {
|
|
_cleanup_bus_message_unref_ sd_bus_message *m =
|
|
call_method("GetHdmiVrrSupport", nullptr);
|
|
int result;
|
|
int r = sd_bus_message_read(m, "b", &result);
|
|
if (r < 0) {
|
|
return false;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
int TvClient::SetHdmiVrrEnabled(bool enable) {
|
|
_cleanup_bus_message_unref_ sd_bus_message *m =
|
|
call_method("SetHdmiVrrEnabled", [&](sd_bus_message *msg) -> bool {
|
|
int r = sd_bus_message_append(msg, "b", enable);
|
|
if (r < 0) {
|
|
return false;
|
|
}
|
|
return true;
|
|
});
|
|
int result;
|
|
int r = sd_bus_message_read(m, "i", &result);
|
|
if (r < 0) {
|
|
return -1;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
bool TvClient::GetHdmiVrrEnabled() {
|
|
_cleanup_bus_message_unref_ sd_bus_message *m =
|
|
call_method("GetHdmiVrrEnabled", nullptr);
|
|
int result;
|
|
int r = sd_bus_message_read(m, "b", &result);
|
|
if (r < 0) {
|
|
return false;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
vdin_vrr_mode_t TvClient::GetHdmiVrrMode() {
|
|
_cleanup_bus_message_unref_ sd_bus_message *m =
|
|
call_method("GetHdmiVrrMode", nullptr);
|
|
int result;
|
|
int r = sd_bus_message_read(m, "i", &result);
|
|
if (r < 0) {
|
|
return (vdin_vrr_mode_t)0;
|
|
}
|
|
return (vdin_vrr_mode_t)result;
|
|
}
|
|
|
|
bool TvClient::GetHdmiQmsSupport() {
|
|
_cleanup_bus_message_unref_ sd_bus_message *m =
|
|
call_method("GetHdmiQmsSupport", nullptr);
|
|
int result;
|
|
int r = sd_bus_message_read(m, "b", &result);
|
|
if (r < 0) {
|
|
return false;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
int TvClient::SetHdmiQmsEnabled(bool enable) {
|
|
_cleanup_bus_message_unref_ sd_bus_message *m =
|
|
call_method("SetHdmiQmsEnabled", [&](sd_bus_message *msg) -> bool {
|
|
int r = sd_bus_message_append(msg, "b", enable);
|
|
if (r < 0) {
|
|
return false;
|
|
}
|
|
return true;
|
|
});
|
|
int result;
|
|
int r = sd_bus_message_read(m, "i", &result);
|
|
if (r < 0) {
|
|
return -1;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
bool TvClient::GetHdmiQmsEnabled() {
|
|
_cleanup_bus_message_unref_ sd_bus_message *m =
|
|
call_method("GetHdmiQmsEnabled", nullptr);
|
|
int result;
|
|
int r = sd_bus_message_read(m, "b", &result);
|
|
if (r < 0) {
|
|
return false;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
int TvClient::GetCurrentStdInfo(struct tvin_std_s *info) {
|
|
_cleanup_bus_message_unref_ sd_bus_message *m =
|
|
call_method("GetCurrentStdInfo", nullptr);
|
|
int r = sd_bus_message_read(m, "iiyyy", &info->source, &info->edid_version,
|
|
&info->allm_enabled, &info->vrr_enabled, &info->qms_enabled);
|
|
if (r < 0) {
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int TvClient::SetAudioDecoderId(int channel, int id) {
|
|
_cleanup_bus_message_unref_ sd_bus_message *m =
|
|
call_method("SetAudioDecoderId", [&](sd_bus_message *msg) -> bool {
|
|
int r = sd_bus_message_append(msg, "ii", channel, id);
|
|
if (r < 0) {
|
|
return false;
|
|
}
|
|
return true;
|
|
});
|
|
int result;
|
|
int r = sd_bus_message_read(m, "i", &result);
|
|
if (r < 0) {
|
|
return -1;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
int TvClient::SetAvAudioModeEnabled (bool enable) {
|
|
_cleanup_bus_message_unref_ sd_bus_message *m =
|
|
call_method("SetAvAudioModeEnabled", [&](sd_bus_message *msg) -> bool {
|
|
int r = sd_bus_message_append(msg, "b", enable);
|
|
if (r < 0) {
|
|
return false;
|
|
}
|
|
return true;
|
|
});
|
|
int result;
|
|
int r = sd_bus_message_read(m, "i", &result);
|
|
if (r < 0) {
|
|
return -1;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
int TvClient::StartTvInPIP(tv_source_input_t source) {
|
|
_cleanup_bus_message_unref_ sd_bus_message *m =
|
|
call_method("StartTvInPIP", [&](sd_bus_message *msg) -> bool {
|
|
int r = sd_bus_message_append(msg, "i", source);
|
|
if (r < 0) {
|
|
return false;
|
|
}
|
|
return true;
|
|
});
|
|
int result;
|
|
int r = sd_bus_message_read(m, "i", &result);
|
|
if (r < 0) {
|
|
return -1;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
int TvClient::StopTvInPIP(tv_source_input_t source) {
|
|
_cleanup_bus_message_unref_ sd_bus_message *m =
|
|
call_method("StopTvInPIP", [&](sd_bus_message *msg) -> bool {
|
|
int r = sd_bus_message_append(msg, "i", source);
|
|
if (r < 0) {
|
|
return false;
|
|
}
|
|
return true;
|
|
});
|
|
int result;
|
|
int r = sd_bus_message_read(m, "i", &result);
|
|
if (r < 0) {
|
|
return -1;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
bool TvClient::GetHdmiDlgSupport() {
|
|
_cleanup_bus_message_unref_ sd_bus_message *m =
|
|
call_method("GetHdmiDlgSupport", nullptr);
|
|
int result;
|
|
int r = sd_bus_message_read(m, "b", &result);
|
|
if (r < 0) {
|
|
return false;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
int TvClient::SetHdmiDlgEnabled(bool enable) {
|
|
_cleanup_bus_message_unref_ sd_bus_message *m =
|
|
call_method("SetHdmiDlgEnabled", [&](sd_bus_message *msg) -> bool {
|
|
int r = sd_bus_message_append(msg, "b", enable);
|
|
if (r < 0) {
|
|
return false;
|
|
}
|
|
return true;
|
|
});
|
|
int result;
|
|
int r = sd_bus_message_read(m, "i", &result);
|
|
if (r < 0) {
|
|
return -1;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
bool TvClient::GetHdmiDlgEnabled() {
|
|
_cleanup_bus_message_unref_ sd_bus_message *m =
|
|
call_method("GetHdmiDlgEnabled", nullptr);
|
|
int result;
|
|
int r = sd_bus_message_read(m, "b", &result);
|
|
if (r < 0) {
|
|
return false;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
|
|
TvClient::TvClient() {
|
|
init_tv_logging();
|
|
|
|
if (gs_signal_bus) {
|
|
int r = sd_bus_match_signal(
|
|
gs_signal_bus, nullptr, TV_SERVICE_DBUS_SERVICE, TV_SERVICE_DBUS_OBJECT,
|
|
TV_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, TV_SERVICE_DBUS_SERVICE, TV_SERVICE_DBUS_OBJECT,
|
|
TV_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();
|
|
}
|
|
|
|
TvClient::~TvClient() {
|
|
LOGD("%s: TvClient has been destructed.\n", __FUNCTION__);
|
|
}
|
|
|
|
int TvClient::setTvClientObserver(TvClientIObserver *observer) {
|
|
if (observer != nullptr) {
|
|
mTvClientObserver.emplace_back(observer);
|
|
LOGD("%s: mTvClientObserver[%p] has been register.\n", __FUNCTION__,
|
|
observer);
|
|
} else {
|
|
LOGD("%s: observer is NULL.\n", __FUNCTION__);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
TvClient *TvClient::GetInstance() {
|
|
static std::shared_ptr<TvClient> inst_;
|
|
if (inst_.get() == nullptr) {
|
|
inst_ = std::shared_ptr<TvClient>(new TvClient(),
|
|
[](TvClient *ptr) { delete ptr; });
|
|
}
|
|
|
|
return inst_.get();
|
|
}
|
|
|
|
void TvClient::Release() {}
|
|
|