Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optical SPDIF audio out #59

Open
wants to merge 23 commits into
base: dev-next
Choose a base branch
from
Open

Conversation

johnboiles
Copy link

@johnboiles johnboiles commented Sep 1, 2024

This PR adds an audio component for SPDIF optical output. All you need to try this is something that can receive optical audio (e.g. soundbar, AV receiver) and an LED. I'm using the debug LED on a Adafruit Feather HUZZAH32. Just put your optical cable up to the LED and it plays audio! I've also tried some real SPDIF transmitters (basically just an LED in a connector).

using simple LED using Toslink connector

This uses (abuses?) the I2S peripheral to stream out a SPDIF bitstream. Because it's not a proper I2s device, I modeled this after usb_audio instead of the i2s_audio. Because of this, however there could be a i2s port collision between the two. Let's discuss how to handle that. SPDIF code is based on this public domain example which works flawlessly for receiving bluetooth audio and outputting it over SPDIF.

Features:

  • Audio out via optical SPDIF
  • Supports filling the buffer with SPDIF silence frames on DMA buffer underflow. (fill_silence option)
  • Supports volume control

Known Issues:

  • This takes the highest I2S port so there could be a collision if you use multiple i2s_audio devices (because the i2s_audio port selection logic doesn't know about it). Let's discuss how to handle this.
  • I can't get the resampler to work on my ESP32 for some reason. I'm getting a failed to allocate even though I log the heap soon after and it says I still have ~240k remaining. Perhaps it only works on boards with PSRAM?
    02:11:13][D][esp-idf:000][resampler]: E (74765) FIR_RESAMPLE: failed to allocate p_out buffer.size 30106 line 2010
    [02:11:13][D][esp-idf:000][resampler]: E (74772) RSP_FILTER: Failed to create the resample handler
    [02:11:13][D][esp-idf:000][resampler]: E (74782) AUDIO_ELEMENT: [resampler] AEL_STATUS_ERROR_OPEN,-1
    
    Update: I'm seeing reports of some rsp_filter bugs in esp-adf v2.5. Apparently the older versions would work without PSRAM and there are maybe some bugs. resampler works ok on my ESP32-S3.

Here's the relevant YAML I've tested with:

YAML for ESP32 (tested on Adafruit Feather HUZZAH32)

esphome:
  name: spdif-media-player

esp32:
  board: esp32dev
  framework:
    type: esp-idf
    sdkconfig_options:
      CONFIG_ESP32_DEFAULT_CPU_FREQ_240: "y"

external_components:
  - source:
      type: git
      url: https://github.com/johnboiles/esphome_audio
      ref: spdif_audio
      #type: local
      #path: /Users/johnboiles/Developer/repos/gnumpi/esphome_audio/esphome/components
    components: [ adf_pipeline, spdif_audio ]

# Enable logging
logger:
  level: DEBUG

# Config for api, wifi, ota
packages:
  common: !include common/common.yaml

wifi:
  power_save_mode: none

spdif_audio:
  pin: GPIO13 # Debug LED on Adafruit Feather HUZZAH32
  fill_silence: true
  debug: false

adf_pipeline:
  - platform: spdif_audio
    id: adf_spdif_out

media_player:
  - platform: adf_pipeline
    id: adf_media_player
    name: spdif-media-player
    internal: false
    keep_pipeline_alive: true
    pipeline:
      - self
      # Not working at the moment for some reason
      # - resampler
      - adf_spdif_out

YAML for ESP32-S3 (Tested on Unexpected Maker ProS3

esphome:
  name: spdif-media-player

esp32:
  board: esp32-s3-devkitc-1
  variant: esp32s3
  framework:
    type: esp-idf
    sdkconfig_options:
      # need to set a s3 compatible board for the adf-sdk to compile
      # board specific code is not used though
      CONFIG_ESP32_S3_BOX_BOARD: "y"
      CONFIG_ESP32S3_DEFAULT_CPU_FREQ_240: "y"
      CONFIG_ESP32S3_DATA_CACHE_64KB:      "y"
      CONFIG_ESP32S3_DATA_CACHE_LINE_64B:  "y"

psram:
  mode: quad
  speed: 80MHz

# Config for api, wifi, ota
packages:
  common: !include common/common.yaml

wifi:
  power_save_mode: none

external_components:
  - source:
      type: git
      url: https://github.com/johnboiles/esphome_audio
      ref: spdif_audio
      #type: local
      #path: /Users/johnboiles/Developer/repos/gnumpi/esphome_audio/esphome/components
    components: [ adf_pipeline, spdif_audio ]

spdif_audio:
  pin: GPIO40
  fill_silence: true
  debug: false

adf_pipeline:
  - platform: spdif_audio
    id: adf_spdif_out

media_player:
  - platform: adf_pipeline
    id: adf_media_player
    name: spdif-media-player
    internal: false
    keep_pipeline_alive: true
    pipeline:
      - self
      - resampler
      - adf_spdif_out

@johnboiles johnboiles force-pushed the spdif_audio branch 2 times, most recently from c32d271 to 2315afe Compare September 1, 2024 09:40
@johnboiles johnboiles marked this pull request as ready for review September 2, 2024 17:59
@johnboiles
Copy link
Author

@gnumpi this is working well for me and I've worked out most of the kinks I think. Would you be available to discuss how to handle potential port collisions?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant