79147248

Date: 2024-11-01 07:41:32
Score: 0.5
Natty:
Report link

Base on the protocol description link (thank to Rauuun) I implemented this algorithm.

ICY_METADATA_INTERVAL = 16000 # bytes
ICY_BYTES_BLOCK_SIZE = 16  # bytes
ICY_METADATA_SIGNAL = "META_EVENT".encode()

async def stream_from_queue(queue: Queue, session_id: str):
    buffer = b""
    ...
        for chunk in <stream_queue>:
            ... # get an audio chunk from queue
                if chunk == ICY_METADATA_SIGNAL:  # if get a special signal we can send some metadata
                    # flush buffer padded with zeros to ICY_METADATA_INTERVAL length
                    yield buffer + (ICY_METADATA_INTERVAL - len(buffer)) * (0).to_bytes()
                    buffer = b""
                    # send a meta message
                    yield preprocess_metadata()
                else:  # send raw audio data
                    buffer += chunk
                    if len(buffer) < ICY_METADATA_INTERVAL:
                        continue
                    yield buffer[:ICY_METADATA_INTERVAL]
                    yield (0).to_bytes() # we have to send at least zero byte as metadata after every ICY_METADATA_INTERVAL
                    buffer = buffer[ICY_METADATA_INTERVAL:]
...


def preprocess_metadata(metadata: str = "META_EVENT") -> bytes:
    icy_metadata_formatted = f"StreamTitle='{metadata}';".encode()
    icy_metadata_block_length = len(icy_metadata_formatted) + 1
    return (
        # number of ICY_BYTES_BLOCK_SIZE blocks needed for this meta message (including this byte)
        (1 + icy_metadata_block_length // ICY_BYTES_BLOCK_SIZE).to_bytes(1, "big")
        # meta message encoded
        + icy_metadata_formatted
        # zero-padded tail to fill the last ICY_BYTES_BLOCK_SIZE
        + (ICY_BYTES_BLOCK_SIZE - icy_metadata_block_length % ICY_BYTES_BLOCK_SIZE)
        * (0).to_bytes(1, "big")
    )

screenshot of a stream with META_EVENT message

Reasons:
  • Probably link only (1):
  • Long answer (-1):
  • Has code block (-0.5):
  • Self-answer (0.5):
  • Low reputation (0.5):
Posted by: Ivan Vinitskyi