package ipcast import ( "crypto/rand" "encoding/hex" "errors" "fmt" "github.com/gin-gonic/gin" "github.com/goccy/go-json" "github.com/sirupsen/logrus" "io" "lcfns/model/common/response" ipResp "lcfns/model/ipcast/response" "net/http" "os" "strconv" "time" ) type IpcastApi struct { } func (api *IpcastApi) Play(c *gin.Context) { url, err := GetIpcastUrl(c, Play) if err != nil { response.FailWithMessage(err.Error(), c) return } data, err := c.GetRawData() if err != nil { response.FailWithMessage("获取请求参数出错", c) logrus.Error(err) return } all, err := ipcastService.Common(url, http.MethodPost, data) if err != nil { response.Fail(c) logrus.Error(err) return } var resp ipResp.PingResp json.Unmarshal(all, &resp) response.OkWithDetailed(resp.Message, "播放成功!", c) } func (api *IpcastApi) Stop(c *gin.Context) { url, err := GetIpcastUrl(c, Stop) if err != nil { response.FailWithMessage(err.Error(), c) return } all, err := ipcastService.Common(url, http.MethodDelete, nil) if err != nil { response.Fail(c) logrus.Error(err) return } var resp ipResp.PingResp json.Unmarshal(all, &resp) response.OkWithDetailed(resp.Message, "操作成功!", c) } func (api *IpcastApi) Status(c *gin.Context) { url, err := GetIpcastUrl(c, Status) if err != nil { response.FailWithMessage(err.Error(), c) return } all, err := ipcastService.Common(url, http.MethodGet, nil) if err != nil { response.Fail(c) logrus.Error(err) return } var resp ipResp.StatusResp json.Unmarshal(all, &resp) response.OkWithData(resp.Data, c) } func (api *IpcastApi) Ping(c *gin.Context) { url, err := GetIpcastUrl(c, Ping) if err != nil { response.FailWithMessage(err.Error(), c) return } all, err := ipcastService.Common(url, http.MethodGet, nil) if err != nil { response.Fail(c) logrus.Error(err) return } var resp ipResp.PingResp json.Unmarshal(all, &resp) response.OkWithData(resp.Message, c) } func (api *IpcastApi) Volume(c *gin.Context) { url, err := GetIpcastUrl(c, Volume) if err != nil { response.FailWithMessage(err.Error(), c) return } data, err := c.GetRawData() if err != nil { response.FailWithMessage("获取请求参数出错", c) logrus.Error(err) return } all, err := ipcastService.Common(url, http.MethodPatch, data) if err != nil { response.Fail(c) logrus.Error(err) return } var resp ipResp.PingResp json.Unmarshal(all, &resp) response.OkWithDetailed(resp.Message, "操作成功!", c) } func (api *IpcastApi) List(c *gin.Context) { } //↓实现语音喊话功能↓ var audio = make(map[string][]byte) // volume 播放⾳量:取值【1~100】 // duration 循环(重复)播放时⻓(秒) // times 循环(重复)播放次数(次) // gap 循环(重复)播放中的间歇时间(秒) // todo 修改ip端口 106.52.134.22 var ipcastData = ` { "url": "http://192.168.110.69:8889/ipcast/AudioSource/%s", "sync": false, "queue": true, "volume": 70, "loop": { "duration": %s, "times": 1, "gap": 2 } } ` // PlayAudio 前端传递mp3资源 func (api *IpcastApi) PlayAudio(c *gin.Context) { fmt.Println("headers:", c.Request.Header) //生成uuid uuid := make([]byte, 8) rand.Read(uuid) uuidString := hex.EncodeToString(uuid) defer func() { go func() { //数据传输完后清除数据 time.Sleep(10 * time.Second) delete(audio, uuidString) }() }() //读取mp3数据 mp3, err := c.FormFile("file") if err != nil { response.FailWithMessage("获取请求参数出错", c) logrus.Error(err) return } open, err := mp3.Open() if err != nil { logrus.Error("open err ", err) return } readAll, err := io.ReadAll(open) if err != nil { logrus.Error("ReadAll err ", err) return } //保存到内存 audio[uuidString] = readAll os.WriteFile("map.wav", readAll, 0644) //播放 t := c.PostForm("timeLength") data := []byte(fmt.Sprintf(ipcastData, uuidString, t)) fmt.Println("data:", string(data)) url, err := GetIpcastUrl(c, Play) if err != nil { response.FailWithMessage(err.Error(), c) return } fmt.Println("url:", url) all, err := ipcastService.Common(url, http.MethodPost, data) if err != nil { response.Fail(c) logrus.Error(err) return } var resp ipResp.PingResp json.Unmarshal(all, &resp) if resp.Code == 200 { response.OkWithDetailed(resp.Message, "播放成功", c) } else { response.FailWithDetailed(resp.Message, "播放失败", c) } } // AudioSource 给ip音柱播放的url资源 func (api *IpcastApi) AudioSource(c *gin.Context) { id := c.Param("id") fmt.Println("id:", id) // 设置响应头,指定内容类型为 audio/mpeg c.Header("Content-Type", "audio/wav") c.Header("Access-Control-Allow-Origin", "*") c.Header("Content-Length", strconv.Itoa(len(audio[id]))) // 将内存中的 MP3 数据作为响应返回给浏览器 c.Data(http.StatusOK, "audio/wav", audio[id]) } //↑实现语音喊话功能↑ const ( Play = iota Stop Status Ping Volume ) func GetIpcastUrl(c *gin.Context, expr byte) (string, error) { baseUrl := IpcastBaseUrl(c) if baseUrl == "" { return "", errors.New("获取baseUrl失败") } switch expr { case Stop, Play: return baseUrl + "/v1/speech", nil case Status: return baseUrl + "/v1/play_status", nil case Ping: return baseUrl + "/v1/check_alive", nil case Volume: return baseUrl + "/v1/volume", nil default: return "", errors.New("获取baseUrl失败") } }