# rtc-go-sdk
接入BRTC的Go SDK, 需要先到百度智能云申请BRTC的AppID, 并设置环境变量APPID_GET_FROM_BAIDU, https://cloud.baidu.com/doc/RTC/index.html

## API 使用文档

### 1. 创建客户端

```go
client := baidurtc.NewBRTCClient()
```

### 2. 配置基本参数

```go
client.SetAppId("your_app_id").
    SetRoomName("room_name").
    SetUserId(12345).
    SetDisplayName("user_name").
    SetToken("your_token")
```

### 3. 设置角色模式

```go
// 设置为发布者（推流）
client.SetAsPublisher(true)

// 设置为订阅者（拉流）
client.SetAsListener(true)

// 设置为自动发布/订阅
client.SetAutoPublish(true)
client.SetAutoSubscribe(true)
```

### 4. 配置媒体选项

```go
// 设置音视频
client.SetHasAudio(true).
    SetHasVideo(true)

// 设置数据通道（用于发送文本/二进制消息）
client.SetHasData(true)

// 设置音视频编解码器
// 视频: H264, H265, VP8, VP9, AV1
// 音频: OPUS, PCMU, PCMA, G722, AAC
client.SetAudioCodec("OPUS").
    SetVideoCodec("H264")

// 设置音频输出为PCM格式
client.SetAudioOutPCM(true)

// 设置Opus输出为OGG格式
client.SetAudioOutOgg(true)
```

### 5. 设置回调 observer

#### 5.1 事件回调 (EventObserver)

```go
type MyEventObserver struct{}

func (m *MyEventObserver) OnDisconnected() {
    fmt.Println("连接断开")
}
func (m *MyEventObserver) OnListenerNACKs(nacks uint64) {}
func (m *MyEventObserver) OnNACKs(nacks uint64) {}

func (m *MyEventObserver) OnRTCLoginOK() {
    fmt.Println("登录成功")
}
func (m *MyEventObserver) OnRTCLoginTimeout() {
    fmt.Println("登录超时")
}
func (m *MyEventObserver) OnRTCLoginError() {
    fmt.Println("登录错误")
}
func (m *MyEventObserver) OnRTCConnectError() {
    fmt.Println("连接错误")
}
func (m *MyEventObserver) OnRTCWebrtcUp(feedId uint64) {
    fmt.Printf("WebRTC连接建立: %d\n", feedId)
}
func (m *MyEventObserver) OnRTCMediaStreamingEvent(feedId uint64, t int, sending bool) {
    fmt.Printf("媒体流事件: feedId=%d, type=%d, sending=%v\n", feedId, t, sending)
}
func (m *MyEventObserver) OnRTCHangUp(feedId uint64) {
    fmt.Printf("用户挂断: %d\n", feedId)
}
func (m *MyEventObserver) OnRTCFeedComing(feedId uint64, name string) {
    fmt.Printf("用户加入: feedId=%d, name=%s\n", feedId, name)
}
func (m *MyEventObserver) OnRTCFeedLeaving(feedId uint64) {
    fmt.Printf("用户离开: %d\n", feedId)
}
func (m *MyEventObserver) OnRTCUserMessage(feedId uint64, msg string) {
    fmt.Printf("收到用户消息: from=%d, msg=%s\n", feedId, msg)
}
func (m *MyEventObserver) OnRTCUserAttribute(feedId uint64, attr string) {
    fmt.Printf("用户属性: %d, %s\n", feedId, attr)
}
func (m *MyEventObserver) OnRTCUserIP(feedId uint64, ip string) {
    fmt.Printf("用户IP: %d, %s\n", feedId, ip)
}
func (m *MyEventObserver) OnRTCUserJoinedRoom(feedId uint64, name string, attr string) {
    fmt.Printf("用户加入房间: %d, %s, attr=%s\n", feedId, name, attr)
}
func (m *MyEventObserver) OnRTCUserLeavingRoom(feedId uint64, name string) {
    fmt.Printf("用户离开房间: %d, %s\n", feedId, name)
}
func (m *MyEventObserver) OnRTCError(error_code int, e string) {
    fmt.Printf("错误: code=%d, msg=%s\n", error_code, e)
}

func (m *MyEventObserver) OnPublisherJoined() {
    fmt.Println("发布者已加入")
}
func (m *MyEventObserver) OnRemoteMediaUnpublished(feedId uint64) {
    fmt.Printf("远程媒体取消发布: %d\n", feedId)
}
func (m *MyEventObserver) OnLocalMediaPublishedOK() {
    fmt.Println("本地媒体发布成功")
}
func (m *MyEventObserver) OnLocalMediaUnpublished() {
    fmt.Println("本地媒体取消发布")
}

client.SetEventObserver(&MyEventObserver{})
```

#### 5.2 媒体数据回调 (MediaObserver)

