github.com/ssetin/penguincast@v0.2.0/src/client/client.go (about)

     1  // Package iceclient - simple client for icecast server
     2  package iceclient
     3  
     4  import (
     5  	"bufio"
     6  	"errors"
     7  	"log"
     8  	"net"
     9  	"net/textproto"
    10  	"os"
    11  	"strconv"
    12  	"strings"
    13  )
    14  
    15  // ================================== PenguinClient ========================================
    16  const (
    17  	cClientName = "penguinClient"
    18  	cVersion    = "0.2"
    19  )
    20  
    21  // PenguinClient ...
    22  type PenguinClient struct {
    23  	urlMount     string
    24  	host         string
    25  	mount        string
    26  	bitRate      int
    27  	dumpFileName string
    28  
    29  	dumpFile *os.File
    30  	conn     net.Conn
    31  }
    32  
    33  // Init - initialize client
    34  func (p *PenguinClient) Init(host string, mount string, dump string) error {
    35  	p.urlMount = "http://" + host + "/" + mount
    36  	p.host = host
    37  	p.mount = mount
    38  	p.dumpFileName = dump
    39  	p.bitRate = 0
    40  
    41  	if dump > "" {
    42  		var err error
    43  		p.dumpFile, err = os.OpenFile(p.dumpFileName, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0666)
    44  		if err != nil {
    45  			return err
    46  		}
    47  	}
    48  
    49  	return nil
    50  }
    51  
    52  func (p *PenguinClient) sayHello(writer *bufio.Writer) error {
    53  	writer.WriteString("GET /")
    54  	writer.WriteString(p.mount)
    55  	writer.WriteString(" HTTP/1.0\r\nicy-metadata: 1\r\nuser-agent: ")
    56  	writer.WriteString(cClientName)
    57  	writer.WriteString("/")
    58  	writer.WriteString(cVersion)
    59  	writer.WriteString("\r\naccept: */*\r\n\r\n")
    60  	writer.Flush()
    61  	return nil
    62  }
    63  
    64  func (p *PenguinClient) getMountInfo(reader *bufio.Reader) error {
    65  	tp := textproto.NewReader(reader)
    66  
    67  	for {
    68  		line, err := tp.ReadLine()
    69  		if err != nil {
    70  			return err
    71  		}
    72  		if line == "" {
    73  			break
    74  		}
    75  		params := strings.Split(line, ":")
    76  		if len(params) == 2 {
    77  			if params[0] == "X-Audiocast-Bitrate" {
    78  				p.bitRate, err = strconv.Atoi(strings.TrimSpace(params[1]))
    79  				if err != nil {
    80  					return err
    81  				}
    82  			}
    83  		}
    84  
    85  	}
    86  
    87  	return nil
    88  }
    89  
    90  // Listen - start to listen the stream during secToListen seconds
    91  func (p *PenguinClient) Listen(secToListen int) error {
    92  	var err error
    93  	//var beginIteration time.Time
    94  	//var iterTime time.Duration
    95  	p.conn, err = net.Dial("tcp", p.host)
    96  
    97  	if err != nil {
    98  		return err
    99  	}
   100  	defer p.conn.Close()
   101  
   102  	if p.dumpFile != nil {
   103  		defer p.dumpFile.Close()
   104  	}
   105  
   106  	reader := bufio.NewReader(p.conn)
   107  	writer := bufio.NewWriter(p.conn)
   108  
   109  	err = p.sayHello(writer)
   110  	if err != nil {
   111  		return err
   112  	}
   113  
   114  	err = p.getMountInfo(reader)
   115  	if err != nil {
   116  		log.Println(err.Error())
   117  		return err
   118  	}
   119  	//p.bitRate = 96
   120  	if p.bitRate == 0 {
   121  		return errors.New("Unknown bitrate")
   122  	}
   123  
   124  	bytesToFinish := secToListen * p.bitRate * 1024 / 8
   125  	readedBytes := 0
   126  	sndBuff := make([]byte, 1024*p.bitRate/8)
   127  
   128  	for readedBytes <= bytesToFinish {
   129  		//beginIteration = time.Now()
   130  		n, err := p.conn.Read(sndBuff)
   131  		if err != nil {
   132  			return err
   133  		}
   134  
   135  		if p.dumpFile != nil && n > 0 {
   136  			p.dumpFile.Write(sndBuff[:n])
   137  		}
   138  		readedBytes += n
   139  
   140  		//iterTime = time.Since(beginIteration)
   141  
   142  		//if iterTime > time.Millisecond*2000 {
   143  		//	log.Printf("Speed: %f Kbit/sec", float64(n)*8/1024/iterTime.Seconds())
   144  		//}
   145  	}
   146  
   147  	return nil
   148  }