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 << "-3: VIDEO_NONE\n";
100 std::cout << "0: VIDEO_640X480_60\n";
101 std::cout << "1: VIDEO_1280X720_25\n";
102 std::cout << "2: VIDEO_1280X720_30\n";
103 std::cout << "4: VIDEO_1920X1080_25\n";
104 std::cout << "5: VIDEO_1920X1080_30\n";
105
106 std::string input;
107 getline(std::cin, input);
108 if (input != "") {
109 videoAttr_.format = static_cast<VideoFormat>(atoi(input.c_str()) + 2);
110 }
111
112 std::cout << "please input audioFormatId:\n(default 13)";
113 std::cout << "-31: AUDIO_NONE\n";
114 std::cout << "0: AUDIO_44100_8_1\n";
115 std::cout << "1: AUDIO_44100_8_2\n";
116 std::cout << "2: AUDIO_44100_16_1\n";
117 std::cout << "3: AUDIO_44100_16_2\n";
118 std::cout << "10: AUDIO_48000_8_1\n";
119 std::cout << "11: AUDIO_48000_8_2\n";
120 std::cout << "12: AUDIO_48000_16_1\n";
121 std::cout << "13: AUDIO_48000_16_2\n";
122
123 getline(std::cin, input);
124 if (input != "") {
125 audioAttr_.format = static_cast<AudioFormat>(atoi(input.c_str()) + 30);
126 }
127 }
128
AddDevice()129 void WfdDemo::AddDevice() {}
RemoveDevice()130 void WfdDemo::RemoveDevice() {}
131
OnError(const CastErrorInfo & errorInfo)132 void WfdDemo::OnError(const CastErrorInfo &errorInfo)
133 {
134 std::cout << "on error. deviceId : " << errorInfo.deviceId << ", errorCode : " << errorInfo.errorCode << '\n';
135 }
136
OnDeviceState(const CastDeviceInfo & deviceInfo)137 void WfdDemo::OnDeviceState(const CastDeviceInfo &deviceInfo)
138 {
139 switch (deviceInfo.state) {
140 case CastDeviceState::CONNECTED: {
141 {
142 std::unique_lock<std::mutex> lock(mutex_);
143 for (int item = 0; item < windowNum_; item++) {
144 if (devicesIsPlaying_[item] == "") {
145 client_->AppendSurface(deviceInfo.deviceId, surfaceIds_[item]);
146 client_->SetMediaFormat(deviceInfo.deviceId, videoAttr_, audioAttr_);
147 client_->Play(deviceInfo.deviceId);
148 devicesIsPlaying_[item] = deviceInfo.deviceId;
149 break;
150 }
151 }
152 break;
153 }
154 }
155 case CastDeviceState::DISCONNECTED: {
156 {
157 std::unique_lock<std::mutex> lock(mutex_);
158 for (int item = 0; item < windowNum_; item++) {
159 if (devicesIsPlaying_[item] == deviceInfo.deviceId) {
160 devicesIsPlaying_[item] = "";
161 }
162 }
163 break;
164 }
165 }
166 default:
167 break;
168 }
169 std::cout << "on OnConnectionChanged : \n";
170 std::cout << "ip : " << deviceInfo.ipAddr.c_str() << '\n';
171 std::cout << "mac : " << deviceInfo.deviceId.c_str() << '\n';
172 std::cout << "state: " << std::string(magic_enum::enum_name(deviceInfo.state)).c_str() << '\n';
173 }
174
OnDeviceFound(const std::vector<CastDeviceInfo> & deviceInfos)175 void WfdDemo::OnDeviceFound(const std::vector<CastDeviceInfo> &deviceInfos)
176 {
177 for (int deviceNum = 0; deviceNum < deviceInfos.size(); deviceNum++) {
178 std::cout << deviceNum << ". device id : " << deviceInfos[deviceNum].deviceId
179 << " device name : " << deviceInfos[deviceNum].deviceName << "\n";
180 }
181 }
182
RunWfdSink()183 void WfdDemo::RunWfdSink()
184 {
185 if (!Init(SINK))
186 return;
187
188 if (client_->Start() == 0) {
189 std::cout << "wifi display sink service start!\n";
190 }
191 SelectMediaFormat();
192
193 std::map<std::string, std::string> cmdMap = {{"1", "Start"}, {"2", "Stop"}, {"3", "SelectMediaFormat"},
194 {"4", "Play"}, {"5", "Pause"}, {"6", "Close"},
195 {"12", "ListDevice"}};
196
197 std::string helpNotice = "select steps: 0-quit;\n"
198 "1-Start; 2-Stop;\n"
199 "3-SelectMediaFormat; 4-Play;\n"
200 "5-Pause; 6-Close;\n"
201 "12-ListDevice\n";
202
203 std::string inputCmd;
204 while (1) {
205 std::cout << helpNotice;
206 getline(std::cin, inputCmd);
207 if (inputCmd == "") {
208 continue;
209 } else if (inputCmd == "0") {
210 break;
211 } else {
212 if (cmdMap.count(inputCmd) == 0) {
213 std::cout << "no cmd: " << inputCmd << ", input agin\n";
214 continue;
215 } else {
216 DoCmd(cmdMap[inputCmd]);
217 }
218 }
219 }
220 }
221
RunWfdSource()222 void WfdDemo::RunWfdSource() {}
223
DoCmd(std::string cmd)224 void WfdDemo::DoCmd(std::string cmd)
225 {
226 if (!client_)
227 return;
228 if (cmd.find("Start") != std::string::npos) {
229 client_->Start();
230 } else if (cmd.find("Stop") != std::string::npos) {
231 client_->Stop();
232 {
233 std::unique_lock<std::mutex> lock(mutex_);
234 for (int item = 0; item < devicesIsPlaying_.size(); item++)
235 devicesIsPlaying_[item] = "";
236 }
237 } else if (WifiDisplayTable_.find(cmd) != WifiDisplayTable_.end()) {
238 std::cout << "enter the window number to operate: \n";
239 int32_t winNum = 0;
240 std::string input;
241 getline(std::cin, input);
242 if (input != "") {
243 winNum = static_cast<int32_t>(atoi(input.c_str()));
244 if (winNum >= windowNum_) {
245 std::cout << "the window not exits\n";
246 return;
247 }
248 }
249 auto iter = WifiDisplayTable_.find(cmd);
250 auto func = iter->second;
251 func(devicesIsPlaying_[winNum]);
252 } else if (cmd.find("SelectMediaFormat") != std::string::npos) {
253 SelectMediaFormat();
254 } else if (cmd.find("StartDiscover") != std::string::npos) {
255 client_->StartDiscover();
256 } else if (cmd.find("StopDiscover") != std::string::npos) {
257 client_->StopDiscover();
258 } else if (cmd.find("AddDevice") != std::string::npos) {
259 CastDeviceInfo info;
260 client_->AddDevice(info);
261 } else if (cmd.find("RemoveDevice") != std::string::npos) {
262 client_->RemoveDevice("0.0.0.0");
263 } else {
264 std::cout << "operation is invalid\n";
265 }
266
267 return;
268 }
269
main()270 int main()
271 {
272 std::cout << "Please select a demo scenario number(default sink): \n";
273 std::cout << "0:wfd sink\n";
274 std::cout << "1:wfd source\n";
275
276 auto wifiDisplay = std::make_shared<WfdDemo>();
277
278 std::string mode;
279 (void)getline(std::cin, mode);
280 if (mode == "" || mode == "0") {
281 wifiDisplay->RunWfdSink();
282 } else if (mode == "1") {
283 wifiDisplay->RunWfdSource();
284 } else {
285 std::cout << "no that selection\n";
286 return 0;
287 }
288
289 std::cout << "wfd test end!\n";
290 return 0;
291 }