Reputation: 3
I'm trying to write my own socket streamer where I connect to a know mp3 source using python's socket, stream the data and try and pass it into alsaaudio as pcm data.
I know have to get the icy-metaint, read that many bytes, get the first byte for the metadata length then continue reading metaint bytes.
Unfortunately I've run out of knowlege and the code below results in white noise being played.
Any help would be amazing. Thank you!
#!/usr/bin/env python
import socket
import sys
import alsaaudio
import time
import threading
import Queue
class Player(threading.Thread):
def __init__(self, messageQueue, metaint):
threading.Thread.__init__(self)
self.metaint = metaint
self.messageQueue = messageQueue
self.device = alsaaudio.PCM()
self.rate = 44100
self.famesize = self.rate
self.device.setrate(self.rate)
self.buffer = ""
def sendPCM(self):
print("Buffer length: " + str(len(self.buffer)))
if len(self.buffer) > self.metaint + 255:
pcmData = self.buffer[:self.metaint]
self.device.write(pcmData)
self.buffer = self.buffer[self.metaint:]
print ("New buffer length 1: " + str(len(self.buffer)))
metaDataLength = ord(self.buffer[:1]) * 16
print ("Metadata length: " + str(metaDataLength))
self.buffer = self.buffer[1:]
print ("New buffer length 2: " + str(len(self.buffer)))
metaData = self.buffer[:metaDataLength]
print len(metaData)
self.buffer = self.buffer[metaDataLength:]
print ("New buffer length 3: " + str(len(self.buffer)))
def run(self):
self.sendPCM()
while True:
message = self.messageQueue.get()
if message: self.buffer += message
self.sendPCM()
self.messageQueue.task_done()
def getResponseHeaders(socket):
data = socket.recv(1024)
while not "\r\n\r\n" in data:
data = data + socket.recv(1024)
return data
def getHeaders(response):
headers = {}
for line in response.splitlines():
if line == '\r\n':
break # end of headers
if ':' in line:
key, value = line.split(':', 1)
headers[key] = value
return headers
HOST = 'bbcmedia.ic.llnwd.net'
GET = '/stream/bbcmedia_lc1_radio1_p?s=1420917253&e=1420931653&h=1ff16ea945bd420669c48ae72d003c09'
PORT = 80
#create an INET, STREAMing socket
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect((HOST, PORT))
client_socket.send("GET %s HTTP/1.0\r\nHost: %s\r\nUser-Agent:%s\r\nIcy-MetaData:%s\r\nRange:%s\r\n\r\n" % (GET, HOST,"VLC/2.0.5 LibVLC/2.0.5", "1", "bytes=0-"))
responseHeaders = getResponseHeaders(client_socket)
headers = getHeaders(responseHeaders)
metaint = int(headers['icy-metaint'])
br = int(headers['icy-br'])
print (metaint)
queue = Queue.Queue()
player = Player(queue, metaint)
player.daemon = True
player.start()
while 1:
queue.put(client_socket.recv(4096))
client_socket.close()
sys.exit(0)
Upvotes: 0
Views: 2016
Reputation: 163234
It doesn't look like you are actually decoding the audio data.
You are attempting to demux the audio data from the metadata, but you must also run the audio data through the codec to get PCM samples. SHOUTcast/Icecast servers do not send raw PCM. They usually use MP3 or AAC wrapped in ADTS.
I'm not a Python coder so I do not know what all you have available to you. An easy way to decode is to use FFmpeg. It supports STDIO, so you can easily pipe data to it and let it handle the stream and return PCM samples.
Upvotes: 1