```go
type MyMediaObserver struct{}

func (m *MyMediaObserver) OnVideoFrame(feedid uint64, video []byte, tpe string) {
    // 收到视频帧数据
    // feedid: 用户ID
    // video: H264/H265视频数据
    // tpe: 视频类型
    fmt.Printf("收到视频: feedId=%d, type=%s, size=%d\n", feedid, tpe, len(video))
}

func (m *MyMediaObserver) OnAudioData(feedid uint64, audio []byte, samlplerate int, channels int) {
    // 收到音频数据（编码格式）
    fmt.Printf("收到音频: feedId=%d, size=%d, rate=%d, channels=%d\n",
        feedid, len(audio), samlplerate, channels)
}

func (m *MyMediaObserver) OnAudioPCM(feedid uint64, pcm []byte, sr int, ch int) {
    // 收到PCM原始音频数据
    fmt.Printf("收到PCM: feedId=%d, size=%d, rate=%d, channels=%d\n",
        feedid, len(pcm), sr, ch)
}

func (m *MyMediaObserver) OnTextData(feedid uint64, txt []byte) {
    // 收到文本消息
    fmt.Printf("收到文本: from=%d, msg=%s\n", feedid, string(txt))
}

func (m *MyMediaObserver) OnLocalMediaConnected() {
    fmt.Println("本地媒体已连接")
}
func (m *MyMediaObserver) OnLocalMediaDisconnected() {
    fmt.Println("本地媒体已断开")
}
func (m *MyMediaObserver) OnRemoteMediaConnected(feedId uint64) {
    fmt.Printf("远程媒体已连接: %d\n", feedId)
}
func (m *MyMediaObserver) OnRemoteMediaDisconnected(feedId uint64) {
    fmt.Printf("远程媒体已断开: %d\n", feedId)
}

client.SetMediaObserver(&MyMediaObserver{})
```

### 6. 登录连接

```go
client.Login()
```

### 7. 推流（发布者）

```go
// 开始推流
client.StartPublish()

// 发送视频帧
// f: H264视频数据
// d: 帧间隔时间
err := client.SendVideo(h264Data, 40*time.Millisecond)

// 发送音频帧（编码格式）
err := client.SendAudio(audioData, 20*time.Millisecond)

// 发送PCM原始音频（需先设置 SetAudioOutPCM 或使用对应编码）
err := client.SendAudioPCM(pcmData, 20*time.Millisecond)

// 停止推流
client.StopPublish()
```

### 8. 拉流（订阅者）

```go
// 订阅指定用户的流
client.SubscribeStreaming(feedId)

// 取消订阅
client.StopSubscribeStreaming(feedId)
```

### 9. 数据通道消息

```go
// 发送文本消息
err := client.SendData("hello")

// 发送二进制数据
err := client.SendRawData([]byte{0x01, 0x02, 0x03})

// 向指定用户发送消息
client.SendMessageToUser("message", userId)

// 获取指定用户IP
client.GetUserIP(userId)
```

### 10. 高级配置

```go
// 设置媒体服务器IP
client.SetMediaServerIP("192.168.1.1")

// 设置服务器URL
client.SetServerURL("webrtc://your-server-url")

// 设置ICE候选IP和端口
client.SetCandidateIP("192.168.1.100").
    SetCandidatePort(8000)

// 设置用户IP
client.SetUserIP("192.168.1.50")

// 设置订阅的FeedId
client.SetFeedId(12345)
```

### 11. 登出断开

```go
client.Logout()
```

### 12. 完整示例

```go
package main

import (
    "fmt"
    "time"

    "baidurtc"
)

type EventHandler struct{}
type MediaHandler struct{}

func main() {
    client := baidurtc.NewBRTCClient()

    // 配置
    client.SetAppId("your_app_id").
        SetRoomName("test_room").
        SetUserId(1001).
        SetDisplayName("publisher").
        SetToken("your_token").
        SetAsPublisher(true).
        SetHasAudio(true).
        SetHasVideo(true).
        SetAudioCodec("OPUS").
        SetVideoCodec("H264")

    // 设置回调
    client.SetEventObserver(&EventHandler{})
    client.SetMediaObserver(&MediaHandler{})

    // 登录
    client.Login()

    // 等待连接成功
    time.Sleep(3 * time.Second)

    // 开始推流
    client.StartPublish()

    // ... 发送媒体数据 ...

    // 登出
    time.Sleep(10 * time.Second)
    client.Logout()
}
```

## SDK 制作
```bash
zip -r BRTC.Go.SDK.Vx.zip baidurtc sdkdemo/res sdkdemo/src docs LICENSE README.md -x "*DS_Store" -x "*/dump*" -x "*/src/sdkdemo"
```

## 测试
进入baidurtc目录执行go test

cd baidurtc

推流测试， 视频使用H264格式，音频格式可配置， 对应的web需要配置一致的音频格式
```bash
go test -run TestPush
go test -run TestPush -ac=opus
go test -run TestPush -ac=pcmu
go test -run TestPush -ac=pcmu -af=raw
go test -run TestPush -ac=pcma
go test -run TestPush -ac=pcma -af=raw
go test -run TestPush -ac=g722
go test -run TestPush -ac=g722 -af=raw16k
```

拉流测试， 视频使用H264格式，音频格式可配置， -adump 支持dump为raw pcm， 对应的web需要配置一致的音频格式
```bash
go test -run TestPull
go test -run TestPull -ac=opus
go test -run TestPull -ac=g722
go test -run TestPull -ac=g722 -adump=raw
go test -run TestPull -ac=pcmu
go test -run TestPull -ac=pcmu -adump=raw
go test -run TestPull -ac=pcma
go test -run TestPull -ac=pcma -adump=raw
```

信令测试， 视频使用H264格式，音频格式可配置，对应的web需要配置一致的音频格式
```bash
go test -run TestSS
go test -run TestSS -ac=opus
go test -run TestSS -ac=g722
go test -run TestSS -ac=pcmu
go test -run TestSS -ac=pcma
```

## 把SDK添加到工作区
```bash
go work use `pwd`/baidurtc
go work use -r `pwd`/thirdparty/pion
```

## 或者, 安装SDK到系统目录
```bash
sudo ln -s `pwd`/baidurtc `go env GOROOT`/src/baidurtc
```

## 编译demo并测试
```bash
export APPID_GET_FROM_BAIDU=
cd sdkdemo/src
go build sdkdemo.go
./sdkdemo -appid=$APPID_GET_FROM_BAIDU
```