bittorrent peer wire download metadata,bdecode fail - python

I write a spider ,it handshake and extend handshake is ok,and i success download metadata but when bdecode ,except failnot a valid bencoded string
i receive data like :
b'\x00\x00</\x14\x01d8:msg_typei1e5:piecei0e10:total_sizei15360eed6:lengthi800927755e4:name12:Zet9 Geo.rar12:piece lengthi1048576e6:pieces15280:3}\xdf\xd64\x90\x15z\x96aN\xe1\x08\xffU\x8c\xbd0m\xc0\xbb\x16\xd5\x13\xad\x9e\xb4\xa1\x1c\x02s\xe2\xc2\x1f\x11\xab\x1c-\xe0\x89{\xd8G\xfbFN\x0e~\xce\xb6pWG!%\xc4\xa3O<{^y0\'\xad\x92\xd2\xf3\xb7Hadq\xc3\x13"\xed\xdb\xfdx}\x05\x0e\xcd\x1e\xfc\xf4\xdc5\x80N\xe8\x8b\xbc\\\x10\x82\xf3i\x08\x81U\xa6\xb0\xf67\xb8\xaa\xebx\xe2\xe9jNv\x87\xfb\x0c\xb9$8\xc5s~\x0f{\x8f\xa4\xa8\x95\x08\xd9\r,X\nz\x9d\x87\x1e/\x1a\x00\x8d\xb3\xbc\x14\x08\xc7\x80\x0b\xecO\xb4M]\x81\xfa\xe1\xb02 C\x8e\xda\xe2)K\xcf\xdf\xee}>\x16\x95\x11|8\x87\x94J<\xe9%\t\xfc!\x12\xe8>\nWR\xb3\x8fp\xeaZ\xb9\xcb\xc9\xe0J\xe6\x91\xde\x08\xd8\x86\x90~\xe3{j\xd0\xbd\x11\xf8\x8f\x9c}\xdc\x13\xd8\xeb\x0c\x06\xb6v\t\x0f_4\x8c\xc2\xe4jn\xcf\xd2\x1bF\xc2\xd3\xd2fz\xa1:z=\xc9;N\x1f\xa6r\xc1\x9fPi\x88g\xd7\xe8\xf1\x15\xee\xbbkLo\xa8\x13\x03p\xc5\x9e\x18\xdc+\xf5\xe1\xe6\x15\xc7(\x83\x050F\xdb\xe3\xc5n\x08\xb6LJk\x15\xb8\xad\xbaM\xb3\x8d\xf8U\xcc\\5/}_\t1\x15\x91\x96\xaa7\xbd,4SL8\xb9_\xb5\x9f3\x93\xce\xff\x08\x18J\xafXy\x11\x8cD\xed\x88\x17\x1a\xa2\xc5e+\xa0\xb4X\xc4\xacsq\xce6\xb2\xce\x8f\x93\xffK\xefn}\x93\xb3!l\x19~\xea\x02\xb3\x8ag\xbeR\x05z\xa7\xac \x19\xc3E\x07~\x06\x8b#5oW\x80\xe5\xa0pQ\x01Y\x9e\xf2\x0e\xa7\xb6\x14\x14\xb9\xb6C\xee(-\xb6\xeb\x12\xa8\xbdVEt#\x99sg_G\xa1\xc1\x10[\xb7CM>R\x82O\xca\x8b\xce\xa5g\xb0\xe9\xad\xa4\xfe0\x8d\x15Emx\x9e\x97\xa3\x037\x83p\xe9{\xe7\xd5\xabx\xfd\xb97l\x1av\xac?\xe4\x1e>.\xd1\xe3\xb7\x81$\t\xfc3\xccr\xe7\xb5\x8dO\x81\xa2\xc8\xfa\x15\x16\xeaR\xeb\x92\x9a* \x81\xca\x90\x03\xa6\xcb:2HX;\xea\xefu\x0eS\xed\x9cZ\xce< \xdf\xfc\xe0\xbc\xff\xda\x916[\x1afl\xe3?\xde\x1a\xbb\xba\xdb\xa4E\x8aR\x11\x9a\xd0|\xb5\x92\x8e\xe6h2-\xe8\x00O\x14\xd5\xb6uk\xa7\xd8"u\x9c\x860\xa5%\xb7\x107^\xc0\xfcJ\xcaA\x8c\xd4\x12\x97\x9eE\x1a\xc5.\x93\xd4\xa3\xdd\n\xfcG\x98r\xb3ck?Gj\xcc\xf6F\xe6`\xd3\xc9\xe5\t\x1aA]\xdd\x01\x1f\xba\xecw\x81\xb6\x0eR\x8a\xdaR\x10\xd5\xae\x92\x003h<`\xe3\xc6\xd5r\xd0\xa4\xc4M2\x1d\xb0\x07+\x9c\xd6\x01\xe1eR\xbaO\x0f\xddo\xb6BM\xa8A:\x7f\x05|I\x16I~\xfbM#\xe7~\xdb\xd8*q!>\\\x1d3nB\xb5&f4D\xcc\xc7_\x03\xa9\xde\xe1\xab1\xd9\xf9\xde\xc6\xae\xf1\x9a}\xdaa4\x1a\x95(S\xf5\xceP\xc2\xf2\xbf\xc8\x01\xe9\xd9\x17\xc2)\x17\xf03\xfcv\n\xe9a\x9f\xda\xf2\x844\xfb$c\xb3mdC^^\xc1=>]\xa5\xefn/)\x00\x1a\xc8\xa0L\xe6\x07\xf8\x0b\xaf8\x18\xac\x02\xe9\x85\xa6=S\x95\x98\xd0\xd7\nA+\xff\x97\\\xa69\xcb(<W\r\xa2\x93]\t\xb6~\xf0\xd5\xb1.\x9b\xf1\xa0\xb2P\xe4%\x8b\x1b\xf7\xfe`\x8c\xae\xf8\xa5\xc1e\xe1`h\n\xb2d\x0e\x05\x07\xc03\x9crZ\xca\x1fg\x83r\x0b]2\xb6\x19\x18m\x8b0T\xc58\x94\x13\x14A\x1d\x17?\x07m\xe1\x8eZ[\rUXN\xc4\xcbK\xdd\xb9\xf3\x04\xd1\x9e\xa8\x04\xc4\xdd\xd3/O$v\xf5\xd5M\xdbd\xc0\xfcF>\xa3\x11\x14\x9bw\xe4\xeb-0\xc0y\xf6\xcc\xfc\x89+,\xeb\xdbx\x0f\xb4\x13\xfc\x86X\x98\x95\x1c\x15|^:\xf7\x0e\xe07\x8f\x18Vi\x86\x1b(\x19n\x08e\\S>\xb8\x154\xd1T\xcd\xa1\xa8\xca\xa2\xaa\xb1G\x03\xb1A\xda\xcaz\x07\xe1\xd5\xc5\xfayR\xdc7\xf9[\x15~\x83_W\x8cn2\x8f\xaf\xa0\xb73+\xefZ#\x04<\xa4\x99#\xac\x99\xc4\xc7\xae\x8b\x93\xa2\xa1vcQ\xb6\xab\r\x94\xb99\xa2\xbf\x9fr\x8c\x17p\xacH\xe5\x92p\xe9q\x92\x8e\x13d\\\x05\xe1TH\x86~\xe8LD\xa1\xe3\xb7\xed\xb4\x8d\xfb\xf6\xd3\xfcN\xa9\x14b\xb3g\x80\x07\x7f\xe3\xd2`\x1ds\x95\xc4}\xf0W\xc7\x96\x98\x97\xa1b\x9a\x89\xaarX\xecKP\xc0\xady \xfau\x88\xca\xb8T\xf5\xf8\x8e\x1f\x08\x7f\x8d\xab\xb6_\xf6\xe7\x17\t\x1bQ\x1b\r)Z#\x19+HTv\xd9\xa2\r\x13\xb4)\xf6\x8e\x8fB\x14F2\x1e\xc8m\xc9N{l\xd5\'\xc13\xc2e\xa7U\\H(-\xab\xd8\xff6l\xbd\xb2\xf1\xf3\xd8)q\xfd\xb5\x1c\xb0\xed>B\xb8+$Tj\xe3OD\xa9\x0f\x0e\xda\xda\x8cZe.\xb5\x9e%\xbc\x9c\x0b\xf2\xe7=gz\xf1D\x05r\x88\xec\x87fd\x1fg\t (\xdf\x89\xc4\x82\xbb~#\xc3\xe6\xb0[\xb9\x82\x82n\x08\x10\xa3\x84\x00`\x00\x8dO\x93A\xb8%;\xde\x10'
i append a 'e' keep still fail,so i think problem in pieces
>>> bencoder.bdecode(b'd6:lengthi800927755e4:name12:Zet9 Geo.rar12:piece lengthi1048576e6:pieces4:1234e')
I get this:
{b'length': 800927755, b'name': b'Zet9 Geo.rar', b'piece length': 1048576, b'pieces': b'1234'}
def request_metadata(_socket,extHandShakeId,piece,timeout=20):
msg = chr(20) + chr(extHandShakeId) + bencoder.bencode({"msg_type":0,"piece":piece}).decode()
msgLen = pack(">I",len(msg))
msg = msgLen+msg.encode()
_socket.send(msg)
#_socket.setblocking(0)
total = b''
start = time()
data = _socket.recv(20*1024)
return data
a piece size 16*1024byte,_socket.recv(20*1024) can't receive all of piece?

