#!/usr/bin/env python ''' client.py: Um cliente de stream de audio. Se conecta a um servidor e recebe um stream de pacotes UDP contendo um áudio. Concatena vários pacotes e converte a onda para mostrá-la na tela como animação. ''' __authors__ = "Eduardo H. Trevisan, Gabriela Stein" __date__ = "2019-06-07" __email__ = "eht17@inf.ufpr.br" __status__ = "Production" import socket import sys import time import getopt import alsaaudio # Biblioteca de audio import pickle # Serializacao dos dados import numpy as np # Tratamento de dados numericos import matplotlib.pyplot as plt # Biblioteca de plot grafico import matplotlib.animation as animation import datetime seq = 1 # Sequencia atual das mensagens lost = 0 # Numero de mensagens perdidas outOfOrder = 0 # Numero de mensagens fora de ordem # Inicializando plot fig = plt.figure(facecolor='black') plt.axes(xlim=(0, 2600), ylim=(-6000, 6000)) ax = plt.subplot(111, frameon=False) # Removendo ticks ax.set_xticks([]) ax.set_yticks([]) def usage(): print('uso: client.py [-d ] [-a
] [-p ]', file=sys.stderr) sys.exit(2) def handle_close(evt): '''Função executada ao fechar a janela, encerra a execução e imprime as estatísticas''' plt.close("all") print(datetime.datetime.now()) print('Encerrando cliente...\n') print(' Numero total de mensagens : ', seq) print(' Numero de mensagens perdidas : ', lost) print('Numero de mensagens fora de ordem : ', outOfOrder) sys.exit(0) # Configurando evento de fechamento da janela fig.canvas.mpl_connect('close_event', handle_close) def init(): '''Função para inicialização da imagem na animação''' im = "" return im def updatefig(*args): '''Escuta dados do servidor e plota onda para animacao''' global seq, outOfOrder, lost line = np.array([]) # Espera 20 mensagens e as concatena para plot da onda for i in range(0,20): msg = "" # Esperando dados response = UDPClientSocket.recvfrom(bufferSize) # Decodificando mensagem msg = pickle.loads(response[0]) if seq == msg[0]: # Se recebemos a mensagem correta out.write(msg[2]) # Tocar audio seq += 1 elif seq < msg[0]: # Se recebemos uma mensagem do futuro out.write(msg[2]) # Tocar audio lost += msg[0] - seq # Contabilizar numero de msg perdidas seq = msg[0] + 1 else: # Se recebemos uma mensagem do passado outOfOrder += 1 # Atualizar contadores de mensagens lost -= 1 # perdidas e fora de ordem # Compilando ondas para plot signal = np.frombuffer(msg[2], dtype='int16') line = np.append(line, signal) # Plotar onda # im = plt.plot(line, 'C1') c = (1,1,1) im = plt.plot(line, color=c) return im if __name__ == '__main__': # Argumentos padroes device = 'default' address = '127.0.0.1' port = '20001' opts, args = getopt.getopt(sys.argv[1:], 'd:a:p:h:') for o, a in opts: if o == '-d': device = a elif o == '-a': address = a elif o == '-p': port = a elif o == '-h': usage() # Abrir dispositivo de saida out = alsaaudio.PCM(alsaaudio.PCM_PLAYBACK, device=device) # Atributos: Mono, 44100 Hz, 16 bit little endian frames out.setchannels(1) out.setrate(44100) out.setformat(alsaaudio.PCM_FORMAT_S16_LE) # Numero de frames por periodo out.setperiodsize(160) # Construir mensagem com endereco do servidor serverAddressPort = (address, int(port)) bytesToSend = str.encode("") bufferSize = 1024 # Criar um socket UDP para o cliente UDPClientSocket = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM) print(datetime.datetime.now()) print("Cliente inicializado") print("Enviando mensagem para: " + address + ":" + port + "\n") # Mandar mensagem para o Servidor UDPClientSocket.sendto(bytesToSend, serverAddressPort) print(datetime.datetime.now()) print("Escutando servidor...\n") # Escutar mensagens e fazer animação ani = animation.FuncAnimation(fig, updatefig, init_func=init, interval=0.005, blit=True) plt.show()