I am having some issues trying to properly send audio data from a file to an Icecast server in Python.
Here is my class :
import requests
from base64 import b64encode
class IcecastClient:
def __init__(self, host, port, mount, user, password, audio_info):
self.host = host
self.port = port
self.mount = mount
self.user = user
self.password = password
self.audio_info = audio_info # Additional audio information
self.stream_url = f"http://{host}:{port}{mount}"
def connect(self):
# Basic Auth Header
auth_header = b64encode(f"{self.user}:{self.password}".encode()).decode("ascii")
self.headers = {
'Authorization': f'Basic {auth_header}',
'Content-Type': 'audio/mpeg',
'Ice-Public': '1',
'Ice-Name': 'Auralyra Stream',
'Ice-Description': 'Streaming with Auralyra',
'Ice-Genre': 'Various',
'Ice-Audio-Info': self.audio_info
}
def stream_audio_file(self, file_path, chunk_size=4096):
with requests.Session() as session:
session.headers = self.headers
with open(file_path, 'rb') as audio_file:
while True:
chunk = audio_file.read(chunk_size)
if not chunk:
break # End of file
try:
response = session.put(self.stream_url, data=chunk)
if response.status_code != 200:
print(f"Streaming failed: {response.status_code} - {response.reason}")
break
except requests.RequestException as e:
print(f"Error while sending audio chunk: {e}")
break
if response.status_code == 200:
print("Streaming successful")
def send_audio(self, audio_chunk):
try:
# Send the chunk using the session with predefined headers
response = self.session.put(self.stream_url, data=audio_chunk)
if response.status_code != 200:
print(f"Streaming failed: {response.status_code} - {response.reason}")
except Exception as e:
print(f"Error while sending audio chunk: {e}")
The problem is that although Icecast recognizes the stream and the status of the mountpoint looks good, trying to listen to the stream doesnt work at all. My guess is that this as to do with how I send the data to the server.
PS: I am trying to avoid using librairies like 'shout' to do that
You can't just send the audio to the server at an arbitrary speed. You must send it at the speed in which it would be played back.
The server doesn't really know or care about the timing information in the stream. It simply buffers a bit, and when clients connect it reads from the buffer and sends them fresh data as it comes in. So, if you shove an hour's worth of audio through the server as fast as it will eat, there will be only a few seconds of buffer available to clients when they connect.
I know you say you don't want to use other libraries for this, but you probably should. You actually need to make a continuous stream and not just send file after file. This means all your assorted audio files to PCM, "playing out" that PCM at the correct rate to the codec, and sending the encoded data to the server as it comes from the codec. This is quite a bit to reinvent. At the very least, you'll have to send your pre-encoded files at the right rate, and those files would have to be free of ID3 tags, and would need to be the same sample rate and channel format.