Go-based FM stereo transmitter with RDS, Windows-first and cross-platform
25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.

254 satır
6.5KB

  1. package factory
  2. import (
  3. "bytes"
  4. "context"
  5. "errors"
  6. "testing"
  7. "time"
  8. "aoiprxkit"
  9. "github.com/jan/fm-rds-tx/internal/config"
  10. )
  11. func TestBuildSourceNone(t *testing.T) {
  12. cfg := config.Default()
  13. cfg.Ingest.Kind = "none"
  14. src, ingress, err := BuildSource(cfg, Deps{})
  15. if err != nil {
  16. t.Fatalf("build source: %v", err)
  17. }
  18. if src != nil || ingress != nil {
  19. t.Fatalf("expected nil source and ingress for kind=none")
  20. }
  21. }
  22. func TestBuildSourceHTTPRawProvidesIngress(t *testing.T) {
  23. cfg := config.Default()
  24. cfg.Ingest.Kind = "http-raw"
  25. src, ingress, err := BuildSource(cfg, Deps{})
  26. if err != nil {
  27. t.Fatalf("build source: %v", err)
  28. }
  29. if src == nil {
  30. t.Fatalf("expected source")
  31. }
  32. if ingress == nil {
  33. t.Fatalf("expected ingress for http-raw")
  34. }
  35. }
  36. func TestBuildSourceKindIsNormalized(t *testing.T) {
  37. cfg := config.Default()
  38. cfg.Ingest.Kind = " HTTP-RAW "
  39. src, ingress, err := BuildSource(cfg, Deps{})
  40. if err != nil {
  41. t.Fatalf("build source: %v", err)
  42. }
  43. if src == nil || ingress == nil {
  44. t.Fatalf("expected source and ingress for normalized http-raw kind")
  45. }
  46. if got := src.Descriptor().Kind; got != "http-raw" {
  47. t.Fatalf("source kind=%q want http-raw", got)
  48. }
  49. }
  50. func TestBuildSourceStdin(t *testing.T) {
  51. cfg := config.Default()
  52. cfg.Ingest.Kind = "stdin"
  53. src, ingress, err := BuildSource(cfg, Deps{Stdin: bytes.NewReader(nil)})
  54. if err != nil {
  55. t.Fatalf("build source: %v", err)
  56. }
  57. if src == nil {
  58. t.Fatalf("expected source")
  59. }
  60. if ingress != nil {
  61. t.Fatalf("expected no ingress for stdin")
  62. }
  63. if got := src.Descriptor().Kind; got != "stdin-pcm" {
  64. t.Fatalf("source kind=%s", got)
  65. }
  66. }
  67. func TestBuildSourceIcecastUsesDecoderPreference(t *testing.T) {
  68. cfg := config.Default()
  69. cfg.Ingest.Kind = "icecast"
  70. cfg.Ingest.Icecast.URL = "http://localhost:8000/stream"
  71. cfg.Ingest.Icecast.Decoder = "ffmpeg"
  72. src, ingress, err := BuildSource(cfg, Deps{})
  73. if err != nil {
  74. t.Fatalf("build source: %v", err)
  75. }
  76. if src == nil {
  77. t.Fatalf("expected source")
  78. }
  79. if ingress != nil {
  80. t.Fatalf("expected no ingress for icecast")
  81. }
  82. if got := src.Descriptor().Codec; got != "ffmpeg" {
  83. t.Fatalf("codec=%s want ffmpeg", got)
  84. }
  85. }
  86. func TestBuildSourceSRT(t *testing.T) {
  87. cfg := config.Default()
  88. cfg.Ingest.Kind = "srt"
  89. cfg.Ingest.SRT.URL = "srt://127.0.0.1:9000?mode=listener"
  90. cfg.Ingest.SRT.Mode = "listener"
  91. cfg.Ingest.SRT.SampleRateHz = 48000
  92. cfg.Ingest.SRT.Channels = 2
  93. src, ingress, err := BuildSource(cfg, Deps{})
  94. if err != nil {
  95. t.Fatalf("build source: %v", err)
  96. }
  97. if src == nil {
  98. t.Fatalf("expected source")
  99. }
  100. if ingress != nil {
  101. t.Fatalf("expected no ingress for srt")
  102. }
  103. if got := src.Descriptor().Kind; got != "srt" {
  104. t.Fatalf("source kind=%s", got)
  105. }
  106. }
  107. func TestBuildSourceAES67(t *testing.T) {
  108. cfg := config.Default()
  109. cfg.Ingest.Kind = "aes67"
  110. cfg.Ingest.AES67.MulticastGroup = "239.69.10.20"
  111. cfg.Ingest.AES67.Port = 5008
  112. cfg.Ingest.AES67.PayloadType = 98
  113. cfg.Ingest.AES67.SampleRateHz = 48000
  114. cfg.Ingest.AES67.Channels = 2
  115. cfg.Ingest.AES67.Encoding = "L24"
  116. cfg.Ingest.AES67.PacketTimeMs = 1
  117. cfg.Ingest.AES67.JitterDepthPackets = 6
  118. src, ingress, err := BuildSource(cfg, Deps{})
  119. if err != nil {
  120. t.Fatalf("build source: %v", err)
  121. }
  122. if src == nil {
  123. t.Fatalf("expected source")
  124. }
  125. if ingress != nil {
  126. t.Fatalf("expected no ingress for aes67")
  127. }
  128. if got := src.Descriptor().Kind; got != "aes67" {
  129. t.Fatalf("source kind=%s", got)
  130. }
  131. }
  132. func TestBuildSourceAES67FromInlineSDP(t *testing.T) {
  133. cfg := config.Default()
  134. cfg.Ingest.Kind = "aes67"
  135. cfg.Ingest.AES67.MulticastGroup = ""
  136. cfg.Ingest.AES67.SDP = "v=0\r\ns=demo\r\nc=IN IP4 239.10.20.30\r\nm=audio 5004 RTP/AVP 97\r\na=rtpmap:97 L24/48000/2\r\na=ptime:1\r\n"
  137. src, _, err := BuildSource(cfg, Deps{})
  138. if err != nil {
  139. t.Fatalf("build source: %v", err)
  140. }
  141. desc := src.Descriptor()
  142. if desc.Transport != "rtp" {
  143. t.Fatalf("transport=%q want rtp", desc.Transport)
  144. }
  145. if desc.SampleRateHz != 48000 || desc.Channels != 2 {
  146. t.Fatalf("shape=%d/%d", desc.SampleRateHz, desc.Channels)
  147. }
  148. }
  149. func TestBuildSourceAES67WithDiscovery(t *testing.T) {
  150. cfg := config.Default()
  151. cfg.Ingest.Kind = "aes67"
  152. cfg.Ingest.AES67.MulticastGroup = ""
  153. cfg.Ingest.AES67.Port = 0
  154. cfg.Ingest.AES67.Discovery.StreamName = "AES67-MAIN"
  155. cfg.Ingest.AES67.Discovery.TimeoutMs = 1500
  156. var gotReq AES67DiscoverRequest
  157. src, _, err := BuildSource(cfg, Deps{
  158. AES67Discover: func(_ context.Context, req AES67DiscoverRequest) (aoiprxkit.SAPAnnouncement, error) {
  159. gotReq = req
  160. return aoiprxkit.SAPAnnouncement{
  161. SDP: "v=0\r\ns=AES67-MAIN\r\nc=IN IP4 239.10.20.30\r\nm=audio 5004 RTP/AVP 97\r\na=rtpmap:97 L24/48000/2\r\na=ptime:1\r\n",
  162. }, nil
  163. },
  164. })
  165. if err != nil {
  166. t.Fatalf("build source: %v", err)
  167. }
  168. if gotReq.StreamName != "AES67-MAIN" {
  169. t.Fatalf("discovery streamName=%q want AES67-MAIN", gotReq.StreamName)
  170. }
  171. if gotReq.Timeout != 1500*time.Millisecond {
  172. t.Fatalf("discovery timeout=%s want 1500ms", gotReq.Timeout)
  173. }
  174. desc := src.Descriptor()
  175. if desc.Detail != "rtp://239.10.20.30:5004 (SAP s=AES67-MAIN)" {
  176. t.Fatalf("descriptor detail=%q", desc.Detail)
  177. }
  178. }
  179. func TestBuildSourceAES67DiscoveryError(t *testing.T) {
  180. cfg := config.Default()
  181. cfg.Ingest.Kind = "aes67"
  182. cfg.Ingest.AES67.MulticastGroup = ""
  183. cfg.Ingest.AES67.Port = 0
  184. cfg.Ingest.AES67.Discovery.StreamName = "AES67-MAIN"
  185. _, _, err := BuildSource(cfg, Deps{
  186. AES67Discover: func(_ context.Context, req AES67DiscoverRequest) (aoiprxkit.SAPAnnouncement, error) {
  187. _ = req
  188. return aoiprxkit.SAPAnnouncement{}, errors.New("timeout")
  189. },
  190. })
  191. if err == nil {
  192. t.Fatalf("expected discovery error")
  193. }
  194. }
  195. func TestBuildSourceUnsupportedKind(t *testing.T) {
  196. cfg := config.Default()
  197. cfg.Ingest.Kind = "nope"
  198. _, _, err := BuildSource(cfg, Deps{})
  199. if err == nil {
  200. t.Fatalf("expected error")
  201. }
  202. }
  203. func TestSampleRateForKind(t *testing.T) {
  204. cfg := config.Default()
  205. cfg.Ingest.Kind = "stdin"
  206. cfg.Ingest.Stdin.SampleRateHz = 48000
  207. if got := SampleRateForKind(cfg); got != 48000 {
  208. t.Fatalf("stdin sample rate=%d", got)
  209. }
  210. cfg.Ingest.Kind = "http-raw"
  211. cfg.Ingest.HTTPRaw.SampleRateHz = 32000
  212. if got := SampleRateForKind(cfg); got != 32000 {
  213. t.Fatalf("http-raw sample rate=%d", got)
  214. }
  215. cfg.Ingest.Kind = "icecast"
  216. if got := SampleRateForKind(cfg); got != 44100 {
  217. t.Fatalf("icecast sample rate=%d", got)
  218. }
  219. cfg.Ingest.Kind = "srt"
  220. cfg.Ingest.SRT.SampleRateHz = 48000
  221. if got := SampleRateForKind(cfg); got != 48000 {
  222. t.Fatalf("srt sample rate=%d", got)
  223. }
  224. cfg.Ingest.Kind = "aes67"
  225. cfg.Ingest.AES67.SampleRateHz = 32000
  226. if got := SampleRateForKind(cfg); got != 32000 {
  227. t.Fatalf("aes67 sample rate=%d", got)
  228. }
  229. }