├── .gitignore ├── LICENSE ├── README.md ├── attachments └── cases.png ├── scratch └── videoStreamer │ ├── frameList.txt │ ├── small.txt │ └── videoStreamTest.cc └── src └── applications ├── helper ├── video-stream-helper.cc └── video-stream-helper.h ├── model ├── video-stream-client.cc ├── video-stream-client.h ├── video-stream-server.cc └── video-stream-server.h └── wscript /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | 34 | # Folder 35 | build/ 36 | .vscode/ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Guoxi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # VideoStream-NS3 2 | The project is designed to provide a simulation of adaptive video streaming over wireless home networks using ns-3. 3 | 4 | ## Introduction 5 | 6 | ### Video Streaming 7 | *Streaming* is a technology used to deliver content from the server to clients over the internet without having to download it. Multimedia streaming is one of the most popular and successful streaming services since it allows the user to watch the video or listen to music almost immediately without having to wait for the file to be completely downloaded. Unlike the file transfer which keeps the file on the device until the user manually deletes it, the streaming data is automatically removed after the user uses it. 8 | 9 | ### Adaptive Streaming 10 | 11 | Traditional progressive video streaming is simply one single video file being streamed over the internet, and the video can be stretched or shrunk to fit different screen resolutions. Regardless of the device playing it, the video file will always be the same. *Adaptive streaming* (also known as Adaptive Bitrate Streaming), instead, is a technique designed to deliver the multimedia contents to the user in the most efficient way and in the highest possible quality for each user. 12 | 13 | ## Installation 14 | 15 | ### Prerequisites 16 | ns-3 (version 3.30), Python (`python 2.7+` or `python 3.5+`), C++ compiler (`clang++` or `g++`) 17 | 18 | ### How to install 19 | 20 | 1. Download and build `ns-3` following the official document [here](https://www.nsnam.org/docs/release/3.30/tutorial/singlehtml/index.html#getting-started). 21 | 2. Copy the files **exactly** into the folders of the `ns-3`. (Be aware of the `wscript` in `src->applications`, otherwise the video streaming application will not be installed!) 22 | 3. Run `./waf` or `./waf build` to build the new application. 23 | 4. Run `./waf --run videoStreamer` for the testing program (you can change `CASE` in `videoStreamTest.cc` for different network environments). 24 | 25 | ### Detailed explanation 26 | 27 | [Frank](https://github.com/Frankytx) and I made a YouTube video for explaning what we did for the project. [Check out here!](https://youtu.be/PEvXoRmz3tk) (Sorry for the microphone issue...) 28 | 29 | ## Results 30 | 31 | ### Network configurations 32 | 33 | ![Different test cases](./attachments/cases.png) 34 | 35 | - (a) P2P network with 1 server and 1 client 36 | - (b) P2P network with 1 server and 2 clients 37 | - (c) Wireless network with 1 server and 3 mobile clients 38 | - (d) Wireless network with 3 servers and 3 mobile clients 39 | 40 | ### Case of requesting lower video quality 41 | 42 | Set a low bandwidth in `videoStreamTest.cc`, e.g., `2 Mbps`, and you are expected to see the drop of video quality level. 43 | 44 | ``` 45 | (......) 46 | At time 3.5 s: Not enough frames in the buffer, rebuffering! 47 | At time 3.61909s client received frame 15 and 56408 bytes from 10.1.1.1 port 5000 48 | At time 3.85341s client received frame 16 and 57350 bytes from 10.1.1.1 port 5000 49 | At time 4.08793s client received frame 17 and 57400 bytes from 10.1.1.1 port 5000 50 | At time 4.33389s client received frame 18 and 60200 bytes from 10.1.1.1 port 5000 51 | At time 4.5 s: Not enough frames in the buffer, rebuffering! 52 | At time 4.58276s client received frame 19 and 60898 bytes from 10.1.1.1 port 5000 53 | At time 4.7944s client received frame 20 and 51800 bytes from 10.1.1.1 port 5000 54 | At time 5.05752s client received frame 21 and 64400 bytes from 10.1.1.1 port 5000 55 | At time 5.27239s client received frame 22 and 52577 bytes from 10.1.1.1 port 5000 56 | At time 5.5 s: Not enough frames in the buffer, rebuffering! 57 | At time 5.50119s: Lower the video quality level! 58 | (......) 59 | ``` 60 | 61 | ### Case of requesting higher video quality 62 | 63 | Set a high bandwidth in `videoStreamTest.cc`, e.g., `100 Mbps`, and make sure the video length is longer than 5 seconds, then you are expected to see the increase of video quality level. 64 | 65 | ``` 66 | (......) 67 | At time 2.5349s client received frame 120 and 277397 bytes from 10.1.1.1 port 5000 68 | At time 2.55769s client received frame 121 and 278819 bytes from 10.1.1.1 port 5000 69 | At time 2.58043s client received frame 122 and 278288 bytes from 10.1.1.1 port 5000 70 | At time 2.60336s client received frame 123 and 280667 bytes from 10.1.1.1 port 5000 71 | At time 2.61411s client received frame 124 and 131446 bytes from 10.1.1.1 port 5000 72 | At time 2.61411s: Increase the video quality level to 4 73 | (......) 74 | ``` 75 | 76 | ## Issues 77 | 78 | - We noticed that the mobile devices will lose connection to the server when it moves out of the range of wireless signals. However, we did not observe the transmission rate dropping when the mobile devices are away from the sever, which requires further investigation on how different modes work in the ns-3 wireless simulator. 79 | - Due to the time limitation, we did not use the real video files for the transmission. It is also a good feature to add some decoders of video file formats to the application. 80 | 81 | ## Resources 82 | 83 | - [Project report](https://arxiv.org/abs/2302.14196) 84 | 85 | ## References 86 | 87 | 1. The ns-3 development team, “ns-3 network simulator.” https://www.nsnam.org/docs/release/3.32/tutorial/html/ introduction.html. Accessed: 2020-11-28. 88 | 2. X. Zhu and B. Girod, “Video streaming over wireless networks,” in 2007 15th European Signal Processing Conference, pp. 1462–1466, IEEE, 2007. 89 | 3. A. Fouda, A. N. Ragab, A. Esswie, M. Marzban, A. Naser, M. Rehan, and A. S. Ibrahim, “Real-time video streaming over ns3-based emulated lte networks,” Int. J. Electr. Commun. Comput. Technol.(IJECCT), vol. 4, no. 3, 2014. 90 | 4. T.-Y. Huang, R. Johari, N. McKeown, M. Trunnell, and M. Watson, “A buffer-based approach to rate adaptation: evidence from a large video streaming service,” in Proceedings of the 2014 ACM conference on SIGCOMM, SIGCOMM ’14, pp. 187–198, Association for Computing Machinery, 2014. 91 | 5. L. Liu, H. Hu, Y. Luo, and Y. Wen, “When Wireless Video Streaming Meets AI: A Deep Learning Approach,” IEEE Wireless Communications, vol. 27, pp. 127–133, Apr. 2020. 92 | -------------------------------------------------------------------------------- /attachments/cases.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guoxiliu/VideoStream-NS3/054ba00dc57f564de687418c65330ce04a285b9e/attachments/cases.png -------------------------------------------------------------------------------- /scratch/videoStreamer/frameList.txt: -------------------------------------------------------------------------------- 1 | 22500 2 | 1027 3 | 1027 4 | 1251 5 | 22636 6 | 22593 7 | 22626 8 | 15050 9 | 22926 10 | 23339 11 | 26280 12 | 24944 13 | 25969 14 | 27451 15 | 29032 16 | 30936 17 | 32650 18 | 34730 19 | 36707 20 | 38966 21 | 34433 22 | 43973 23 | 36659 24 | 49429 25 | 42759 26 | 46410 27 | 48635 28 | 50249 29 | 50631 30 | 52178 31 | 55745 32 | 60943 33 | 65005 34 | 67296 35 | 69890 36 | 71600 37 | 72903 38 | 75015 39 | 74854 40 | 73319 41 | 73862 42 | 77080 43 | 82012 44 | 90658 45 | 96708 46 | 100561 47 | 103916 48 | 105798 49 | 108052 50 | 109675 51 | 110747 52 | 56146 53 | 54469 54 | 57457 55 | 61621 56 | 63931 57 | 62513 58 | 60671 59 | 59565 60 | 59701 61 | 60348 62 | 60570 63 | 58923 64 | 58557 65 | 60107 66 | 64330 67 | 66053 68 | 65791 69 | 65156 70 | 65059 71 | 66752 72 | 67503 73 | 67790 74 | 66862 75 | 65750 76 | 65901 77 | 67890 78 | 70140 79 | 71955 80 | 72043 81 | 72216 82 | 71592 83 | 73977 84 | 74830 85 | 75714 86 | 76603 87 | 76106 88 | 76415 89 | 76077 90 | 75688 91 | 75788 92 | 76751 93 | 77694 94 | 79898 95 | 81612 96 | 83322 97 | 84763 98 | 85356 99 | 86716 100 | 85507 101 | 86130 102 | 86482 103 | 85640 104 | 86529 105 | 86904 106 | 86811 107 | 88105 108 | 88030 109 | 88869 110 | 89207 111 | 90065 112 | 90945 113 | 91623 114 | 91060 115 | 91779 116 | 91793 117 | 93050 118 | 91600 119 | 91644 120 | 92524 121 | 93399 122 | 93873 123 | 93696 124 | 94489 125 | 44282 126 | 110656 127 | 44352 128 | 54820 129 | 115393 130 | 98243 131 | 44023 132 | 53157 133 | 117307 134 | 44303 135 | 55330 136 | 56967 137 | 59199 138 | 129154 139 | 46822 140 | 56169 141 | 56420 142 | 58243 143 | 133284 144 | 45230 145 | 56231 146 | 57520 147 | 59943 148 | 60511 149 | 138707 150 | 46227 151 | 57350 152 | 57251 153 | 57145 154 | 132918 155 | 41697 156 | 126178 157 | 41776 158 | 54092 159 | 134132 160 | 44668 161 | 57502 162 | 61783 163 | 62429 164 | 62868 165 | 145062 166 | 44479 167 | 53950 168 | 57542 169 | 58993 170 | 144009 171 | 44322 172 | 50900 173 | 53383 174 | 54700 175 | 142577 176 | 40894 177 | 126871 178 | 44257 179 | 59380 180 | 66967 181 | 161884 182 | 57713 183 | 72000 184 | 75189 185 | 77259 186 | 173487 187 | 56045 188 | 68473 189 | 74747 190 | 178342 191 | 58403 192 | 71974 193 | 173576 194 | 55703 195 | 74778 196 | 78558 197 | 189728 198 | 70097 199 | 93087 200 | 213493 201 | 188919 202 | 87582 203 | 101264 204 | 103758 205 | 106731 206 | 107697 207 | 107077 208 | 106446 209 | 106410 210 | 103918 211 | 219117 212 | 71711 213 | 82417 214 | 82816 215 | 84657 216 | 82638 217 | 192031 218 | 57044 219 | 75692 220 | 85680 221 | 96338 222 | 109481 223 | 120607 224 | 126489 225 | 267500 226 | 116503 227 | 134687 228 | 140704 229 | 145199 230 | 145375 231 | 147509 232 | 145197 233 | 145001 234 | 142932 235 | 145948 236 | 144885 237 | 146343 238 | 139826 239 | 135990 240 | 129713 241 | 125604 242 | 116901 243 | 247227 244 | 67410 245 | 83514 246 | 83795 247 | 209646 248 | 63082 249 | 89391 250 | 104813 251 | 254380 252 | 106304 253 | 137301 254 | 140217 255 | 145495 256 | 145706 257 | 145681 258 | 146780 259 | 149775 260 | 149150 261 | 149582 262 | 149060 263 | 150446 264 | 151195 265 | 152186 266 | 152389 267 | 153297 268 | 154411 269 | 155350 270 | 154077 271 | 150299 272 | 649446 273 | 228691 274 | 234340 275 | 123890 276 | 135213 277 | 136110 278 | 78392 279 | 158349 280 | 63136 281 | 143206 282 | 108753 283 | 97812 284 | 83723 285 | 67105 286 | 553988 287 | 154265 288 | 78073 289 | 86790 290 | 94749 291 | 97036 292 | 99221 293 | 98787 294 | 100536 295 | 100951 296 | 102333 297 | 101864 298 | 101540 299 | 101192 300 | 101410 301 | 101278 302 | 100963 303 | 101194 304 | 101070 305 | 100650 306 | 100832 307 | 100541 308 | 100276 309 | 100780 310 | 100727 311 | 102240 312 | 101679 313 | 101853 314 | 102376 315 | 102198 316 | 101963 317 | 101795 318 | 102454 319 | 102532 320 | 102375 321 | 102837 322 | 102922 323 | 102137 324 | 102292 325 | 238369 326 | 78512 327 | 95601 328 | 96269 329 | 101930 330 | 101255 331 | 102981 332 | 101806 333 | 102217 334 | 100906 335 | 234909 336 | 77609 337 | 93895 338 | 95816 339 | 100547 340 | 99969 341 | 231167 342 | 77586 343 | 95423 344 | 96157 345 | 101134 346 | 100555 347 | 101918 348 | 102452 349 | 235689 350 | 78324 351 | 95655 352 | 96461 353 | 101875 354 | 100398 355 | 101766 356 | 101074 357 | 102069 358 | 101409 359 | 102730 360 | 235170 361 | 79736 362 | 96258 363 | 97596 364 | 101630 365 | 101840 366 | 101792 367 | 102796 368 | 235719 369 | 79499 370 | 97303 371 | 98715 372 | 102534 373 | 102404 374 | 102338 375 | 234050 376 | 79637 377 | 96354 378 | 96857 379 | 151806 380 | 6512 381 | 8901 382 | 11142 383 | 12282 384 | 6232 385 | 13026 386 | 22707 387 | 29641 388 | 29022 389 | 29555 390 | 29701 391 | 30466 392 | 32193 393 | 34344 394 | 45887 395 | 42533 396 | 34119 397 | 25615 398 | 24020 399 | 23030 400 | 23335 401 | 22042 402 | 21027 403 | 21549 404 | 22645 405 | 23612 406 | 24018 407 | 24007 408 | 23311 409 | 22993 410 | 21164 411 | 21279 412 | 21839 413 | 20612 414 | 21336 415 | 18406 416 | 34716 417 | 39551 418 | 39576 419 | 25832 420 | 32012 421 | 35775 422 | 40346 423 | 45200 424 | 42008 425 | 32995 426 | 33151 427 | 34345 428 | 31510 429 | 23977 430 | 25629 431 | 32061 432 | 38247 433 | 49735 434 | 53169 435 | 49236 436 | 41924 437 | 26462 438 | 20619 439 | 20599 440 | 20381 441 | 18090 442 | 17543 443 | 17565 444 | 20184 445 | 20242 446 | 20118 447 | 20640 448 | 22488 449 | 21382 450 | 18190 451 | 18943 452 | 19085 453 | 18869 454 | 19402 455 | 17623 456 | 17722 457 | 18891 458 | 22057 459 | 20720 460 | 18077 461 | 17235 462 | 17831 463 | 17538 464 | 18021 465 | 17647 466 | 17770 467 | 17705 468 | 16356 469 | 20859 470 | 20972 471 | 18175 472 | 17094 473 | 18167 474 | 18972 475 | 18807 476 | 18944 477 | 31189 478 | 43024 479 | 55550 480 | 53425 481 | 38855 482 | 36946 483 | 31646 484 | 36531 485 | 33596 486 | 33161 487 | 32212 488 | 38069 489 | 42324 490 | 48799 491 | 63889 492 | 85092 493 | 62562 494 | 72415 495 | 55499 496 | 54257 497 | 53687 498 | 52617 499 | 49876 500 | 53584 -------------------------------------------------------------------------------- /scratch/videoStreamer/small.txt: -------------------------------------------------------------------------------- 1 | 22500 2 | 1027 3 | 1027 4 | 1251 5 | 22636 6 | 22593 7 | 22626 8 | 15050 9 | 22926 10 | 23339 11 | 26280 12 | 24944 13 | 25969 14 | 27451 15 | 29032 16 | 30936 17 | 32650 18 | 34730 19 | 36707 20 | 38966 21 | 34433 22 | 43973 23 | 36659 24 | 49429 25 | 42759 26 | 46410 27 | 48635 28 | 50249 29 | 50631 30 | 52178 -------------------------------------------------------------------------------- /scratch/videoStreamer/videoStreamTest.cc: -------------------------------------------------------------------------------- 1 | /***************************************************** 2 | * 3 | * File: videoStreamTest.cc 4 | * 5 | * Explanation: This script modifies the tutorial first.cc 6 | * to test the video stream application. 7 | * 8 | *****************************************************/ 9 | #include "ns3/core-module.h" 10 | #include "ns3/network-module.h" 11 | #include "ns3/internet-module.h" 12 | #include "ns3/point-to-point-module.h" 13 | #include "ns3/applications-module.h" 14 | #include "ns3/wifi-module.h" 15 | #include "ns3/mobility-module.h" 16 | #include "ns3/csma-module.h" 17 | #include "ns3/netanim-module.h" 18 | 19 | using namespace ns3; 20 | 21 | //#define NS3_LOG_ENABLE 22 | 23 | /** 24 | * @brief The test cases include: 25 | * 1. P2P network with 1 server and 1 client 26 | * 2. P2P network with 1 server and 2 clients 27 | * 3. Wireless network with 1 server and 3 mobile clients 28 | * 4. Wireless network with 3 servers and 3 mobile clients 29 | */ 30 | #define CASE 1 31 | 32 | NS_LOG_COMPONENT_DEFINE ("VideoStreamTest"); 33 | 34 | int 35 | main (int argc, char *argv[]) 36 | { 37 | CommandLine cmd; 38 | cmd.Parse (argc, argv); 39 | 40 | Time::SetResolution (Time::NS); 41 | LogComponentEnable ("VideoStreamClientApplication", LOG_LEVEL_INFO); 42 | LogComponentEnable ("VideoStreamServerApplication", LOG_LEVEL_INFO); 43 | 44 | if (CASE == 1) 45 | { 46 | NodeContainer nodes; 47 | nodes.Create (2); 48 | 49 | PointToPointHelper pointToPoint; 50 | pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("100Mbps")); 51 | pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms")); 52 | 53 | NetDeviceContainer devices; 54 | devices = pointToPoint.Install (nodes); 55 | 56 | InternetStackHelper stack; 57 | stack.Install (nodes); 58 | 59 | Ipv4AddressHelper address; 60 | address.SetBase ("10.1.1.0", "255.255.255.0"); 61 | 62 | Ipv4InterfaceContainer interfaces = address.Assign (devices); 63 | 64 | VideoStreamClientHelper videoClient (interfaces.GetAddress (0), 5000); 65 | ApplicationContainer clientApp = videoClient.Install (nodes.Get (1)); 66 | clientApp.Start (Seconds (0.5)); 67 | clientApp.Stop (Seconds (100.0)); 68 | 69 | VideoStreamServerHelper videoServer (5000); 70 | videoServer.SetAttribute ("MaxPacketSize", UintegerValue (1400)); 71 | videoServer.SetAttribute ("FrameFile", StringValue ("./scratch/videoStreamer/frameList.txt")); 72 | // videoServer.SetAttribute ("FrameSize", UintegerValue (4096)); 73 | 74 | ApplicationContainer serverApp = videoServer.Install (nodes.Get (0)); 75 | serverApp.Start (Seconds (0.0)); 76 | serverApp.Stop (Seconds (100.0)); 77 | 78 | pointToPoint.EnablePcap ("videoStream", devices.Get (1), false); 79 | Simulator::Run (); 80 | Simulator::Destroy (); 81 | } 82 | 83 | else if (CASE == 2) 84 | { 85 | NodeContainer nodes; 86 | nodes.Create (3); 87 | NodeContainer n0n1= NodeContainer (nodes.Get(0), nodes.Get(1)); 88 | NodeContainer n0n2= NodeContainer (nodes.Get(0), nodes.Get(2)); 89 | 90 | PointToPointHelper pointToPoint; 91 | pointToPoint.SetDeviceAttribute ("DataRate", StringValue ("2Mbps")); 92 | pointToPoint.SetChannelAttribute ("Delay", StringValue ("2ms")); 93 | 94 | NetDeviceContainer d0d1= pointToPoint.Install (n0n1); 95 | NetDeviceContainer d0d2= pointToPoint.Install (n0n2); 96 | 97 | InternetStackHelper stack; 98 | stack.Install (nodes); 99 | 100 | Ipv4AddressHelper address; 101 | address.SetBase ("10.1.1.0", "255.255.255.0"); 102 | address.Assign (d0d1); 103 | 104 | address.SetBase ("10.1.2.0", "255.255.255.0"); 105 | address.Assign (d0d2); 106 | 107 | //Ipv4InterfaceContainer interfaces = address.Assign (devices); 108 | Ipv4InterfaceContainer i0i1 = address.Assign (d0d1); 109 | Ipv4InterfaceContainer i0i2 = address.Assign (d0d2); 110 | 111 | VideoStreamClientHelper videoClient1 (i0i1.GetAddress (0), 5000); 112 | ApplicationContainer clientApp1 = videoClient1.Install (nodes.Get (1)); 113 | clientApp1.Start (Seconds (1.0)); 114 | clientApp1.Stop (Seconds (100.0)); 115 | 116 | VideoStreamClientHelper videoClient2 (i0i2.GetAddress (0), 5000); 117 | ApplicationContainer clientApp2 = videoClient2.Install (nodes.Get (2)); 118 | clientApp2.Start (Seconds (0.5)); 119 | clientApp2.Stop (Seconds (100.0)); 120 | 121 | VideoStreamServerHelper videoServer (5000); 122 | videoServer.SetAttribute ("MaxPacketSize", UintegerValue (1400)); 123 | videoServer.SetAttribute ("FrameFile", StringValue ("./scratch/videoStreamer/small.txt")); 124 | // videoServer.SetAttribute ("FrameSize", UintegerValue (4096)); 125 | 126 | ApplicationContainer serverApp = videoServer.Install (nodes.Get (0)); 127 | serverApp.Start (Seconds (0.0)); 128 | serverApp.Stop (Seconds (100.0)); 129 | 130 | pointToPoint.EnablePcap ("videoStream", d0d1.Get (1), false); 131 | pointToPoint.EnablePcap ("videoStream", d0d2.Get (1), false); 132 | Simulator::Run (); 133 | Simulator::Destroy (); 134 | } 135 | else if (CASE == 3) 136 | { 137 | const uint32_t nWifi = 3, nAp = 1; 138 | NodeContainer wifiStaNodes; 139 | wifiStaNodes.Create (nWifi); 140 | NodeContainer wifiApNode; 141 | wifiApNode.Create(nAp); 142 | 143 | YansWifiChannelHelper channel = YansWifiChannelHelper::Default (); 144 | YansWifiPhyHelper phy = YansWifiPhyHelper::Default (); 145 | phy.SetChannel (channel.Create ()); 146 | 147 | WifiHelper wifi; 148 | wifi.SetRemoteStationManager ("ns3::AarfWifiManager"); 149 | 150 | 151 | WifiMacHelper mac; 152 | Ssid ssid = Ssid ("ns-3-aqiao"); 153 | mac.SetType ("ns3::StaWifiMac", 154 | "Ssid", SsidValue (ssid), 155 | "ActiveProbing", BooleanValue (false)); 156 | 157 | NetDeviceContainer staDevices; 158 | staDevices = wifi.Install (phy, mac, wifiStaNodes); 159 | 160 | mac.SetType ("ns3::ApWifiMac", 161 | "Ssid", SsidValue (ssid)); 162 | 163 | NetDeviceContainer apDevices; 164 | apDevices = wifi.Install (phy, mac, wifiApNode); 165 | 166 | MobilityHelper mobility; 167 | mobility.SetPositionAllocator ("ns3::GridPositionAllocator", 168 | "MinX", DoubleValue (0.0), 169 | "MinY", DoubleValue (0.0), 170 | "DeltaX", DoubleValue (30.0), 171 | "DeltaY", DoubleValue (30.0), 172 | "GridWidth", UintegerValue (2), 173 | "LayoutType", StringValue ("RowFirst")); 174 | 175 | 176 | mobility.SetMobilityModel ("ns3::RandomWalk2dMobilityModel", "Bounds", RectangleValue (Rectangle (-50, 50, -50, 50))); 177 | mobility.Install (wifiStaNodes); 178 | 179 | mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel"); 180 | mobility.Install (wifiApNode); 181 | 182 | InternetStackHelper stack; 183 | stack.Install (wifiApNode); 184 | stack.Install (wifiStaNodes); 185 | 186 | Ipv4AddressHelper address; 187 | 188 | address.SetBase ("10.1.3.0", "255.255.255.0"); 189 | 190 | Ipv4InterfaceContainer apInterfaces; 191 | apInterfaces = address.Assign (apDevices); 192 | Ipv4InterfaceContainer wifiInterfaces; 193 | wifiInterfaces=address.Assign (staDevices); 194 | 195 | //UdpEchoServerHelper echoServer (9); 196 | VideoStreamServerHelper videoServer (5000); 197 | videoServer.SetAttribute ("MaxPacketSize", UintegerValue (1400)); 198 | videoServer.SetAttribute ("FrameFile", StringValue ("./scratch/videoStreamer/small.txt")); 199 | for(uint m=0; m node) const 25 | { 26 | return ApplicationContainer (InstallPriv (node)); 27 | } 28 | 29 | ApplicationContainer 30 | VideoStreamServerHelper::Install (std::string nodeName) const 31 | { 32 | Ptr node = Names::Find (nodeName); 33 | return ApplicationContainer (InstallPriv (node)); 34 | } 35 | 36 | ApplicationContainer 37 | VideoStreamServerHelper::Install (NodeContainer c) const 38 | { 39 | ApplicationContainer apps; 40 | for (NodeContainer::Iterator i = c.Begin(); i != c.End(); i++) 41 | { 42 | apps.Add (InstallPriv (*i)); 43 | } 44 | 45 | return apps; 46 | } 47 | 48 | Ptr 49 | VideoStreamServerHelper::InstallPriv (Ptr node) const 50 | { 51 | Ptr app = m_factory.Create (); 52 | node->AddApplication (app); 53 | 54 | return app; 55 | } 56 | 57 | VideoStreamClientHelper::VideoStreamClientHelper(Address ip, uint16_t port) 58 | { 59 | m_factory.SetTypeId (VideoStreamClient::GetTypeId ()); 60 | SetAttribute ("RemoteAddress", AddressValue (ip)); 61 | SetAttribute ("RemotePort", UintegerValue (port)); 62 | } 63 | 64 | 65 | VideoStreamClientHelper::VideoStreamClientHelper(Address addr) 66 | { 67 | m_factory.SetTypeId (VideoStreamClient::GetTypeId ()); 68 | SetAttribute ("RemoteAddress", AddressValue (addr)); 69 | } 70 | 71 | void 72 | VideoStreamClientHelper::SetAttribute(std::string name, const AttributeValue &value) 73 | { 74 | m_factory.Set (name, value); 75 | } 76 | 77 | ApplicationContainer 78 | VideoStreamClientHelper::Install (Ptr node) const 79 | { 80 | return ApplicationContainer (InstallPriv (node)); 81 | } 82 | 83 | ApplicationContainer 84 | VideoStreamClientHelper::Install (std::string nodeName) const 85 | { 86 | Ptr node = Names::Find (nodeName); 87 | return ApplicationContainer (InstallPriv (node)); 88 | } 89 | 90 | ApplicationContainer 91 | VideoStreamClientHelper::Install (NodeContainer c) const 92 | { 93 | ApplicationContainer apps; 94 | for (NodeContainer::Iterator i = c.Begin(); i != c.End(); i++) 95 | { 96 | apps.Add (InstallPriv (*i)); 97 | } 98 | 99 | return apps; 100 | } 101 | 102 | Ptr 103 | VideoStreamClientHelper::InstallPriv (Ptr node) const 104 | { 105 | Ptr app = m_factory.Create (); 106 | node->AddApplication (app); 107 | 108 | return app; 109 | } 110 | 111 | } // namespace ns3 -------------------------------------------------------------------------------- /src/applications/helper/video-stream-helper.h: -------------------------------------------------------------------------------- 1 | /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ 2 | 3 | #ifndef VIDEO_STREAM_HELPER_H 4 | #define VIDEO_STREAM_HELPER_H 5 | 6 | #include 7 | #include "ns3/application-container.h" 8 | #include "ns3/node-container.h" 9 | #include "ns3/object-factory.h" 10 | #include "ns3/ipv4-address.h" 11 | #include "ns3/ipv6-address.h" 12 | 13 | namespace ns3 { 14 | 15 | /** 16 | * @brief Create a server application that sends the video frames to a client. 17 | */ 18 | class VideoStreamServerHelper 19 | { 20 | private: 21 | /** 22 | * @brief Install an ns3::VideoStreamServer on the node configured with all the 23 | * attributes set with SetAttribute. 24 | * 25 | * @param node the node on which an VideoStreamServer will be installed 26 | * @return Ptr 27 | */ 28 | Ptr InstallPriv (Ptr node) const; 29 | ObjectFactory m_factory; 30 | 31 | public: 32 | /** 33 | * @brief Construct a new VideoStreamServerHelper object. 34 | * 35 | * @param port the port the server will receive incoming packets 36 | */ 37 | VideoStreamServerHelper (uint16_t port); 38 | 39 | /** 40 | * @brief Record an attribute to be set in each application after it is created. 41 | * 42 | * @param name the name of the attribute to set 43 | * @param value the value of the attribute to set 44 | */ 45 | void SetAttribute (std::string name, const AttributeValue &value); 46 | 47 | /** 48 | * @brief Create a VideoStreamServerApplication on the specified node. 49 | * 50 | * @param node the node on which to create the application 51 | * @return ApplicationContainer holding the created application 52 | */ 53 | ApplicationContainer Install (Ptr node) const; 54 | 55 | /** 56 | * @brief Create a VideoStreamServerApplication on the specified node. 57 | * 58 | * @param nodeName the node on which to create the application 59 | * @return ApplicationContainer holding the created application 60 | */ 61 | ApplicationContainer Install (std::string nodeName) const; 62 | 63 | /** 64 | * @brief Create a VideoStreamServerApplication on the specified node. 65 | * 66 | * @param c the nodes on which to create the applications 67 | * @return ApplicationContainer with one application per node in the NodeContainer 68 | */ 69 | ApplicationContainer Install (NodeContainer c) const; 70 | }; 71 | 72 | class VideoStreamClientHelper 73 | { 74 | private: 75 | /** 76 | * @brief Install an ns3::VideoStreamClient on the node configured with all the 77 | * attributes set with SetAttribute. 78 | * 79 | * @param node the node on which an VideoStreamClient will be installed 80 | * @return Ptr 81 | */ 82 | Ptr InstallPriv (Ptr node) const; 83 | ObjectFactory m_factory; 84 | 85 | public: 86 | /** 87 | * @brief Construct a new VideoStreamClientHelper object. 88 | * 89 | * @param ip the IP address of the remote server 90 | * @param port the port number of the remote server 91 | */ 92 | VideoStreamClientHelper (Address ip, uint16_t port); 93 | /** 94 | * @brief Construct a new VideoStreamClientHelper object. 95 | * 96 | * @param addr the address of the remote server 97 | */ 98 | VideoStreamClientHelper (Address addr); 99 | 100 | /** 101 | * @brief Record an attribute to be set in each application after it is created. 102 | * 103 | * @param name the name of the attribute to set 104 | * @param value the value of the attribute to set 105 | */ 106 | void SetAttribute (std::string name, const AttributeValue &value); 107 | 108 | /** 109 | * @brief Create a VideoStreamClientApplication on the specified node. 110 | * 111 | * @param node the node on which to create the application 112 | * @return ApplicationContainer holding the created application 113 | */ 114 | ApplicationContainer Install (Ptr node) const; 115 | 116 | /** 117 | * @brief Create a VideoStreamClientApplication on the specified node. 118 | * 119 | * @param nodeName the node on which to create the application 120 | * @return ApplicationContainer holding the created application 121 | */ 122 | ApplicationContainer Install (std::string nodeName) const; 123 | 124 | /** 125 | * @brief Create a VideoStreamClientApplication on the specified node. 126 | * 127 | * @param c the nodes on which to create the applications 128 | * @return ApplicationContainer with one application per node in the NodeContainer 129 | */ 130 | ApplicationContainer Install (NodeContainer c) const; 131 | }; 132 | 133 | } // namespace ns3 134 | 135 | #endif /* VIDEO_STREAM_HELPER_H */ -------------------------------------------------------------------------------- /src/applications/model/video-stream-client.cc: -------------------------------------------------------------------------------- 1 | /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ 2 | 3 | #include "ns3/log.h" 4 | #include "ns3/ipv4-address.h" 5 | #include "ns3/ipv6-address.h" 6 | #include "ns3/nstime.h" 7 | #include "ns3/inet-socket-address.h" 8 | #include "ns3/inet6-socket-address.h" 9 | #include "ns3/socket.h" 10 | #include "ns3/simulator.h" 11 | #include "ns3/socket-factory.h" 12 | #include "ns3/packet.h" 13 | #include "ns3/uinteger.h" 14 | #include "ns3/trace-source-accessor.h" 15 | #include "video-stream-client.h" 16 | 17 | namespace ns3 { 18 | 19 | NS_LOG_COMPONENT_DEFINE ("VideoStreamClientApplication"); 20 | 21 | NS_OBJECT_ENSURE_REGISTERED (VideoStreamClient); 22 | 23 | TypeId 24 | VideoStreamClient::GetTypeId (void) 25 | { 26 | static TypeId tid = TypeId ("ns3::VideoStreamClient") 27 | .SetParent () 28 | .SetGroupName ("Applications") 29 | .AddConstructor () 30 | .AddAttribute ("RemoteAddress", "The destination address of the outbound packets", 31 | AddressValue (), 32 | MakeAddressAccessor (&VideoStreamClient::m_peerAddress), 33 | MakeAddressChecker ()) 34 | .AddAttribute ("RemotePort", "The destination port of the outbound packets", 35 | UintegerValue (5000), 36 | MakeUintegerAccessor (&VideoStreamClient::m_peerPort), 37 | MakeUintegerChecker ()) 38 | 39 | ; 40 | return tid; 41 | } 42 | 43 | VideoStreamClient::VideoStreamClient () 44 | { 45 | NS_LOG_FUNCTION (this); 46 | m_initialDelay = 3; 47 | m_lastBufferSize = 0; 48 | m_currentBufferSize = 0; 49 | m_frameSize = 0; 50 | m_frameRate = 25; 51 | m_videoLevel = 3; 52 | m_stopCounter = 0; 53 | m_lastRecvFrame = 1e6; 54 | m_rebufferCounter = 0; 55 | m_bufferEvent = EventId(); 56 | m_sendEvent = EventId(); 57 | } 58 | 59 | VideoStreamClient::~VideoStreamClient () 60 | { 61 | NS_LOG_FUNCTION (this); 62 | m_socket = 0; 63 | } 64 | 65 | void 66 | VideoStreamClient::SetRemote (Address ip, uint16_t port) 67 | { 68 | NS_LOG_FUNCTION (this << ip << port); 69 | m_peerAddress = ip; 70 | m_peerPort = port; 71 | } 72 | 73 | void 74 | VideoStreamClient::SetRemote (Address addr) 75 | { 76 | NS_LOG_FUNCTION (this << addr); 77 | m_peerAddress = addr; 78 | } 79 | 80 | void 81 | VideoStreamClient::DoDispose (void) 82 | { 83 | NS_LOG_FUNCTION (this); 84 | Application::DoDispose (); 85 | } 86 | 87 | void 88 | VideoStreamClient::StartApplication (void) 89 | { 90 | NS_LOG_FUNCTION (this); 91 | 92 | if (m_socket == 0) 93 | { 94 | TypeId tid = TypeId::LookupByName ("ns3::UdpSocketFactory"); 95 | m_socket = Socket::CreateSocket (GetNode (), tid); 96 | if (Ipv4Address::IsMatchingType (m_peerAddress) == true) 97 | { 98 | if (m_socket->Bind () == -1) 99 | { 100 | NS_FATAL_ERROR ("Failed to bind socket"); 101 | } 102 | m_socket->Connect (InetSocketAddress(Ipv4Address::ConvertFrom (m_peerAddress), m_peerPort)); 103 | } 104 | else if (Ipv6Address::IsMatchingType (m_peerAddress) == true) 105 | { 106 | if (m_socket->Bind6 () == -1) 107 | { 108 | NS_FATAL_ERROR ("Failed to bind socket"); 109 | } 110 | m_socket->Connect (m_peerAddress); 111 | } 112 | else if (InetSocketAddress::IsMatchingType (m_peerAddress) == true) 113 | { 114 | if (m_socket->Bind () == -1) 115 | { 116 | NS_FATAL_ERROR ("Failed to bind socket"); 117 | } 118 | m_socket->Connect (m_peerAddress); 119 | } 120 | else if (Inet6SocketAddress::IsMatchingType (m_peerAddress) == true) 121 | { 122 | if (m_socket->Bind6 () == -1) 123 | { 124 | NS_FATAL_ERROR ("Failed to bind socket"); 125 | } 126 | m_socket->Connect (m_peerAddress); 127 | } 128 | else 129 | { 130 | NS_ASSERT_MSG (false, "Incompatible address type: " << m_peerAddress); 131 | } 132 | } 133 | 134 | m_socket->SetRecvCallback (MakeCallback (&VideoStreamClient::HandleRead, this)); 135 | m_sendEvent = Simulator::Schedule (MilliSeconds (1.0), &VideoStreamClient::Send, this); 136 | m_bufferEvent = Simulator::Schedule (Seconds (m_initialDelay), &VideoStreamClient::ReadFromBuffer, this); 137 | } 138 | 139 | void 140 | VideoStreamClient::StopApplication () 141 | { 142 | NS_LOG_FUNCTION (this); 143 | 144 | if (m_socket != 0) 145 | { 146 | m_socket->Close (); 147 | m_socket->SetRecvCallback (MakeNullCallback> ()); 148 | m_socket = 0; 149 | } 150 | 151 | Simulator::Cancel (m_bufferEvent); 152 | } 153 | 154 | void 155 | VideoStreamClient::Send (void) 156 | { 157 | NS_LOG_FUNCTION (this); 158 | NS_ASSERT (m_sendEvent.IsExpired ()); 159 | 160 | uint8_t dataBuffer[10]; 161 | sprintf((char *) dataBuffer, "%hu", 0); 162 | Ptr firstPacket = Create (dataBuffer, 10); 163 | m_socket->Send (firstPacket); 164 | 165 | if (Ipv4Address::IsMatchingType (m_peerAddress)) 166 | { 167 | NS_LOG_INFO ("At time " << Simulator::Now ().GetSeconds () << "s client sent 10 bytes to " << 168 | Ipv4Address::ConvertFrom (m_peerAddress) << " port " << m_peerPort); 169 | } 170 | else if (Ipv6Address::IsMatchingType (m_peerAddress)) 171 | { 172 | NS_LOG_INFO ("At time " << Simulator::Now ().GetSeconds () << "s client sent 10 bytes to " << 173 | Ipv6Address::ConvertFrom (m_peerAddress) << " port " << m_peerPort); 174 | } 175 | else if (InetSocketAddress::IsMatchingType (m_peerAddress)) 176 | { 177 | NS_LOG_INFO ("At time " << Simulator::Now ().GetSeconds () << "s client sent 10 bytes to " << 178 | InetSocketAddress::ConvertFrom (m_peerAddress).GetIpv4 () << " port " << InetSocketAddress::ConvertFrom (m_peerAddress).GetPort ()); 179 | } 180 | else if (Inet6SocketAddress::IsMatchingType (m_peerAddress)) 181 | { 182 | NS_LOG_INFO ("At time " << Simulator::Now ().GetSeconds () << "s client sent 10 bytes to " << 183 | Inet6SocketAddress::ConvertFrom (m_peerAddress).GetIpv6 () << " port " << Inet6SocketAddress::ConvertFrom (m_peerAddress).GetPort ()); 184 | } 185 | } 186 | 187 | uint32_t 188 | VideoStreamClient::ReadFromBuffer (void) 189 | { 190 | // NS_LOG_INFO ("At time " << Simulator::Now ().GetSeconds () << " s, last buffer size: " << m_lastBufferSize << ", current buffer size: " << m_currentBufferSize); 191 | if (m_currentBufferSize < m_frameRate) 192 | { 193 | 194 | if (m_lastBufferSize == m_currentBufferSize) 195 | { 196 | m_stopCounter++; 197 | // If the counter reaches 3, which means the client has been waiting for 3 sec, and no packets arrived. 198 | // In this case, we think the video streaming has finished, and there is no need to schedule the event. 199 | if (m_stopCounter < 3) 200 | { 201 | m_bufferEvent = Simulator::Schedule (Seconds (1.0), &VideoStreamClient::ReadFromBuffer, this); 202 | } 203 | } 204 | else 205 | { 206 | NS_LOG_INFO ("At time " << Simulator::Now ().GetSeconds () << " s: Not enough frames in the buffer, rebuffering!"); 207 | m_stopCounter = 0; // reset the stopCounter 208 | m_rebufferCounter++; 209 | m_bufferEvent = Simulator::Schedule (Seconds (1.0), &VideoStreamClient::ReadFromBuffer, this); 210 | } 211 | 212 | m_lastBufferSize = m_currentBufferSize; 213 | return (-1); 214 | } 215 | else 216 | { 217 | NS_LOG_INFO ("At time " << Simulator::Now ().GetSeconds () << " s: Play video frames from the buffer"); 218 | if (m_stopCounter > 0) m_stopCounter = 0; // reset the stopCounter 219 | if (m_rebufferCounter > 0) m_rebufferCounter = 0; // reset the rebufferCounter 220 | m_currentBufferSize -= m_frameRate; 221 | 222 | m_bufferEvent = Simulator::Schedule (Seconds (1.0), &VideoStreamClient::ReadFromBuffer, this); 223 | m_lastBufferSize = m_currentBufferSize; 224 | return (m_currentBufferSize); 225 | } 226 | } 227 | 228 | void 229 | VideoStreamClient::HandleRead (Ptr socket) 230 | { 231 | NS_LOG_FUNCTION (this << socket); 232 | 233 | Ptr packet; 234 | Address from; 235 | Address localAddress; 236 | while ((packet = socket->RecvFrom (from))) 237 | { 238 | socket->GetSockName (localAddress); 239 | if (InetSocketAddress::IsMatchingType (from)) 240 | { 241 | uint8_t recvData[packet->GetSize()]; 242 | packet->CopyData (recvData, packet->GetSize ()); 243 | uint32_t frameNum; 244 | sscanf ((char *) recvData, "%u", &frameNum); 245 | 246 | if (frameNum == m_lastRecvFrame) 247 | { 248 | m_frameSize += packet->GetSize (); 249 | } 250 | else 251 | { 252 | if (frameNum > 0) 253 | { 254 | NS_LOG_INFO ("At time " << Simulator::Now ().GetSeconds () << "s client received frame " << frameNum-1 << " and " << m_frameSize << " bytes from " << InetSocketAddress::ConvertFrom (from).GetIpv4 () << " port " << InetSocketAddress::ConvertFrom (from).GetPort ()); 255 | } 256 | 257 | m_currentBufferSize++; 258 | m_lastRecvFrame = frameNum; 259 | m_frameSize = packet->GetSize (); 260 | } 261 | 262 | // The rebuffering event has happend 3+ times, which suggest the client to lower the video quality. 263 | if (m_rebufferCounter >= 3) 264 | { 265 | if (m_videoLevel > 1) 266 | { 267 | NS_LOG_INFO ("At time " << Simulator::Now ().GetSeconds () << "s: Lower the video quality level!"); 268 | m_videoLevel--; 269 | // reflect the change to the server 270 | uint8_t dataBuffer[10]; 271 | sprintf((char *) dataBuffer, "%hu", m_videoLevel); 272 | Ptr levelPacket = Create (dataBuffer, 10); 273 | socket->SendTo (levelPacket, 0, from); 274 | m_rebufferCounter = 0; 275 | } 276 | } 277 | 278 | // If the current buffer size supports 5+ seconds video, we can try to increase the video quality level. 279 | if (m_currentBufferSize > 5 * m_frameRate) 280 | { 281 | if (m_videoLevel < MAX_VIDEO_LEVEL) 282 | { 283 | m_videoLevel++; 284 | // reflect the change to the server 285 | uint8_t dataBuffer[10]; 286 | sprintf((char *) dataBuffer, "%hu", m_videoLevel); 287 | Ptr levelPacket = Create (dataBuffer, 10); 288 | socket->SendTo (levelPacket, 0, from); 289 | m_currentBufferSize = m_frameRate; 290 | NS_LOG_INFO ("At time " << Simulator::Now ().GetSeconds() << "s: Increase the video quality level to " << m_videoLevel); 291 | } 292 | } 293 | } 294 | } 295 | } 296 | 297 | } // namespace ns3 -------------------------------------------------------------------------------- /src/applications/model/video-stream-client.h: -------------------------------------------------------------------------------- 1 | /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ 2 | 3 | #ifndef VIDEO_STREAM_CLIENT_H 4 | #define VIDEO_STREAM_CLIENT_H 5 | 6 | #include "ns3/application.h" 7 | #include "ns3/event-id.h" 8 | #include "ns3/ptr.h" 9 | #include "ns3/address.h" 10 | #include "ns3/traced-callback.h" 11 | 12 | #define MAX_VIDEO_LEVEL 6 13 | 14 | namespace ns3 { 15 | 16 | class Socket; 17 | class Packet; 18 | 19 | /** 20 | * @brief A Video Stream Client 21 | */ 22 | class VideoStreamClient : public Application 23 | { 24 | public: 25 | /** 26 | * @brief Get the type ID. 27 | * 28 | * @return the object TypeId 29 | */ 30 | static TypeId GetTypeId (void); 31 | VideoStreamClient (); 32 | virtual ~VideoStreamClient (); 33 | 34 | /** 35 | * @brief Set the server address and port. 36 | * 37 | * @param ip server IP address 38 | * @param port server port 39 | */ 40 | void SetRemote (Address ip, uint16_t port); 41 | /** 42 | * @brief Set the server address. 43 | * 44 | * @param addr server address 45 | */ 46 | void SetRemote (Address addr); 47 | 48 | protected: 49 | virtual void DoDispose (void); 50 | 51 | private: 52 | virtual void StartApplication (void); 53 | virtual void StopApplication (void); 54 | 55 | /** 56 | * @brief Send the packet to the remote server. 57 | */ 58 | void Send (void); 59 | 60 | /** 61 | * @brief Read data from the frame buffer. If the buffer does not have 62 | * enough frames, it will reschedule the reading event next second. 63 | * 64 | * @return the updated buffer size (-1 if the buffer size is smaller than the fps) 65 | */ 66 | uint32_t ReadFromBuffer (void); 67 | 68 | /** 69 | * @brief Handle a packet reception. 70 | * 71 | * This function is called by lower layers. 72 | * 73 | * @param socket the socket the packet was received to 74 | */ 75 | void HandleRead (Ptr socket); 76 | 77 | Ptr m_socket; //!< Socket 78 | Address m_peerAddress; //!< Remote peer address 79 | uint16_t m_peerPort; //!< Remote peer port 80 | 81 | uint16_t m_initialDelay; //!< Seconds to wait before displaying the content 82 | uint16_t m_stopCounter; //!< Counter to decide if the video streaming finishes 83 | uint16_t m_rebufferCounter; //!< Counter of the rebuffering event 84 | uint16_t m_videoLevel; //!< The quality of the video from the server 85 | uint32_t m_frameRate; //!< Number of frames per second to be played 86 | uint32_t m_frameSize; //!< Total size of packets from one frame 87 | uint32_t m_lastRecvFrame; //!< Last received frame number 88 | uint32_t m_lastBufferSize; //!< Last size of the buffer 89 | uint32_t m_currentBufferSize; //!< Size of the frame buffer 90 | 91 | EventId m_bufferEvent; //!< Event to read from the buffer 92 | EventId m_sendEvent; //!< Event to send data to the server 93 | 94 | }; 95 | 96 | } // namespace ns3 97 | 98 | #endif /* VIDEO_STREAM_CLIENT_H */ 99 | -------------------------------------------------------------------------------- /src/applications/model/video-stream-server.cc: -------------------------------------------------------------------------------- 1 | /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ 2 | 3 | #include "ns3/log.h" 4 | #include "ns3/ipv4-address.h" 5 | #include "ns3/ipv6-address.h" 6 | #include "ns3/address-utils.h" 7 | #include "ns3/nstime.h" 8 | #include "ns3/inet-socket-address.h" 9 | #include "ns3/inet6-socket-address.h" 10 | #include "ns3/socket.h" 11 | #include "ns3/udp-socket.h" 12 | #include "ns3/simulator.h" 13 | #include "ns3/socket-factory.h" 14 | #include "ns3/packet.h" 15 | #include "ns3/uinteger.h" 16 | #include "ns3/video-stream-server.h" 17 | 18 | namespace ns3 { 19 | 20 | NS_LOG_COMPONENT_DEFINE ("VideoStreamServerApplication"); 21 | 22 | NS_OBJECT_ENSURE_REGISTERED (VideoStreamServer); 23 | 24 | TypeId 25 | VideoStreamServer::GetTypeId (void) 26 | { 27 | static TypeId tid = TypeId ("ns3::VideoStreamServer") 28 | .SetParent () 29 | .SetGroupName("Applications") 30 | .AddConstructor () 31 | .AddAttribute ("Interval", "The time to wait between packets", 32 | TimeValue (Seconds (0.01)), 33 | MakeTimeAccessor (&VideoStreamServer::m_interval), 34 | MakeTimeChecker ()) 35 | .AddAttribute ("Port", "Port on which we listen for incoming packets.", 36 | UintegerValue (5000), 37 | MakeUintegerAccessor (&VideoStreamServer::m_port), 38 | MakeUintegerChecker ()) 39 | .AddAttribute ("MaxPacketSize", "The maximum size of a packet", 40 | UintegerValue (1400), 41 | MakeUintegerAccessor (&VideoStreamServer::m_maxPacketSize), 42 | MakeUintegerChecker ()) 43 | .AddAttribute ("FrameFile", "The file that contains the video frame sizes", 44 | StringValue (""), 45 | MakeStringAccessor (&VideoStreamServer::SetFrameFile, &VideoStreamServer::GetFrameFile), 46 | MakeStringChecker ()) 47 | .AddAttribute ("VideoLength", "The length of the video in seconds", 48 | UintegerValue (60), 49 | MakeUintegerAccessor (&VideoStreamServer::m_videoLength), 50 | MakeUintegerChecker ()) 51 | ; 52 | return tid; 53 | } 54 | 55 | VideoStreamServer::VideoStreamServer () 56 | { 57 | NS_LOG_FUNCTION (this); 58 | m_socket = 0; 59 | m_frameRate = 25; 60 | m_frameSizeList = std::vector(); 61 | } 62 | 63 | VideoStreamServer::~VideoStreamServer () 64 | { 65 | NS_LOG_FUNCTION (this); 66 | m_socket = 0; 67 | } 68 | 69 | void 70 | VideoStreamServer::DoDispose (void) 71 | { 72 | NS_LOG_FUNCTION (this); 73 | Application::DoDispose (); 74 | } 75 | 76 | void 77 | VideoStreamServer::StartApplication (void) 78 | { 79 | NS_LOG_FUNCTION (this); 80 | 81 | if (m_socket == 0) 82 | { 83 | TypeId tid = TypeId::LookupByName ("ns3::UdpSocketFactory"); 84 | m_socket = Socket::CreateSocket (GetNode (), tid); 85 | InetSocketAddress local = InetSocketAddress (Ipv4Address::GetAny (), m_port); 86 | if (m_socket->Bind (local) == -1) 87 | { 88 | NS_FATAL_ERROR ("Failed to bind socket"); 89 | } 90 | if (addressUtils::IsMulticast (m_local)) 91 | { 92 | Ptr udpSocket = DynamicCast (m_socket); 93 | if (udpSocket) 94 | { 95 | udpSocket->MulticastJoinGroup (0, m_local); 96 | } 97 | else 98 | { 99 | NS_FATAL_ERROR ("Error: Failed to join multicast group"); 100 | } 101 | } 102 | } 103 | 104 | m_socket->SetAllowBroadcast (true); 105 | m_socket->SetRecvCallback (MakeCallback (&VideoStreamServer::HandleRead, this)); 106 | } 107 | 108 | void 109 | VideoStreamServer::StopApplication () 110 | { 111 | NS_LOG_FUNCTION (this); 112 | 113 | 114 | if (m_socket != 0) 115 | { 116 | m_socket->Close(); 117 | m_socket->SetRecvCallback (MakeNullCallback> ()); 118 | m_socket = 0; 119 | } 120 | 121 | for (auto iter = m_clients.begin (); iter != m_clients.end (); iter++) 122 | { 123 | Simulator::Cancel (iter->second->m_sendEvent); 124 | } 125 | 126 | } 127 | 128 | void 129 | VideoStreamServer::SetFrameFile (std::string frameFile) 130 | { 131 | NS_LOG_FUNCTION (this << frameFile); 132 | m_frameFile = frameFile; 133 | if (frameFile != "") 134 | { 135 | std::string line; 136 | std::ifstream fileStream(frameFile); 137 | while (std::getline (fileStream, line)) 138 | { 139 | int result = std::stoi(line); 140 | m_frameSizeList.push_back (result); 141 | } 142 | } 143 | NS_LOG_INFO ("Frame list size: " << m_frameSizeList.size()); 144 | } 145 | 146 | std::string 147 | VideoStreamServer::GetFrameFile (void) const 148 | { 149 | NS_LOG_FUNCTION (this); 150 | return m_frameFile; 151 | } 152 | 153 | void 154 | VideoStreamServer::SetMaxPacketSize (uint32_t maxPacketSize) 155 | { 156 | m_maxPacketSize = maxPacketSize; 157 | } 158 | 159 | uint32_t 160 | VideoStreamServer::GetMaxPacketSize (void) const 161 | { 162 | return m_maxPacketSize; 163 | } 164 | 165 | void 166 | VideoStreamServer::Send (uint32_t ipAddress) 167 | { 168 | NS_LOG_FUNCTION (this); 169 | 170 | uint32_t frameSize, totalFrames; 171 | ClientInfo *clientInfo = m_clients.at (ipAddress); 172 | 173 | NS_ASSERT (clientInfo->m_sendEvent.IsExpired ()); 174 | // If the frame sizes are not from the text file, and the list is empty 175 | if (m_frameSizeList.empty ()) 176 | { 177 | frameSize = m_frameSizes[clientInfo->m_videoLevel]; 178 | totalFrames = m_videoLength * m_frameRate; 179 | } 180 | else 181 | { 182 | frameSize = m_frameSizeList[clientInfo->m_sent] * clientInfo->m_videoLevel; 183 | totalFrames = m_frameSizeList.size (); 184 | } 185 | 186 | // the frame might require several packets to send 187 | for (uint i = 0; i < frameSize / m_maxPacketSize; i++) 188 | { 189 | SendPacket (clientInfo, m_maxPacketSize); 190 | } 191 | uint32_t remainder = frameSize % m_maxPacketSize; 192 | SendPacket (clientInfo, remainder); 193 | 194 | NS_LOG_INFO ("At time " << Simulator::Now ().GetSeconds () << "s server sent frame " << clientInfo->m_sent << " and " << frameSize << " bytes to " << InetSocketAddress::ConvertFrom (clientInfo->m_address).GetIpv4 () << " port " << InetSocketAddress::ConvertFrom (clientInfo->m_address).GetPort ()); 195 | 196 | clientInfo->m_sent += 1; 197 | if (clientInfo->m_sent < totalFrames) 198 | { 199 | clientInfo->m_sendEvent = Simulator::Schedule (m_interval, &VideoStreamServer::Send, this, ipAddress); 200 | } 201 | } 202 | 203 | void 204 | VideoStreamServer::SendPacket (ClientInfo *client, uint32_t packetSize) 205 | { 206 | uint8_t dataBuffer[packetSize]; 207 | sprintf ((char *) dataBuffer, "%u", client->m_sent); 208 | Ptr p = Create (dataBuffer, packetSize); 209 | if (m_socket->SendTo (p, 0, client->m_address) < 0) 210 | { 211 | NS_LOG_INFO ("Error while sending " << packetSize << "bytes to " << InetSocketAddress::ConvertFrom (client->m_address).GetIpv4 () << " port " << InetSocketAddress::ConvertFrom (client->m_address).GetPort ()); 212 | } 213 | } 214 | 215 | void 216 | VideoStreamServer::HandleRead (Ptr socket) 217 | { 218 | NS_LOG_FUNCTION (this << socket); 219 | 220 | Ptr packet; 221 | Address from; 222 | Address localAddress; 223 | while ((packet = socket->RecvFrom (from))) 224 | { 225 | socket->GetSockName (localAddress); 226 | if (InetSocketAddress::IsMatchingType (from)) 227 | { 228 | NS_LOG_INFO ("At time " << Simulator::Now ().GetSeconds () << "s server received " << packet->GetSize () << " bytes from " << InetSocketAddress::ConvertFrom (from).GetIpv4 () << " port " << InetSocketAddress::ConvertFrom (from).GetPort ()); 229 | 230 | uint32_t ipAddr = InetSocketAddress::ConvertFrom (from).GetIpv4 ().Get (); 231 | 232 | // the first time we received the message from the client 233 | if (m_clients.find (ipAddr) == m_clients.end ()) 234 | { 235 | ClientInfo *newClient = new ClientInfo(); 236 | newClient->m_sent = 0; 237 | newClient->m_videoLevel = 3; 238 | newClient->m_address = from; 239 | // newClient->m_sendEvent = EventId (); 240 | m_clients[ipAddr] = newClient; 241 | newClient->m_sendEvent = Simulator::Schedule (Seconds (0.0), &VideoStreamServer::Send, this, ipAddr); 242 | } 243 | else 244 | { 245 | uint8_t dataBuffer[10]; 246 | packet->CopyData (dataBuffer, 10); 247 | 248 | uint16_t videoLevel; 249 | sscanf((char *) dataBuffer, "%hu", &videoLevel); 250 | NS_LOG_INFO ("At time " << Simulator::Now ().GetSeconds () << "s server received video level " << videoLevel); 251 | m_clients.at (ipAddr)->m_videoLevel = videoLevel; 252 | } 253 | } 254 | } 255 | } 256 | 257 | } // namespace ns3 -------------------------------------------------------------------------------- /src/applications/model/video-stream-server.h: -------------------------------------------------------------------------------- 1 | /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ 2 | 3 | #ifndef VIDEO_STREAM_SERVER_H 4 | #define VIDEO_STREAM_SERVER_H 5 | 6 | #include "ns3/application.h" 7 | #include "ns3/event-id.h" 8 | #include "ns3/ptr.h" 9 | #include "ns3/string.h" 10 | #include "ns3/ipv4-address.h" 11 | #include "ns3/traced-callback.h" 12 | 13 | #include 14 | #include 15 | namespace ns3 { 16 | 17 | class Socket; 18 | class Packet; 19 | 20 | /** 21 | * @brief A Video Stream Server 22 | */ 23 | class VideoStreamServer : public Application 24 | { 25 | public: 26 | /** 27 | * @brief Get the type ID. 28 | * 29 | * @return the object TypeId 30 | */ 31 | static TypeId GetTypeId (void); 32 | 33 | VideoStreamServer (); 34 | 35 | virtual ~VideoStreamServer (); 36 | 37 | /** 38 | * @brief Set the name of the file containing the frame sizes. 39 | * 40 | * @param frameFile the file name 41 | */ 42 | void SetFrameFile (std::string frameFile); 43 | 44 | /** 45 | * @brief Get the name of the file containing the frame sizes. 46 | * 47 | * @return the file name 48 | */ 49 | std::string GetFrameFile (void) const; 50 | 51 | /** 52 | * @brief Set the maximum packet size. 53 | * 54 | * @param maxPacketSize the largest number of bytes a packet can be 55 | */ 56 | void SetMaxPacketSize (uint32_t maxPacketSize); 57 | 58 | /** 59 | * @brief Get the maximum packet size. 60 | * 61 | * @return uint32_t the largest number of bytes a packet can be 62 | */ 63 | uint32_t GetMaxPacketSize (void) const; 64 | 65 | protected: 66 | virtual void DoDispose (void); 67 | 68 | private: 69 | 70 | virtual void StartApplication (void); 71 | virtual void StopApplication (void); 72 | 73 | /** 74 | * @brief The information required for each client. 75 | */ 76 | typedef struct ClientInfo 77 | { 78 | Address m_address; //!< Address 79 | uint32_t m_sent; //!< Counter for sent frames 80 | uint16_t m_videoLevel; //! Video level 81 | EventId m_sendEvent; //! Send event used by the client 82 | } ClientInfo; //! To be compatible with C language 83 | 84 | /** 85 | * @brief Send a packet with specified size. 86 | * 87 | * @param packetSize the number of bytes for the packet to be sent 88 | */ 89 | void SendPacket (ClientInfo *client, uint32_t packetSize); 90 | 91 | /** 92 | * @brief Send the video frame to the given ipv4 address. 93 | * 94 | * @param ipAddress ipv4 address 95 | */ 96 | void Send (uint32_t ipAddress); 97 | 98 | /** 99 | * @brief Handle a packet reception. 100 | * 101 | * This function is called by lower layers. 102 | * 103 | * @param socket the socket the packet was received to 104 | */ 105 | void HandleRead (Ptr socket); 106 | 107 | Time m_interval; //!< Packet inter-send time 108 | uint32_t m_maxPacketSize; //!< Maximum size of the packet to be sent 109 | Ptr m_socket; //!< Socket 110 | 111 | uint16_t m_port; //!< The port 112 | Address m_local; //!< Local multicast address 113 | 114 | uint32_t m_frameRate; //!< Number of frames per second to be sent 115 | uint32_t m_videoLength; //!< Length of the video in seconds 116 | std::string m_frameFile; //!< Name of the file containing frame sizes 117 | std::vector m_frameSizeList; //!< List of video frame sizes 118 | 119 | std::unordered_map m_clients; //!< Information saved for each client 120 | const uint32_t m_frameSizes[6] = {0, 230400, 345600, 921600, 2073600, 2211840}; //!< Frame size for 360p, 480p, 720p, 1080p and 2K 121 | }; 122 | 123 | } // namespace ns3 124 | 125 | 126 | #endif /* VIDEO_STREAM_SERVER_H */ -------------------------------------------------------------------------------- /src/applications/wscript: -------------------------------------------------------------------------------- 1 | ## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- 2 | 3 | def build(bld): 4 | module = bld.create_ns3_module('applications', ['internet', 'config-store','stats']) 5 | module.source = [ 6 | 'model/bulk-send-application.cc', 7 | 'model/onoff-application.cc', 8 | 'model/packet-sink.cc', 9 | 'model/udp-client.cc', 10 | 'model/udp-server.cc', 11 | 'model/seq-ts-header.cc', 12 | 'model/udp-trace-client.cc', 13 | 'model/packet-loss-counter.cc', 14 | 'model/udp-echo-client.cc', 15 | 'model/udp-echo-server.cc', 16 | 'model/video-stream-client.cc', 17 | 'model/video-stream-server.cc', 18 | 'model/application-packet-probe.cc', 19 | 'model/three-gpp-http-client.cc', 20 | 'model/three-gpp-http-server.cc', 21 | 'model/three-gpp-http-header.cc', 22 | 'model/three-gpp-http-variables.cc', 23 | 'helper/bulk-send-helper.cc', 24 | 'helper/on-off-helper.cc', 25 | 'helper/packet-sink-helper.cc', 26 | 'helper/udp-client-server-helper.cc', 27 | 'helper/udp-echo-helper.cc', 28 | 'helper/video-stream-helper.cc', 29 | 'helper/three-gpp-http-helper.cc', 30 | ] 31 | 32 | applications_test = bld.create_ns3_module_test_library('applications') 33 | applications_test.source = [ 34 | 'test/three-gpp-http-client-server-test.cc', 35 | 'test/udp-client-server-test.cc' 36 | ] 37 | 38 | headers = bld(features='ns3header') 39 | headers.module = 'applications' 40 | headers.source = [ 41 | 'model/bulk-send-application.h', 42 | 'model/onoff-application.h', 43 | 'model/packet-sink.h', 44 | 'model/udp-client.h', 45 | 'model/udp-server.h', 46 | 'model/seq-ts-header.h', 47 | 'model/udp-trace-client.h', 48 | 'model/packet-loss-counter.h', 49 | 'model/udp-echo-client.h', 50 | 'model/udp-echo-server.h', 51 | 'model/video-stream-client.h', 52 | 'model/video-stream-server.h', 53 | 'model/application-packet-probe.h', 54 | 'model/three-gpp-http-client.h', 55 | 'model/three-gpp-http-server.h', 56 | 'model/three-gpp-http-header.h', 57 | 'model/three-gpp-http-variables.h', 58 | 'helper/bulk-send-helper.h', 59 | 'helper/on-off-helper.h', 60 | 'helper/packet-sink-helper.h', 61 | 'helper/udp-client-server-helper.h', 62 | 'helper/udp-echo-helper.h', 63 | 'helper/video-stream-helper.h', 64 | 'helper/three-gpp-http-helper.h' 65 | ] 66 | 67 | if (bld.env['ENABLE_EXAMPLES']): 68 | bld.recurse('examples') 69 | 70 | bld.ns3_python_bindings() 71 | --------------------------------------------------------------------------------