|
15 | 15 | #include <srs_app_utility.hpp> |
16 | 16 | #include <srs_kernel_codec.hpp> |
17 | 17 | #include <srs_kernel_error.hpp> |
| 18 | +#include <srs_kernel_mp4.hpp> |
18 | 19 | #include <srs_kernel_packet.hpp> |
19 | 20 | #include <srs_kernel_rtc_rtcp.hpp> |
20 | 21 | #include <srs_kernel_utility.hpp> |
@@ -1416,3 +1417,88 @@ VOID TEST(HttpApiPaginationTest, ParsePagination) |
1416 | 1417 | EXPECT_EQ(500, count); |
1417 | 1418 | } |
1418 | 1419 | } |
| 1420 | + |
| 1421 | +// Mock SrsHlsM4sSegment to capture dts passed to reap() |
| 1422 | +// Used for testing issue #4594 |
| 1423 | +class MockSrsHlsM4sSegmentForBug4594 : public SrsHlsM4sSegment |
| 1424 | +{ |
| 1425 | +public: |
| 1426 | + uint64_t captured_reap_dts_; |
| 1427 | + bool reap_called_; |
| 1428 | + |
| 1429 | + MockSrsHlsM4sSegmentForBug4594() : SrsHlsM4sSegment(NULL), captured_reap_dts_(0), reap_called_(false) {} |
| 1430 | + virtual ~MockSrsHlsM4sSegmentForBug4594() {} |
| 1431 | + |
| 1432 | + // Override reap to capture the dts parameter |
| 1433 | + virtual srs_error_t reap(uint64_t dts) { |
| 1434 | + reap_called_ = true; |
| 1435 | + captured_reap_dts_ = dts; |
| 1436 | + return srs_success; |
| 1437 | + } |
| 1438 | +}; |
| 1439 | + |
| 1440 | +// Mock factory to create MockSrsHlsM4sSegmentForBug4594 |
| 1441 | +class MockAppFactoryForBug4594 : public SrsAppFactory |
| 1442 | +{ |
| 1443 | +public: |
| 1444 | + MockSrsHlsM4sSegmentForBug4594 *mock_segment_; |
| 1445 | + |
| 1446 | + MockAppFactoryForBug4594() : mock_segment_(NULL) {} |
| 1447 | + virtual ~MockAppFactoryForBug4594() {} |
| 1448 | + |
| 1449 | + virtual SrsHlsM4sSegment *create_hls_m4s_segment(ISrsFileWriter *fw) { |
| 1450 | + mock_segment_ = new MockSrsHlsM4sSegmentForBug4594(); |
| 1451 | + return mock_segment_; |
| 1452 | + } |
| 1453 | +}; |
| 1454 | + |
| 1455 | +// Test for issue #4594: SrsHlsMp4Controller::on_unpublish() passes video_dts_=0 to reap() |
| 1456 | +// for audio-only streams. |
| 1457 | +// |
| 1458 | +// When on_unpublish() is called for audio-only streams, the muxer's video_dts_ is 0 because |
| 1459 | +// write_video() is never called. This causes reap(0) to be called, leading to |
| 1460 | +// incorrect last sample duration calculation (overflow to huge values like 4294894594). |
| 1461 | +// |
| 1462 | +// @see https://github.com/ossrs/srs/issues/4594 |
| 1463 | +// @see https://github.com/ossrs/srs/pull/4602 |
| 1464 | +VOID TEST(HlsFmp4AudioOnlyBugTest, OnUnpublishUsesVideoDtsZeroForAudioOnly) |
| 1465 | +{ |
| 1466 | + srs_error_t err; |
| 1467 | + |
| 1468 | + // Create SrsHlsMp4Controller - the entry point for HLS fMP4 |
| 1469 | + SrsHlsMp4Controller controller; |
| 1470 | + |
| 1471 | + // Access the internal muxer |
| 1472 | + SrsHlsFmp4Muxer *muxer = controller.muxer_; |
| 1473 | + |
| 1474 | + // Set up mock request (required by do_segment_close for async hooks) |
| 1475 | + MockRequest mock_req("test_vhost", "live", "stream"); |
| 1476 | + muxer->req_ = &mock_req; |
| 1477 | + |
| 1478 | + // Create mock segment that captures the dts passed to reap() |
| 1479 | + MockSrsHlsM4sSegmentForBug4594 *mock_segment = new MockSrsHlsM4sSegmentForBug4594(); |
| 1480 | + muxer->current_ = mock_segment; |
| 1481 | + |
| 1482 | + // Simulate audio-only stream condition: |
| 1483 | + // - controller.audio_dts_ has a value (audio packets were written) |
| 1484 | + // - controller.video_dts_ is 0 (no video packets, write_video() never called) |
| 1485 | + controller.audio_dts_ = 72702; // Example audio DTS in milliseconds |
| 1486 | + controller.video_dts_ = 0; // No video for audio-only stream |
| 1487 | + |
| 1488 | + // Call on_unpublish() - this triggers the bug path |
| 1489 | + HELPER_EXPECT_SUCCESS(controller.on_unpublish()); |
| 1490 | + |
| 1491 | + // Verify reap was called |
| 1492 | + ASSERT_TRUE(mock_segment->reap_called_) << "reap() should have been called by on_unpublish()"; |
| 1493 | + |
| 1494 | + // THE BUG TEST: |
| 1495 | + // This test SHOULD FAIL on the buggy develop branch because |
| 1496 | + // captured_reap_dts_ will be 0 instead of a proper audio timestamp (72702) |
| 1497 | + EXPECT_GT(mock_segment->captured_reap_dts_, 0u) |
| 1498 | + << "Bug #4594: on_unpublish() resulted in reap(dts=0) for audio-only stream! " |
| 1499 | + << "Expected non-zero dts (e.g., audio_dts_=" << controller.audio_dts_ << ") " |
| 1500 | + << "but reap() received " << mock_segment->captured_reap_dts_; |
| 1501 | + |
| 1502 | + // Cleanup |
| 1503 | + muxer->req_ = NULL; |
| 1504 | +} |
0 commit comments