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