使用 python 流式传输 mp3 icecast 数据
Stream mp3 icecast data using python
我正在尝试编写自己的套接字流式传输器,我使用 python 的套接字连接到已知的 mp3 源,流式传输数据并尝试将其作为 pcm 数据传递到 alsaaudio。
我知道必须获取 icy-metaint,读取那么多字节,获取元数据长度的第一个字节,然后继续读取 metaint 字节。
不幸的是,我 运行 缺乏知识,下面的代码导致播放白噪声。
任何帮助都会很棒。谢谢!
#!/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)
您似乎并没有真正解码音频数据。
您正在尝试从元数据中解复用音频数据,但您还必须 运行 音频数据通过编解码器获取 PCM 样本。 SHOUTcast/Icecast 服务器不发送原始 PCM。他们通常使用包裹在 ADTS 中的 MP3 或 AAC。
我不是 Python 编码员,所以我不知道您有什么可用的。一种简单的解码方法是使用 FFmpeg。它支持 STDIO,因此您可以轻松地将数据传输到它并让它处理流和 return PCM 样本。
我正在尝试编写自己的套接字流式传输器,我使用 python 的套接字连接到已知的 mp3 源,流式传输数据并尝试将其作为 pcm 数据传递到 alsaaudio。
我知道必须获取 icy-metaint,读取那么多字节,获取元数据长度的第一个字节,然后继续读取 metaint 字节。
不幸的是,我 运行 缺乏知识,下面的代码导致播放白噪声。
任何帮助都会很棒。谢谢!
#!/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)
您似乎并没有真正解码音频数据。
您正在尝试从元数据中解复用音频数据,但您还必须 运行 音频数据通过编解码器获取 PCM 样本。 SHOUTcast/Icecast 服务器不发送原始 PCM。他们通常使用包裹在 ADTS 中的 MP3 或 AAC。
我不是 Python 编码员,所以我不知道您有什么可用的。一种简单的解码方法是使用 FFmpeg。它支持 STDIO,因此您可以轻松地将数据传输到它并让它处理流和 return PCM 样本。