Go-based FM stereo transmitter with RDS, Windows-first and cross-platform
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

272 行
7.3KB

  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. if got := src.Descriptor().Origin; got == nil || got.Kind != "url" {
  86. t.Fatalf("expected icecast origin kind url, got %+v", got)
  87. }
  88. }
  89. func TestBuildSourceSRT(t *testing.T) {
  90. cfg := config.Default()
  91. cfg.Ingest.Kind = "srt"
  92. cfg.Ingest.SRT.URL = "srt://127.0.0.1:9000?mode=listener"
  93. cfg.Ingest.SRT.Mode = "listener"
  94. cfg.Ingest.SRT.SampleRateHz = 48000
  95. cfg.Ingest.SRT.Channels = 2
  96. src, ingress, err := BuildSource(cfg, Deps{})
  97. if err != nil {
  98. t.Fatalf("build source: %v", err)
  99. }
  100. if src == nil {
  101. t.Fatalf("expected source")
  102. }
  103. if ingress != nil {
  104. t.Fatalf("expected no ingress for srt")
  105. }
  106. if got := src.Descriptor().Kind; got != "srt" {
  107. t.Fatalf("source kind=%s", got)
  108. }
  109. if got := src.Descriptor().Origin; got == nil || got.Kind != "url" || got.Mode != "listener" {
  110. t.Fatalf("expected srt origin url/listener, got %+v", got)
  111. }
  112. }
  113. func TestBuildSourceAES67(t *testing.T) {
  114. cfg := config.Default()
  115. cfg.Ingest.Kind = "aes67"
  116. cfg.Ingest.AES67.MulticastGroup = "239.69.10.20"
  117. cfg.Ingest.AES67.Port = 5008
  118. cfg.Ingest.AES67.PayloadType = 98
  119. cfg.Ingest.AES67.SampleRateHz = 48000
  120. cfg.Ingest.AES67.Channels = 2
  121. cfg.Ingest.AES67.Encoding = "L24"
  122. cfg.Ingest.AES67.PacketTimeMs = 1
  123. cfg.Ingest.AES67.JitterDepthPackets = 6
  124. src, ingress, err := BuildSource(cfg, Deps{})
  125. if err != nil {
  126. t.Fatalf("build source: %v", err)
  127. }
  128. if src == nil {
  129. t.Fatalf("expected source")
  130. }
  131. if ingress != nil {
  132. t.Fatalf("expected no ingress for aes67")
  133. }
  134. if got := src.Descriptor().Kind; got != "aes67" {
  135. t.Fatalf("source kind=%s", got)
  136. }
  137. }
  138. func TestBuildSourceAES67FromInlineSDP(t *testing.T) {
  139. cfg := config.Default()
  140. cfg.Ingest.Kind = "aes67"
  141. cfg.Ingest.AES67.MulticastGroup = ""
  142. 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"
  143. src, _, err := BuildSource(cfg, Deps{})
  144. if err != nil {
  145. t.Fatalf("build source: %v", err)
  146. }
  147. desc := src.Descriptor()
  148. if desc.Transport != "rtp" {
  149. t.Fatalf("transport=%q want rtp", desc.Transport)
  150. }
  151. if desc.SampleRateHz != 48000 || desc.Channels != 2 {
  152. t.Fatalf("shape=%d/%d", desc.SampleRateHz, desc.Channels)
  153. }
  154. if desc.Origin == nil || desc.Origin.Kind != "sdp-inline" {
  155. t.Fatalf("origin=%+v want sdp-inline", desc.Origin)
  156. }
  157. if desc.Origin.Endpoint != "rtp://239.10.20.30:5004" {
  158. t.Fatalf("origin endpoint=%q", desc.Origin.Endpoint)
  159. }
  160. }
  161. func TestBuildSourceAES67WithDiscovery(t *testing.T) {
  162. cfg := config.Default()
  163. cfg.Ingest.Kind = "aes67"
  164. cfg.Ingest.AES67.MulticastGroup = ""
  165. cfg.Ingest.AES67.Port = 0
  166. cfg.Ingest.AES67.Discovery.StreamName = "AES67-MAIN"
  167. cfg.Ingest.AES67.Discovery.TimeoutMs = 1500
  168. var gotReq AES67DiscoverRequest
  169. src, _, err := BuildSource(cfg, Deps{
  170. AES67Discover: func(_ context.Context, req AES67DiscoverRequest) (aoiprxkit.SAPAnnouncement, error) {
  171. gotReq = req
  172. return aoiprxkit.SAPAnnouncement{
  173. 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",
  174. }, nil
  175. },
  176. })
  177. if err != nil {
  178. t.Fatalf("build source: %v", err)
  179. }
  180. if gotReq.StreamName != "AES67-MAIN" {
  181. t.Fatalf("discovery streamName=%q want AES67-MAIN", gotReq.StreamName)
  182. }
  183. if gotReq.Timeout != 1500*time.Millisecond {
  184. t.Fatalf("discovery timeout=%s want 1500ms", gotReq.Timeout)
  185. }
  186. desc := src.Descriptor()
  187. if desc.Detail != "rtp://239.10.20.30:5004 (SAP s=AES67-MAIN)" {
  188. t.Fatalf("descriptor detail=%q", desc.Detail)
  189. }
  190. if desc.Origin == nil || desc.Origin.Kind != "sap-discovery" {
  191. t.Fatalf("origin=%+v want sap-discovery", desc.Origin)
  192. }
  193. if desc.Origin.StreamName != "AES67-MAIN" {
  194. t.Fatalf("origin streamName=%q", desc.Origin.StreamName)
  195. }
  196. }
  197. func TestBuildSourceAES67DiscoveryError(t *testing.T) {
  198. cfg := config.Default()
  199. cfg.Ingest.Kind = "aes67"
  200. cfg.Ingest.AES67.MulticastGroup = ""
  201. cfg.Ingest.AES67.Port = 0
  202. cfg.Ingest.AES67.Discovery.StreamName = "AES67-MAIN"
  203. _, _, err := BuildSource(cfg, Deps{
  204. AES67Discover: func(_ context.Context, req AES67DiscoverRequest) (aoiprxkit.SAPAnnouncement, error) {
  205. _ = req
  206. return aoiprxkit.SAPAnnouncement{}, errors.New("timeout")
  207. },
  208. })
  209. if err == nil {
  210. t.Fatalf("expected discovery error")
  211. }
  212. }
  213. func TestBuildSourceUnsupportedKind(t *testing.T) {
  214. cfg := config.Default()
  215. cfg.Ingest.Kind = "nope"
  216. _, _, err := BuildSource(cfg, Deps{})
  217. if err == nil {
  218. t.Fatalf("expected error")
  219. }
  220. }
  221. func TestSampleRateForKind(t *testing.T) {
  222. cfg := config.Default()
  223. cfg.Ingest.Kind = "stdin"
  224. cfg.Ingest.Stdin.SampleRateHz = 48000
  225. if got := SampleRateForKind(cfg); got != 48000 {
  226. t.Fatalf("stdin sample rate=%d", got)
  227. }
  228. cfg.Ingest.Kind = "http-raw"
  229. cfg.Ingest.HTTPRaw.SampleRateHz = 32000
  230. if got := SampleRateForKind(cfg); got != 32000 {
  231. t.Fatalf("http-raw sample rate=%d", got)
  232. }
  233. cfg.Ingest.Kind = "icecast"
  234. if got := SampleRateForKind(cfg); got != 44100 {
  235. t.Fatalf("icecast sample rate=%d", got)
  236. }
  237. cfg.Ingest.Kind = "srt"
  238. cfg.Ingest.SRT.SampleRateHz = 48000
  239. if got := SampleRateForKind(cfg); got != 48000 {
  240. t.Fatalf("srt sample rate=%d", got)
  241. }
  242. cfg.Ingest.Kind = "aes67"
  243. cfg.Ingest.AES67.SampleRateHz = 32000
  244. if got := SampleRateForKind(cfg); got != 32000 {
  245. t.Fatalf("aes67 sample rate=%d", got)
  246. }
  247. }