diff --git a/.gitignore b/.gitignore index abde2aa4..bb61ab17 100644 --- a/.gitignore +++ b/.gitignore @@ -15,4 +15,7 @@ channel_temp/ log/ # ignore dist -webui/dist/ \ No newline at end of file +webui/dist/ + +#ignore data +data/ \ No newline at end of file diff --git a/go-silk/silk.go b/go-silk/silk.go index 7205c72b..f3b53cb9 100644 --- a/go-silk/silk.go +++ b/go-silk/silk.go @@ -182,116 +182,250 @@ func EncodePcmBuffToSilk(src []byte, sampleRate, bitRate int, tencent bool) (dst _ = binary.Write(&out, binary.LittleEndian, nBytes) _, _ = out.Write(payload[:nBytes]) } - if !tencent { - _ = binary.Write(&out, binary.LittleEndian, int16(-1)) - } + // if !tencent { + // _ = binary.Write(&out, binary.LittleEndian, int16(-1)) + // } + dst = out.Bytes() + fmt.Printf("dst 长度: %d\n", len(dst)) + return } +// func EncodePcmBuffToSilkv2(src []byte, sampleRate, bitRate int, tencent bool) (dst []byte, err error) { +// var tls = libc.NewTLS() +// var reader = bytes.NewBuffer(src) +// var encControl sdk.SDK_EncControlStruct +// var encStatus sdk.SDK_EncControlStruct +// var packetSizeMs = int32(20) +// { // default setting +// encControl.FAPI_sampleRate = int32(sampleRate) +// encControl.FmaxInternalSampleRate = 24000 +// encControl.FpacketSize = (packetSizeMs * int32(sampleRate)) / 1000 +// encControl.FpacketLossPercentage = int32(0) +// encControl.FuseInBandFEC = 0 +// encControl.FuseDTX = 0 +// encControl.Fcomplexity = 2 +// encControl.FbitRate = int32(bitRate) +// } +// var encSizeBytes int32 +// ret := sdk.SDK_Get_Encoder_Size(tls, uintptr(unsafe.Pointer(&encSizeBytes))) +// if ret != 0 { +// return nil, fmt.Errorf("SKP_Silk_create_encoder returned %d", ret) +// } +// psEnc := libc.Xmalloc(tls, types.Size_t(encSizeBytes)) +// defer libc.Xfree(tls, psEnc) +// ret = sdk.SDK_InitEncoder(tls, psEnc, uintptr(unsafe.Pointer(&encStatus))) +// if ret != 0 { +// return nil, fmt.Errorf("SKP_Silk_reset_encoder returned %d", ret) +// } +// var frameSize = sampleRate / 1000 * 40 +// fmt.Printf("包长:%v", frameSize) +// var ( +// nBytes = int16(250 * 5) +// in = make([]byte, frameSize) +// payload = make([]byte, nBytes) +// out = bytes.Buffer{} +// totPackets, sumBytes, sumActBytes, totActPackets = 0, 0, 0, 0 +// smplsSinceLastPacket = 0 +// ) +// if tencent { +// _, _ = out.Write([]byte("\x02#!SILK_V3")) +// } else { +// _, _ = out.Write([]byte("#!SILK_V3")) +// } +// var counter int +// for { +// counter, err = reader.Read(in) +// if err != nil { +// if err == io.EOF { +// err = nil +// break +// } +// return +// } +// if counter < frameSize { +// break +// } +// nBytes = int16(1250) +// ret = sdk.SDK_Encode( +// tls, +// psEnc, +// uintptr(unsafe.Pointer(&encControl)), +// uintptr(unsafe.Pointer(&in[0])), +// int32(counter)/2, +// uintptr(unsafe.Pointer(&payload[0])), +// uintptr(unsafe.Pointer(&nBytes)), +// ) + +// if ret != 0 { +// return nil, fmt.Errorf("SKP_Silk_Encode returned %d", ret) +// } + +// packetSizeMs = (1000 * int32(encControl.FpacketSize)) / encControl.FAPI_sampleRate +// smplsSinceLastPacket += counter + +// if (1000 * smplsSinceLastPacket / sampleRate) == int(packetSizeMs) { +// totPackets++ +// sumBytes += int(nBytes) +// nrg := 0.0 +// for k := 0; k < counter; k++ { +// nrg += float64(in[k]) * float64(in[k]) +// } +// if (nrg / float64(counter)) > 1e3 { +// sumActBytes += int(nBytes) +// totActPackets++ +// } + +// if !tencent { +// _ = binary.Write(&out, binary.BigEndian, nBytes) +// } else { +// _ = binary.Write(&out, binary.LittleEndian, nBytes) +// } +// _, _ = out.Write(payload[:nBytes]) +// smplsSinceLastPacket = 0 +// } +// } +// if !tencent { +// _ = binary.Write(&out, binary.LittleEndian, int16(-1)) +// } +// dst = out.Bytes() +// return +// } + // Assuming necessary imports and definitions -func EncodePcmBuffToSilkv2(src []byte, sampleRate, bitRate int, tencent, bigEndian bool, complexityMode int) (dst []byte, err error) { - var tls = libc.NewTLS() - var reader = bytes.NewBuffer(src) - var encControl sdk.SDK_EncControlStruct - var encStatus sdk.SDK_EncControlStruct - var packetSizeMs = int32(20) - var frameSizeReadFromFileMs = int32(20) +// func EncodePcmBuffToSilkv2(src []byte, sampleRate, bitRate int, tencent, bigEndian bool, complexityMode int) (dst []byte, err error) { +// var tls = libc.NewTLS() +// var reader = bytes.NewBuffer(src) +// var encControl sdk.SDK_EncControlStruct +// var encStatus sdk.SDK_EncControlStruct +// var packetSizeMs = int32(20) +// var frameSizeReadFromFileMs = int32(20) - // Setting based on the complexity mode (could be passed as a parameter) - encControl.Fcomplexity = int32(complexityMode) +// // Setting based on the complexity mode (could be passed as a parameter) +// encControl.Fcomplexity = int32(complexityMode) - // Default settings - encControl.FAPI_sampleRate = int32(sampleRate) - encControl.FmaxInternalSampleRate = 24000 - encControl.FpacketSize = (packetSizeMs * int32(sampleRate)) / 1000 - encControl.FpacketLossPercentage = int32(0) - encControl.FuseInBandFEC = 0 - encControl.FuseDTX = 0 - encControl.FbitRate = int32(bitRate) +// // Default settings +// encControl.FAPI_sampleRate = int32(sampleRate) +// encControl.FpacketSize = (packetSizeMs * int32(sampleRate)) / 1000 +// encControl.FpacketLossPercentage = int32(0) +// encControl.FuseInBandFEC = 0 +// encControl.FuseDTX = 0 +// encControl.FbitRate = int32(bitRate) - // Create Encoder - var encSizeBytes int32 - ret := sdk.SDK_Get_Encoder_Size(tls, uintptr(unsafe.Pointer(&encSizeBytes))) - if ret != 0 { - return nil, fmt.Errorf("SKP_Silk_create_encoder returned %d", ret) - } +// // Set max internal sample rate +// maxInternalFsHz := int32(24000) +// if encControl.FAPI_sampleRate < maxInternalFsHz { +// maxInternalFsHz = encControl.FAPI_sampleRate +// } +// encControl.FmaxInternalSampleRate = maxInternalFsHz - // Memory management - psEnc := libc.Xmalloc(tls, types.Size_t(encSizeBytes)) - defer libc.Xfree(tls, psEnc) +// // Create Encoder +// var encSizeBytes int32 +// ret := sdk.SDK_Get_Encoder_Size(tls, uintptr(unsafe.Pointer(&encSizeBytes))) +// if ret != 0 { +// return nil, fmt.Errorf("SKP_Silk_create_encoder returned %d", ret) +// } - // Reset Encoder - ret = sdk.SDK_InitEncoder(tls, psEnc, uintptr(unsafe.Pointer(&encStatus))) - if ret != 0 { - return nil, fmt.Errorf("SKP_Silk_reset_encoder returned %d", ret) - } +// // Memory management +// psEnc := libc.Xmalloc(tls, types.Size_t(encSizeBytes)) +// defer libc.Xfree(tls, psEnc) - var ( - nBytes = int16(250 * 5) - in = make([]byte, frameSizeReadFromFileMs*int32(sampleRate)/1000) - payload = make([]byte, nBytes) - out = bytes.Buffer{} - ) +// // Reset Encoder +// ret = sdk.SDK_InitEncoder(tls, psEnc, uintptr(unsafe.Pointer(&encStatus))) +// if ret != 0 { +// return nil, fmt.Errorf("SKP_Silk_reset_encoder returned %d", ret) +// } - // Add Silk header to stream - if tencent { - _, _ = out.Write([]byte("\x02#!SILK_V3")) - } else { - _, _ = out.Write([]byte("#!SILK_V3")) - } +// var ( +// nBytes = int16(250 * 5) +// in = make([]byte, frameSizeReadFromFileMs*int32(sampleRate)/1000) +// payload = make([]byte, nBytes) +// out = bytes.Buffer{} +// ) - // Encoding loop - var counter int - for { - counter, err = reader.Read(in) - if err != nil { - if err == io.EOF { - err = nil - break - } - return - } +// // Add Silk header to stream +// if tencent { +// _, _ = out.Write([]byte("\x02#!SILK_V3")) +// } else { +// _, _ = out.Write([]byte("#!SILK_V3")) +// } - if bigEndian { - SwapEndian(in) - } +// // Encoding loop +// var counter int +// var smplsSinceLastPacket int +// for { +// counter, err = reader.Read(in) +// if err != nil { +// if err == io.EOF { +// err = nil +// break +// } +// return +// } - nBytes = int16(1250) - ret = sdk.SDK_Encode( - tls, - psEnc, - uintptr(unsafe.Pointer(&encControl)), - uintptr(unsafe.Pointer(&in[0])), - int32(counter)/2, - uintptr(unsafe.Pointer(&payload[0])), - uintptr(unsafe.Pointer(&nBytes)), - ) +// // Fill the rest of the buffer with zeros if necessary +// if counter < len(in) { +// for i := counter; i < len(in); i++ { +// in[i] = 0 +// } +// } - if ret != 0 { - return nil, fmt.Errorf("SKP_Silk_Encode returned %d", ret) - } +// // Swap bytes if the system is big-endian +// if bigEndian { +// SwapEndian(in, counter) +// } - _ = binary.Write(&out, binary.LittleEndian, nBytes) - _, _ = out.Write(payload[:nBytes]) - } +// //log.Printf("Before encoding: nBytes = %d, counter = %d", nBytes, counter) +// //log.Printf("encControl: %+v", encControl) +// nBytes = 1250 +// ret = sdk.SDK_Encode( +// tls, +// psEnc, +// uintptr(unsafe.Pointer(&encControl)), +// uintptr(unsafe.Pointer(&in[0])), +// int32(counter)/2, +// uintptr(unsafe.Pointer(&payload[0])), +// uintptr(unsafe.Pointer(&nBytes)), +// ) +// if ret != 0 { +// return nil, fmt.Errorf("SKP_Silk_Encode returned %d", ret) +// } +// // Packet handling logic +// packetSizeMs := (1000 * int(encControl.FpacketSize)) / int(encControl.FAPI_sampleRate) +// smplsSinceLastPacket += counter +// if ((1000 * smplsSinceLastPacket) / int(sampleRate)) == packetSizeMs { +// // Swap bytes if the system is big-endian +// if bigEndian { +// var buf [2]byte +// binary.BigEndian.PutUint16(buf[:], uint16(nBytes)) +// nBytes = int16(binary.LittleEndian.Uint16(buf[:])) +// } - if !tencent { - _ = binary.Write(&out, binary.LittleEndian, int16(-1)) - } +// // Write the payload +// _ = binary.Write(&out, binary.LittleEndian, nBytes) +// _, _ = out.Write(payload[:nBytes]) +// smplsSinceLastPacket = 0 +// } +// } - dst = out.Bytes() - return -} +// if !tencent { +// _ = binary.Write(&out, binary.LittleEndian, int16(-1)) +// } + +// dst = out.Bytes() +// return -func SwapEndian(data []byte) { - if len(data)%2 != 0 { - panic("SwapEndian requires an even length byte slice") +// } + +func SwapEndian(data []byte, length int) { + if length%2 != 0 { + // The length should be even, as we are swapping 16-bit values. + panic("length of data for SwapEndian should be even") } - for i := 0; i < len(data); i += 2 { + for i := 0; i < length; i += 2 { data[i], data[i+1] = data[i+1], data[i] } } - diff --git a/handlers/send_group_msg.go b/handlers/send_group_msg.go index ac01e685..d0426991 100644 --- a/handlers/send_group_msg.go +++ b/handlers/send_group_msg.go @@ -128,7 +128,7 @@ func handleSendGroupMsg(client callapi.Client, api openapi.OpenAPI, apiv2 openap for _, url := range urls { var singleItem = make(map[string][]string) singleItem[key] = []string{url} // 创建一个只包含一个 URL 的 singleItem - mylog.Println("singleItem:", singleItem) + //mylog.Println("singleItem:", singleItem) msgseq := echo.GetMappingSeq(messageID) echo.AddMappingSeq(messageID, msgseq+1) groupReply := generateGroupMessage(messageID, singleItem, "", msgseq+1) diff --git a/silk/exec/silk_codec-android-arm64 b/silk/exec/silk_codec-android-arm64 new file mode 100644 index 00000000..213c9071 Binary files /dev/null and b/silk/exec/silk_codec-android-arm64 differ diff --git a/silk/exec/silk_codec-android-x86 b/silk/exec/silk_codec-android-x86 new file mode 100644 index 00000000..ed5292a9 Binary files /dev/null and b/silk/exec/silk_codec-android-x86 differ diff --git a/silk/exec/silk_codec-android-x86_64 b/silk/exec/silk_codec-android-x86_64 new file mode 100644 index 00000000..2b1e93f6 Binary files /dev/null and b/silk/exec/silk_codec-android-x86_64 differ diff --git a/silk/exec/silk_codec-linux-arm64 b/silk/exec/silk_codec-linux-arm64 new file mode 100644 index 00000000..aaa1ecda Binary files /dev/null and b/silk/exec/silk_codec-linux-arm64 differ diff --git a/silk/exec/silk_codec-linux-x64 b/silk/exec/silk_codec-linux-x64 new file mode 100644 index 00000000..f84903f3 Binary files /dev/null and b/silk/exec/silk_codec-linux-x64 differ diff --git a/silk/exec/silk_codec-macos b/silk/exec/silk_codec-macos new file mode 100644 index 00000000..5155d103 Binary files /dev/null and b/silk/exec/silk_codec-macos differ diff --git a/silk/silk.go b/silk/silk.go index 3c90bc01..7e6db60c 100644 --- a/silk/silk.go +++ b/silk/silk.go @@ -1,14 +1,9 @@ -//go:build (linux || (windows && !arm && !arm64) || darwin) && (386 || amd64 || arm || arm64) && !race && !nosilk -// +build linux windows,!arm,!arm64 darwin -// +build 386 amd64 arm arm64 -// +build !race -// +build !nosilk - package silk import ( "bytes" "crypto/md5" + "embed" "encoding/hex" "errors" "fmt" @@ -17,14 +12,17 @@ import ( "os" "os/exec" "path" + "runtime" "strconv" "strings" "github.com/hoshinonyaruko/gensokyo/config" "github.com/hoshinonyaruko/gensokyo/mylog" - "github.com/wdvxdr1123/go-silk" ) +//go:embed exec/* +var silkCodecs embed.FS + const ( // HeaderAmr AMR文件头 HeaderAmr = "#!AMR" @@ -36,6 +34,54 @@ const silkCachePath = "data/cache" const limit = 4 * 1024 +func getSilkCodecPath() (string, error) { + var codecFileName string + switch runtime.GOOS { + case "windows": + switch runtime.GOARCH { + case "amd64": + codecFileName = "silk_codec-windows-static-x64.exe" + case "386": + codecFileName = "silk_codec-windows-static-x86.exe" + default: + return "", fmt.Errorf("unsupported architecture: %s", runtime.GOARCH) + } + case "linux": + switch runtime.GOARCH { + case "amd64": + codecFileName = "silk_codec-linux-x64" + case "arm64": + codecFileName = "silk_codec-linux-arm64" + default: + return "", fmt.Errorf("unsupported architecture for Linux: %s", runtime.GOARCH) + } + case "darwin": + switch runtime.GOARCH { + case "amd64": + codecFileName = "silk_codec-macos" + case "arm64": + codecFileName = "silk_codec-macos" + default: + return "", fmt.Errorf("unsupported architecture for macOS: %s", runtime.GOARCH) + } + case "android": + switch runtime.GOARCH { + case "arm64": + codecFileName = "silk_codec-android-arm64" + case "x86": + codecFileName = "silk_codec-android-x86" + case "x86_64": + codecFileName = "silk_codec-android-x86_64" + default: + return "", fmt.Errorf("unsupported architecture for macOS: %s", runtime.GOARCH) + } + default: + return "", fmt.Errorf("unsupported platform: %s", runtime.GOOS) + } + + return "exec/" + codecFileName, nil +} + // EncoderSilk 将音频编码为Silk func EncoderSilk(data []byte) []byte { h := md5.New() @@ -120,26 +166,92 @@ func encode(record []byte, tempName string) (silkWav []byte) { mylog.Errorf("convert pcm file error") return nil } - defer os.Remove(pcmPath) + + //defer os.Remove(pcmPath) + //todo 有大佬可以试试完善go-silk 这部分编码转换 + //努力了很久,都没成功播放 // 3. 转silk - pcm, err := os.ReadFile(pcmPath) + // pcm, err := os.ReadFile(pcmPath) + // if err != nil { + // mylog.Printf("read pcm file err") + // return nil + // } + // //silkWav, err = silk.EncodePcmBuffToSilkv2(pcm, sampleRate, bitRate, true, false, 2) + // silkWav, err = silk.EncodePcmBuffToSilk(pcm, sampleRate, bitRate, true) + // if err != nil { + // mylog.Printf("silk encode error:%v", err) + // return nil + // } + + silkPath := path.Join(silkCachePath, tempName+".silk") + + // err = os.WriteFile(silkPath, silkWav, 0o666) + // if err != nil { + // mylog.Printf("silk encode error2") + // return nil + // } + + // 调用silk_codec转换为Silk + + // 获取silk_codec文件名 + codecFileName, err := getSilkCodecPath() if err != nil { - mylog.Printf("read pcm file err") + mylog.Errorf("failed to get codec path: %v", err) return nil } - silkWav, err = silk.EncodePcmBuffToSilkv2(pcm, sampleRate, bitRate, true, false, 2) + // 从嵌入的文件系统中读取silk_codec二进制文件 + codecData, err := silkCodecs.ReadFile(codecFileName) if err != nil { - mylog.Printf("silk encode error") + mylog.Errorf("failed to read codec data: %v", err) return nil } - silkPath := path.Join(silkCachePath, tempName+".silk") - err = os.WriteFile(silkPath, silkWav, 0o666) + + // 根据操作系统确定临时文件的扩展名 + tempFilePattern := "silk_codec*" + if runtime.GOOS == "windows" { + tempFilePattern += ".exe" + } + + // 创建临时文件 + tmpFile, err := os.CreateTemp("", tempFilePattern) + if err != nil { + mylog.Errorf("failed to create temp file: %v", err) + return nil + } + defer os.Remove(tmpFile.Name()) // 清理临时文件 + + // 写入二进制数据到临时文件 + if _, err := tmpFile.Write(codecData); err != nil { + mylog.Errorf("failed to write codec data to temp file: %v", err) + return nil + } + if err := tmpFile.Close(); err != nil { + mylog.Errorf("failed to close temp file: %v", err) + return nil + } + + // 确保临时文件可执行 + if err := os.Chmod(tmpFile.Name(), 0700); err != nil { + mylog.Errorf("failed to chmod temp file: %v", err) + return nil + } + + // 使用临时文件执行silk_codec + cmd = exec.Command(tmpFile.Name(), "pts", "-i", pcmPath, "-o", silkPath, "-s", "24000") + if err := cmd.Run(); err != nil { + mylog.Errorf("silk encode error: %v", err) + return nil + } + + // 读取Silk文件 + silkWav, err = os.ReadFile(silkPath) if err != nil { - mylog.Printf("silk encode error2") + mylog.Errorf("read silk file error: %v", err) return nil } + return silkWav } diff --git a/silk/silk_unsupport.go b/silk/silk_unsupport.go deleted file mode 100644 index 1011ecc3..00000000 --- a/silk/silk_unsupport.go +++ /dev/null @@ -1,16 +0,0 @@ -//go:build (!arm && !arm64 && !amd64 && !386) || (!windows && !linux && !darwin) || (windows && arm) || (windows && arm64) || race || nosilk -// +build !arm,!arm64,!amd64,!386 !windows,!linux,!darwin windows,arm windows,arm64 race nosilk - -package silk - -import "errors" - -// encode 将音频编码为Silk -func encode(record []byte, tempName string) ([]byte, error) { - return nil, errors.New("not supported now") -} - -// resample 将silk重新编码为 24000 bit rate -func resample(data []byte) []byte { - return data -} diff --git a/sys/restart_unix.go b/sys/restart_unix.go index e3dbc71e..18ec706d 100644 --- a/sys/restart_unix.go +++ b/sys/restart_unix.go @@ -21,7 +21,7 @@ func NewRestarter() *UnixRestarter { func (r *UnixRestarter) Restart(executableName string) error { scriptContent := "#!/bin/sh\n" + "sleep 1\n" + // Sleep for a bit to allow the main application to exit - "exec ./" + executableName + "\n" + "exec ." + executableName + "\n" scriptName := "restart.sh" if err := os.WriteFile(scriptName, []byte(scriptContent), 0755); err != nil { diff --git a/template/config_template.go b/template/config_template.go index 43fd97b7..05b8ff09 100644 --- a/template/config_template.go +++ b/template/config_template.go @@ -44,7 +44,7 @@ settings: image_limit : 100 #每分钟上传的最大图片数量,可自行增加 master_id : ["1","2"] #群场景尚未开放获取管理员和列表能力,手动从日志中获取需要设置为管理,的user_id并填入(适用插件有权限判断场景) record_sampleRate : 24000 #语音文件的采样率 最高48000 默认24000 单位Khz - record_bitRate : 24000 #语音文件的比特率 默认24000 代表 24 kbps 最高无限 请根据带宽 您发送的实际码率调整 + record_bitRate : 24000 #语音文件的比特率 默认25000 代表 25 kbps 最高无限 请根据带宽 您发送的实际码率调整 #正向ws设置 diff --git a/wsclient/ws.go b/wsclient/ws.go index 62d90fbe..6ae853fa 100644 --- a/wsclient/ws.go +++ b/wsclient/ws.go @@ -124,7 +124,7 @@ func (client *WebSocketClient) processFailedMessages(failuresChan chan map[strin // 处理信息,调用腾讯api func (c *WebSocketClient) recvMessage(msg []byte) { var message callapi.ActionMessage - mylog.Println("Received from onebotv11 server raw:", string(msg)) + //mylog.Println("Received from onebotv11 server raw:", string(msg)) err := json.Unmarshal(msg, &message) if err != nil { mylog.Printf("Error unmarshalling message: %v, Original message: %s", err, string(msg))