file.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. package utils
  2. import (
  3. "encoding/base64"
  4. "fmt"
  5. "io"
  6. "log"
  7. "os"
  8. "os/exec"
  9. "path/filepath"
  10. "pbx-api-gin/internal/pkg/configs"
  11. "pbx-api-gin/pkg/lfshook"
  12. "strconv"
  13. "strings"
  14. )
  15. // FileExists checks if a file exists and is not a directory before we
  16. // try using it to prevent further errors.
  17. func FileExists(filename string) bool {
  18. info, err := os.Stat(filename)
  19. if os.IsNotExist(err) {
  20. return false
  21. }
  22. return !info.IsDir()
  23. }
  24. func GetDuration(filePath string) (int, error) {
  25. cmd := exec.Command("ffprobe",
  26. "-v", "quiet",
  27. "-show_entries", "format=duration",
  28. "-of", "default=nw=1:nokey=1",
  29. filePath,
  30. )
  31. output, err := cmd.Output()
  32. if err != nil {
  33. return 0, err
  34. }
  35. // 解析输出(纯数字,单位秒)
  36. durationStr := strings.TrimSpace(string(output))
  37. duration, err := strconv.ParseFloat(durationStr, 64)
  38. if err != nil {
  39. return 0, err
  40. }
  41. return int(duration), nil
  42. }
  43. func AudioFileEncode(dstFile, srcFile string) error {
  44. // Step 1:获取 Base64 编码结果
  45. data := "sripis123"
  46. encoded := base64.StdEncoding.EncodeToString([]byte(data))
  47. // Step 2: 创建一个新文件,写入 Base64 编码结果
  48. outputFile, err := os.Create(dstFile)
  49. if err != nil {
  50. return err
  51. }
  52. defer outputFile.Close()
  53. _, err = outputFile.WriteString(encoded)
  54. if err != nil {
  55. return err
  56. }
  57. // Step 3: 打开 audio.wav 文件
  58. audioFile, err := os.Open(srcFile)
  59. if err != nil {
  60. return err
  61. }
  62. defer audioFile.Close()
  63. // Step 4: 读取源文件的全部内容
  64. data1, err := io.ReadAll(audioFile)
  65. if err != nil {
  66. return err
  67. }
  68. // Step 5: 对读取的内容进行 Base64 编码
  69. encoded1 := base64.StdEncoding.EncodeToString(data1)
  70. // Step 6: 写入 Base64 编码后的内容
  71. _, err = outputFile.WriteString(encoded1)
  72. if err != nil {
  73. return err
  74. }
  75. return err
  76. }
  77. // ConvertAndSegmentWAV 将 WAV 文件转为 22kHz 并每 180 秒切分,返回生成的文件名列表
  78. func ConvertAndSegmentWAV(inputFile string, outputPrefix string) ([]string, error) {
  79. // 输出文件命名模式,如:output_%03d.wav
  80. outputPattern := outputPrefix + "_%03d.wav"
  81. // 构建 ffmpeg 命令
  82. cmd := exec.Command("ffmpeg",
  83. "-i", inputFile, // 输入文件
  84. "-ar", "22050", // 设置采样率为 22050 Hz (22kHz)
  85. "-f", "segment", // 启用分段模式
  86. "-segment_time", "180", // 每段 180 秒
  87. "-c:a", "pcm_s16le", // 音频编码格式(标准 WAV)
  88. "-reset_timestamps", "1", // 重置时间戳,每个片段从 0 开始
  89. outputPattern, // 输出文件命名规则
  90. )
  91. // 执行命令并捕获输出
  92. output, err := cmd.CombinedOutput()
  93. if err != nil && !strings.Contains(string(output), "Conversion failed!") {
  94. // 即使有警告(如非关键错误),只要文件生成了就继续解析
  95. log.Printf("ffmpeg 执行时有警告: %v", err)
  96. }
  97. // 解析输出,提取所有生成的文件名
  98. files := extractFilenamesFromFFmpegOutput(outputPrefix)
  99. lfshook.NewLogger().Infof("=============== found after convert outfiles %+v ", files)
  100. return files, nil
  101. }
  102. // extractFilenamesFromFFmpegOutput 从 ffmpeg 输出日志中提取生成的文件名
  103. func extractFilenamesFromFFmpegOutput(prefix string) []string {
  104. pattern := fmt.Sprintf("%s_*", prefix)
  105. matches, err := filepath.Glob(pattern)
  106. if err != nil {
  107. log.Fatal("模式匹配错误:", err)
  108. }
  109. return matches
  110. }
  111. func WriteLogToFile(message string) {
  112. // 打开文件,支持追加模式,如果文件不存在则创建
  113. file, err := os.OpenFile(configs.ConfigGlobal.RecordEventLog, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
  114. if err != nil {
  115. return
  116. }
  117. defer file.Close()
  118. // 创建一个写入到文件的日志器
  119. logger := log.New(file, "", log.LstdFlags)
  120. // 写入日志消息
  121. logger.Println(message)
  122. }
  123. var Logger *log.Logger
  124. func init() {
  125. file, _ := os.OpenFile("/data/test/log/recordEvent.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
  126. Logger = log.New(file, "", log.LstdFlags) // 自动带时间戳
  127. }
  128. func GetPadInfo(base string) (padType, padNum, connectedCab string) {
  129. // 按 '/' 分割字符串
  130. parts := strings.Split(base, "/")
  131. // 取最后一段
  132. lastPart := parts[len(parts)-1]
  133. // 最后一段中,按‘-’分割返回前三段:parts[0], parts[1], parts[2] → PAD-2411-1411
  134. ret := strings.Split(lastPart, "-")
  135. if len(ret) < 3 {
  136. return
  137. }
  138. return ret[1], ret[2], ret[3]
  139. }