file.go 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  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/pkg/lfshook"
  11. "strconv"
  12. "strings"
  13. )
  14. // FileExists checks if a file exists and is not a directory before we
  15. // try using it to prevent further errors.
  16. func FileExists(filename string) bool {
  17. info, err := os.Stat(filename)
  18. if os.IsNotExist(err) {
  19. return false
  20. }
  21. return !info.IsDir()
  22. }
  23. func GetDuration(filePath string) (int, error) {
  24. cmd := exec.Command("ffprobe",
  25. "-v", "quiet",
  26. "-show_entries", "format=duration",
  27. "-of", "default=nw=1:nokey=1",
  28. filePath,
  29. )
  30. output, err := cmd.Output()
  31. if err != nil {
  32. lfshook.NewLogger().Logger.Infof("=======GetDuration err:%+v ! ============", output)
  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. lfshook.NewLogger().Logger.Infof("=======ConvertAndSegmentWAV err:%+v ! ============", output)
  97. }
  98. // 解析输出,提取所有生成的文件名
  99. files := extractFilenamesFromFFmpegOutput(outputPrefix)
  100. //lfshook.NewLogger().Infof("found after convert outfiles %+v ", files)
  101. return files, nil
  102. }
  103. // extractFilenamesFromFFmpegOutput 从 ffmpeg 输出日志中提取生成的文件名
  104. func extractFilenamesFromFFmpegOutput(prefix string) []string {
  105. pattern := fmt.Sprintf("%s_*", prefix)
  106. matches, err := filepath.Glob(pattern)
  107. if err != nil {
  108. //log.Fatal("模式匹配错误:", err)
  109. lfshook.NewLogger().Logger.Infof("=======模式匹配错误:%+v ! ============", err)
  110. }
  111. return matches
  112. }
  113. var Logger *log.Logger
  114. var LoggerDebug *log.Logger
  115. func init() {
  116. file, _ := os.OpenFile("/data/test/log/recordEvent.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
  117. //Logger = log.New(file, "", log.LstdFlags) // 自动带时间戳
  118. Logger = log.New(file, "", log.LstdFlags|log.Lmicroseconds)
  119. //lfshook.NewLogger().Printf("software version: V10.01")
  120. fileDebug, _ := os.OpenFile("/data/test/log/debug.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
  121. //Logger = log.New(file, "", log.LstdFlags) // 自动带时间戳
  122. LoggerDebug = log.New(fileDebug, "", log.LstdFlags|log.Lmicroseconds|log.Llongfile)
  123. }
  124. func GetPadInfo(base string) (padType, padNum, connectedCab string) {
  125. // 按 '/' 分割字符串
  126. parts := strings.Split(base, "/")
  127. // 取最后一段
  128. lastPart := parts[len(parts)-1]
  129. // 最后一段中,按‘-’分割返回前三段:parts[0], parts[1], parts[2] → PAD-2411-1411
  130. ret := strings.Split(lastPart, "-")
  131. if len(ret) < 3 {
  132. return
  133. }
  134. return ret[0], ret[1], ret[2]
  135. }