func (c *Client) Listen() error {
	if err := c.listenTryLock.Lock(); err != nil {
		return fmt.Errorf("already listening: %s", err.Error())
	}
	go func() {
		buf := make([]byte, maxDataBufferSize)
		for {
			n, from, err := c.conn.ReadFrom(buf)
			if err != nil {
				c.log.Debugf("exiting read loop: %s", err.Error())
				break
			}
			_, err = c.HandleInbound(buf[:n], from)
			if err != nil {
				c.log.Debugf("exiting read loop: %s", err.Error())
				break
			}
		}
		c.listenTryLock.Unlock()
	}()
	return nil
}
Listen will have this client start listening on the conn provided via the config.
This is optional. If not used, you will need to call HandleInbound method
to supply incoming data, instead.
package turn
import (
	b64 "encoding/base64"
	"fmt"
	"math"
	"net"
	"sync"
	"time"
	"github.com/pion/logging"
	"github.com/pion/stun"
	"github.com/pion/transport/vnet"
	"github.com/pion/turn/internal/client"
	"github.com/pion/turn/internal/proto"
	"github.com/pkg/errors"
)
const (
	defaultRTO        = 200 * time.Millisecond
	maxRtxCount       = 7               
	maxDataBufferSize = math.MaxUint16  
)
type ClientConfig struct {
	STUNServerAddr string  
	TURNServerAddr string  
	Username       string
	Password       string
	Realm          string
	Software       string
	RTO            time.Duration
	Conn           net.PacketConn  
	LoggerFactory  logging.LoggerFactory
	Net            *vnet.Net
}
type Client struct {
	conn          net.PacketConn          
	stunServ      net.Addr                
	turnServ      net.Addr                
	stunServStr   string                  
	turnServStr   string                  
	username      stun.Username           
	password      string                  
	realm         stun.Realm              
	integrity     stun.MessageIntegrity   
	software      stun.Software           
	trMap         *client.TransactionMap  
	rto           time.Duration           
	relayedConn   *client.UDPConn         
	allocTryLock  client.TryLock          
	listenTryLock client.TryLock          
	net           *vnet.Net               
	mutex         sync.RWMutex            
	log           logging.LeveledLogger   
}
func NewClient(config *ClientConfig) (*Client, error) {
	log := config.LoggerFactory.NewLogger("turnc")
	if config.Conn == nil {
		return nil, fmt.Errorf("conn cannot not be nil")
	}
	if config.Net == nil {
		config.Net = vnet.NewNet(nil)  
	} else if config.Net.IsVirtual() {
		log.Warn("vnet is enabled")
	}
	var stunServ, turnServ net.Addr
	var stunServStr, turnServStr string
	var err error
	if len(config.STUNServerAddr) > 0 {
		log.Debugf("resolving %s", config.STUNServerAddr)
		stunServ, err = config.Net.ResolveUDPAddr("udp4", config.STUNServerAddr)
		if err != nil {
			return nil, err
		}
		stunServStr = stunServ.String()
		log.Debugf("stunServ: %s", stunServStr)
	}
	if len(config.TURNServerAddr) > 0 {
		log.Debugf("resolving %s", config.TURNServerAddr)
		turnServ, err = config.Net.ResolveUDPAddr("udp4", config.TURNServerAddr)
		if err != nil {
			return nil, err
		}
		turnServStr = turnServ.String()
		log.Debugf("turnServ: %s", turnServStr)
	}
	rto := defaultRTO
	if config.RTO > 0 {
		rto = config.RTO
	}
	c := &Client{
		conn:        config.Conn,
		stunServ:    stunServ,
		turnServ:    turnServ,
		stunServStr: stunServStr,
		turnServStr: turnServStr,
		username:    stun.NewUsername(config.Username),
		password:    config.Password,
		realm:       stun.NewRealm(config.Realm),
		software:    stun.NewSoftware(config.Software),
		net:         config.Net,
		trMap:       client.NewTransactionMap(),
		rto:         rto,
		log:         log,
	}
	return c, nil
}
func (c *Client) TURNServerAddr() net.Addr {
	return c.turnServ
}
func (c *Client) STUNServerAddr() net.Addr {
	return c.stunServ
}
func (c *Client) Username() stun.Username {
	return c.username
}
func (c *Client) Realm() stun.Realm {
	return c.realm
}
func (c *Client) WriteTo(data []byte, to net.Addr) (int, error) {
	return c.conn.WriteTo(data, to)
}