1e0e9324cSopenharmony_ci/*
2e0e9324cSopenharmony_ci * Copyright (c) 2023 Shenzhen Kaihong Digital Industry Development Co., Ltd.
3e0e9324cSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4e0e9324cSopenharmony_ci * you may not use this file except in compliance with the License.
5e0e9324cSopenharmony_ci * You may obtain a copy of the License at
6e0e9324cSopenharmony_ci *
7e0e9324cSopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8e0e9324cSopenharmony_ci *
9e0e9324cSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10e0e9324cSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11e0e9324cSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12e0e9324cSopenharmony_ci * See the License for the specific language governing permissions and
13e0e9324cSopenharmony_ci * limitations under the License.
14e0e9324cSopenharmony_ci */
15e0e9324cSopenharmony_ci
16e0e9324cSopenharmony_ci#include "wfd_demo.h"
17e0e9324cSopenharmony_ci#include <cstdint>
18e0e9324cSopenharmony_ci#include <functional>
19e0e9324cSopenharmony_ci#include <iostream>
20e0e9324cSopenharmony_ci#include <mutex>
21e0e9324cSopenharmony_ci#include <string>
22e0e9324cSopenharmony_ci#include <vector>
23e0e9324cSopenharmony_ci#include "extend/magic_enum/magic_enum.hpp"
24e0e9324cSopenharmony_ci#include "impl/scene/wfd/wfd_def.h"
25e0e9324cSopenharmony_ci#include "math.h"
26e0e9324cSopenharmony_ci#include "surface.h"
27e0e9324cSopenharmony_ci#include "surface_utils.h"
28e0e9324cSopenharmony_ci#include "transaction/rs_transaction.h"
29e0e9324cSopenharmony_ci#include "ui/rs_surface_node.h"
30e0e9324cSopenharmony_ci#include "utils/utils.h"
31e0e9324cSopenharmony_ci#include "window.h"
32e0e9324cSopenharmony_ci#include "window_option.h"
33e0e9324cSopenharmony_ci
34e0e9324cSopenharmony_ciusing namespace OHOS;
35e0e9324cSopenharmony_ciusing namespace OHOS::Sharing;
36e0e9324cSopenharmony_ci
37e0e9324cSopenharmony_ciVideoFormat DEFAULT_VIDEO_FORMAT = VideoFormat::VIDEO_1920X1080_30;
38e0e9324cSopenharmony_ciAudioFormat DEFAULT_AUDIO_FORMAT = AudioFormat::AUDIO_48000_16_2;
39e0e9324cSopenharmony_ciint32_t DEFAULT_WINDOW_WIDTH = 1920;
40e0e9324cSopenharmony_ciint32_t DEFAULT_WINDOW_HEIGHT = 1080;
41e0e9324cSopenharmony_cistd::vector<std::pair<int32_t, int32_t>> position{{0, 0}, {960, 0}, {0, 540}, {960, 540}};
42e0e9324cSopenharmony_ci
43e0e9324cSopenharmony_cibool WfdDemo::Init(const WfdMode mode)
44e0e9324cSopenharmony_ci{
45e0e9324cSopenharmony_ci    std::cout << "to get wifi display " << std::string(magic_enum::enum_name(mode)).c_str() << '\n';
46e0e9324cSopenharmony_ci    client_ = MiracastFactory::GetInstance(mode);
47e0e9324cSopenharmony_ci    if (!client_) {
48e0e9324cSopenharmony_ci        std::cout << "create wfd client error\n";
49e0e9324cSopenharmony_ci        return false;
50e0e9324cSopenharmony_ci    }
51e0e9324cSopenharmony_ci    client_->SetListener(shared_from_this());
52e0e9324cSopenharmony_ci
53e0e9324cSopenharmony_ci    // when mode is SINK, init a window to display
54e0e9324cSopenharmony_ci    if (mode == SINK) {
55e0e9324cSopenharmony_ci        InitWindow();
56e0e9324cSopenharmony_ci        WifiDisplayTable_.emplace("Play", std::bind(&WifiDisplay::Play, client_, std::placeholders::_1));
57e0e9324cSopenharmony_ci        WifiDisplayTable_.emplace("Pause", std::bind(&WifiDisplay::Pause, client_, std::placeholders::_1));
58e0e9324cSopenharmony_ci        WifiDisplayTable_.emplace("Close", std::bind(&WifiDisplay::Close, client_, std::placeholders::_1));
59e0e9324cSopenharmony_ci    }
60e0e9324cSopenharmony_ci    return true;
61e0e9324cSopenharmony_ci}
62e0e9324cSopenharmony_ci
63e0e9324cSopenharmony_civoid WfdDemo::InitWindow()
64e0e9324cSopenharmony_ci{
65e0e9324cSopenharmony_ci    if (!surfaceIds_.empty())
66e0e9324cSopenharmony_ci        return;
67e0e9324cSopenharmony_ci    std::cout << "create window enter\n";
68e0e9324cSopenharmony_ci
69e0e9324cSopenharmony_ci    for (int i = 0; i < windowNum_; i++) {
70e0e9324cSopenharmony_ci        sptr<Rosen::WindowOption> option = new Rosen::WindowOption();
71e0e9324cSopenharmony_ci        option->SetWindowRect({position[i].first, position[i].second, DEFAULT_WINDOW_WIDTH / sqrt(windowNum_),
72e0e9324cSopenharmony_ci                               DEFAULT_WINDOW_HEIGHT / sqrt(windowNum_)});
73e0e9324cSopenharmony_ci        option->SetWindowType(Rosen::WindowType::WINDOW_TYPE_APP_LAUNCHING);
74e0e9324cSopenharmony_ci        option->SetWindowMode(Rosen::WindowMode::WINDOW_MODE_FULLSCREEN);
75e0e9324cSopenharmony_ci        sptr<Rosen::Window> window = Rosen::Window::Create("wifi display window:" + std::to_string(i), option);
76e0e9324cSopenharmony_ci        auto surfaceNode = window->GetSurfaceNode();
77e0e9324cSopenharmony_ci        surfaceNode->SetFrameGravity(Rosen::Gravity::RESIZE);
78e0e9324cSopenharmony_ci        Rosen::RSTransaction::FlushImplicitTransaction();
79e0e9324cSopenharmony_ci        sptr<Surface> surface = surfaceNode->GetSurface();
80e0e9324cSopenharmony_ci        window->SetRequestedOrientation(Rosen::Orientation::HORIZONTAL);
81e0e9324cSopenharmony_ci        window->Show();
82e0e9324cSopenharmony_ci        auto surfaceId = surface->GetUniqueId();
83e0e9324cSopenharmony_ci        surfaceIds_.push_back(surfaceId);
84e0e9324cSopenharmony_ci        int ret = SurfaceUtils::GetInstance()->Add(surfaceId, surface);
85e0e9324cSopenharmony_ci        if (ret != 0)
86e0e9324cSopenharmony_ci            std::cout << "add failed\n";
87e0e9324cSopenharmony_ci        devicesIsPlaying_.push_back("");
88e0e9324cSopenharmony_ci    }
89e0e9324cSopenharmony_ci}
90e0e9324cSopenharmony_ci
91e0e9324cSopenharmony_civoid WfdDemo::SelectMediaFormat()
92e0e9324cSopenharmony_ci{
93e0e9324cSopenharmony_ci    videoAttr_.codecType = CodecType::CODEC_H264;
94e0e9324cSopenharmony_ci    videoAttr_.format = 7;
95e0e9324cSopenharmony_ci    audioAttr_.codecType = CodecType::CODEC_AAC;
96e0e9324cSopenharmony_ci    audioAttr_.format = 43;
97e0e9324cSopenharmony_ci
98e0e9324cSopenharmony_ci    std::cout << "please input videoFormatId:(default 4)\n";
99e0e9324cSopenharmony_ci    std::cout << "0: VIDEO_640X480_60\n";
100e0e9324cSopenharmony_ci    std::cout << "1: VIDEO_1280X720_25\n";
101e0e9324cSopenharmony_ci    std::cout << "2: VIDEO_1280X720_30\n";
102e0e9324cSopenharmony_ci    std::cout << "4: VIDEO_1920X1080_25\n";
103e0e9324cSopenharmony_ci    std::cout << "5: VIDEO_1920X1080_30\n";
104e0e9324cSopenharmony_ci
105e0e9324cSopenharmony_ci    std::string input;
106e0e9324cSopenharmony_ci    getline(std::cin, input);
107e0e9324cSopenharmony_ci    if (input != "") {
108e0e9324cSopenharmony_ci        videoAttr_.format = static_cast<VideoFormat>(atoi(input.c_str()) + 2);
109e0e9324cSopenharmony_ci    }
110e0e9324cSopenharmony_ci
111e0e9324cSopenharmony_ci    std::cout << "please input audioFormatId:\n(default 13)";
112e0e9324cSopenharmony_ci    std::cout << "0: AUDIO_44100_8_1\n";
113e0e9324cSopenharmony_ci    std::cout << "1: AUDIO_44100_8_2\n";
114e0e9324cSopenharmony_ci    std::cout << "2: AUDIO_44100_16_1\n";
115e0e9324cSopenharmony_ci    std::cout << "3: AUDIO_44100_16_2\n";
116e0e9324cSopenharmony_ci    std::cout << "10: AUDIO_48000_8_1\n";
117e0e9324cSopenharmony_ci    std::cout << "11: AUDIO_48000_8_2\n";
118e0e9324cSopenharmony_ci    std::cout << "12: AUDIO_48000_16_1\n";
119e0e9324cSopenharmony_ci    std::cout << "13: AUDIO_48000_16_2\n";
120e0e9324cSopenharmony_ci
121e0e9324cSopenharmony_ci    getline(std::cin, input);
122e0e9324cSopenharmony_ci    if (input != "") {
123e0e9324cSopenharmony_ci        audioAttr_.format = static_cast<AudioFormat>(atoi(input.c_str()) + 30);
124e0e9324cSopenharmony_ci    }
125e0e9324cSopenharmony_ci}
126e0e9324cSopenharmony_ci
127e0e9324cSopenharmony_civoid WfdDemo::AddDevice() {}
128e0e9324cSopenharmony_civoid WfdDemo::RemoveDevice() {}
129e0e9324cSopenharmony_ci
130e0e9324cSopenharmony_civoid WfdDemo::OnError(const CastErrorInfo &errorInfo)
131e0e9324cSopenharmony_ci{
132e0e9324cSopenharmony_ci    std::cout << "on error. deviceId : " << errorInfo.deviceId << ", errorCode : " << errorInfo.errorCode << '\n';
133e0e9324cSopenharmony_ci}
134e0e9324cSopenharmony_ci
135e0e9324cSopenharmony_civoid WfdDemo::OnDeviceState(const CastDeviceInfo &deviceInfo)
136e0e9324cSopenharmony_ci{
137e0e9324cSopenharmony_ci    switch (deviceInfo.state) {
138e0e9324cSopenharmony_ci        case CastDeviceState::CONNECTED: {
139e0e9324cSopenharmony_ci            {
140e0e9324cSopenharmony_ci                std::unique_lock<std::mutex> lock(mutex_);
141e0e9324cSopenharmony_ci                for (int item = 0; item < windowNum_; item++) {
142e0e9324cSopenharmony_ci                    if (devicesIsPlaying_[item] == "") {
143e0e9324cSopenharmony_ci                        client_->AppendSurface(deviceInfo.deviceId, surfaceIds_[item]);
144e0e9324cSopenharmony_ci                        client_->SetMediaFormat(deviceInfo.deviceId, videoAttr_, audioAttr_);
145e0e9324cSopenharmony_ci                        client_->Play(deviceInfo.deviceId);
146e0e9324cSopenharmony_ci                        devicesIsPlaying_[item] = deviceInfo.deviceId;
147e0e9324cSopenharmony_ci                        break;
148e0e9324cSopenharmony_ci                    }
149e0e9324cSopenharmony_ci                }
150e0e9324cSopenharmony_ci                break;
151e0e9324cSopenharmony_ci            }
152e0e9324cSopenharmony_ci        }
153e0e9324cSopenharmony_ci        case CastDeviceState::DISCONNECTED: {
154e0e9324cSopenharmony_ci            {
155e0e9324cSopenharmony_ci                std::unique_lock<std::mutex> lock(mutex_);
156e0e9324cSopenharmony_ci                for (int item = 0; item < windowNum_; item++) {
157e0e9324cSopenharmony_ci                    if (devicesIsPlaying_[item] == deviceInfo.deviceId) {
158e0e9324cSopenharmony_ci                        devicesIsPlaying_[item] = "";
159e0e9324cSopenharmony_ci                    }
160e0e9324cSopenharmony_ci                }
161e0e9324cSopenharmony_ci                break;
162e0e9324cSopenharmony_ci            }
163e0e9324cSopenharmony_ci        }
164e0e9324cSopenharmony_ci        default:
165e0e9324cSopenharmony_ci            break;
166e0e9324cSopenharmony_ci    }
167e0e9324cSopenharmony_ci    std::cout << "on OnConnectionChanged : \n";
168e0e9324cSopenharmony_ci    std::cout << "ip : " << deviceInfo.ipAddr.c_str() << '\n';
169e0e9324cSopenharmony_ci    std::cout << "mac : " << deviceInfo.deviceId.c_str() << '\n';
170e0e9324cSopenharmony_ci    std::cout << "state: " << std::string(magic_enum::enum_name(deviceInfo.state)).c_str() << '\n';
171e0e9324cSopenharmony_ci}
172e0e9324cSopenharmony_ci
173e0e9324cSopenharmony_civoid WfdDemo::OnDeviceFound(const std::vector<CastDeviceInfo> &deviceInfos)
174e0e9324cSopenharmony_ci{
175e0e9324cSopenharmony_ci    for (int deviceNum = 0; deviceNum < deviceInfos.size(); deviceNum++) {
176e0e9324cSopenharmony_ci        std::cout << deviceNum << ". device id : " << deviceInfos[deviceNum].deviceId
177e0e9324cSopenharmony_ci                  << " device name : " << deviceInfos[deviceNum].deviceName << "\n";
178e0e9324cSopenharmony_ci    }
179e0e9324cSopenharmony_ci}
180e0e9324cSopenharmony_ci
181e0e9324cSopenharmony_civoid WfdDemo::RunWfdSink()
182e0e9324cSopenharmony_ci{
183e0e9324cSopenharmony_ci    if (!Init(SINK))
184e0e9324cSopenharmony_ci        return;
185e0e9324cSopenharmony_ci
186e0e9324cSopenharmony_ci    if (client_->Start() == 0) {
187e0e9324cSopenharmony_ci        std::cout << "wifi display sink service start!\n";
188e0e9324cSopenharmony_ci    }
189e0e9324cSopenharmony_ci    SelectMediaFormat();
190e0e9324cSopenharmony_ci
191e0e9324cSopenharmony_ci    std::map<std::string, std::string> cmdMap = {{"1", "Start"},      {"2", "Stop"},  {"3", "SelectMediaFormat"},
192e0e9324cSopenharmony_ci                                                 {"4", "Play"},       {"5", "Pause"}, {"6", "Close"},
193e0e9324cSopenharmony_ci                                                 {"12", "ListDevice"}};
194e0e9324cSopenharmony_ci
195e0e9324cSopenharmony_ci    std::string helpNotice = "select steps:        0-quit;\n"
196e0e9324cSopenharmony_ci                             "1-Start;             2-Stop;\n"
197e0e9324cSopenharmony_ci                             "3-SelectMediaFormat; 4-Play;\n"
198e0e9324cSopenharmony_ci                             "5-Pause;             6-Close;\n"
199e0e9324cSopenharmony_ci                             "12-ListDevice\n";
200e0e9324cSopenharmony_ci
201e0e9324cSopenharmony_ci    std::string inputCmd;
202e0e9324cSopenharmony_ci    while (1) {
203e0e9324cSopenharmony_ci        std::cout << helpNotice;
204e0e9324cSopenharmony_ci        getline(std::cin, inputCmd);
205e0e9324cSopenharmony_ci        if (inputCmd == "") {
206e0e9324cSopenharmony_ci            continue;
207e0e9324cSopenharmony_ci        } else if (inputCmd == "0") {
208e0e9324cSopenharmony_ci            break;
209e0e9324cSopenharmony_ci        } else {
210e0e9324cSopenharmony_ci            if (cmdMap.count(inputCmd) == 0) {
211e0e9324cSopenharmony_ci                std::cout << "no cmd: " << inputCmd << ", input agin\n";
212e0e9324cSopenharmony_ci                continue;
213e0e9324cSopenharmony_ci            } else {
214e0e9324cSopenharmony_ci                DoCmd(cmdMap[inputCmd]);
215e0e9324cSopenharmony_ci            }
216e0e9324cSopenharmony_ci        }
217e0e9324cSopenharmony_ci    }
218e0e9324cSopenharmony_ci}
219e0e9324cSopenharmony_ci
220e0e9324cSopenharmony_civoid WfdDemo::RunWfdSource() {}
221e0e9324cSopenharmony_ci
222e0e9324cSopenharmony_civoid WfdDemo::DoCmd(std::string cmd)
223e0e9324cSopenharmony_ci{
224e0e9324cSopenharmony_ci    if (!client_)
225e0e9324cSopenharmony_ci        return;
226e0e9324cSopenharmony_ci    if (cmd.find("Start") != std::string::npos) {
227e0e9324cSopenharmony_ci        client_->Start();
228e0e9324cSopenharmony_ci    } else if (cmd.find("Stop") != std::string::npos) {
229e0e9324cSopenharmony_ci        client_->Stop();
230e0e9324cSopenharmony_ci        {
231e0e9324cSopenharmony_ci            std::unique_lock<std::mutex> lock(mutex_);
232e0e9324cSopenharmony_ci            for (int item = 0; item < devicesIsPlaying_.size(); item++)
233e0e9324cSopenharmony_ci                devicesIsPlaying_[item] = "";
234e0e9324cSopenharmony_ci        }
235e0e9324cSopenharmony_ci    } else if (WifiDisplayTable_.find(cmd) != WifiDisplayTable_.end()) {
236e0e9324cSopenharmony_ci        std::cout << "enter the window number to operate: \n";
237e0e9324cSopenharmony_ci        int32_t winNum = 0;
238e0e9324cSopenharmony_ci        std::string input;
239e0e9324cSopenharmony_ci        getline(std::cin, input);
240e0e9324cSopenharmony_ci        if (input != "") {
241e0e9324cSopenharmony_ci            winNum = static_cast<int32_t>(atoi(input.c_str()));
242e0e9324cSopenharmony_ci            if (winNum >= windowNum_) {
243e0e9324cSopenharmony_ci                std::cout << "the window not exits\n";
244e0e9324cSopenharmony_ci                return;
245e0e9324cSopenharmony_ci            }
246e0e9324cSopenharmony_ci        }
247e0e9324cSopenharmony_ci        auto iter = WifiDisplayTable_.find(cmd);
248e0e9324cSopenharmony_ci        auto func = iter->second;
249e0e9324cSopenharmony_ci        func(devicesIsPlaying_[winNum]);
250e0e9324cSopenharmony_ci    } else if (cmd.find("SelectMediaFormat") != std::string::npos) {
251e0e9324cSopenharmony_ci        SelectMediaFormat();
252e0e9324cSopenharmony_ci    } else if (cmd.find("StartDiscover") != std::string::npos) {
253e0e9324cSopenharmony_ci        client_->StartDiscover();
254e0e9324cSopenharmony_ci    } else if (cmd.find("StopDiscover") != std::string::npos) {
255e0e9324cSopenharmony_ci        client_->StopDiscover();
256e0e9324cSopenharmony_ci    } else if (cmd.find("AddDevice") != std::string::npos) {
257e0e9324cSopenharmony_ci        CastDeviceInfo info;
258e0e9324cSopenharmony_ci        client_->AddDevice(info);
259e0e9324cSopenharmony_ci    } else if (cmd.find("RemoveDevice") != std::string::npos) {
260e0e9324cSopenharmony_ci        client_->RemoveDevice("0.0.0.0");
261e0e9324cSopenharmony_ci    } else {
262e0e9324cSopenharmony_ci        std::cout << "operation is invalid\n";
263e0e9324cSopenharmony_ci    }
264e0e9324cSopenharmony_ci
265e0e9324cSopenharmony_ci    return;
266e0e9324cSopenharmony_ci}
267e0e9324cSopenharmony_ci
268e0e9324cSopenharmony_ciint main()
269e0e9324cSopenharmony_ci{
270e0e9324cSopenharmony_ci    std::cout << "Please select a demo scenario number(default sink): \n";
271e0e9324cSopenharmony_ci    std::cout << "0:wfd sink\n";
272e0e9324cSopenharmony_ci    std::cout << "1:wfd source\n";
273e0e9324cSopenharmony_ci
274e0e9324cSopenharmony_ci    auto wifiDisplay = std::make_shared<WfdDemo>();
275e0e9324cSopenharmony_ci
276e0e9324cSopenharmony_ci    std::string mode;
277e0e9324cSopenharmony_ci    (void)getline(std::cin, mode);
278e0e9324cSopenharmony_ci    if (mode == "" || mode == "0") {
279e0e9324cSopenharmony_ci        wifiDisplay->RunWfdSink();
280e0e9324cSopenharmony_ci    } else if (mode == "1") {
281e0e9324cSopenharmony_ci        wifiDisplay->RunWfdSource();
282e0e9324cSopenharmony_ci    } else {
283e0e9324cSopenharmony_ci        std::cout << "no that selection\n";
284e0e9324cSopenharmony_ci        return 0;
285e0e9324cSopenharmony_ci    }
286e0e9324cSopenharmony_ci
287e0e9324cSopenharmony_ci    std::cout << "wfd test end!\n";
288e0e9324cSopenharmony_ci    return 0;
289e0e9324cSopenharmony_ci}