The problem over here:
data = _socket.recv(20*1024)
function replace this:
def request_metadata(_socket,extHandShakeId,piece,timeout=20):
msg = chr(20) + chr(extHandShakeId) + bencoder.bencode({"msg_type":0,"piece":piece}).decode()
msgLen = pack(">I",len(msg))
msg = msgLen+msg.encode()
_socket.send(msg)
total = b''
while True:
try:
data = _socket.recv(20*1024)
if data:
total = total + data
except socket.timeout as e:
print(str(e))
break
return total
end i can bdecode that metadata
{b'length': 800927755, b'name': b'Zet9 Geo.rar', b'piece length': 1048576, b'pieces': b'3}\xdf\xd64\x90\x15z\x96aN........

Related

Python - Getting output of socket

I am trying to get the output after the lolimessage was sent but i get no output
try:
xmr = ''
data = s.recv(1024)
d = data.decode("UTF-8")
xmr += d
if "loli" in xmr:
s.send(lolimessage + enter)
print("Loli Sent")
else:
print("loli NOT sent")
except:
s.close()
try:
xmr = ''
data = s.recv(1024)
d = data.decode("UTF-8")
xmr += d
print(xmr)
except:
print("fail to print")
s.close()
The loli part works and prints out data but on the 2nd try i get "fail to print", can any1 plz help
s.send(lolimessage + enter)
send it in bytes with encoding
s.send(bytes(lolimessage + enter, "utf-8"))

Sending and receiving package in python

This is a console chat app on a TCP socket server. The client will send the request/message to the server and the server will distribute the message to the target user or provide requested information.I am currently running into a problem regarding the recv package on the server side. I received the package and was able to print it out. However the system still give me a syntax error for some reason.
Thanks.
This is my client:
import socket
import select
import errno
import sys, struct
import pickle
HEADER_LENGTH = 1024
IP = "127.0.0.1"
PORT = 9669
def send_login_request(username):
package = [1]
length = len(username)
if length > 1019:
print ("Error: Username too long")
sys.exit()
package += struct.pack("I", length)
package += username
return package
def send_message(recv_id, message):
package = [2]
length = len(message)
if length > 1015:
print('message too long')
sys.exit()
package += recv_id
package += struct.pack('I', length)
package += message
return package
def send_con_request(conv_id):
package = [3]
length = len(id)
if length > 1015:
print('id too long')
sys.exit()
package += struct.pack("I", length)
package += conv_id
return package
# Create a socket
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Connect to a given ip and port
client_socket.connect((IP, PORT))
client_socket.setblocking(False)
my_username = input("Username: ")
request = send_login_request(my_username)
user_request = str(request)
client_socket.send(user_request.encode())
username_conf = client_socket.recv(HEADER_LENGTH).decode()
if username_conf == "Welcome to the server":
con_id = input("Please enter conversation's id, if don't have one, please enter no ")
if con_id == 'no':
con_request = send_con_request(con_id)
con_request = str(con_request)
client_socket.send(con_request.encode())
else:
con_request = send_con_request(con_id)
con_request = str(con_request)
client_socket.send(con_request.encode())
conversation = client_socket.recv(HEADER_LENGTH).decode()
recv_id = input("Please enter receiver's id")
while True:
# Wait for user to input a message
message = input(f'{my_username} > ').encode()
# If message is not empty - send it
if message:
send_message = send_message(recv_id,message)
client_socket.send(bytes(send_message))
try:
while True:
message_receiver = client_socket.recv(HEADER_LENGTH).decode()
x = message_receiver.split('|')
print(x)
username = x[0]
message = x[1]
# Print message
print(f'{username} > {message}')
except IOError as e:
if e.errno != errno.EAGAIN and e.errno != errno.EWOULDBLOCK:
print('Reading error: {}'.format(str(e)))
sys.exit()
# We just did not receive anything
continue
except Exception as e:
# Any other exception - something happened, exit
print('Reading error: {}'.format(str(e)))
sys.exit()
This is my server:
import socket
import select
import struct
import sys
import pickle
HEADER_LENGTH = 1024
conversation ={}
users = [
{
'username': 'user1',
'user_id': 1
},
{
'username': 'user2',
'user_id': 2
},
{
'username': 'user3',
'user_id': 3
},
{
'username': 'user4',
'user_id': 4
},
{
'username': 'user5',
'user_id': 5
}
]
def login(username):
for user in users:
if user['username'] == username:
return user
else:
return False
IP = "127.0.0.1"
PORT = 9669
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_socket.bind((IP, PORT))
server_socket.listen()
# List of sockets for select.select()
sockets_list = [server_socket]
# List of connected clients - socket as a key, user header and name as data
clients_socket = {}
sessions = {
(1,2) : '1.txt',
(3,4) : '2.txt'
}
def getRecvSocket(user_id):
try:
return sessions[user_id]
except:
return None
def sendErrorMes(socketid, mes):
package = [9]
length = len(mes)
if length > 1019:
length = 1019
package += struct.pack("I", length)
package += mes
print(f'Listening for connections on {IP}:{PORT}...')
# Handles message receiving
def receive_message(client_socket):
try:
receive_message = client_socket.recv(HEADER_LENGTH)
return receive_message
except:
return False
while True:
read_sockets, _, exception_sockets = select.select(sockets_list, [], sockets_list)
# Iterate over notified sockets
for notified_socket in read_sockets:
# If notified socket is a server socket - new connection, accept it
if notified_socket == server_socket:
client_socket, client_address = server_socket.accept()
sockets_list.append(client_socket)
else:
# Receive message
package = receive_message(notified_socket)
print(package)
package_recv = eval(package.decode())
print(package_recv)
print(type(package_recv))
package_type = package_recv[0]
if package_type == 1:
size = struct.unpack("I", package[1:5])
if size[0] > 1019:
continue
username = package[5:5+size[0]]
username = username.decode()
# username = package_recv[1]
user = login(username)
if user == False:
notified_socket.send("no user found".encode())
else:
sessions[user["user_id"]] = notified_socket
notified_socket.send(("Welcome to the server").encode())
elif package_type == 2:
recv_id = struct.unpack("I", package[1:5])
size = struct.unpack("I", package[5:9])
if size[0] > 1015:
continue
# recv_id = package_recv[1]
if getRecvSocket(recv_id) == None:
sendErrorMes(notified_socket, "User is offline")
else:
message = package[9:9+size[0]]
# message = package_recv[2]
for socket in sessions.values():
if socket == notified_socket:
user = sessions[notified_socket]
# print(f'Received message from {user}, {message}')
# fIterate over connected clients and broadcast message
for client_socket in clients_socket:
# if clients[client_socket] == receive_user and client_socket != notified_socket:
# But don't sent it to sender
if client_socket != notified_socket and clients_socket[client_socket] == recv_id:
# Send user and message (both with their headers)
# We are reusing here message header sent by sender, and saved username header send by user when he connected
a = sessions[notified_socket]
b = recv_id
with open(f"{conversation[a,b]}.txt", "w"):
f.write(user + message)
client_socket.send((user + "|" + message).encode())
if message is False:
# print('Closed connection from: {}'.format(user))
# Remove from list for socket.socket()
sockets_list.remove(notified_socket)
# Remove from our list of users
del clients_socket[notified_socket]
continue
elif package_type == 3:
size = struct.unpack("I", package[1:5])
if size[0] > 1019:
continue
convo_id = package[5:5+size[0]]
convo_id = convo_id.decode()
# convo_id = package_recv[2]
if convo_id in conversation:
with open(conversation[convo_id], 'rb') as file_to_send:
for data in file_to_send:
notified_socket.sendall(data)
print('send successful')
else:
f = open(f"{len(conversation)+1}.txt", "w+")
This is the error in the server side which I am having a problem to locate and solve:
Listening for connections on 127.0.0.1:9669...
b"[1, 5, 0, 0, 0, 'u', 's', 'e', 'r', '1']"
[1, 5, 0, 0, 0, 'u', 's', 'e', 'r', '1']
<class 'list'>
b''
Traceback (most recent call last):
File "c:/Users/Duong Dang/Desktop/bai 2.3/server.py", line 134, in <module>
package_recv = eval(package.decode())
File "<string>", line 0
^
SyntaxError: unexpected EOF while parsing
The sending code doesn't make a lot of sense. You're creating a python list which is a most strange way to implement a protocol. You're then taking python's string representation of that list and sending it to the server. You're not doing anything on the server side to ensure that you got the entire message. Then you're using eval to interpret the string you created on the client. That is a very dangerous practice, as your peer can essentially instruct your python interpreter to do literally anything.
Also, your send_con_request is calling len(id) which won't work at all because id is a python built-in that doesn't supply a __len__ method. I assume that was supposed to be len(conv_id)?
Anyway, you should rework your protocol. Use the struct tools to create the correct binary string you want. There are tons of possible ways to structure this but here's one. On the client side, create a fixed-length header that identifies which request type you're sending and the length of the remaining "payload" bytes. You'll convert your string (username or whatever) into bytes first with str.encode.
import struct
# ProtoHeader encodes a 16 bit request identifer, plus a 32 bit payload
# length. A protocol data unit consists of this 6-byte header followed by
# payload bytes (which will vary according to the request)
ProtoHeader = struct.Struct("!HI")
LoginRequest = 1
SomeOtherRequest = 2
...
def format_login_request(username):
""" Create a protocol block containing a user login request.
Return the byte string containing the encoded request """
username_bytes = username.encode()
proto_block = ProtoHeader.pack(LoginRequest, len(username_bytes)) + username_bytes
return proto_block
...
conn.sendall(format_login_request(username))
On the server side, you will first receive the fixed-length header (which tells you what the request type was and how many other payload bytes are present). Then receive those remaining bytes ensuring that you get exactly that many. socket.recv does not guarantee that you will receive exactly the number of bytes sent in any particular send from the peer. It does guarantee that you will get them in the right order so you must keep receiving until you got exactly the number you expected. That's why it's important to have fixed length byte strings as a header and to encode the number of bytes expected in variable length payloads.
The server would look something like this:
import struct
ProtoHeader = struct.Struct("!HI")
LoginRequest = 1
def receive_bytes(conn, count):
""" General purpose receiver:
Receive exactly #count bytes from #conn """
buf = b''
remaining = count
while remaining > 0:
# Receive part or all of data
tbuf = conn.recv(remaining)
tbuf_len = len(tbuf)
if tbuf_len == 0:
# Really you probably want to return 0 here if buf is empty and
# allow the higher-level routine to determine if the EOF is at
# a proper message boundary in which case, you silently close the
# connection. You would normally only raise an exception if you
# EOF in the *middle* of a message.
raise RuntimeError("end of file")
buf += tbuf
remaining -= tbuf_len
return buf
def receive_proto_block(conn):
""" Receive the next protocol block from #conn. Return a tuple of
request_type (integer) and payload (byte string) """
proto_header = receive_bytes(conn, ProtoHeader.size)
request_type, payload_length = ProtoHeader.unpack(proto_header)
payload = receive_bytes(conn, payload_length)
return request_type, payload
...
request_type, payload = receive_proto_block(conn)
if request_type == LoginRequest:
username = payload.decode()

getting part of the recv() buffer

I have this code, that print the http server response, but now I'm trying to get the only the status code, and from there make decisions.
like :
Code:200 - print ok
code:404 - print page not found
etc
PS: cant use http library
from socket import *
#constants variables
target_host = 'localhost'
target_port = 80
target_dir = 'dashboard/index.html'
# create a socket object
client = socket(AF_INET, SOCK_STREAM) # create an INET (IPv4), STREAMing socket (TCP)
# connect the client
client.connect((target_host,target_port))
# send some data
request = "GET /%s HTTP/1.1\r\nHost:%s\r\n\r\n" % (target_dir, target_host)
#Send data to the socket.
client.send(request.encode())
# receive some data
data = b''
while True: #while data
buffer = client.recv(2048) #recieve a 2048 bytes data from socket
if not buffer: #no more data, break
break
data += buffer #concatenate buffer data
client.close() #close buffer
#display the response
print(data.decode())
I would change the reception loop as below: extract the first line, split it, interpret the second word as an integer.
line = b''
while True:
c = client.recv(1)
if not c or c=='\n':
break
line += c
status = -1
line = line.split()
if len(line)>=2:
try:
status = int(line[1])
except:
pass
print(status)
If we heavily rely on try we can simplify the second part
try:
status = int(line.split()[1])
except:
status = -1
print(status)

How can I monitor client side inputs and send input requests from server every 5 seconds if no input is received?

I want to set up tcp server and client where server monitors client input and sends a request every 3 seconds if no input is received. Then client replies with its time. This goes on in an infinite loop. Also, they both have an option to exit the infinite loop. I don't know how to add the exit functionality as send(), recv() and input() block the code execution.
I have tried using select with 3 second timeout, it didn't work. I have tried threading but it stops after first user input until the next user input. I want it to go infinitely unless user wants to exit.
Infinite loop for communication:
client side:
while True:
data = ClientSocket.recv(1024).decode()
print("From Server: " + str(data))
# clear string
data = ''
data = 'Random Number: ' + str(random.randint(1, 101))
current_time = datetime.now()
required_format = (current_time.strftime("Date: %Y-%m-%d\tTime: %H:%M:%S.%f")[:-3])
data = data + "\t" + required_format + '\n'
ClientSocket.send(data.encode())
print("Sending: " + str(data))
data = ''
Server Side:
while True:
data = ''
data = 'Please enter a response.'
print("Sending: " + str(data))
ClientSocket.send(data.encode())
# clear string
data = ''
data = ClientSocket.recv(1024).decode()
print("From Client: " + str(data))
Select function that i tried:
readlist = [ClientSocket]
incoming = select.select(readlist, [], [], 3)
if incoming:
#perform a chat function here
else:
#use the code mentioned above for automated messages
This is the threading feature that I tried:
Python 3 Timed Input
How can I restrict time for recv(), send() and input() while sending and receiving message request and acknowledgements?
Please let me know if you would like to see the full code.
Something like this should work for you
server.py
inputs = [server]
outputs = []
messages = {}
try:
while inputs:
readable, writable, error = select.select(inputs, outputs, [])
for sock in readable:
if sock is server:
client, _ = sock.accept()
inputs.append(client)
messages[client] = Queue()
else:
data = sock.recv(1024).decode()
if data and data != 'exit\n':
print(data)
messages[sock].put(data)
if sock not in outputs:
outputs.append(sock)
else:
print('Client disconnected')
sock.close()
inputs.remove(sock)
for sock in outputs:
try:
msg = messages[sock].get_nowait()
sock.send(msg.upper().encode())
except Empty:
sleep(3)
sock.send(b'No data recieved')
outputs.remove(sock)
except KeyboardInterrupt:
server.close()
client.py
inputs = [sock, sys.stdin]
while inputs:
readable, _, _ = select.select(inputs, [], [])
for s in readable:
if s is sock:
data = sock.recv(1024).decode()
if data:
if data.lower() != 'exit':
print('{}'.format(data))
sys.stdout.write('You: ')
sys.stdout.flush()
else:
exiting('Server')
else:
exiting('Server')
else:
msg = sys.stdin.readline()
sock.send(msg.encode())
sys.stdout.write('You: ')

Stream mp3 icecast data using python

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)
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.

Categories

Resources