code: func (p *packetPacker) PackPacket() (*packedPacket, error) {
  	packet, err := p.maybePackCryptoPacket()
  	if err != nil {
  		return nil, err
  	}
  	if packet != nil {
  		return packet, nil
  	}
  
  	encLevel, sealer := p.cryptoSetup.GetSealer()
  	header := p.getHeader(encLevel)
  	headerLen := header.GetLength(p.version)
  	if err != nil {
  		return nil, err
  	}
  
  	maxSize := p.maxPacketSize - protocol.ByteCount(sealer.Overhead()) - headerLen
  	payload, err := p.composeNextPacket(maxSize)
  	if err != nil {
  		return nil, err
  	}
  
  	// check if we have anything to send
  	if len(payload.frames) == 0 && payload.ack == nil {
  		return nil, nil
  	}
  	if len(payload.frames) == 0 { // the packet only contains an ACK
  		if p.numNonAckElicitingAcks >= protocol.MaxNonAckElicitingAcks {
  			ping := &wire.PingFrame{}
  			payload.frames = append(payload.frames, ping)
  			payload.length += ping.Length(p.version)
  			p.numNonAckElicitingAcks = 0
  		} else {
  			p.numNonAckElicitingAcks++
  		}
  	} else {
  		p.numNonAckElicitingAcks = 0
  	}
  
  	return p.writeAndSealPacket(header, payload, encLevel, sealer)
  }
docs: // PackPacket packs a new packet
  // the other controlFrames are sent in the next packet, but might be queued and sent in the next packet if the packet would overflow MaxPacketSize otherwise