file.go 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  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. lfshook.NewLogger().Logger.Infof("=======GetDuration err:%+v ! ============", output)
  34. return 0, err
  35. }
  36. // 解析输出(纯数字,单位秒)
  37. durationStr := strings.TrimSpace(string(output))
  38. duration, err := strconv.ParseFloat(durationStr, 64)
  39. if err != nil {
  40. return 0, err
  41. }
  42. return int(duration), nil
  43. }
  44. func AudioFileEncode(dstFile, srcFile string) error {
  45. // Step 1:获取 Base64 编码结果
  46. data := "sripis123"
  47. encoded := base64.StdEncoding.EncodeToString([]byte(data))
  48. // Step 2: 创建一个新文件,写入 Base64 编码结果
  49. outputFile, err := os.Create(dstFile)
  50. if err != nil {
  51. return err
  52. }
  53. defer outputFile.Close()
  54. _, err = outputFile.WriteString(encoded)
  55. if err != nil {
  56. return err
  57. }
  58. // Step 3: 打开 audio.wav 文件
  59. audioFile, err := os.Open(srcFile)
  60. if err != nil {
  61. return err
  62. }
  63. defer audioFile.Close()
  64. // Step 4: 读取源文件的全部内容
  65. data1, err := io.ReadAll(audioFile)
  66. if err != nil {
  67. return err
  68. }
  69. // Step 5: 对读取的内容进行 Base64 编码
  70. encoded1 := base64.StdEncoding.EncodeToString(data1)
  71. // Step 6: 写入 Base64 编码后的内容
  72. _, err = outputFile.WriteString(encoded1)
  73. if err != nil {
  74. return err
  75. }
  76. return err
  77. }
  78. // ConvertAndSegmentWAV 将 WAV 文件转为 22kHz 并每 180 秒切分,返回生成的文件名列表
  79. func ConvertAndSegmentWAV(inputFile string, outputPrefix string) ([]string, error) {
  80. // 输出文件命名模式,如:output_%03d.wav
  81. outputPattern := outputPrefix + "_%03d.wav"
  82. // 构建 ffmpeg 命令
  83. cmd := exec.Command("ffmpeg",
  84. "-i", inputFile, // 输入文件
  85. "-ar", "22050", // 设置采样率为 22050 Hz (22kHz)
  86. "-f", "segment", // 启用分段模式
  87. "-segment_time", "180", // 每段 180 秒
  88. "-c:a", "pcm_s16le", // 音频编码格式(标准 WAV)
  89. "-reset_timestamps", "1", // 重置时间戳,每个片段从 0 开始
  90. outputPattern, // 输出文件命名规则
  91. )
  92. // 执行命令并捕获输出
  93. output, err := cmd.CombinedOutput()
  94. if err != nil && !strings.Contains(string(output), "Conversion failed!") {
  95. // 即使有警告(如非关键错误),只要文件生成了就继续解析
  96. //log.Printf("ffmpeg 执行时有警告: %v", err)
  97. lfshook.NewLogger().Logger.Infof("=======ConvertAndSegmentWAV err:%+v ! ============", output)
  98. }
  99. // 解析输出,提取所有生成的文件名
  100. files := extractFilenamesFromFFmpegOutput(outputPrefix)
  101. //lfshook.NewLogger().Infof("found after convert outfiles %+v ", files)
  102. return files, nil
  103. }
  104. // extractFilenamesFromFFmpegOutput 从 ffmpeg 输出日志中提取生成的文件名
  105. func extractFilenamesFromFFmpegOutput(prefix string) []string {
  106. pattern := fmt.Sprintf("%s_*", prefix)
  107. matches, err := filepath.Glob(pattern)
  108. if err != nil {
  109. //log.Fatal("模式匹配错误:", err)
  110. lfshook.NewLogger().Logger.Infof("=======模式匹配错误:%+v ! ============", err)
  111. }
  112. return matches
  113. }
  114. var Logger *log.Logger
  115. var LoggerDebug *log.Logger
  116. func InitLog() {
  117. lfshook.NewLogger().Logger.Infof("=======模式匹配错误:%+v ! ============", configs.ConfigGlobal)
  118. file, _ := os.OpenFile(configs.ConfigGlobal.RecordEventLog, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
  119. //Logger = log.New(file, "", log.LstdFlags) // 自动带时间戳
  120. Logger = log.New(file, "", log.LstdFlags|log.Lmicroseconds)
  121. //lfshook.NewLogger().Printf("software version: V10.01")
  122. fileDebug, _ := os.OpenFile(configs.ConfigGlobal.DebugLogPath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
  123. //Logger = log.New(file, "", log.LstdFlags) // 自动带时间戳
  124. LoggerDebug = log.New(fileDebug, "", log.LstdFlags|log.Lmicroseconds|log.Llongfile)
  125. }
  126. func GetPadInfo(base string) (padType, padNum, connectedCab string) {
  127. // 按 '/' 分割字符串
  128. parts := strings.Split(base, "/")
  129. // 取最后一段
  130. lastPart := parts[len(parts)-1]
  131. // 最后一段中,按‘-’分割返回前三段:parts[0], parts[1], parts[2] → PAD-2411-1411
  132. ret := strings.Split(lastPart, "-")
  133. if len(ret) < 3 {
  134. return
  135. }
  136. return ret[0], ret[1], ret[2]
  137. }