├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── amf ├── amf0.go ├── amf0_test.go ├── amf3.go ├── decoder.go ├── encoder.go └── mapping.go ├── flv ├── flv.go ├── reader.go └── writer.go └── rtmp ├── chunk.go ├── client.go ├── conn.go ├── handshake.go ├── message.go ├── request.go ├── rtmp.go ├── rtmp_test.go ├── server.go └── stream.go /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | 3 | bin/ 4 | pkg/ 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | sudo: false 3 | go: 4 | - 1.6 5 | 6 | before_install: 7 | - go get github.com/mattn/goveralls 8 | - go get golang.org/x/tools/cmd/cover 9 | - go get github.com/golang/lint/golint 10 | 11 | script: 12 | - go test -v -coverprofile=amf.coverprofile ./amf 13 | - go test -v -coverprofile=flv.coverprofile ./flv 14 | - go test -v -coverprofile=rtmp.coverprofile ./rtmp 15 | - 'echo "mode: set" > .coverage && grep -h -v "mode: set" *.coverprofile >> .coverage' 16 | - $HOME/gopath/bin/goveralls -coverprofile=.coverage -service=travis-ci 17 | - $HOME/gopath/bin/golint ./... 18 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Vasily Vasilyev 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 | # Golang: RTMP Protocol 2 | 3 | ## Features 4 | 5 | - [x] AMF0 Encoder/Decoder 6 | - [ ] AMF3 Encoder/Decoder 7 | - [ ] FLV Reader/Writer 8 | - [x] RTMP Client 9 | - [ ] RTMP Server 10 | 11 | ## Installation 12 | 13 | ```sh 14 | go get github.com/pixelbender/go-rtmp 15 | ``` 16 | 17 | ## RTMP Client 18 | 19 | ```go 20 | package main 21 | 22 | import ( 23 | "github.com/pixelbender/go-rtmp/rtmp" 24 | "fmt" 25 | ) 26 | 27 | func main() { 28 | conn, err := rtmp.Dial("rtmp://example.org/app") 29 | if err != nil { 30 | fmt.Println(err) 31 | } else { 32 | defer conn.Close() 33 | fmt.Println(conn) 34 | } 35 | } 36 | ``` 37 | 38 | ## Specifications 39 | 40 | - [AMF0: Action Message Format](http://wwwimages.adobe.com/content/dam/Adobe/en/devnet/amf/pdf/amf0-file-format-specification.pdf) 41 | - [AMF3: Action Message Format](http://wwwimages.adobe.com/www.adobe.com/content/dam/Adobe/en/devnet/amf/pdf/amf-file-format-spec.pdf) 42 | - [FLV: Video File Format Specification v10](https://www.adobe.com/content/dam/Adobe/en/devnet/flv/pdfs/video_file_format_spec_v10.pdf) 43 | - [FLV: Adobe Flash Video File Format Specification v10.1](http://download.macromedia.com/f4v/video_file_format_spec_v10_1.pdf) 44 | - [RTMP: Real-Time Messaging Protocol](https://www.adobe.com/content/dam/Adobe/en/devnet/rtmp/pdf/rtmp_specification_1.0.pdf) 45 | - [RTMFP: Real-Time Media Flow Protocol](https://tools.ietf.org/html/rfc7016) 46 | - [RTMFP Profile for Flash Communication](https://tools.ietf.org/html/rfc7425) 47 | -------------------------------------------------------------------------------- /amf/amf0.go: -------------------------------------------------------------------------------- 1 | package amf 2 | 3 | import ( 4 | "encoding/binary" 5 | "math" 6 | "reflect" 7 | "time" 8 | ) 9 | 10 | const ( 11 | amf0Number = uint8(0x00) // float64 12 | amf0Boolean = uint8(0x01) // bool 13 | amf0String = uint8(0x02) // string 14 | amf0Object = uint8(0x03) // map[string]interface{} 15 | amf0Null = uint8(0x05) // nil 16 | amf0Undefined = uint8(0x06) // nil 17 | amf0Reference = uint8(0x07) // pointer 18 | amf0Array = uint8(0x08) // []interface{} or map[string]interface{} 19 | amf0ObjectEnd = uint8(0x09) 20 | amf0StrictArray = uint8(0x0a) // []interface{} 21 | amf0Date = uint8(0x0b) // time.Time 22 | amf0StringExt = uint8(0x0c) // stirng 23 | amf0Xml = uint8(0x0f) // string 24 | amf0Instance = uint8(0x10) // map[string]interface{} 25 | ) 26 | 27 | type amf0Encoder struct { 28 | *Writer 29 | } 30 | 31 | func (enc *amf0Encoder) Encode(v interface{}) error { 32 | if m, ok := v.(Marshaler); ok { 33 | return m.MarshalAMF(enc.Writer) 34 | } 35 | return encodeValue(reflect.ValueOf(v), enc) 36 | } 37 | 38 | func (enc *amf0Encoder) WriteNull() { 39 | enc.Next(1)[0] = amf0Null 40 | } 41 | 42 | func (enc *amf0Encoder) WriteBool(v bool) { 43 | b := enc.Next(2) 44 | b[0] = amf0Boolean 45 | if v { 46 | b[1] = 1 47 | } else { 48 | b[1] = 0 49 | } 50 | } 51 | 52 | func (enc *amf0Encoder) WriteInt(v int64) { 53 | enc.WriteFloat(float64(v)) 54 | } 55 | 56 | func (enc *amf0Encoder) WriteUint(v uint64) { 57 | enc.WriteFloat(float64(v)) 58 | } 59 | 60 | func (enc *amf0Encoder) WriteFloat(v float64) { 61 | b := enc.Next(9) 62 | b[0] = amf0Number 63 | putFloat64(b[1:], v) 64 | } 65 | 66 | func (enc *amf0Encoder) WriteString(v string) { 67 | copy(enc.initStringHeader(len(v)), v) 68 | } 69 | 70 | func (enc *amf0Encoder) WriteBytes(v []byte) { 71 | copy(enc.initStringHeader(len(v)), v) 72 | } 73 | 74 | func (enc *amf0Encoder) WriteTime(v time.Time) { 75 | b := enc.Next(11) 76 | b[0] = amf0Date 77 | putFloat64(b[1:], float64(v.UnixNano()/1e6)) 78 | b[9] = 0 79 | b[10] = 0 80 | } 81 | 82 | func (enc *amf0Encoder) initStringHeader(n int) []byte { 83 | if n > 0xffff { 84 | b := enc.Next(n + 5) 85 | b[0] = amf0StringExt 86 | be.PutUint32(b[1:], uint32(n)) 87 | return b[5:] 88 | } 89 | b := enc.Next(n + 3) 90 | b[0] = amf0String 91 | be.PutUint16(b[1:], uint16(n)) 92 | return b[3:] 93 | } 94 | 95 | func (enc *amf0Encoder) writeString(v string) { 96 | n := len(v) 97 | b := enc.Next(n + 2) 98 | be.PutUint16(b, uint16(n)) 99 | copy(b[2:], v) 100 | } 101 | 102 | func (enc *amf0Encoder) writeReference(v reflect.Value) bool { 103 | // TODO: implement references 104 | return false 105 | } 106 | 107 | func (enc *amf0Encoder) writeSlice(v reflect.Value) (err error) { 108 | if enc.writeReference(v) { 109 | return 110 | } 111 | b := enc.Next(5) 112 | b[0] = amf0StrictArray 113 | n := v.Len() 114 | be.PutUint32(b[1:], uint32(n)) 115 | for i := 0; i < n; i++ { 116 | if err = encodeValue(v.Index(i), enc); err != nil { 117 | return 118 | } 119 | } 120 | return 121 | } 122 | 123 | func (enc *amf0Encoder) writeStruct(v reflect.Value) (err error) { 124 | if enc.writeReference(v) { 125 | return 126 | } 127 | m := getStructMapping(v.Type()) 128 | b := enc.Next(1) 129 | b[0] = amf0Object 130 | for _, f := range m.fields { 131 | r := v.Field(f.index) 132 | if f.opt && isEmptyValue(r) { 133 | continue 134 | } 135 | enc.writeString(f.name) 136 | if err = encodeValue(r, enc); err != nil { 137 | return 138 | } 139 | } 140 | putUint24(enc.Next(3), uint32(amf0ObjectEnd)) 141 | return 142 | } 143 | 144 | func (enc *amf0Encoder) writeMap(v reflect.Value) (err error) { 145 | if enc.writeReference(v) { 146 | return 147 | } 148 | b := enc.Next(1) 149 | b[0] = amf0Object 150 | for _, k := range v.MapKeys() { 151 | switch k.Kind() { 152 | case reflect.String: 153 | if n := k.String(); n != "" { 154 | enc.writeString(n) 155 | if err = encodeValue(v.MapIndex(k), enc); err != nil { 156 | return 157 | } 158 | } 159 | default: 160 | return &errUnsupportedKeyType{k.Type()} 161 | } 162 | } 163 | putUint24(enc.Next(3), uint32(amf0ObjectEnd)) 164 | return 165 | } 166 | 167 | type amf0Decoder struct { 168 | *Reader 169 | b []byte 170 | err error 171 | refs map[uint16]interface{} 172 | } 173 | 174 | func (dec *amf0Decoder) Decode(v interface{}) error { 175 | if v == nil { 176 | return errDecodeNil 177 | } 178 | if m, ok := v.(Unmarshaler); ok { 179 | return m.UnmarshalAMF(dec.Reader) 180 | } 181 | r := reflect.ValueOf(v) 182 | if r.Kind() != reflect.Ptr { 183 | return errDecodeNotPtr 184 | } 185 | return decodeValue(r, dec) 186 | } 187 | 188 | func (dec *amf0Decoder) Skip() error { 189 | if dec.next(1) && dec.skipValue(dec.b[0]) { 190 | return nil 191 | } 192 | return dec.err 193 | } 194 | 195 | func (dec *amf0Decoder) ReadBool() (v bool, err error) { 196 | if dec.next(1) { 197 | switch m := dec.b[0]; m { 198 | case amf0Boolean: 199 | v, err = dec.readBool() 200 | default: 201 | dec.skipValue(m) 202 | err = &errUnexpectedMarker{m, "bool"} 203 | } 204 | } else { 205 | err = dec.err 206 | } 207 | return 208 | } 209 | 210 | func (dec *amf0Decoder) ReadInt() (v int64, err error) { 211 | if dec.next(1) { 212 | switch m := dec.b[0]; m { 213 | case amf0Number: 214 | var f float64 215 | f, err = dec.readFloat() 216 | v = int64(f) 217 | default: 218 | dec.skipValue(m) 219 | err = &errUnexpectedMarker{m, "int"} 220 | } 221 | } else { 222 | err = dec.err 223 | } 224 | return 225 | } 226 | 227 | func (dec *amf0Decoder) ReadUint() (v uint64, err error) { 228 | if dec.next(1) { 229 | switch m := dec.b[0]; m { 230 | case amf0Number: 231 | var f float64 232 | f, err = dec.readFloat() 233 | v = uint64(f) 234 | default: 235 | dec.skipValue(m) 236 | err = &errUnexpectedMarker{m, "uint"} 237 | } 238 | } else { 239 | err = dec.err 240 | } 241 | return 242 | } 243 | 244 | func (dec *amf0Decoder) ReadFloat() (v float64, err error) { 245 | if dec.next(1) { 246 | switch m := dec.b[0]; m { 247 | case amf0Number: 248 | v, err = dec.readFloat() 249 | default: 250 | dec.skipValue(m) 251 | err = &errUnexpectedMarker{m, "float"} 252 | } 253 | } else { 254 | err = dec.err 255 | } 256 | return 257 | } 258 | 259 | func (dec *amf0Decoder) ReadString() (v string, err error) { 260 | if dec.next(1) { 261 | switch m := dec.b[0]; m { 262 | case amf0String: 263 | v, err = dec.readString(false) 264 | case amf0Null, amf0Undefined: 265 | case amf0StringExt, amf0Xml: 266 | v, err = dec.readString(true) 267 | default: 268 | dec.skipValue(m) 269 | err = &errUnexpectedMarker{m, "string"} 270 | } 271 | } else { 272 | err = dec.err 273 | } 274 | return 275 | } 276 | 277 | func (dec *amf0Decoder) ReadBytes() (v []byte, err error) { 278 | if dec.next(1) { 279 | switch m := dec.b[0]; m { 280 | case amf0String: 281 | v, err = dec.readBytes(false) 282 | case amf0Null, amf0Undefined: 283 | case amf0StringExt, amf0Xml: 284 | v, err = dec.readBytes(true) 285 | default: 286 | dec.skipValue(m) 287 | err = &errUnexpectedMarker{m, "bytes"} 288 | } 289 | } else { 290 | err = dec.err 291 | } 292 | return 293 | } 294 | 295 | func (dec *amf0Decoder) ReadTime() (v time.Time, err error) { 296 | if dec.next(1) { 297 | switch m := dec.b[0]; m { 298 | case amf0Date: 299 | v, err = dec.readTime() 300 | default: 301 | dec.skipValue(m) 302 | err = &errUnexpectedMarker{m, "time"} 303 | } 304 | } else { 305 | err = dec.err 306 | } 307 | return 308 | } 309 | 310 | func (dec *amf0Decoder) next(n int) bool { 311 | dec.b, dec.err = dec.Next(n) 312 | return dec.err == nil 313 | } 314 | 315 | func (dec *amf0Decoder) read() (interface{}, error) { 316 | if !dec.next(1) { 317 | return nil, dec.err 318 | } 319 | switch m := dec.b[0]; m { 320 | case amf0Number: 321 | return dec.readFloat() 322 | case amf0Boolean: 323 | return dec.readBool() 324 | case amf0String: 325 | return dec.readString(false) 326 | case amf0Array: 327 | dec.next(4) 328 | fallthrough 329 | case amf0Object: 330 | return dec.readObject() 331 | case amf0Null, amf0Undefined: 332 | return nil, nil 333 | case amf0Reference: 334 | return dec.readReference() 335 | case amf0StrictArray: 336 | return dec.readStrictArray() 337 | case amf0Date: 338 | return dec.readTime() 339 | case amf0StringExt, amf0Xml: 340 | return dec.readString(true) 341 | case amf0Instance: 342 | if dec.skipString(false) { 343 | return dec.readObject() 344 | } 345 | default: 346 | dec.err = ErrFormat 347 | } 348 | return nil, dec.err 349 | } 350 | 351 | func (dec *amf0Decoder) readBool() (v bool, err error) { 352 | if dec.next(1) { 353 | v = dec.b[0] != 0 354 | } else { 355 | err = dec.err 356 | } 357 | return 358 | } 359 | 360 | func (dec *amf0Decoder) readFloat() (v float64, err error) { 361 | if dec.next(8) { 362 | v = getFloat64(dec.b) 363 | } else { 364 | err = dec.err 365 | } 366 | return 367 | } 368 | 369 | func (dec *amf0Decoder) readString(ext bool) (v string, err error) { 370 | var b []byte 371 | if b, err = dec.getBytes(ext); err == nil { 372 | v = string(b) 373 | } 374 | return 375 | } 376 | 377 | func (dec *amf0Decoder) readBytes(ext bool) (v []byte, err error) { 378 | var b []byte 379 | if b, err = dec.getBytes(ext); err == nil { 380 | v = make([]byte, len(b)) 381 | copy(v, b) 382 | } 383 | return 384 | } 385 | 386 | func (dec *amf0Decoder) getBytes(ext bool) (v []byte, err error) { 387 | if ext { 388 | if dec.next(4) { 389 | dec.next(int(be.Uint32(dec.b))) 390 | } 391 | } else { 392 | if dec.next(2) { 393 | dec.next(int(be.Uint16(dec.b))) 394 | } 395 | } 396 | if dec.err != nil { 397 | err = dec.err 398 | return 399 | } 400 | v = dec.b 401 | return 402 | } 403 | 404 | func (dec *amf0Decoder) readTime() (v time.Time, err error) { 405 | if dec.next(10) { 406 | v = time.Unix(0, int64(getFloat64(dec.b))*1e6).UTC() 407 | } else { 408 | err = dec.err 409 | } 410 | return 411 | } 412 | 413 | func (dec *amf0Decoder) readReference() (v interface{}, err error) { 414 | // FIXME: implement 415 | return nil, nil 416 | } 417 | 418 | func (dec *amf0Decoder) readStruct(v reflect.Value) (err error) { 419 | if dec.next(1) { 420 | switch m := dec.b[0]; m { 421 | case amf0Array: 422 | dec.next(4) 423 | fallthrough 424 | case amf0Object: 425 | err = dec.readStructData(v) 426 | default: 427 | err = &errUnexpectedMarker{m, v.Type().String()} 428 | } 429 | } else { 430 | err = dec.err 431 | } 432 | return 433 | } 434 | 435 | func (dec *amf0Decoder) readStructData(v reflect.Value) (err error) { 436 | m := getStructMapping(v.Type()) 437 | var n string 438 | for { 439 | if n, err = dec.readString(false); err != nil { 440 | return 441 | } else if n == "" { 442 | break 443 | } 444 | if f := m.names[n]; f != nil { 445 | decodeValue(v.Field(f.index), dec) 446 | continue 447 | } 448 | if err = dec.Skip(); err != nil { 449 | return 450 | } 451 | } 452 | dec.next(1) 453 | return 454 | } 455 | 456 | func (dec *amf0Decoder) readMap(v reflect.Value) (err error) { 457 | if dec.next(1) { 458 | switch m := dec.b[0]; m { 459 | case amf0Array: 460 | dec.next(4) 461 | fallthrough 462 | case amf0Object: 463 | err = dec.readMapData(v) 464 | default: 465 | err = &errUnexpectedMarker{m, v.Type().String()} 466 | } 467 | } else { 468 | err = dec.err 469 | } 470 | return 471 | } 472 | 473 | func (dec *amf0Decoder) readMapData(v reflect.Value) (err error) { 474 | e := v.Type().Elem() 475 | if v.IsNil() { 476 | v.Set(reflect.MakeMap(v.Type())) 477 | } 478 | var n string 479 | for { 480 | if n, err = dec.readString(false); err != nil { 481 | return 482 | } else if n == "" { 483 | break 484 | } 485 | p := reflect.New(e) 486 | if err = decodeValue(p, dec); err != nil { 487 | return 488 | } 489 | v.SetMapIndex(reflect.ValueOf(n), p.Elem()) 490 | } 491 | dec.next(1) 492 | return 493 | } 494 | 495 | func (dec *amf0Decoder) readSlice(v reflect.Value) (err error) { 496 | if dec.next(1) { 497 | switch m := dec.b[0]; m { 498 | case amf0StrictArray: 499 | err = dec.readSliceData(v) 500 | default: 501 | err = &errUnexpectedMarker{m, v.Type().String()} 502 | } 503 | } else { 504 | err = dec.err 505 | } 506 | return 507 | } 508 | 509 | func (dec *amf0Decoder) readSliceData(v reflect.Value) (err error) { 510 | if !dec.next(4) { 511 | return dec.err 512 | } 513 | k := v.Type().Elem() 514 | n := int(be.Uint32(dec.b)) 515 | if v.IsNil() { 516 | v.Set(reflect.MakeSlice(v.Type(), 0, 10)) 517 | } 518 | for i := 0; i < n; i++ { 519 | p := reflect.New(k) 520 | if err = decodeValue(p, dec); err != nil { 521 | return 522 | } 523 | v.Set(reflect.Append(v, p.Elem())) 524 | } 525 | return 526 | } 527 | 528 | func (dec *amf0Decoder) readStrictArray() (v []interface{}, err error) { 529 | err = dec.readSliceData(reflect.ValueOf(v)) 530 | return 531 | } 532 | 533 | func (dec *amf0Decoder) readObject() (v map[string]interface{}, err error) { 534 | err = dec.readMapData(reflect.ValueOf(v)) 535 | return 536 | } 537 | 538 | func (dec *amf0Decoder) skipValue(m uint8) bool { 539 | switch m { 540 | case amf0Number: 541 | return dec.next(8) 542 | case amf0Boolean: 543 | return dec.next(1) 544 | case amf0String: 545 | return dec.skipString(false) 546 | case amf0Object: 547 | return dec.skipObject() 548 | case amf0Null, amf0Undefined: 549 | return true 550 | case amf0Reference: 551 | return dec.next(2) 552 | case amf0Array: 553 | return dec.next(2) && dec.skipObject() 554 | case amf0StrictArray: 555 | return dec.skipStrictArray() 556 | case amf0Date: 557 | return dec.next(10) 558 | case amf0StringExt, amf0Xml: 559 | return dec.skipString(true) 560 | case amf0Instance: 561 | return dec.skipString(false) && dec.skipObject() 562 | default: 563 | dec.err = ErrFormat 564 | } 565 | return false 566 | } 567 | 568 | func (dec *amf0Decoder) skipString(ext bool) bool { 569 | if ext { 570 | if dec.next(4) { 571 | return dec.next(int(be.Uint32(dec.b))) 572 | } 573 | } else { 574 | if dec.next(2) { 575 | return dec.next(int(be.Uint16(dec.b))) 576 | } 577 | } 578 | return false 579 | } 580 | 581 | func (dec *amf0Decoder) skipObject() bool { 582 | for dec.next(2) { 583 | n := int(be.Uint16(dec.b)) 584 | if dec.next(n) && n > 0 && dec.Skip() == nil { 585 | continue 586 | } 587 | break 588 | } 589 | return dec.next(1) 590 | } 591 | 592 | func (dec *amf0Decoder) skipStrictArray() bool { 593 | if dec.next(4) { 594 | n := int(be.Uint32(dec.b)) 595 | for n > 0 && dec.Skip() == nil { 596 | n-- 597 | } 598 | return n == 0 599 | } 600 | return false 601 | } 602 | 603 | func getFloat64(b []byte) float64 { 604 | return math.Float64frombits(be.Uint64(b)) 605 | } 606 | 607 | func putFloat64(b []byte, v float64) { 608 | be.PutUint64(b, math.Float64bits(v)) 609 | } 610 | 611 | func putUint24(b []byte, v uint32) { 612 | b[0] = byte(v >> 16) 613 | b[1] = byte(v >> 8) 614 | b[2] = byte(v) 615 | } 616 | 617 | var be = binary.BigEndian 618 | -------------------------------------------------------------------------------- /amf/amf0_test.go: -------------------------------------------------------------------------------- 1 | package amf 2 | 3 | import ( 4 | "encoding/hex" 5 | "encoding/json" 6 | "math" 7 | "reflect" 8 | "testing" 9 | "time" 10 | ) 11 | 12 | type testMap map[string]interface{} 13 | 14 | type testStruct struct { 15 | Zero interface{} `amf:"zero"` 16 | One int `amf:"one"` 17 | Two string `amf:"two"` 18 | Three float64 `amf:"three"` 19 | Four int `amf:"four"` 20 | Five []byte `amf:"five"` 21 | Six []int `amf:"six"` 22 | Seven time.Time `amf:"seven"` 23 | Eight testMap `amf:"eight"` 24 | Nine struct { 25 | A string `amf:"a"` 26 | } `amf:"nine"` 27 | } 28 | 29 | func TestEncodeDecodeStruct(t *testing.T) { 30 | ts, _ := time.Parse("02 Jan 06 15:04", "02 Jan 06 15:04") 31 | four := 4 32 | five := []byte("five") 33 | in := &testStruct{ 34 | Zero: nil, 35 | One: 1, 36 | Two: "2", 37 | Three: 3, 38 | Four: four, 39 | Five: five, 40 | Six: []int{0, 1, 2, 3, 4, 5}, 41 | Seven: ts, 42 | Eight: testMap{ 43 | "a": float64(1), 44 | "b": "2", 45 | "c": nil, 46 | }, 47 | } 48 | in.Nine.A = "inline" 49 | enc := NewEncoder(0) 50 | err := enc.Encode(in) 51 | if err != nil { 52 | t.Fatal("encode:", err) 53 | } 54 | b := enc.Bytes() 55 | 56 | out := &testStruct{} 57 | dec := NewDecoder(0, b) 58 | err = dec.Decode(out) 59 | if err != nil { 60 | t.Fatal("decode:", err) 61 | } 62 | 63 | b, _ = json.Marshal(out) 64 | if !reflect.DeepEqual(in, out) { 65 | t.Fatalf("decode: %v != %v", in, out) 66 | } 67 | } 68 | 69 | func TestPlainTypes(t *testing.T) { 70 | decode := func(h string, v interface{}) { 71 | b, err := hex.DecodeString(h) 72 | if err != nil { 73 | t.Fatal("hex:", h) 74 | } 75 | dec := NewDecoder(0, b) 76 | var r interface{} 77 | err = dec.Decode(&r) 78 | if err != nil { 79 | t.Fatal("decode:", err, v) 80 | } 81 | if r != v { 82 | t.Fatalf("decode: %v != %v", r, v) 83 | } 84 | } 85 | encode := func(v interface{}, h string) { 86 | enc := NewEncoder(0) 87 | err := enc.Encode(v) 88 | if err != nil { 89 | t.Fatal("encode:", err, v) 90 | } 91 | b := enc.Bytes() 92 | if r := hex.EncodeToString(b); r != h { 93 | t.Fatalf("encode: %v %s != %s", v, r, h) 94 | } 95 | } 96 | assert := func(v interface{}, h string, r interface{}) { 97 | encode(v, h) 98 | decode(h, r) 99 | } 100 | assert(nil, "05", nil) 101 | assert("Hello", "02000548656c6c6f", "Hello") 102 | assert("Привет", "02000cd09fd180d0b8d0b2d0b5d182", "Привет") 103 | assert(true, "0101", true) 104 | assert(false, "0100", false) 105 | assert(uint8(1), "003ff0000000000000", float64(1)) 106 | assert(uint16(2), "004000000000000000", float64(2)) 107 | assert(uint32(3), "004008000000000000", float64(3)) 108 | assert(uint64(4), "004010000000000000", float64(4)) 109 | assert(uint(5), "004014000000000000", float64(5)) 110 | assert(uintptr(6), "004018000000000000", float64(6)) 111 | assert(uint64(math.MaxUint64), "0043f0000000000000", float64(math.MaxUint64)) 112 | assert(0, "000000000000000000", float64(0)) 113 | assert(int8(-1), "00bff0000000000000", float64(-1)) 114 | assert(int16(-2), "00c000000000000000", float64(-2)) 115 | assert(int32(-3), "00c008000000000000", float64(-3)) 116 | assert(int64(-4), "00c010000000000000", float64(-4)) 117 | assert(int(-5), "00c014000000000000", float64(-5)) 118 | assert(math.MaxInt64, "0043e0000000000000", float64(math.MaxInt64)) 119 | assert(float32(1), "003ff0000000000000", float64(1)) 120 | assert(float64(1), "003ff0000000000000", float64(1)) 121 | assert(math.Inf(1), "007ff0000000000000", math.Inf(1)) 122 | assert(math.Inf(-1), "00fff0000000000000", math.Inf(-1)) 123 | assert(math.MaxFloat64, "007fefffffffffffff", float64(math.MaxFloat64)) 124 | 125 | ts, _ := time.Parse("02 Jan 06 15:04", "02 Jan 06 15:04") 126 | assert(ts, "0b427088ba56b000000000", ts) 127 | } 128 | -------------------------------------------------------------------------------- /amf/amf3.go: -------------------------------------------------------------------------------- 1 | package amf 2 | 3 | // 4 | //import ( 5 | // "reflect" 6 | // "time" 7 | //) 8 | // 9 | //const ( 10 | // amf3Undefined = uint8(0x00) // nil 11 | // amf3Null = uint8(0x01) // nil 12 | // amf3False = uint8(0x02) // false 13 | // amf3True = uint8(0x03) // true 14 | // amf3Integer = uint8(0x04) // int64 15 | // amf3Double = uint8(0x05) // float64 16 | // amf3String = uint8(0x06) // string 17 | // amf3XmlDoc = uint8(0x07) // string 18 | // amf3Date = uint8(0x08) // time.Time 19 | // amf3Array = uint8(0x09) // []interface{} or map[string]interface{} 20 | // amf3Object = uint8(0x0a) // map[string]interface{} 21 | // amf3Xml = uint8(0x0b) // string 22 | // amf3ByteArray = uint8(0x0c) // []byte 23 | // amf3IntVector = uint8(0x0d) // []int32 24 | // amf3UintVector = uint8(0x0e) // []uint32 25 | // amf3DoubleVector = uint8(0x0f) // []float64 26 | // amf3ObjectVector = uint8(0x10) // []interface{} 27 | // amf3Dictionary = uint8(0x11) // map[interface{}]interface{} 28 | //) 29 | // 30 | //type amf3Encoder struct { 31 | // *Writer 32 | //} 33 | // 34 | //func (enc *amf3Encoder) Encode(v interface{}) error { 35 | // return encodeValue(reflect.ValueOf(v), enc) 36 | //} 37 | // 38 | //func (enc *amf3Encoder) WriteNull() { 39 | // enc.Next(1)[0] = amf3Null 40 | //} 41 | // 42 | //func (enc *amf3Encoder) WriteBool(v bool) { 43 | // if b := enc.Next(1); v { 44 | // b[1] = amf3True 45 | // } else { 46 | // b[0] = amf3False 47 | // } 48 | //} 49 | // 50 | //func (enc *amf3Encoder) WriteInt(v int64) { 51 | // if 0 <= v && v < 0x40000000 { 52 | // enc.Next(1)[0] = amf3Integer 53 | // enc.writeUint29(uint32(v)) 54 | // } else { 55 | // enc.WriteFloat(float64(v)) 56 | // } 57 | //} 58 | // 59 | //func (enc *amf3Encoder) WriteUint(v uint64) { 60 | // if v < 0x40000000 { 61 | // enc.Next(1)[0] = amf3Integer 62 | // enc.writeUint29(uint32(v)) 63 | // } else { 64 | // enc.WriteFloat(float64(v)) 65 | // } 66 | //} 67 | // 68 | //func (enc *amf3Encoder) WriteFloat(v float64) { 69 | // b := enc.Next(9) 70 | // b[0] = amf3Double 71 | // putFloat64(b[1:], v) 72 | //} 73 | // 74 | //func (enc *amf3Encoder) WriteString(v string) { 75 | // b := enc.Next(1) 76 | // b[0] = amf3String 77 | // enc.writeString(v) 78 | //} 79 | // 80 | //func (enc *amf3Encoder) WriteBytes(v []byte) { 81 | // b := enc.Next(1) 82 | // b[0] = amf3ByteArray 83 | // if enc.writeReference(v) { 84 | // return 85 | // } 86 | // n := len(v) 87 | // enc.writeLen(n) 88 | // copy(enc.Next(n), v) 89 | //} 90 | // 91 | //func (enc *amf3Encoder) WriteTime(v time.Time) { 92 | // b := enc.Next(1) 93 | // b[0] = amf0Date 94 | // if enc.writeReference(v) { 95 | // return 96 | // } 97 | // b = enc.Next(9) 98 | // b[0] = 0x01 99 | // putFloat64(b[1:], float64(v.UnixNano()/1e6)) 100 | //} 101 | // 102 | //func (enc *amf3Encoder) writeReference(v interface{}) bool { 103 | // // TODO: implement references 104 | // return false 105 | //} 106 | // 107 | //func (enc *amf3Encoder) writeUint29(v uint32) { 108 | // if v < 0x80 { 109 | // b := enc.Next(1) 110 | // b[0] = byte(v) 111 | // } else if v < 0x4000 { 112 | // b := enc.Next(2) 113 | // b[0] = byte(v>>7 | 0x80) 114 | // b[1] = byte(v & 0x7f) 115 | // } else if v < 0x200000 { 116 | // b := enc.Next(3) 117 | // b[0] = byte(v>>14 | 0x80) 118 | // b[1] = byte(v>>7&0x7f | 0x80) 119 | // b[2] = byte(v & 0x7f) 120 | // } else if v < 0x40000000 { 121 | // b := enc.Next(4) 122 | // b[0] = byte(v>>22 | 0x80) 123 | // b[0] = byte(v>>15&0x7f | 0x80) 124 | // b[1] = byte(v>>8&0x7f | 0x80) 125 | // b[2] = byte(v) 126 | // } else { 127 | // // Not supported, use float 128 | // } 129 | //} 130 | // 131 | //func (enc *amf3Encoder) writeLen(v int) { 132 | // enc.writeUint29(uint32(v)<<1|0x01) 133 | //} 134 | // 135 | //func (enc *amf3Encoder) writeString(v string) { 136 | // if enc.writeReference(v) { 137 | // return 138 | // } 139 | // n := len(v) 140 | // enc.writeLen(n) 141 | // copy(enc.Next(n), v) 142 | //} 143 | // 144 | //func (enc *amf3Encoder) encodeEmpty() { 145 | // enc.Next(1)[0] = 0x01 146 | //} 147 | // 148 | //func (enc *amf3Encoder) encodeSlice(v reflect.Value) (err error) { 149 | // b := enc.Next(1) 150 | // b[0] = amf3Array 151 | // if enc.writeReference(v) { 152 | // return 153 | // } 154 | // n := v.Len() 155 | // enc.writeLen(n) 156 | // enc.encodeEmpty() 157 | // for i := 0; i < n; i++ { 158 | // if err = encodeValue(v.Index(i), enc); err != nil { 159 | // return 160 | // } 161 | // } 162 | // return 163 | //} 164 | // 165 | //func (enc *amf3Encoder) encodeStruct(v reflect.Value) (err error) { 166 | // b := enc.Next(1) 167 | // b[0] = amf3Array 168 | // if enc.writeReference(v) { 169 | // return 170 | // } 171 | // // .....0 = ref 172 | // // ....01 = traits-ref () 173 | // // ..d011 = traits (number of sealed traits member names) 174 | // // ...111 = traits-ext 175 | // 176 | // // 177 | // // TODO: reference map 178 | // //m := getStructMapping(v.Type()) 179 | // //for _, f := range m.fields { 180 | // // 181 | // //} 182 | // return errors.New("not implemented") 183 | //} 184 | // 185 | //func (enc *amf3Encoder) encodeMap(v reflect.Value) (err error) { 186 | // // TODO: reference map 187 | // return errors.New("not implemented") 188 | //} 189 | // 190 | //func (enc *amf3Encoder) encodeDict(v reflect.Value) (err error) { 191 | // // TODO: reference map 192 | // b := enc.Next(1) 193 | // b[0] = amf3Dictionary 194 | // n := v.Len() 195 | // enc.writeLen(n) 196 | // enc.Next(1)[0] = 0 197 | // for _, k := range v.MapKeys() { 198 | // if err = enc.EncodeValue(k); err != nil { 199 | // return 200 | // } 201 | // if err = enc.EncodeValue(v.MapIndex(k)); err != nil { 202 | // return 203 | // } 204 | // } 205 | // return 206 | //} 207 | // 208 | //// 209 | ////type amf3Decoder struct { 210 | //// *Reader 211 | ////} 212 | //// 213 | ////func (dec *amf3Decoder) Decode(v interface{}) error { 214 | //// return nil 215 | ////} 216 | //// 217 | ////func (dec *amf3Decoder) Skip() error { 218 | //// return nil 219 | ////} 220 | //// 221 | ////func (dec *amf3Decoder) DecodeNext() (interface{}, error) { 222 | //// return nil, nil 223 | ////} 224 | //// 225 | ////func (dec *amf3Decoder) DecodeInt() (int64, error) { 226 | //// return 0, nil 227 | ////} 228 | //// 229 | ////func (dec *amf3Decoder) DecodeUint() (uint64, error) { 230 | //// return 0, nil 231 | ////} 232 | //// 233 | ////func (dec *amf3Decoder) DecodeFloat() (float64, error) { 234 | //// return 0, nil 235 | ////} 236 | //// 237 | ////func (dec *amf3Decoder) DecodeString() (string, error) { 238 | //// return "", nil 239 | ////} 240 | ////func (dec *amf3Decoder) DecodeBytes() ([]byte, error) { 241 | //// return nil, nil 242 | ////} 243 | //// 244 | -------------------------------------------------------------------------------- /amf/decoder.go: -------------------------------------------------------------------------------- 1 | package amf 2 | 3 | import ( 4 | "io" 5 | "time" 6 | ) 7 | 8 | type Unmarshaler interface { 9 | UnmarshalAMF(r *Reader) error 10 | } 11 | 12 | type Decoder interface { 13 | Decode(v interface{}) error 14 | Skip() error 15 | ReadBool() (bool, error) 16 | ReadInt() (int64, error) 17 | ReadUint() (uint64, error) 18 | ReadFloat() (float64, error) 19 | ReadString() (string, error) 20 | ReadBytes() ([]byte, error) 21 | ReadTime() (time.Time, error) 22 | } 23 | 24 | func NewDecoder(ver uint8, v []byte) Decoder { 25 | r := &Reader{buf: v} 26 | //if ver == 3 { 27 | // return &amf3Decoder{Reader: r} 28 | //} 29 | return &amf0Decoder{Reader: r} 30 | } 31 | 32 | type Reader struct { 33 | buf []byte 34 | pos int 35 | } 36 | 37 | func (r *Reader) Next(n int) ([]byte, error) { 38 | p := r.pos + n 39 | if len(r.buf) < r.pos+n { 40 | return nil, io.EOF 41 | } 42 | off := r.pos 43 | r.pos = p 44 | return r.buf[off : off+n], nil 45 | } 46 | -------------------------------------------------------------------------------- /amf/encoder.go: -------------------------------------------------------------------------------- 1 | package amf 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | // Marshaler is the interface implemented by objects that can marshal themselves into valid AMF. 8 | type Marshaler interface { 9 | MarshalAMF(w *Writer) error 10 | } 11 | 12 | type Encoder interface { 13 | Encode(v interface{}) error 14 | WriteNull() 15 | WriteBool(v bool) 16 | WriteInt(v int64) 17 | WriteUint(v uint64) 18 | WriteFloat(v float64) 19 | WriteString(v string) 20 | WriteBytes(v []byte) 21 | WriteTime(v time.Time) 22 | Reset() 23 | Next(n int) []byte 24 | Bytes() []byte 25 | } 26 | 27 | func NewEncoder(ver uint8) Encoder { 28 | w := &Writer{} 29 | //if ver == 3 { 30 | // return &amf3Encoder{writer:w} 31 | //} 32 | return &amf0Encoder{Writer: w} 33 | } 34 | 35 | type Writer struct { 36 | buf []byte 37 | pos int 38 | } 39 | 40 | func (w *Writer) Reset() { 41 | w.pos = 0 42 | } 43 | 44 | func (w *Writer) Next(n int) (b []byte) { 45 | p := w.pos + n 46 | if len(w.buf) < p { 47 | b := make([]byte, (1+((p-1)>>10))<<10) 48 | if w.pos > 0 { 49 | copy(b, w.buf[:w.pos]) 50 | } 51 | w.buf = b 52 | } 53 | b, w.pos = w.buf[w.pos:p], p 54 | return 55 | } 56 | 57 | func (w *Writer) Bytes() []byte { 58 | return w.buf[:w.pos] 59 | } 60 | -------------------------------------------------------------------------------- /amf/mapping.go: -------------------------------------------------------------------------------- 1 | package amf 2 | 3 | import ( 4 | "errors" 5 | "reflect" 6 | "runtime" 7 | "strconv" 8 | "strings" 9 | "sync" 10 | "time" 11 | ) 12 | 13 | var ErrFormat = errors.New("amf: incorrect format") 14 | 15 | var timeType = reflect.TypeOf(time.Time{}) 16 | 17 | var cache map[reflect.Type]*mapping 18 | var mu sync.RWMutex 19 | 20 | func getStructMapping(t reflect.Type) (m *mapping) { 21 | mu.RLock() 22 | m = cache[t] 23 | mu.RUnlock() 24 | if m != nil { 25 | return 26 | } 27 | mu.Lock() 28 | defer mu.Unlock() 29 | if cache == nil { 30 | cache = make(map[reflect.Type]*mapping) 31 | } else if m = cache[t]; m != nil { 32 | return 33 | } 34 | n := t.NumField() 35 | m = &mapping{ 36 | make(map[string]*field), 37 | make([]*field, 0, n), 38 | } 39 | for i := 0; i < n; i++ { 40 | f := t.Field(i) 41 | tag := strings.Split(f.Tag.Get("amf"), ",") 42 | name := tag[0] 43 | if name == "" { 44 | continue 45 | } 46 | fc := &field{index: i, name: name} 47 | if len(tag) > 1 { 48 | fc.opt = tag[1] == "omitempty" 49 | } 50 | m.names[name] = fc 51 | m.fields = append(m.fields, fc) 52 | } 53 | return 54 | } 55 | 56 | type mapping struct { 57 | names map[string]*field 58 | fields []*field 59 | } 60 | 61 | type field struct { 62 | index int 63 | name string 64 | opt bool 65 | } 66 | 67 | func isEmptyValue(v reflect.Value) bool { 68 | // TODO: detect empty values 69 | return false 70 | } 71 | 72 | type errEncUnsType reflect.Kind 73 | 74 | func (err errEncUnsType) Error() string { 75 | return "amf: encode " + reflect.Kind(err).String() 76 | } 77 | 78 | type errUnsupportedType struct { 79 | t reflect.Type 80 | } 81 | 82 | func (err *errUnsupportedType) Error() string { 83 | return "amf: unsupported type " + err.t.String() 84 | } 85 | 86 | type errUnsupportedKeyType struct { 87 | t reflect.Type 88 | } 89 | 90 | func (err *errUnsupportedKeyType) Error() string { 91 | return "amf: unsupported key type: " + err.t.String() 92 | } 93 | 94 | type errUnsupportedMarker struct { 95 | m uint8 96 | } 97 | 98 | func (err *errUnsupportedMarker) Error() string { 99 | return "amf: unsupported marker: 0x" + strconv.FormatInt(int64(err.m), 16) 100 | } 101 | 102 | type errUnsVersion uint8 103 | 104 | func (err errUnsVersion) Error() string { 105 | return "amf: unsupported version: " + strconv.Itoa(int(err)) 106 | } 107 | 108 | type errUnexpectedMarker struct { 109 | marker uint8 110 | expected string 111 | } 112 | 113 | func (err errUnexpectedMarker) Error() string { 114 | return "amf: marker 0x" + strconv.FormatInt(int64(err.marker), 16) + ", expected 0x" + err.expected 115 | } 116 | 117 | var errDecodeNil = errors.New("amf: decoding nil") 118 | 119 | var errDecodeNotPtr = errors.New("amf: decoding not a pointer") 120 | 121 | type valueEncoder interface { 122 | Encoder 123 | writeSlice(v reflect.Value) error 124 | writeMap(v reflect.Value) error 125 | writeStruct(v reflect.Value) error 126 | } 127 | 128 | func encodeValue(v reflect.Value, enc valueEncoder) error { 129 | switch v.Kind() { 130 | case reflect.Invalid: 131 | enc.WriteNull() 132 | case reflect.Bool: 133 | enc.WriteBool(v.Bool()) 134 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 135 | enc.WriteInt(v.Int()) 136 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 137 | enc.WriteUint(v.Uint()) 138 | case reflect.Float32, reflect.Float64: 139 | enc.WriteFloat(v.Float()) 140 | case reflect.String: 141 | enc.WriteString(v.String()) 142 | case reflect.Slice, reflect.Array: 143 | switch v.Type().Elem().Kind() { 144 | case reflect.Uint8: 145 | enc.WriteBytes(v.Bytes()) 146 | default: 147 | return enc.writeSlice(v) 148 | } 149 | case reflect.Struct: 150 | if v.Type() == timeType { 151 | enc.WriteTime(v.Interface().(time.Time)) 152 | } else { 153 | return enc.writeStruct(v) 154 | } 155 | case reflect.Map: 156 | return enc.writeMap(v) 157 | case reflect.Ptr: 158 | return encodeValue(v.Elem(), enc) 159 | case reflect.Interface: 160 | if !v.IsValid() { 161 | enc.WriteNull() 162 | } else { 163 | return encodeValue(v.Elem(), enc) 164 | } 165 | default: 166 | return errEncUnsType(v.Kind()) 167 | } 168 | return nil 169 | } 170 | 171 | type valueDecoder interface { 172 | Decoder 173 | readSlice(v reflect.Value) error 174 | readMap(v reflect.Value) error 175 | readStruct(v reflect.Value) error 176 | read() (interface{}, error) 177 | } 178 | 179 | func decodeValue(v reflect.Value, dec valueDecoder) (err error) { 180 | defer func() { 181 | if r := recover(); r != nil { 182 | if _, ok := r.(runtime.Error); ok { 183 | panic(r) 184 | } 185 | err = r.(error) 186 | } 187 | }() 188 | switch v.Kind() { 189 | case reflect.Bool: 190 | var r bool 191 | if r, err = dec.ReadBool(); err == nil { 192 | v.SetBool(r) 193 | } 194 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 195 | var r int64 196 | if r, err = dec.ReadInt(); err == nil { 197 | v.SetInt(r) 198 | } 199 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 200 | var r uint64 201 | if r, err = dec.ReadUint(); err == nil { 202 | v.SetUint(r) 203 | } 204 | case reflect.Float32, reflect.Float64: 205 | var r float64 206 | if r, err = dec.ReadFloat(); err == nil { 207 | v.SetFloat(r) 208 | } 209 | case reflect.String: 210 | var r string 211 | if r, err = dec.ReadString(); err == nil { 212 | v.SetString(r) 213 | } 214 | case reflect.Slice: 215 | switch v.Type().Elem().Kind() { 216 | case reflect.Uint8: 217 | var b []byte 218 | if b, err = dec.ReadBytes(); err == nil { 219 | v.SetBytes(b) 220 | } 221 | default: 222 | err = dec.readSlice(v) 223 | } 224 | case reflect.Struct: 225 | if v.Type() == timeType { 226 | var r time.Time 227 | if r, err = dec.ReadTime(); err == nil { 228 | v.Set(reflect.ValueOf(r)) 229 | } 230 | } else { 231 | err = dec.readStruct(v) 232 | } 233 | case reflect.Map: 234 | switch v.Type().Key().Kind() { 235 | case reflect.String: 236 | err = dec.readMap(v) 237 | default: 238 | err = &errUnsupportedKeyType{v.Type().Key()} 239 | } 240 | case reflect.Ptr: 241 | if v.IsNil() { 242 | v.Set(reflect.New(v.Type().Elem())) 243 | } 244 | err = decodeValue(v.Elem(), dec) 245 | case reflect.Interface: 246 | var r interface{} 247 | if r, err = dec.read(); r != nil && err == nil { 248 | v.Set(reflect.ValueOf(r)) 249 | } 250 | default: 251 | dec.Skip() 252 | err = &errUnsupportedType{v.Type()} 253 | } 254 | return 255 | } 256 | -------------------------------------------------------------------------------- /flv/flv.go: -------------------------------------------------------------------------------- 1 | package flv 2 | 3 | type Header struct { 4 | Signature uint32 5 | Version uint8 6 | Flags uint8 7 | } 8 | 9 | func NewHeader(flags uint8) *Header { 10 | return &Header{sign, 1, flags} 11 | } 12 | 13 | type Tag struct { 14 | Type uint8 15 | Size int 16 | Time int64 17 | Stream uint32 18 | } 19 | 20 | const ( 21 | TypeAudio = uint8(0x8) 22 | TypeVideo = uint8(0x9) 23 | TypeData = uint8(0x12) 24 | ) 25 | 26 | const sign = uint32(0x464C56) 27 | -------------------------------------------------------------------------------- /flv/reader.go: -------------------------------------------------------------------------------- 1 | package flv 2 | 3 | import ( 4 | "bufio" 5 | "errors" 6 | "io" 7 | ) 8 | 9 | // ErrFormat is returned by Reader when a stream is not a valid FLV data. 10 | var ErrFormat = errors.New("flv: incorrect format") 11 | 12 | // Reader reads FLV header and tags from an input stream. 13 | type Reader struct { 14 | buf *bufio.Reader 15 | seeker io.ReadSeeker 16 | r io.Reader 17 | skip *io.LimitedReader 18 | header *Header 19 | tag *Tag 20 | } 21 | 22 | // NewReader returns a new reader that reads from r. 23 | func NewReader(r io.Reader) *Reader { 24 | seeker, _ := r.(io.ReadSeeker) 25 | buf, _ := r.(*bufio.Reader) 26 | if buf != nil { 27 | buf = bufio.NewReader(r) 28 | } 29 | return &Reader{buf: buf, seeker: seeker, r: r} 30 | } 31 | 32 | // Read reads FLV header 33 | func (r *Reader) ReadHeader() (h *Header, err error) { 34 | if h = r.header; h != nil { 35 | return 36 | } 37 | var b []byte 38 | if b, err = r.buf.Peek(13); err != nil { 39 | return 40 | } 41 | h = &Header{ 42 | Signature: getUint24(b[0:]), 43 | Version: b[3], 44 | Flags: b[4], 45 | } 46 | off := getUint32(b[5:]) - 9 47 | if h.Signature != sign || h.Version != 1 || off < 0 { 48 | return nil, ErrFormat 49 | } 50 | if _, err = r.buf.Discard(15); err != nil { 51 | return 52 | } 53 | if off > 0 { 54 | r.skip = io.LimitReader(r.buf, off) 55 | } 56 | return 57 | } 58 | 59 | // Read reads FLV tag and returns data reader. 60 | // Data reader is not valid after next Read. 61 | func (r *Reader) ReadTag() (tag *Tag, data io.Reader, err error) { 62 | if r.header == nil { 63 | if _, err = r.ReadHeader(); err != nil { 64 | return 65 | } 66 | } 67 | r.Skip() 68 | var b []byte 69 | if b, err = r.buf.Peek(15); err != nil { 70 | return 71 | } 72 | if _, err = r.buf.Discard(15); err != nil { 73 | return 74 | } 75 | if p := getUint32(b); r.tag != nil && r.tag.Size+11 != p { 76 | err = ErrFormat 77 | return 78 | } 79 | tag = &Tag{ 80 | Type: b[4], 81 | Size: getInt24(b[5:]), 82 | Time: getTime(b[8:]), 83 | Stream: getUint24(b[12:]), 84 | } 85 | data = io.LimitReader(r.buf, tag.Size) 86 | r.tag, r.skip = tag, data 87 | return 88 | } 89 | 90 | // Skip skips unread data before next FLV tag 91 | func (r *Reader) Skip() (err error) { 92 | if r.skip == nil { 93 | return 94 | } 95 | n := r.skip.N 96 | if n > 0 { 97 | b := int64(r.buf.Buffered()) 98 | if b < n && r.seeker != nil { 99 | _, err = r.seeker.Seek(n-b, 1) 100 | r.buf.Reset(r.r) 101 | } else { 102 | _, err = r.buf.Discard(n) 103 | } 104 | } 105 | return 106 | } 107 | 108 | func getInt24(b []byte) int { 109 | return int(b[2]) | int(b[1])<<8 | int(b[0])<<16 110 | } 111 | 112 | func getUint24(b []byte) uint32 { 113 | return uint32(b[2]) | uint32(b[1])<<8 | uint32(b[0])<<16 114 | } 115 | 116 | func getTime(b []byte) int64 { 117 | return int64(getUint24(b) | uint32(b[3])<<24) 118 | } 119 | 120 | func getUint32(b []byte) uint32 { 121 | return uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24 122 | } 123 | -------------------------------------------------------------------------------- /flv/writer.go: -------------------------------------------------------------------------------- 1 | package flv 2 | 3 | import ( 4 | "bufio" 5 | "errors" 6 | "io" 7 | ) 8 | 9 | // ErrFormat is returned by Reader when a stream is not a valid FLV data. 10 | var ErrFormat = errors.New("flv: incorrect format") 11 | 12 | // Writer writes FLV header and tags from an input stream. 13 | type Writer struct { 14 | buf *bufio.Writer 15 | seeker io.WriteSeeker 16 | r io.Writer 17 | skip *io.LimitedReader 18 | header *Header 19 | tag *Tag 20 | } 21 | 22 | // NewReader returns a new reader that reads from r. 23 | func NewWriter(w io.Writer) *Writer { 24 | seeker, _ := w.(io.WriteSeeker) 25 | buf, _ := w.(*bufio.Writer) 26 | if buf != nil { 27 | buf = bufio.NewWriter(w) 28 | } 29 | return &Writer{buf, seeker, w} 30 | } 31 | 32 | // Read reads FLV header 33 | func (r *Reader) WriteHeader() (h *Header, err error) { 34 | if h = r.header; h != nil { 35 | return 36 | } 37 | var b []byte 38 | if b, err = r.buf.Peek(13); err != nil { 39 | return 40 | } 41 | h = &Header{ 42 | Signature: getUint24(b[0:]), 43 | Version: b[3], 44 | Flags: b[4], 45 | } 46 | off := getUint32(b[5:]) - 9 47 | if h.Signature != sign || h.Version != 1 || off < 0 { 48 | return nil, ErrFormat 49 | } 50 | if off > 0 { 51 | r.skip = io.LimitReader(r.buf, off) 52 | } 53 | return 54 | } 55 | 56 | // Read reads FLV tag and returns data reader. 57 | // Data reader is not valid after next Read. 58 | func (r *Reader) ReadTag() (tag *Tag, data io.Reader, err error) { 59 | if r.header == nil { 60 | if _, err = r.ReadHeader(); err != nil { 61 | return 62 | } 63 | } 64 | r.Skip() 65 | var b []byte 66 | if b, err = r.buf.Peek(15); err != nil { 67 | return 68 | } 69 | if p := getUint32(b); r.tag != nil && r.tag.Size+11 != p { 70 | err = ErrFormat 71 | return 72 | } 73 | tag = &Tag{ 74 | Type: b[4], 75 | Size: getInt24(b[5:]), 76 | Time: getTime(b[8:]), 77 | Stream: getUint24(b[12:]), 78 | } 79 | data = io.LimitReader(r.buf, tag.Size) 80 | r.tag, r.skip = tag, data 81 | return 82 | } 83 | 84 | // Skip skips unread data before next FLV tag 85 | func (r *Reader) Skip() (err error) { 86 | if r.skip == nil { 87 | return 88 | } 89 | n := r.skip.N 90 | if n > 0 { 91 | b := int64(r.buf.Buffered()) 92 | if b < n && r.seeker != nil { 93 | _, err = r.seeker.Seek(n-b, 1) 94 | r.buf.Reset(r.r) 95 | } else { 96 | _, err = r.buf.Discard(n) 97 | } 98 | } 99 | r.skip = nil 100 | return 101 | } 102 | -------------------------------------------------------------------------------- /rtmp/chunk.go: -------------------------------------------------------------------------------- 1 | package rtmp 2 | 3 | import ( 4 | "bufio" 5 | "encoding/binary" 6 | "io" 7 | "sync" 8 | ) 9 | 10 | const ( 11 | fmtFull = uint8(0x00) 12 | fmtStream = uint8(0x01) 13 | fmtDelta = uint8(0x02) 14 | fmtData = uint8(0x03) 15 | ) 16 | 17 | const timeOverflow = int64(0xffffff) 18 | 19 | type chunk struct { 20 | Id uint32 21 | Time int64 22 | Type uint8 23 | Stream uint32 24 | Data []byte 25 | } 26 | 27 | type reader struct { 28 | buf *bufio.Reader 29 | mux map[uint32]*chunkReader 30 | skip int 31 | size int 32 | } 33 | 34 | func newReader(r io.Reader) *reader { 35 | return &reader{ 36 | buf: bufio.NewReaderSize(r, bufferSize), 37 | mux: make(map[uint32]*chunkReader), 38 | size: 128, 39 | } 40 | } 41 | 42 | func (r *reader) ReadChunk() (ch *chunk, err error) { 43 | var fmt uint8 44 | var id uint32 45 | for { 46 | r.discard() 47 | if fmt, id, err = r.readHeader(); err != nil { 48 | return nil, err 49 | } 50 | cr, ok := r.mux[id] 51 | if !ok { 52 | cr = new(chunkReader) 53 | cr.Id = id 54 | r.mux[id] = cr 55 | } 56 | if ch, err = cr.Read(r, fmt); ch != nil || err != nil { 57 | return 58 | } 59 | } 60 | } 61 | 62 | func (r *reader) Peek(n int) ([]byte, error) { 63 | r.discard() 64 | r.skip = n 65 | return r.buf.Peek(n) 66 | } 67 | 68 | func (r *reader) Read(b []byte) (int, error) { 69 | r.discard() 70 | return r.buf.Read(b) 71 | } 72 | 73 | func (r *reader) discard() { 74 | if r.skip > 0 { 75 | r.buf.Discard(r.skip) 76 | r.skip = 0 77 | } 78 | } 79 | 80 | func (r *reader) readHeader() (fmt uint8, id uint32, err error) { 81 | var b byte 82 | if b, err = r.buf.ReadByte(); err != nil { 83 | return 84 | } 85 | fmt, id = b>>6&0x03, uint32(b&0x3f) 86 | if id == 0 { 87 | if b, err = r.buf.ReadByte(); err != nil { 88 | return 89 | } 90 | id = uint32(b) + 64 91 | } else if id == 1 { 92 | a, _ := r.buf.ReadByte() 93 | if b, err = r.buf.ReadByte(); err != nil { 94 | return 95 | } 96 | id = uint32(a)<<8 + uint32(b) + 64 97 | } 98 | return 99 | } 100 | 101 | type chunkReader struct { 102 | chunk 103 | buf []byte 104 | pos int 105 | len int 106 | } 107 | 108 | func (cr *chunkReader) Reset(n int) { 109 | if len(cr.buf) < n { 110 | cr.buf = make([]byte, (1+(n>>8))<<8) 111 | } 112 | cr.len, cr.pos = n, 0 113 | } 114 | 115 | func (cr *chunkReader) Read(r *reader, fmt uint8) (ch *chunk, err error) { 116 | switch fmt { 117 | case fmtFull: 118 | err = cr.readFullHeader(r) 119 | case fmtStream: 120 | err = cr.readStreamHeader(r) 121 | case fmtDelta: 122 | err = cr.readDeltaHeader(r) 123 | } 124 | if err != nil { 125 | return 126 | } 127 | return cr.readPayload(r) 128 | } 129 | 130 | func (cr *chunkReader) readPayload(r *reader) (ch *chunk, err error) { 131 | n := cr.len - cr.pos 132 | if n > r.size { 133 | n = r.size 134 | } else if cr.pos == 0 && cr.len <= bufferSize { 135 | if cr.Data, err = r.Peek(cr.len); err != nil { 136 | return 137 | } 138 | ch = &cr.chunk 139 | return 140 | } 141 | off := cr.pos + n 142 | if _, err = r.Read(cr.buf[cr.pos:off]); err != nil { 143 | return 144 | } 145 | if off == cr.len { 146 | cr.pos, cr.Data, ch = 0, cr.buf[:off], &cr.chunk 147 | } else { 148 | cr.pos = off 149 | } 150 | return 151 | } 152 | 153 | func (cr *chunkReader) readFullHeader(r *reader) (err error) { 154 | var b []byte 155 | if b, err = r.Peek(11); err != nil { 156 | return 157 | } 158 | cr.Time = int64(getUint24(b)) 159 | cr.Reset(int(getUint24(b[3:]))) 160 | cr.Type = b[6] 161 | cr.Stream = le.Uint32(b[7:]) 162 | if cr.Time == timeOverflow { 163 | if b, err = r.Peek(4); err != nil { 164 | return 165 | } 166 | cr.Time = int64(be.Uint32(b)) 167 | } 168 | return 169 | } 170 | 171 | func (cr *chunkReader) readStreamHeader(r *reader) (err error) { 172 | var b []byte 173 | if b, err = r.Peek(7); err != nil { 174 | return 175 | } 176 | dt := int64(getUint24(b)) 177 | cr.Reset(int(getUint24(b[3:]))) 178 | cr.Type = b[6] 179 | if dt == timeOverflow { 180 | if b, err = r.Peek(4); err != nil { 181 | return 182 | } 183 | dt = int64(be.Uint32(b)) 184 | } 185 | cr.Time += dt 186 | return 187 | } 188 | 189 | func (cr *chunkReader) readDeltaHeader(r *reader) (err error) { 190 | var b []byte 191 | if b, err = r.Peek(3); err != nil { 192 | return 193 | } 194 | dt := int64(getUint24(b)) 195 | cr.pos = 0 196 | if dt == timeOverflow { 197 | if b, err = r.Peek(4); err != nil { 198 | return 199 | } 200 | dt = int64(be.Uint32(b)) 201 | } 202 | cr.Time += dt 203 | return 204 | } 205 | 206 | type writer struct { 207 | mu sync.Mutex 208 | w io.Writer 209 | buf []byte 210 | pos int 211 | ack int 212 | size int 213 | } 214 | 215 | func newWriter(w io.Writer) *writer { 216 | return &writer{ 217 | w: w, 218 | size: 128, 219 | } 220 | } 221 | 222 | func (w *writer) next(n int) (b []byte) { 223 | p := w.pos + n 224 | if len(w.buf) < p { 225 | w.grow(n << 1) 226 | } 227 | b, w.pos = w.buf[w.pos:p], p 228 | return 229 | } 230 | 231 | func (w *writer) grow(n int) { 232 | p := w.pos + n 233 | if len(w.buf) < p { 234 | buf := make([]byte, (1+(p>>10))<<10) 235 | if w.pos > 0 { 236 | copy(buf, w.buf[:w.pos]) 237 | } 238 | w.buf = buf 239 | } 240 | } 241 | 242 | func (w *writer) WriteFull(id uint32, ts int64, ct uint8, str uint32, data []byte) { 243 | w.mu.Lock() 244 | defer w.mu.Unlock() 245 | 246 | n := len(data) 247 | w.grow(n + 18 + 3*int(n/w.size)) 248 | w.writeHeader(fmtFull, id) 249 | w.writeFullHeader(ts, ct, str, n) 250 | for n > 0 { 251 | if n > w.size { 252 | n -= copy(w.next(w.size), data) 253 | data = data[w.size:] 254 | w.writeHeader(fmtData, id) 255 | } else { 256 | copy(w.next(n), data) 257 | return 258 | } 259 | } 260 | } 261 | 262 | func (w *writer) writeHeader(fmt uint8, id uint32) { 263 | if fmt <<= 6; id < 64 { 264 | b := w.next(1) 265 | b[0] = fmt | uint8(id) 266 | } else if id -= 64; id <= 0xff { 267 | b := w.next(2) 268 | b[0] = fmt 269 | b[1] = uint8(id) 270 | } else { 271 | b := w.next(3) 272 | b[0] = fmt | 1 273 | be.PutUint16(b[1:], uint16(id)) 274 | } 275 | } 276 | 277 | func (w *writer) writeFullHeader(ts int64, ct uint8, str uint32, n int) { 278 | var b []byte 279 | if ts < timeOverflow { 280 | b = w.next(11) 281 | putUint24(b, uint32(ts)) 282 | } else { 283 | b = w.next(15) 284 | putUint24(b, uint32(timeOverflow)) 285 | be.PutUint32(b[11:], uint32(ts)) 286 | } 287 | putUint24(b[3:], uint32(n)) 288 | b[6] = ct 289 | le.PutUint32(b[7:], str) 290 | } 291 | 292 | func (w *writer) writeStreamHeader(dt int64, ct uint8, n int) { 293 | var b []byte 294 | if dt < timeOverflow { 295 | b = w.next(7) 296 | putUint24(b, uint32(dt)) 297 | } else { 298 | b = w.next(11) 299 | putUint24(b, uint32(timeOverflow)) 300 | be.PutUint32(b[7:], uint32(dt)) 301 | } 302 | putUint24(b[3:], uint32(n)) 303 | b[6] = ct 304 | } 305 | 306 | func (w *writer) writeDeltaHeader(dt int64) { 307 | if dt < timeOverflow { 308 | b := w.next(3) 309 | putUint24(b, uint32(dt)) 310 | } else { 311 | b := w.next(7) 312 | putUint24(b, uint32(timeOverflow)) 313 | be.PutUint32(b[4:], uint32(dt)) 314 | } 315 | } 316 | 317 | func (w *writer) Flush() (err error) { 318 | w.mu.Lock() 319 | defer w.mu.Unlock() 320 | 321 | if w.pos > 0 { 322 | _, err = w.w.Write(w.buf[:w.pos]) 323 | w.pos = 0 324 | } 325 | return 326 | } 327 | 328 | func getUint24(b []byte) uint32 { 329 | return uint32(b[2]) | uint32(b[1])<<8 | uint32(b[0])<<16 330 | } 331 | 332 | func putUint24(b []byte, v uint32) { 333 | b[0] = byte(v >> 16) 334 | b[1] = byte(v >> 8) 335 | b[2] = byte(v) 336 | } 337 | 338 | var be = binary.BigEndian 339 | var le = binary.LittleEndian 340 | -------------------------------------------------------------------------------- /rtmp/client.go: -------------------------------------------------------------------------------- 1 | package rtmp 2 | -------------------------------------------------------------------------------- /rtmp/conn.go: -------------------------------------------------------------------------------- 1 | package rtmp 2 | 3 | import ( 4 | "errors" 5 | "log" 6 | "net" 7 | "sync" 8 | "time" 9 | ) 10 | 11 | var ErrTimeout = errors.New("rtmp: i/o timeout") 12 | 13 | var bufferSize = 4096 14 | 15 | // A Conn represents the RTMP connection and implements the RTMP protocol over net.Conn interface. 16 | type Conn struct { 17 | net.Conn 18 | r *reader 19 | w *writer 20 | 21 | RequestTimeout time.Duration 22 | req requestMux 23 | 24 | str map[int64]*Stream 25 | strmu sync.RWMutex 26 | } 27 | 28 | // NewConn creates a Conn connection on the given net.Conn 29 | func NewConn(inner net.Conn) *Conn { 30 | c := &Conn{ 31 | Conn: inner, 32 | r: newReader(inner), 33 | w: newWriter(inner), 34 | RequestTimeout: 5 * time.Second, 35 | str: make(map[int64]*Stream), 36 | } 37 | return c 38 | } 39 | 40 | func (c *Conn) Serve() error { 41 | // var str *Stream 42 | for { 43 | ch, err := c.r.ReadChunk() 44 | if err != nil { 45 | return err 46 | } 47 | switch ch.Type { 48 | case msgSetChunkSize: 49 | if len(ch.Data) == 4 { 50 | c.r.size = int(be.Uint32(ch.Data)) 51 | log.Printf("chunk size=%v", c.r.size) 52 | } 53 | case msgAckSize: 54 | if len(ch.Data) == 4 { 55 | //r.ack = int(getUint32(result.Data)) 56 | } 57 | case msgSetBandwidth: 58 | if len(ch.Data) == 5 { 59 | //r.bw = int(getUint32(result.Data)) 60 | } 61 | case msgAmf0Command, msgAmf3Command: 62 | c.req.handleChunk(ch) 63 | default: 64 | log.Printf("chunk %+v", ch) 65 | } 66 | } 67 | } 68 | 69 | func (c *Conn) Request(name string, args ...interface{}) (*Response, error) { 70 | return c.req.request(c, 0, name, args...) 71 | } 72 | 73 | func (c *Conn) CreateStream() (str *Stream, err error) { 74 | var res *Response 75 | if res, err = c.Request("createStream", nil); err != nil { 76 | return 77 | } 78 | if err = res.Skip(); err != nil { 79 | return 80 | } 81 | var id int64 82 | if id, err = res.DecodeInt(); err != nil { 83 | return 84 | } 85 | str = &Stream{conn: c, id: uint32(id)} 86 | c.strmu.Lock() 87 | c.str[id] = str 88 | c.strmu.Unlock() 89 | return 90 | } 91 | 92 | func (c *Conn) Handshake() (err error) { 93 | b := make([]byte, 3073) 94 | ch := &handshakeHello{ 95 | Proto: 0x03, 96 | Time: uint32(0), 97 | Version: uint32(0), 98 | } 99 | ts := time.Now() 100 | if _, err = c.Write(ch.pack(b, nil)); err != nil { 101 | return 102 | } 103 | if _, err = c.Read(b[:3073]); err != nil { 104 | return 105 | } 106 | rt := time.Now().Sub(ts) 107 | sh, sa := &handshakeHello{}, &handshakeAck{} 108 | sh.unpack(b[:1537], nil) 109 | 110 | b = b[1537:3073] 111 | sa.unpack(b) 112 | if sh.Proto != ch.Proto { 113 | return ErrHandshake 114 | } 115 | ca := &handshakeAck{ 116 | Time: sh.Time, 117 | RecvTime: uint32(rt / time.Millisecond), 118 | } 119 | _, err = c.Write(ca.pack(b)) 120 | 121 | log.Printf("handshake done") 122 | 123 | c.w.size = 10000 124 | be.PutUint32(b, uint32(c.w.size)) 125 | c.w.WriteFull(0x2, 0, msgSetChunkSize, 0, b[:4]) 126 | be.PutUint32(b, 250000) 127 | c.w.WriteFull(0x2, 0, msgAckSize, 0, b[:4]) 128 | 129 | return nil 130 | } 131 | -------------------------------------------------------------------------------- /rtmp/handshake.go: -------------------------------------------------------------------------------- 1 | package rtmp 2 | 3 | import ( 4 | "bytes" 5 | "crypto/hmac" 6 | "crypto/rand" 7 | "crypto/sha256" 8 | "errors" 9 | ) 10 | 11 | var ErrHandshake = errors.New("rtmp: handshake error") 12 | 13 | type handshakeHello struct { 14 | Proto uint8 15 | Time uint32 16 | Version uint32 17 | Digest []byte // 32 bytes 18 | PubKey []byte 19 | } 20 | 21 | func (h *handshakeHello) pack(b []byte, key []byte) []byte { 22 | b[0] = h.Proto 23 | be.PutUint32(b[1:], h.Time) 24 | be.PutUint32(b[5:], h.Version) 25 | rand.Read(b[9:1537]) 26 | return b[:1537] 27 | } 28 | 29 | func (h *handshakeHello) unpack(b []byte, key []byte) { 30 | h.Proto = b[0] 31 | h.Time = be.Uint32(b[1:]) 32 | h.Version = be.Uint32(b[5:]) 33 | //if !h.unpackDigest(b, key, h.offset(b, 772) % 728 + 776, 768) { 34 | // h.unpackDigest(b, key, h.offset(b, 8) % 728 + 12, 1532) 35 | //} 36 | } 37 | 38 | func (h *handshakeHello) unpackDigest(b []byte, key []byte, off int, pos int) bool { 39 | if 0 <= off && off+32 <= len(b) { 40 | dig := b[off : off+32] 41 | crc := h.digest(b, key, off) 42 | if bytes.Compare(dig, crc) == 0 { 43 | h.Digest = crc 44 | off = h.offset(b, pos) 45 | if 0 < off && off+128 <= len(b) { 46 | h.PubKey = make([]byte, 128) 47 | copy(h.PubKey, b[off:off+128]) 48 | } 49 | return true 50 | } 51 | } 52 | return false 53 | } 54 | 55 | func (h *handshakeHello) offset(b []byte, off int) int { 56 | return int(b[off]) + int(b[off+1]) + int(b[off+2]) + int(b[off+3]) 57 | } 58 | 59 | func (h *handshakeHello) digest(b []byte, key []byte, off int) []byte { 60 | r := hmac.New(sha256.New, key) 61 | if off > 0 { 62 | r.Write(b[:off]) 63 | } 64 | if off+32 < len(b) { 65 | r.Write(b[off+32:]) 66 | } 67 | return r.Sum(nil) 68 | } 69 | 70 | type handshakeAck struct { 71 | Time uint32 72 | RecvTime uint32 73 | Digest []byte 74 | } 75 | 76 | func (a *handshakeAck) pack(b []byte) []byte { 77 | be.PutUint32(b, a.Time) 78 | be.PutUint32(b[4:], a.RecvTime) 79 | rand.Read(b[8:1536]) 80 | return b[:1536] 81 | } 82 | 83 | func (a *handshakeAck) unpack(b []byte) { 84 | a.Time = be.Uint32(b) 85 | a.RecvTime = be.Uint32(b[4:]) 86 | } 87 | 88 | func serverHandshake(c *Conn) (err error) { 89 | /*b := make([]byte, 3073) 90 | b[0] = 0x03 91 | ct, cv := uint32(wallclock()), uint32(0x10000000) 92 | be.PutUint32(b[1:], ct) 93 | be.PutUint32(b[5:], cv) 94 | rand.Read(b[9:1537]) 95 | if _, err = c.Write(b); err != nil { 96 | return 97 | } 98 | 99 | if _, err = c.Read(b[:1537]); err != nil { 100 | return 101 | } 102 | if b[0] != 0x03 { 103 | return ErrHandshake 104 | } 105 | ct, _ := getUint32(b[1:]), getUint32(b[5:]) 106 | st, sv := uint32(wallclock()), uint32(0x10000000) 107 | be.PutUint32(b[1:], st) 108 | be.PutUint32(b[5:], sv) 109 | be.PutUint32(b[1537:], st) 110 | be.PutUint32(b[1541:], ct) 111 | rand.Read(b[1545:]) 112 | if _, err = c.Write(b); err != nil { 113 | return 114 | } 115 | if _, err = c.Read(b[:1537]); err != nil { 116 | return 117 | } 118 | return*/ 119 | return nil 120 | } 121 | -------------------------------------------------------------------------------- /rtmp/message.go: -------------------------------------------------------------------------------- 1 | package rtmp 2 | 3 | const ( 4 | msgSetChunkSize = uint8(0x01) 5 | msgAbort = uint8(0x02) 6 | msgAck = uint8(0x03) 7 | msgUserControl = uint8(0x04) 8 | msgAckSize = uint8(0x05) 9 | msgSetBandwidth = uint8(0x06) 10 | msgEdge = uint8(0x07) 11 | msgAudio = uint8(0x08) 12 | msgVideo = uint8(0x09) 13 | msgAmf3Meta = uint8(0x0f) 14 | msgAmf3Shared = uint8(0x10) 15 | msgAmf3Command = uint8(0x11) 16 | msgAmf0Meta = uint8(0x12) 17 | msgAmf0Shared = uint8(0x13) 18 | msgAmf0Command = uint8(0x14) 19 | msgAggregate = uint8(0x15) 20 | msgMax = uint8(0x16) 21 | ) 22 | 23 | const ( 24 | ctrlStreamBegin = uint8(0x00) 25 | ctrlStreamEOF = uint8(0x01) 26 | ctrlStreamDry = uint8(0x02) 27 | ctrlStreamSetBuffer = uint8(0x03) 28 | ctrlStreamIsRecorded = uint8(0x04) 29 | ctrlPingRequest = uint8(0x06) 30 | ctrlPingResponse = uint8(0x07) 31 | ) 32 | 33 | const ( 34 | limitHard = uint8(0x00) 35 | limitSoft = uint8(0x01) 36 | limitDynamic = uint8(0x02) 37 | ) 38 | 39 | type ClientInfo struct { 40 | App string `amf:"app"` 41 | FlashVer string `amf:"flashVer"` 42 | Capabilities uint16 `amf:"capabilities"` 43 | AudioCodecs uint16 `amf:"audioCodecs"` 44 | VideoCodecs uint16 `amf:"videoCodecs"` 45 | //VideoFunction uint8 `amf:"videoFunction"` 46 | ObjectEncoding uint8 `amf:"objectEncoding"` 47 | //UsingProxy bool `amf:"fpad"` 48 | SwfURL string `amf:"swfUrl,omitempty"` 49 | PageUrl string `amf:"pageUrl,omitempty"` 50 | TcURL string `amf:"tcUrl,omitempty"` 51 | } 52 | -------------------------------------------------------------------------------- /rtmp/request.go: -------------------------------------------------------------------------------- 1 | package rtmp 2 | 3 | import ( 4 | "fmt" 5 | "github.com/pixelbender/go-rtmp/amf" 6 | "log" 7 | "sync" 8 | "time" 9 | ) 10 | 11 | type Response struct { 12 | amf.Decoder 13 | name string 14 | } 15 | 16 | func (req *Response) error() error { 17 | if req.name == "_error" { 18 | return &ErrorResponse{} 19 | } 20 | return nil 21 | } 22 | 23 | type ErrorResponse struct { 24 | amf.Decoder 25 | } 26 | 27 | func (err *ErrorResponse) Error() string { 28 | params := make([]interface{}, 0, 10) 29 | for { 30 | var v interface{} 31 | if err.Decode(&v) != nil { 32 | break 33 | } 34 | params = append(params, v) 35 | } 36 | return fmt.Sprintf("rtmp: error response %+v", params) 37 | } 38 | 39 | type requestMux struct { 40 | seq int64 41 | req map[int64]chan *Response 42 | mu sync.Mutex 43 | } 44 | 45 | func (r *requestMux) handleChunk(ch *chunk) error { 46 | d := make([]byte, len(ch.Data)) 47 | copy(d, ch.Data) 48 | 49 | // TODO: peeker 50 | 51 | dec := amf.NewDecoderBytes(0, d) 52 | name, err := dec.DecodeString() 53 | if err != nil { 54 | return err 55 | } 56 | id, err := dec.DecodeInt() 57 | if err != nil { 58 | return err 59 | } 60 | 61 | tx, res := r.getRequest(id), &Response{dec, name} 62 | if tx != nil { 63 | select { 64 | case tx <- res: 65 | default: 66 | } 67 | } else { 68 | log.Printf("unhandled: %v", id) 69 | for { 70 | var p interface{} 71 | err := res.Decode(&p) 72 | if err != nil { 73 | break 74 | } 75 | log.Printf("%+v", p) 76 | } 77 | } 78 | 79 | return nil 80 | } 81 | 82 | func (r *requestMux) newRequest() (id int64, tx chan *Response) { 83 | tx = make(chan *Response, 1) 84 | r.mu.Lock() 85 | r.seq++ 86 | id = r.seq 87 | if r.req == nil { 88 | r.req = make(map[int64]chan *Response) 89 | } 90 | r.req[id] = tx 91 | r.mu.Unlock() 92 | return 93 | } 94 | 95 | func (r *requestMux) getRequest(id int64) (tx chan *Response) { 96 | r.mu.Lock() 97 | tx = r.req[id] 98 | delete(r.req, id) 99 | r.mu.Unlock() 100 | return 101 | } 102 | 103 | func (r *requestMux) deleteRequest(id int64) { 104 | r.mu.Lock() 105 | delete(r.req, id) 106 | r.mu.Unlock() 107 | } 108 | 109 | func (r *requestMux) write(c *Conn, str uint32, name string, args ...interface{}) error { 110 | enc := amf.NewEncoder(0) 111 | enc.EncodeString(name) 112 | enc.EncodeInt(0) 113 | enc.EncodeNull() 114 | for _, it := range args { 115 | if err := enc.Encode(it); err != nil { 116 | return err 117 | } 118 | } 119 | c.w.WriteFull(0x3, 0, msgAmf0Command, str, enc.Bytes()) 120 | return nil 121 | } 122 | 123 | func (r *requestMux) request(c *Conn, str uint32, name string, args ...interface{}) (res *Response, err error) { 124 | id, tx := r.newRequest() 125 | defer r.deleteRequest(id) 126 | 127 | log.Printf("%s(%v) %+v", name, str, args) 128 | 129 | enc := amf.NewEncoder(0) 130 | enc.EncodeString(name) 131 | enc.EncodeInt(id) 132 | for _, it := range args { 133 | if err = enc.Encode(it); err != nil { 134 | return 135 | } 136 | } 137 | c.w.WriteFull(0x3, 0, msgAmf0Command, str, enc.Bytes()) 138 | 139 | if err = c.w.Flush(); err != nil { 140 | return 141 | } 142 | 143 | select { 144 | case res, _ = <-tx: 145 | if res == nil { 146 | err = ErrTimeout 147 | } else { 148 | err = res.error() 149 | } 150 | case <-time.After(c.RequestTimeout): 151 | err = ErrTimeout 152 | } 153 | 154 | return 155 | } 156 | -------------------------------------------------------------------------------- /rtmp/rtmp.go: -------------------------------------------------------------------------------- 1 | package rtmp 2 | 3 | import ( 4 | "net" 5 | "net/url" 6 | "strings" 7 | ) 8 | 9 | // TODO: dial with dialer 10 | 11 | func Dial(uri string) (*Conn, error) { 12 | u, err := url.Parse(uri) 13 | if err != nil { 14 | return nil, err 15 | } 16 | host, port, err := net.SplitHostPort(u.Host) 17 | if err != nil { 18 | host = u.Host 19 | } 20 | var c net.Conn 21 | switch strings.ToLower(u.Scheme) { 22 | case "rtmps": 23 | //... 24 | case "rtmp": 25 | if port == "" { 26 | port = "1935" 27 | } 28 | if c, err = net.Dial("tcp", net.JoinHostPort(host, port)); err != nil { 29 | return nil, err 30 | } 31 | } 32 | conn := NewConn(c) 33 | err = conn.Handshake() 34 | if err != nil { 35 | return nil, err 36 | } 37 | return conn, nil 38 | } 39 | -------------------------------------------------------------------------------- /rtmp/rtmp_test.go: -------------------------------------------------------------------------------- 1 | package rtmp 2 | 3 | import ( 4 | "testing" 5 | ) 6 | 7 | func TestRTMP(t *testing.T) { 8 | //c, err := Dial("rtmp://example.org/live") 9 | //if err != nil { 10 | // t.Fatal("dial rtmp:", err) 11 | //} 12 | //log.Printf("handshake done") 13 | //c.Setup() 14 | //for { 15 | // ch, err := c.ReadChunk() 16 | // if err != nil { 17 | // t.Fatal("read chunk:", err) 18 | // } 19 | // if ch.Type == msgAmf0Command { 20 | // dec := amf.NewDecoder(bytes.NewReader(ch.Data)) 21 | // for { 22 | // v, err := dec.DecodeNext() 23 | // if err != nil { 24 | // t.Fatal("decode error:", err) 25 | // } 26 | // log.Printf("decode: %#v", v) 27 | // } 28 | // } 29 | // log.Printf("chunk %#v", ch) 30 | //} 31 | } 32 | -------------------------------------------------------------------------------- /rtmp/server.go: -------------------------------------------------------------------------------- 1 | package rtmp 2 | 3 | import ( 4 | "crypto/tls" 5 | "fmt" 6 | "log" 7 | "net" 8 | "time" 9 | ) 10 | 11 | // Server represents a RTMP server. 12 | type Server struct { 13 | } 14 | 15 | func (srv *Server) ListenAndServe(network, addr string) error { 16 | switch network { 17 | case "tcp", "tcp4", "tcp6": 18 | l, err := net.Listen(network, addr) 19 | if err != nil { 20 | return err 21 | } 22 | return srv.Serve(tcpKeepAliveListener{l.(*net.TCPListener)}) 23 | } 24 | return fmt.Errorf("stun: listen unsupported network %v", network) 25 | } 26 | 27 | func (srv *Server) ListenAndServeTLS(network, addr, certFile, keyFile string) error { 28 | cert, err := tls.LoadX509KeyPair(certFile, keyFile) 29 | if err != nil { 30 | return err 31 | } 32 | config := &tls.Config{Certificates: []tls.Certificate{cert}} 33 | l, err := net.Listen(network, addr) 34 | if err != nil { 35 | return err 36 | } 37 | l = tls.NewListener(tcpKeepAliveListener{l.(*net.TCPListener)}, config) 38 | return srv.Serve(l) 39 | } 40 | 41 | // Multiple goroutines may invoke Serve on the same Listener simultaneously. 42 | func (srv *Server) Serve(l net.Listener) error { 43 | for { 44 | c, err := l.Accept() 45 | if err != nil { 46 | if ne, ok := err.(net.Error); ok && ne.Temporary() { 47 | time.Sleep(time.Millisecond) 48 | continue 49 | } 50 | return err 51 | } 52 | go srv.serveConn(c) 53 | } 54 | } 55 | 56 | func (srv *Server) serveConn(conn net.Conn) error { 57 | c := NewConn(conn) 58 | defer c.Close() 59 | //err := clientHandshake(c) 60 | var err error 61 | if err != nil { 62 | log.Printf("handshake: %v", err) 63 | } else { 64 | log.Printf("handshake done") 65 | } 66 | return nil 67 | } 68 | 69 | type tcpKeepAliveListener struct { 70 | *net.TCPListener 71 | } 72 | 73 | func (l tcpKeepAliveListener) Accept() (net.Conn, error) { 74 | c, err := l.AcceptTCP() 75 | if err != nil { 76 | return nil, err 77 | } 78 | c.SetKeepAlive(true) 79 | c.SetKeepAlivePeriod(time.Minute) 80 | return c, nil 81 | } 82 | -------------------------------------------------------------------------------- /rtmp/stream.go: -------------------------------------------------------------------------------- 1 | package rtmp 2 | 3 | type Stream struct { 4 | conn *Conn 5 | id uint32 6 | } 7 | 8 | func (s *Stream) Send(name string, args ...interface{}) { 9 | s.conn.req.write(s.conn, s.id, name, args...) 10 | } 11 | 12 | func (s *Stream) Flush() error { 13 | return s.conn.w.Flush() 14 | } 15 | 16 | func (s *Stream) Play(name string) error { 17 | s.Send("receiveAudio", true) 18 | s.Send("receiveVideo", true) 19 | s.Send("play", name) 20 | return s.Flush() 21 | } 22 | 23 | func (s *Stream) Close() error { 24 | s.Send("closeStream") 25 | return s.Flush() 26 | } 27 | --------------------------------------------------------------------------------