|
- package decoder
-
- import (
- "context"
- "fmt"
- "io"
- "strings"
-
- "github.com/jan/fm-rds-tx/internal/ingest"
- )
-
- var ErrUnsupported = fmt.Errorf("decoder unsupported")
-
- type StreamMeta struct {
- ContentType string
- SampleRateHz int
- Channels int
- SourceID string
- }
-
- type Decoder interface {
- Name() string
- DecodeStream(ctx context.Context, r io.Reader, meta StreamMeta, emit func(ingest.PCMChunk) error) error
- }
-
- type Builder func() Decoder
-
- type Registry struct {
- byName map[string]Builder
- }
-
- func NewRegistry() *Registry {
- return &Registry{byName: map[string]Builder{}}
- }
-
- func (r *Registry) Register(name string, builder Builder) {
- if r == nil || builder == nil {
- return
- }
- r.byName[strings.ToLower(strings.TrimSpace(name))] = builder
- }
-
- func (r *Registry) Create(name string) (Decoder, error) {
- if r == nil {
- return nil, fmt.Errorf("%w: registry nil", ErrUnsupported)
- }
- builder, ok := r.byName[strings.ToLower(strings.TrimSpace(name))]
- if !ok {
- return nil, fmt.Errorf("%w: %s", ErrUnsupported, name)
- }
- return builder(), nil
- }
-
- func (r *Registry) SelectByContentType(contentType string) (Decoder, error) {
- ct := strings.ToLower(strings.TrimSpace(contentType))
- switch {
- case strings.Contains(ct, "mpeg"), strings.Contains(ct, "mp3"):
- return r.Create("mp3")
- case strings.Contains(ct, "ogg"), strings.Contains(ct, "vorbis"):
- return r.Create("oggvorbis")
- case strings.Contains(ct, "aac"), strings.Contains(ct, "adts"):
- return r.Create("aac")
- default:
- return nil, fmt.Errorf("%w: content-type=%s", ErrUnsupported, contentType)
- }
- }
|