gobot.io/x/gobot/v2@v2.1.0/platforms/parrot/bebop/client/client.go (about) 1 package client 2 3 import ( 4 "bytes" 5 "encoding/binary" 6 "fmt" 7 "net" 8 "time" 9 ) 10 11 func validatePitch(val int) int { 12 if val > 100 { 13 return 100 14 } else if val < 0 { 15 return 0 16 } 17 18 return val 19 } 20 21 type tmpFrame struct { 22 arstreamACK ARStreamACK 23 fragments map[int][]byte 24 frame []byte 25 waitForIframe bool 26 frameFlags int 27 } 28 29 type ARStreamACK struct { 30 FrameNumber int 31 HighPacketsAck uint64 32 LowPacketsAck uint64 33 } 34 35 type ARStreamFrame struct { 36 FrameNumber int 37 FrameFlags int 38 FragmentNumber int 39 FragmentsPerFrame int 40 Frame []byte 41 } 42 43 func NewARStreamFrame(buf []byte) ARStreamFrame { 44 // 45 // ARSTREAM_NetworkHeaders_DataHeader_t; 46 // 47 // uint16_t frameNumber; 48 // uint8_t frameFlags; // Infos on the current frame 49 // uint8_t fragmentNumber; // Index of the current fragment in current frame 50 // uint8_t fragmentsPerFrame; // Number of fragments in current frame 51 // 52 // * frameFlags structure : 53 // * x x x x x x x x 54 // * | | | | | | | \-> FLUSH FRAME 55 // * | | | | | | \-> UNUSED 56 // * | | | | | \-> UNUSED 57 // * | | | | \-> UNUSED 58 // * | | | \-> UNUSED 59 // * | | \-> UNUSED 60 // * | \-> UNUSED 61 // * \-> UNUSED 62 // * 63 // 64 65 frame := ARStreamFrame{ 66 FrameFlags: int(buf[2]), 67 FragmentNumber: int(buf[3]), 68 FragmentsPerFrame: int(buf[4]), 69 } 70 71 var number uint16 72 binary.Read(bytes.NewReader(buf[0:2]), binary.LittleEndian, &number) 73 74 frame.FrameNumber = int(number) 75 76 frame.Frame = buf[5:] 77 78 return frame 79 } 80 81 type NetworkFrame struct { 82 Type int 83 Seq int 84 Id int 85 Size int 86 Data []byte 87 } 88 89 func NewNetworkFrame(buf []byte) NetworkFrame { 90 frame := NetworkFrame{ 91 Type: int(buf[0]), 92 Id: int(buf[1]), 93 Seq: int(buf[2]), 94 Data: []byte{}, 95 } 96 97 var size uint32 98 binary.Read(bytes.NewReader(buf[3:7]), binary.LittleEndian, &size) 99 frame.Size = int(size) 100 101 frame.Data = buf[7:frame.Size] 102 103 return frame 104 } 105 106 func networkFrameGenerator() func(*bytes.Buffer, byte, byte) *bytes.Buffer { 107 //func networkFrameGenerator() func(*bytes.Buffer, byte, byte) NetworkFrame { 108 // 109 // ARNETWORKAL_Frame_t 110 // 111 // uint8 type - frame type ARNETWORK_FRAME_TYPE 112 // uint8 id - identifier of the buffer sending the frame 113 // uint8 seq - sequence number of the frame 114 // uint32 size - size of the frame 115 // 116 117 // each frame id has it's own sequence number 118 seq := make(map[byte]byte) 119 120 hlen := 7 // size of ARNETWORKAL_Frame_t header 121 122 return func(cmd *bytes.Buffer, frameType byte, id byte) *bytes.Buffer { 123 if _, ok := seq[id]; !ok { 124 seq[id] = 0 125 } 126 127 seq[id]++ 128 129 if seq[id] > 255 { 130 seq[id] = 0 131 } 132 133 ret := &bytes.Buffer{} 134 ret.WriteByte(frameType) 135 ret.WriteByte(id) 136 ret.WriteByte(seq[id]) 137 138 size := &bytes.Buffer{} 139 binary.Write(size, binary.LittleEndian, uint32(cmd.Len()+hlen)) 140 141 ret.Write(size.Bytes()) 142 ret.Write(cmd.Bytes()) 143 144 return ret 145 } 146 } 147 148 type Pcmd struct { 149 Flag int 150 Roll int 151 Pitch int 152 Yaw int 153 Gaz int 154 Psi float32 155 } 156 157 type Bebop struct { 158 IP string 159 NavData map[string]string 160 Pcmd Pcmd 161 tmpFrame tmpFrame 162 C2dPort int 163 D2cPort int 164 RTPStreamPort int 165 RTPControlPort int 166 DiscoveryPort int 167 c2dClient *net.UDPConn 168 d2cClient *net.UDPConn 169 discoveryClient *net.TCPConn 170 networkFrameGenerator func(*bytes.Buffer, byte, byte) *bytes.Buffer 171 video chan []byte 172 writeChan chan []byte 173 } 174 175 func New() *Bebop { 176 return &Bebop{ 177 IP: "192.168.42.1", 178 NavData: make(map[string]string), 179 C2dPort: 54321, 180 D2cPort: 43210, 181 RTPStreamPort: 55004, 182 RTPControlPort: 55005, 183 DiscoveryPort: 44444, 184 networkFrameGenerator: networkFrameGenerator(), 185 Pcmd: Pcmd{ 186 Flag: 0, 187 Roll: 0, 188 Pitch: 0, 189 Yaw: 0, 190 Gaz: 0, 191 Psi: 0, 192 }, 193 tmpFrame: tmpFrame{}, 194 video: make(chan []byte), 195 writeChan: make(chan []byte), 196 } 197 } 198 199 func (b *Bebop) write(buf []byte) (int, error) { 200 b.writeChan <- buf 201 return 0, nil 202 } 203 204 func (b *Bebop) Discover() error { 205 addr, err := net.ResolveTCPAddr("tcp", fmt.Sprintf("%s:%d", b.IP, b.DiscoveryPort)) 206 207 if err != nil { 208 return err 209 } 210 211 b.discoveryClient, err = net.DialTCP("tcp", nil, addr) 212 213 if err != nil { 214 return err 215 } 216 217 b.discoveryClient.Write( 218 []byte( 219 fmt.Sprintf(`{ 220 "controller_type": "computer", 221 "controller_name": "go-bebop", 222 "d2c_port": "%d", 223 "arstream2_client_stream_port": "%d", 224 "arstream2_client_control_port": "%d", 225 }`, 226 b.D2cPort, 227 b.RTPStreamPort, 228 b.RTPControlPort), 229 ), 230 ) 231 232 data := make([]byte, 10240) 233 234 _, err = b.discoveryClient.Read(data) 235 236 if err != nil { 237 return err 238 } 239 240 return b.discoveryClient.Close() 241 } 242 243 func (b *Bebop) Connect() error { 244 err := b.Discover() 245 246 if err != nil { 247 return err 248 } 249 250 c2daddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", b.IP, b.C2dPort)) 251 252 if err != nil { 253 return err 254 } 255 256 b.c2dClient, err = net.DialUDP("udp", nil, c2daddr) 257 258 if err != nil { 259 return err 260 } 261 262 d2caddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf(":%d", b.D2cPort)) 263 264 if err != nil { 265 return err 266 } 267 b.d2cClient, err = net.ListenUDP("udp", d2caddr) 268 if err != nil { 269 return err 270 } 271 272 go func() { 273 for { 274 _, err := b.c2dClient.Write(<-b.writeChan) 275 276 if err != nil { 277 fmt.Println(err) 278 } 279 } 280 }() 281 282 go func() { 283 for { 284 data := make([]byte, 40960) 285 i, _, err := b.d2cClient.ReadFromUDP(data) 286 if err != nil { 287 fmt.Println("d2cClient error:", err) 288 } 289 290 b.packetReceiver(data[0:i]) 291 } 292 }() 293 294 // send pcmd values at 40hz 295 go func() { 296 // wait a little bit so that there is enough time to get some ACKs 297 time.Sleep(500 * time.Millisecond) 298 for { 299 _, err := b.write(b.generatePcmd().Bytes()) 300 if err != nil { 301 fmt.Println("pcmd c2dClient.Write", err) 302 } 303 time.Sleep(25 * time.Millisecond) 304 } 305 }() 306 307 if err := b.GenerateAllStates(); err != nil { 308 return err 309 } 310 if err := b.FlatTrim(); err != nil { 311 return err 312 } 313 314 return nil 315 } 316 317 func (b *Bebop) FlatTrim() error { 318 // 319 // ARCOMMANDS_Generator_GenerateARDrone3PilotingFlatTrim 320 // 321 322 cmd := &bytes.Buffer{} 323 324 cmd.WriteByte(ARCOMMANDS_ID_PROJECT_ARDRONE3) 325 cmd.WriteByte(ARCOMMANDS_ID_ARDRONE3_CLASS_PILOTING) 326 327 tmp := &bytes.Buffer{} 328 binary.Write(tmp, binary.LittleEndian, uint16(ARCOMMANDS_ID_ARDRONE3_PILOTING_CMD_FLATTRIM)) 329 330 cmd.Write(tmp.Bytes()) 331 332 _, err := b.write(b.networkFrameGenerator(cmd, ARNETWORKAL_FRAME_TYPE_DATA, BD_NET_CD_NONACK_ID).Bytes()) 333 return err 334 } 335 336 func (b *Bebop) GenerateAllStates() error { 337 // 338 // ARCOMMANDS_Generator_GenerateCommonCommonAllStates 339 // 340 341 cmd := &bytes.Buffer{} 342 343 cmd.WriteByte(ARCOMMANDS_ID_PROJECT_COMMON) 344 cmd.WriteByte(ARCOMMANDS_ID_COMMON_CLASS_COMMON) 345 346 tmp := &bytes.Buffer{} 347 binary.Write(tmp, binary.LittleEndian, uint16(ARCOMMANDS_ID_COMMON_COMMON_CMD_ALLSTATES)) 348 349 cmd.Write(tmp.Bytes()) 350 351 _, err := b.write(b.networkFrameGenerator(cmd, ARNETWORKAL_FRAME_TYPE_DATA, BD_NET_CD_NONACK_ID).Bytes()) 352 return err 353 } 354 355 func (b *Bebop) TakeOff() error { 356 // 357 // ARCOMMANDS_Generator_GenerateARDrone3PilotingTakeOff 358 // 359 360 cmd := &bytes.Buffer{} 361 362 cmd.WriteByte(ARCOMMANDS_ID_PROJECT_ARDRONE3) 363 cmd.WriteByte(ARCOMMANDS_ID_ARDRONE3_CLASS_PILOTING) 364 365 tmp := &bytes.Buffer{} 366 binary.Write(tmp, binary.LittleEndian, uint16(ARCOMMANDS_ID_ARDRONE3_PILOTING_CMD_TAKEOFF)) 367 368 cmd.Write(tmp.Bytes()) 369 370 _, err := b.write(b.networkFrameGenerator(cmd, ARNETWORKAL_FRAME_TYPE_DATA, BD_NET_CD_NONACK_ID).Bytes()) 371 return err 372 } 373 374 func (b *Bebop) Land() error { 375 // 376 // ARCOMMANDS_Generator_GenerateARDrone3PilotingLanding 377 // 378 379 cmd := &bytes.Buffer{} 380 381 cmd.WriteByte(ARCOMMANDS_ID_PROJECT_ARDRONE3) 382 cmd.WriteByte(ARCOMMANDS_ID_ARDRONE3_CLASS_PILOTING) 383 384 tmp := &bytes.Buffer{} 385 binary.Write(tmp, binary.LittleEndian, uint16(ARCOMMANDS_ID_ARDRONE3_PILOTING_CMD_LANDING)) 386 387 cmd.Write(tmp.Bytes()) 388 389 _, err := b.write(b.networkFrameGenerator(cmd, ARNETWORKAL_FRAME_TYPE_DATA, BD_NET_CD_NONACK_ID).Bytes()) 390 return err 391 } 392 393 func (b *Bebop) Up(val int) error { 394 b.Pcmd.Flag = 1 395 b.Pcmd.Gaz = validatePitch(val) 396 return nil 397 } 398 399 func (b *Bebop) Down(val int) error { 400 b.Pcmd.Flag = 1 401 b.Pcmd.Gaz = validatePitch(val) * -1 402 return nil 403 } 404 405 func (b *Bebop) Forward(val int) error { 406 b.Pcmd.Flag = 1 407 b.Pcmd.Pitch = validatePitch(val) 408 return nil 409 } 410 411 func (b *Bebop) Backward(val int) error { 412 b.Pcmd.Flag = 1 413 b.Pcmd.Pitch = validatePitch(val) * -1 414 return nil 415 } 416 417 func (b *Bebop) Right(val int) error { 418 b.Pcmd.Flag = 1 419 b.Pcmd.Roll = validatePitch(val) 420 return nil 421 } 422 423 func (b *Bebop) Left(val int) error { 424 b.Pcmd.Flag = 1 425 b.Pcmd.Roll = validatePitch(val) * -1 426 return nil 427 } 428 429 func (b *Bebop) Clockwise(val int) error { 430 b.Pcmd.Flag = 1 431 b.Pcmd.Yaw = validatePitch(val) 432 return nil 433 } 434 435 func (b *Bebop) CounterClockwise(val int) error { 436 b.Pcmd.Flag = 1 437 b.Pcmd.Yaw = validatePitch(val) * -1 438 return nil 439 } 440 441 func (b *Bebop) Stop() error { 442 b.Pcmd = Pcmd{ 443 Flag: 0, 444 Roll: 0, 445 Pitch: 0, 446 Yaw: 0, 447 Gaz: 0, 448 Psi: 0, 449 } 450 451 return nil 452 } 453 454 func (b *Bebop) generatePcmd() *bytes.Buffer { 455 // 456 // ARCOMMANDS_Generator_GenerateARDrone3PilotingPCMD 457 // 458 // uint8 - flag Boolean flag to activate roll/pitch movement 459 // int8 - roll Roll consign for the drone [-100;100] 460 // int8 - pitch Pitch consign for the drone [-100;100] 461 // int8 - yaw Yaw consign for the drone [-100;100] 462 // int8 - gaz Gaz consign for the drone [-100;100] 463 // float - psi [NOT USED] - Magnetic north heading of the 464 // controlling device (deg) [-180;180] 465 // 466 467 cmd := &bytes.Buffer{} 468 tmp := &bytes.Buffer{} 469 470 cmd.WriteByte(ARCOMMANDS_ID_PROJECT_ARDRONE3) 471 cmd.WriteByte(ARCOMMANDS_ID_ARDRONE3_CLASS_PILOTING) 472 473 tmp = &bytes.Buffer{} 474 binary.Write(tmp, binary.LittleEndian, uint16(ARCOMMANDS_ID_ARDRONE3_PILOTING_CMD_PCMD)) 475 cmd.Write(tmp.Bytes()) 476 477 tmp = &bytes.Buffer{} 478 binary.Write(tmp, binary.LittleEndian, uint8(b.Pcmd.Flag)) 479 cmd.Write(tmp.Bytes()) 480 481 tmp = &bytes.Buffer{} 482 binary.Write(tmp, binary.LittleEndian, int8(b.Pcmd.Roll)) 483 cmd.Write(tmp.Bytes()) 484 485 tmp = &bytes.Buffer{} 486 binary.Write(tmp, binary.LittleEndian, int8(b.Pcmd.Pitch)) 487 cmd.Write(tmp.Bytes()) 488 489 tmp = &bytes.Buffer{} 490 binary.Write(tmp, binary.LittleEndian, int8(b.Pcmd.Yaw)) 491 cmd.Write(tmp.Bytes()) 492 493 tmp = &bytes.Buffer{} 494 binary.Write(tmp, binary.LittleEndian, int8(b.Pcmd.Gaz)) 495 cmd.Write(tmp.Bytes()) 496 497 tmp = &bytes.Buffer{} 498 binary.Write(tmp, binary.LittleEndian, uint32(b.Pcmd.Psi)) 499 cmd.Write(tmp.Bytes()) 500 501 return b.networkFrameGenerator(cmd, ARNETWORKAL_FRAME_TYPE_DATA, BD_NET_CD_NONACK_ID) 502 } 503 504 func (b *Bebop) createAck(frame NetworkFrame) *bytes.Buffer { 505 // 506 // ARNETWORK_Receiver_ThreadRun 507 // 508 509 // 510 // libARNetwork/Sources/ARNETWORK_Manager.h#ARNETWORK_Manager_IDOutputToIDAck 511 // 512 513 return b.networkFrameGenerator(bytes.NewBuffer([]byte{uint8(frame.Seq)}), 514 ARNETWORKAL_FRAME_TYPE_ACK, 515 byte(uint16(frame.Id)+(ARNETWORKAL_MANAGER_DEFAULT_ID_MAX/2)), 516 ) 517 } 518 519 func (b *Bebop) createPong(frame NetworkFrame) *bytes.Buffer { 520 return b.networkFrameGenerator(bytes.NewBuffer(frame.Data), 521 ARNETWORKAL_FRAME_TYPE_DATA, 522 ARNETWORK_MANAGER_INTERNAL_BUFFER_ID_PONG, 523 ) 524 } 525 526 func (b *Bebop) packetReceiver(buf []byte) { 527 frame := NewNetworkFrame(buf) 528 529 // 530 // libARNetwork/Sources/ARNETWORK_Receiver.c#ARNETWORK_Receiver_ThreadRun 531 // 532 if frame.Type == int(ARNETWORKAL_FRAME_TYPE_DATA_WITH_ACK) { 533 ack := b.createAck(frame).Bytes() 534 _, err := b.write(ack) 535 536 if err != nil { 537 fmt.Println("ARNETWORKAL_FRAME_TYPE_DATA_WITH_ACK", err) 538 } 539 } 540 541 if frame.Type == int(ARNETWORKAL_FRAME_TYPE_DATA_LOW_LATENCY) && 542 frame.Id == int(BD_NET_DC_VIDEO_DATA_ID) { 543 544 arstreamFrame := NewARStreamFrame(frame.Data) 545 546 ack := b.createARStreamACK(arstreamFrame).Bytes() 547 _, err := b.write(ack) 548 if err != nil { 549 fmt.Println("ARNETWORKAL_FRAME_TYPE_DATA_LOW_LATENCY", err) 550 } 551 } 552 553 // 554 // libARNetwork/Sources/ARNETWORK_Receiver.c#ARNETWORK_Receiver_ThreadRun 555 // 556 if frame.Id == int(ARNETWORK_MANAGER_INTERNAL_BUFFER_ID_PING) { 557 pong := b.createPong(frame).Bytes() 558 _, err := b.write(pong) 559 if err != nil { 560 fmt.Println("ARNETWORK_MANAGER_INTERNAL_BUFFER_ID_PING", err) 561 } 562 } 563 } 564 565 func (b *Bebop) StartRecording() error { 566 buf := b.videoRecord(ARCOMMANDS_ARDRONE3_MEDIARECORD_VIDEO_RECORD_START) 567 568 b.write(b.networkFrameGenerator(buf, ARNETWORKAL_FRAME_TYPE_DATA, BD_NET_CD_NONACK_ID).Bytes()) 569 return nil 570 } 571 572 func (b *Bebop) StopRecording() error { 573 buf := b.videoRecord(ARCOMMANDS_ARDRONE3_MEDIARECORD_VIDEO_RECORD_STOP) 574 575 b.write(b.networkFrameGenerator(buf, ARNETWORKAL_FRAME_TYPE_DATA, BD_NET_CD_NONACK_ID).Bytes()) 576 return nil 577 } 578 579 func (b *Bebop) videoRecord(state byte) *bytes.Buffer { 580 // 581 // ARCOMMANDS_Generator_GenerateARDrone3MediaRecordVideo 582 // 583 584 cmd := &bytes.Buffer{} 585 586 cmd.WriteByte(ARCOMMANDS_ID_PROJECT_ARDRONE3) 587 cmd.WriteByte(ARCOMMANDS_ID_ARDRONE3_CLASS_MEDIARECORD) 588 589 tmp := &bytes.Buffer{} 590 binary.Write(tmp, 591 binary.LittleEndian, 592 uint16(ARCOMMANDS_ID_ARDRONE3_MEDIARECORD_CMD_VIDEO), 593 ) 594 595 cmd.Write(tmp.Bytes()) 596 597 tmp = &bytes.Buffer{} 598 binary.Write(tmp, binary.LittleEndian, uint32(state)) 599 600 cmd.Write(tmp.Bytes()) 601 602 cmd.WriteByte(0) 603 604 return cmd 605 } 606 607 func (b *Bebop) Video() chan []byte { 608 return b.video 609 } 610 611 func (b *Bebop) HullProtection(protect bool) error { 612 // 613 // ARCOMMANDS_Generator_GenerateARDrone3SpeedSettingsHullProtection 614 // 615 616 cmd := &bytes.Buffer{} 617 618 cmd.WriteByte(ARCOMMANDS_ID_PROJECT_ARDRONE3) 619 cmd.WriteByte(ARCOMMANDS_ID_ARDRONE3_CLASS_SPEEDSETTINGS) 620 621 tmp := &bytes.Buffer{} 622 binary.Write(tmp, 623 binary.LittleEndian, 624 uint16(ARCOMMANDS_ID_ARDRONE3_SPEEDSETTINGS_CMD_HULLPROTECTION), 625 ) 626 627 cmd.Write(tmp.Bytes()) 628 629 tmp = &bytes.Buffer{} 630 binary.Write(tmp, binary.LittleEndian, bool2int8(protect)) 631 cmd.Write(tmp.Bytes()) 632 633 _, err := b.write(b.networkFrameGenerator(cmd, ARNETWORKAL_FRAME_TYPE_DATA, BD_NET_CD_NONACK_ID).Bytes()) 634 return err 635 } 636 637 func (b *Bebop) Outdoor(outdoor bool) error { 638 // 639 // ARCOMMANDS_Generator_GenerateARDrone3SpeedSettingsOutdoor 640 // 641 642 cmd := &bytes.Buffer{} 643 644 cmd.WriteByte(ARCOMMANDS_ID_PROJECT_ARDRONE3) 645 cmd.WriteByte(ARCOMMANDS_ID_ARDRONE3_CLASS_SPEEDSETTINGS) 646 647 tmp := &bytes.Buffer{} 648 binary.Write(tmp, 649 binary.LittleEndian, 650 uint16(ARCOMMANDS_ID_ARDRONE3_SPEEDSETTINGS_CMD_OUTDOOR), 651 ) 652 653 cmd.Write(tmp.Bytes()) 654 655 tmp = &bytes.Buffer{} 656 binary.Write(tmp, binary.LittleEndian, bool2int8(outdoor)) 657 cmd.Write(tmp.Bytes()) 658 659 _, err := b.write(b.networkFrameGenerator(cmd, ARNETWORKAL_FRAME_TYPE_DATA, BD_NET_CD_NONACK_ID).Bytes()) 660 return err 661 } 662 663 func (b *Bebop) VideoEnable(enable bool) error { 664 cmd := &bytes.Buffer{} 665 666 cmd.WriteByte(ARCOMMANDS_ID_PROJECT_ARDRONE3) 667 cmd.WriteByte(ARCOMMANDS_ID_ARDRONE3_CLASS_MEDIASTREAMING) 668 669 tmp := &bytes.Buffer{} 670 binary.Write(tmp, 671 binary.LittleEndian, 672 uint16(ARCOMMANDS_ID_ARDRONE3_MEDIASTREAMING_CMD_VIDEOENABLE), 673 ) 674 675 cmd.Write(tmp.Bytes()) 676 677 tmp = &bytes.Buffer{} 678 binary.Write(tmp, binary.LittleEndian, bool2int8(enable)) 679 cmd.Write(tmp.Bytes()) 680 681 _, err := b.write(b.networkFrameGenerator(cmd, ARNETWORKAL_FRAME_TYPE_DATA, BD_NET_CD_NONACK_ID).Bytes()) 682 return err 683 } 684 685 func (b *Bebop) VideoStreamMode(mode int8) error { 686 cmd := &bytes.Buffer{} 687 688 cmd.WriteByte(ARCOMMANDS_ID_PROJECT_ARDRONE3) 689 cmd.WriteByte(ARCOMMANDS_ID_ARDRONE3_CLASS_MEDIASTREAMING) 690 691 tmp := &bytes.Buffer{} 692 binary.Write(tmp, 693 binary.LittleEndian, 694 uint16(ARCOMMANDS_ID_ARDRONE3_MEDIASTREAMING_CMD_VIDEOSTREAMMODE), 695 ) 696 697 cmd.Write(tmp.Bytes()) 698 699 tmp = &bytes.Buffer{} 700 binary.Write(tmp, binary.LittleEndian, mode) 701 cmd.Write(tmp.Bytes()) 702 703 _, err := b.write(b.networkFrameGenerator(cmd, ARNETWORKAL_FRAME_TYPE_DATA, BD_NET_CD_NONACK_ID).Bytes()) 704 return err 705 } 706 707 func bool2int8(b bool) int8 { 708 if b { 709 return 1 710 } 711 return 0 712 } 713 714 func (b *Bebop) createARStreamACK(frame ARStreamFrame) *bytes.Buffer { 715 // 716 // ARSTREAM_NetworkHeaders_AckPacket_t; 717 // 718 // uint16_t frameNumber; // id of the current frame 719 // uint64_t highPacketsAck; // Upper 64 packets bitfield 720 // uint64_t lowPacketsAck; // Lower 64 packets bitfield 721 // 722 // libARStream/Sources/ARSTREAM_NetworkHeaders.c#ARSTREAM_NetworkHeaders_AckPacketSetFlag 723 // 724 725 // 726 // each bit in the highPacketsAck and lowPacketsAck correspond to the 727 // fragmentsPerFrame which have been received per frameNumber, so time to 728 // flip some bits! 729 // 730 if frame.FrameNumber != b.tmpFrame.arstreamACK.FrameNumber { 731 if len(b.tmpFrame.fragments) > 0 { 732 emit := false 733 734 // if we missed some frames, wait for the next iframe 735 if frame.FrameNumber != b.tmpFrame.arstreamACK.FrameNumber+1 { 736 b.tmpFrame.waitForIframe = true 737 } 738 739 // if it's an iframe 740 if b.tmpFrame.frameFlags == 1 { 741 b.tmpFrame.waitForIframe = false 742 emit = true 743 } else if !b.tmpFrame.waitForIframe { 744 emit = true 745 } 746 747 if emit { 748 skip := false 749 750 for i := 0; i < len(b.tmpFrame.fragments); i++ { 751 // check if any fragments are missing 752 if len(b.tmpFrame.fragments[i]) == 0 { 753 skip = true 754 break 755 } 756 b.tmpFrame.frame = append(b.tmpFrame.frame, b.tmpFrame.fragments[i]...) 757 } 758 759 if !skip { 760 select { 761 case b.video <- b.tmpFrame.frame: 762 default: 763 } 764 } 765 } 766 } 767 768 b.tmpFrame.fragments = make(map[int][]byte) 769 b.tmpFrame.frame = []byte{} 770 b.tmpFrame.arstreamACK.FrameNumber = frame.FrameNumber 771 b.tmpFrame.frameFlags = frame.FrameFlags 772 } 773 b.tmpFrame.fragments[frame.FragmentNumber] = frame.Frame 774 775 if frame.FragmentNumber < 64 { 776 b.tmpFrame.arstreamACK.LowPacketsAck |= uint64(1) << uint64(frame.FragmentNumber) 777 } else { 778 b.tmpFrame.arstreamACK.HighPacketsAck |= uint64(1) << uint64(frame.FragmentNumber-64) 779 } 780 781 ackPacket := &bytes.Buffer{} 782 tmp := &bytes.Buffer{} 783 784 binary.Write(tmp, binary.LittleEndian, uint16(b.tmpFrame.arstreamACK.FrameNumber)) 785 ackPacket.Write(tmp.Bytes()) 786 787 tmp = &bytes.Buffer{} 788 binary.Write(tmp, binary.LittleEndian, uint64(b.tmpFrame.arstreamACK.HighPacketsAck)) 789 ackPacket.Write(tmp.Bytes()) 790 791 tmp = &bytes.Buffer{} 792 binary.Write(tmp, binary.LittleEndian, uint64(b.tmpFrame.arstreamACK.LowPacketsAck)) 793 ackPacket.Write(tmp.Bytes()) 794 795 return b.networkFrameGenerator(ackPacket, ARNETWORKAL_FRAME_TYPE_DATA, BD_NET_CD_VIDEO_ACK_ID) 796 }