import os from datetime import datetime, timedelta import pause import pydub from pydub.utils import make_chunks from source.behaviors.roles import base from source.managers import Manager from source.packets import AudioPacket from source.utils.crypto.type import CipherType class MasterRole(base.BaseRole): """ Role used when the machine is declared as the master. It will be the machine responsible for emitting data that the others peers should play together. """ TARGET_SIZE: int = 60 * 1024 # set an upper bound because of the IPv6 maximum packet size. def __init__(self, manager: "Manager"): super().__init__(manager) # generate a random secret key for AES communication self.manager.communication.secret_key = os.urandom(32) # prepare the audio file that will be streamed # TODO(Faraphel): use another audio source self.audio = pydub.AudioSegment.from_file("../assets/Caravan Palace - Wonderland.mp3") self.play_time = datetime.now() # calculate the number of bytes per milliseconds in the audio bytes_per_ms = self.audio.frame_rate * self.audio.sample_width * self.audio.channels / 1000 # calculate the required chunk duration to reach that size self.chunk_duration = timedelta(milliseconds=self.TARGET_SIZE / bytes_per_ms) # split the audio into chunks self.chunks = make_chunks(self.audio, self.chunk_duration.total_seconds() * 1000) def handle(self): # TODO(Faraphel): check if another server is emitting sound in the network. Return to undefined if yes # get the next chunk chunk = self.chunks.pop(0) # broadcast it in the network audio_packet = AudioPacket( datetime.now() + timedelta(seconds=5), # play it in some seconds to let all the machines get the sample chunk.channels, chunk.frame_rate, chunk.sample_width, chunk.raw_data, ) self.manager.communication.broadcast(audio_packet, CipherType.AES_CBC) # wait for the audio to play # TODO(Faraphel): should adapt to the compute time above pause.until(datetime.now() + self.chunk_duration)