Main streaming function that handles manifest updates and segment downloads. Args: fetcher: StreamFetcher instance to handle HTTP requests stop_event: Threading event to signal when to stop fetching start_sequence: Initial sequence number to start from
(fetcher: StreamFetcher, stop_event: threading.Event, start_sequence: int = 0)
| 676 | } |
| 677 | |
| 678 | def fetch_stream(fetcher: StreamFetcher, stop_event: threading.Event, start_sequence: int = 0): |
| 679 | """ |
| 680 | Main streaming function that handles manifest updates and segment downloads. |
| 681 | |
| 682 | Args: |
| 683 | fetcher: StreamFetcher instance to handle HTTP requests |
| 684 | stop_event: Threading event to signal when to stop fetching |
| 685 | start_sequence: Initial sequence number to start from |
| 686 | |
| 687 | The function implements the core HLS fetching logic: |
| 688 | - Fetches and parses manifest files |
| 689 | - Downloads new segments when they become available |
| 690 | - Handles stream switches with proper discontinuity marking |
| 691 | - Maintains buffer state and segment sequence numbering |
| 692 | """ |
| 693 | # Remove global stream_manager reference |
| 694 | retry_delay = 1 |
| 695 | max_retry_delay = 8 |
| 696 | last_segment_time = 0 |
| 697 | buffer_initialized = False |
| 698 | manifest_update_needed = True |
| 699 | segment_duration = None |
| 700 | |
| 701 | while not stop_event.is_set(): |
| 702 | try: |
| 703 | now = time.time() |
| 704 | |
| 705 | # Only update manifest when it's time for next segment |
| 706 | should_update = ( |
| 707 | manifest_update_needed or |
| 708 | not segment_duration or |
| 709 | (last_segment_time and (now - last_segment_time) >= segment_duration * 0.8) |
| 710 | ) |
| 711 | |
| 712 | if should_update: |
| 713 | manifest_data, final_url = fetcher.download(fetcher.stream_url) |
| 714 | manifest = m3u8.loads(manifest_data.decode()) |
| 715 | |
| 716 | if not manifest.segments: |
| 717 | continue |
| 718 | |
| 719 | with buffer_lock: |
| 720 | manifest_content = manifest_data.decode() |
| 721 | new_segments = {} |
| 722 | |
| 723 | if fetcher.manager.switching_stream: # Use fetcher.manager instead of stream_manager |
| 724 | # Stream switch - only get latest segment |
| 725 | manifest_segments = [manifest.segments[-1]] |
| 726 | seq_start = fetcher.manager.next_sequence |
| 727 | max_segments = 1 |
| 728 | logging.debug(f"Processing stream switch - getting latest segment at sequence {seq_start}") |
| 729 | elif not buffer_initialized: |
| 730 | # Initial buffer |
| 731 | manifest_segments = manifest.segments[-Config.INITIAL_SEGMENTS:] |
| 732 | seq_start = fetcher.manager.next_sequence |
| 733 | max_segments = Config.INITIAL_SEGMENTS |
| 734 | logging.debug(f"Starting initial buffer at sequence {seq_start}") |
| 735 | else: |
no test coverage detected