From 45638020dee4e3c80f712fc666ba68913b347eee Mon Sep 17 00:00:00 2001 From: Cezar H <29507335+usernein@users.noreply.github.com> Date: Wed, 3 Jun 2020 09:45:39 -0300 Subject: [PATCH 1/2] Add more controls, information and events Added the methods seek, next_file, previous_file Added the events file_changed, file_progress Added info about the current file being played in the attributes current_file, current_file_index and current_bytes_offset --- tgvoip_pyrogram/file_stream_call.py | 114 +++++++++++++++++++++++++--- 1 file changed, 103 insertions(+), 11 deletions(-) diff --git a/tgvoip_pyrogram/file_stream_call.py b/tgvoip_pyrogram/file_stream_call.py index 842c3d7..618cf9e 100644 --- a/tgvoip_pyrogram/file_stream_call.py +++ b/tgvoip_pyrogram/file_stream_call.py @@ -16,21 +16,30 @@ # You should have received a copy of the GNU Lesser General Public License # along with PytgVoIP. If not, see . +import os +from threading import Thread from collections import deque from typing import Union, List, IO from tgvoip_pyrogram import VoIPOutgoingCall, VoIPIncomingCall, VoIPService from tgvoip_pyrogram.base_call import VoIPCallBase - class VoIPFileStreamCallMixin(VoIPCallBase): def __init__(self, *args, **kwargs): super(VoIPFileStreamCallMixin, self).__init__(*args, **kwargs) self.input_files = deque() self.hold_files = deque() + self.current_file_index = 0 + self.last_file_name = None + self.current_file = None + self.current_bytes_offset = 0 + self.force_seek = False self.output_file = None self.ctrl.set_send_audio_frame_callback(self._read_frame) self.ctrl.set_recv_audio_frame_callback(self._write_frame) + self.file_changed_handlers = [] + self.file_progress_handlers = [] + self.last_progress_percentage = 0 def __del__(self): self.clear_play_queue() @@ -70,11 +79,19 @@ def clear_play_queue(self): for f in self.input_files: f.close() self.input_files.clear() + self.clear_file_info() def clear_hold_queue(self): for f in self.hold_files: f.close() self.hold_files.clear() + self.clear_file_info() + + def clear_file_info(self): + self.last_file_name = None + self.current_file = None + self.current_file_index = 0 + self.current_bytes_offset = 0 def unset_output_file(self): if self.output_file: @@ -83,22 +100,97 @@ def unset_output_file(self): def _read_frame(self, length: int) -> bytes: frame = b'' - if len(self.input_files): - frame = self.input_files[0].read(length) - if len(frame) != length: - self.input_files[0].close() - self.input_files.popleft() - elif len(self.hold_files): - frame = self.hold_files[0].read(length) - if len(frame) != length: - self.hold_files[0].seek(0) - self.hold_files.rotate(-1) + file_index = self.current_file_index + files = self.hold_files if len(self.hold_files) else self.input_files + + if file_index >= len(files): + print('file index unnexistent') + return + self.current_file = file = files[file_index] + if self.force_seek: + file.seek(self.current_bytes_offset) + self.force_seek = False + frame = file.read(length) + self.current_bytes_offset = file.tell() + + if not hasattr(file, 'size'): + file.size = os.path.getsize(file.name) + + if self.last_file_name != file.name: + self.file_changed() + self.last_file_name = file.name + self.file_progress(self.current_bytes_offset, file.size, (self.current_bytes_offset*100)/file.size) + + if len(frame) != length: + self.next_file() return frame def _write_frame(self, frame: bytes) -> None: if self.output_file: self.output_file.write(frame) + def on_file_changed(self, func: callable) -> callable: # the current file on self.hold_files has changed + self.file_changed_handlers.append(func) + return func + + def on_file_progress(self, func: callable) -> callable: # when a frame is sent + self.file_progress_handlers.append(func) + return func + + def file_changed(self): + args = (self, self.current_file, self.current_file_index) + for handler in self.file_changed_handlers: + callable(handler) and Thread(target=handler, args=args).start() + + def file_progress(self, bytes_offset: int, total_bytes: int, percentage: int): + if self.last_progress_percentage == round(percentage, 1): + return + args = (self, bytes_offset, total_bytes, percentage) + self.last_progress_percentage = round(percentage, 1) + for handler in self.file_progress_handlers: + callable(handler) and Thread(target=handler, args=args).start() + + def previous_file(self): + if len(self.input_files): + print('previous_file can only be used with play_on_hold') + return + file_index = self.current_file_index + file = self.hold_files[file_index] + file.seek(0) + self.current_bytes_offset = 0 + self.current_file_index = file_index-1 if file_index-1 >= 0 else len(self.hold_files)-1 + self.current_file = self.hold_files[self.current_file_index] + return self.current_file + + def next_file(self): + file_index = self.current_file_index + if len(self.input_files): + file = self.input_files[file_index] + file.close() + self.input_files.popleft() + self.current_file = self.input_files[self.current_file_index] + elif len(self.hold_files): + file = self.hold_files[file_index] + file.seek(0) + self.current_bytes_offset = 0 + self.current_file_index = file_index+1 if file_index+1 < len(self.hold_files) else 0 + self.current_file = self.hold_files[self.current_file_index] + return self.current_file + + def seek(self, bytes_offset: int, file_index: int = None): + # round to the largest even number lower than or equal to bytes_offset + even,rest = divmod(bytes_offset, 2) + bytes_offset *= 2 + + files = self.hold_files if len(self.hold_files) else self.input_files + if file_index >= len(files): + print('file index unnexistent') + return + if file_index != None: + self.current_file_index = file_index + self.current_file = files[file_index] + self.current_bytes_offset = bytes_offset + self.force_seek = True class VoIPOutgoingFileStreamCall(VoIPFileStreamCallMixin, VoIPOutgoingCall): pass From 78c51b1574d474973d6c2f09496d877cee5a126f Mon Sep 17 00:00:00 2001 From: Cezar H <29507335+usernein@users.noreply.github.com> Date: Thu, 4 Jun 2020 01:50:27 -0300 Subject: [PATCH 2/2] Fix wrong calc --- tgvoip_pyrogram/file_stream_call.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tgvoip_pyrogram/file_stream_call.py b/tgvoip_pyrogram/file_stream_call.py index 618cf9e..0b0dedc 100644 --- a/tgvoip_pyrogram/file_stream_call.py +++ b/tgvoip_pyrogram/file_stream_call.py @@ -180,7 +180,7 @@ def next_file(self): def seek(self, bytes_offset: int, file_index: int = None): # round to the largest even number lower than or equal to bytes_offset even,rest = divmod(bytes_offset, 2) - bytes_offset *= 2 + bytes_offset = even*2 files = self.hold_files if len(self.hold_files) else self.input_files if file_index >= len(files):