def channel_metadata(self, channel_number, rewind=0): channel_number = int(channel_number) rewind = int(rewind) if channel_number not in self.sbe.sxm.lineup: return self.file_not_found() channel = self.sbe.sxm.lineup[channel_number] channel_id = str(channel['channelKey']) packet = next(self.sbe.sxm.packet_generator(channel_id, rewind)) metadata = None for pes_packet in mpegutils.parse_transport_stream(packet): if pes_packet['pid'] == 1024: for es_packet in mpegutils.parse_packetized_elementary_stream(pes_packet['payload']): new_meta = mpegutils.parse_sxm_metadata(es_packet['payload']) if not metadata and new_meta: metadata = new_meta response = json.dumps({ 'channel': channel, 'nowplaying': { 'artist': metadata[1], 'title': metadata[0], 'album': metadata[2], }, }, sort_keys=True, indent=4).encode('utf-8') self.send_standard_headers(len(response), { 'Content-type': 'application/json', }) self.wfile.write(response)
def channel_metadata(self, channel_number, rewind=0): channel_number = int(channel_number) rewind = int(rewind) if channel_number not in self.sbe.sxm.lineup: return self.file_not_found() channel = self.sbe.sxm.lineup[channel_number] channel_id = str(channel['channelKey']) packet = next(self.sbe.sxm.packet_generator(channel_id, rewind)) metadata = None for pes_packet in mpegutils.parse_transport_stream(packet): if pes_packet['pid'] == 1024: for es_packet in mpegutils.parse_packetized_elementary_stream( pes_packet['payload']): new_meta = mpegutils.parse_sxm_metadata( es_packet['payload']) if not metadata and new_meta: metadata = new_meta response = json.dumps( { 'channel': channel, 'nowplaying': { 'artist': metadata[1], 'title': metadata[0], 'album': metadata[2], }, }, sort_keys=True, indent=4).encode('utf-8') self.send_standard_headers(len(response), { 'Content-type': 'application/json', }) self.wfile.write(response)
def channel_stream(self, channel_number, rewind=0): channel_number = int(channel_number) rewind = int(rewind) if channel_number not in self.sbe.sxm.lineup: return self.file_not_found() channel = self.sbe.sxm.lineup[channel_number] url = 'http://{}:{}/'.format(self.sbe.config('hostname'), self.sbe.config('port')) logging.info('Streaming: Channel #{} "{}" with rewind {}'.format( channel_number, channel['name'], rewind)) self.protocol_version = 'ICY' # if we don't pretend to be shoutcast, doctors HATE us self.send_response_only(200) self.send_header('Content-type', 'audio/aacp') self.send_header('icy-br', '64') self.send_header('icy-name', channel['name']) self.send_header('icy-genre', channel['genre']) self.send_header('icy-url', url) self.send_header('icy-metaint', '32768') self.end_headers() channel_id = str(channel['channelKey']) track_title = '' start_time = None new_meta = False audio = bytearray() for ts_packet in self.sbe.sxm.packet_generator(channel_id, rewind): pes_streams = collections.defaultdict(bytearray) for pes_packet in mpegutils.parse_transport_stream(ts_packet): if 'payload' in pes_packet: pes_streams[pes_packet['pid']].extend(pes_packet['payload']) for pid, pes_stream in pes_streams.items(): for es_packet in mpegutils.parse_packetized_elementary_stream(pes_stream): if pid == 768: audio.extend(es_packet['payload']) elif pid == 1024: metadata = mpegutils.parse_sxm_metadata(es_packet['payload']) if metadata: new_title = '{} - {}'.format(metadata[1], metadata[0]) if new_title != track_title: logging.info("Now playing: " + new_title) track_title = new_title new_meta = True if len(audio) >= 32768: if new_meta: meta_title = ("StreamTitle='" + track_title.replace("'", '') + "';").encode('utf-8') meta_length = math.ceil(len(meta_title) / 16) meta_buffer = bytes((meta_length,)) + meta_title + (b'\x00' * ((meta_length * 16) - len(meta_title))) new_meta = False logging.debug('Metadata: ' + repr(meta_buffer)) else: meta_buffer = b'\x00' audio_interval = audio[:32768] del audio[:32768] try: self.wfile.write(audio_interval) self.wfile.write(meta_buffer) if start_time != None and time.time() - start_time < 4: time.sleep(4 - (time.time() - start_time)) start_time = time.time() except (ConnectionResetError, ConnectionAbortedError) as e: logging.info('Connection dropped: ' + str(e)) return
def channel_stream(self, channel_number, rewind=0): channel_number = int(channel_number) rewind = int(rewind) if channel_number not in self.sbe.sxm.lineup: return self.file_not_found() channel = self.sbe.sxm.lineup[channel_number] url = 'http://{}:{}/'.format(self.sbe.config('hostname'), self.sbe.config('port')) logging.info('Streaming: Channel #{} "{}" with rewind {}'.format( channel_number, channel['name'], rewind)) self.protocol_version = 'ICY' # if we don't pretend to be shoutcast, doctors HATE us self.send_response_only(200) self.send_header('Content-type', 'audio/aacp') self.send_header('icy-br', '64') self.send_header('icy-name', channel['name']) self.send_header('icy-genre', channel['genre']) self.send_header('icy-url', url) self.send_header('icy-metaint', '32768') self.end_headers() channel_id = str(channel['channelKey']) track_title = '' start_time = None new_meta = False audio = bytearray() for ts_packet in self.sbe.sxm.packet_generator(channel_id, rewind): pes_streams = collections.defaultdict(bytearray) for pes_packet in mpegutils.parse_transport_stream(ts_packet): if 'payload' in pes_packet: pes_streams[pes_packet['pid']].extend( pes_packet['payload']) for pid, pes_stream in pes_streams.items(): for es_packet in mpegutils.parse_packetized_elementary_stream( pes_stream): if pid == 768: audio.extend(es_packet['payload']) elif pid == 1024: metadata = mpegutils.parse_sxm_metadata( es_packet['payload']) if metadata: new_title = '{} - {}'.format( metadata[1], metadata[0]) if new_title != track_title: logging.info("Now playing: " + new_title) track_title = new_title new_meta = True if len(audio) >= 32768: if new_meta: meta_title = ("StreamTitle='" + track_title.replace("'", '') + "';").encode('utf-8') meta_length = math.ceil(len(meta_title) / 16) meta_buffer = bytes( (meta_length, )) + meta_title + (b'\x00' * ( (meta_length * 16) - len(meta_title))) new_meta = False logging.debug('Metadata: ' + repr(meta_buffer)) else: meta_buffer = b'\x00' audio_interval = audio[:32768] del audio[:32768] try: self.wfile.write(audio_interval) self.wfile.write(meta_buffer) if start_time != None and time.time( ) - start_time < 4: time.sleep(4 - (time.time() - start_time)) start_time = time.time() except (ConnectionResetError, ConnectionAbortedError) as e: logging.info('Connection dropped: ' + str(e)) return