OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 4 * Use of this source code is governed by a BSD-style license |
5 * that can be found in the LICENSE file in the root of the source | 5 * that can be found in the LICENSE file in the root of the source |
6 * tree. An additional intellectual property rights grant can be found | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
(...skipping 382 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
393 int num_media_packets = code_params_[code_index].num_media_packets; | 393 int num_media_packets = code_params_[code_index].num_media_packets; |
394 int num_fec_packets = code_params_[code_index].num_fec_packets; | 394 int num_fec_packets = code_params_[code_index].num_fec_packets; |
395 int tot_num_packets = num_media_packets + num_fec_packets; | 395 int tot_num_packets = num_media_packets + num_fec_packets; |
396 rtc::scoped_ptr<uint8_t[]> state(new uint8_t[tot_num_packets]); | 396 rtc::scoped_ptr<uint8_t[]> state(new uint8_t[tot_num_packets]); |
397 memset(state.get() , 0, tot_num_packets); | 397 memset(state.get() , 0, tot_num_packets); |
398 | 398 |
399 int num_loss_configurations = static_cast<int>(pow(2.0f, tot_num_packets)); | 399 int num_loss_configurations = static_cast<int>(pow(2.0f, tot_num_packets)); |
400 // Loop over all loss configurations for the symbol sequence of length | 400 // Loop over all loss configurations for the symbol sequence of length |
401 // |tot_num_packets|. In this version we process up to (k=12, m=12) codes, | 401 // |tot_num_packets|. In this version we process up to (k=12, m=12) codes, |
402 // and get exact expressions for the residual loss. | 402 // and get exact expressions for the residual loss. |
403 // TODO (marpan): For larger codes, loop over some random sample of loss | 403 // TODO(marpan): For larger codes, loop over some random sample of loss |
404 // configurations, sampling driven by the underlying statistical loss model | 404 // configurations, sampling driven by the underlying statistical loss model |
405 // (importance sampling). | 405 // (importance sampling). |
406 | 406 |
407 // The symbols/packets are arranged as a sequence of source/media packets | 407 // The symbols/packets are arranged as a sequence of source/media packets |
408 // followed by FEC packets. This is the sequence ordering used in the RTP. | 408 // followed by FEC packets. This is the sequence ordering used in the RTP. |
409 // A configuration refers to a sequence of received/lost (0/1 bit) states | 409 // A configuration refers to a sequence of received/lost (0/1 bit) states |
410 // for the string of packets/symbols. For example, for a (k=4,m=3) code | 410 // for the string of packets/symbols. For example, for a (k=4,m=3) code |
411 // (4 media packets, 3 FEC packets), with 2 losses (one media and one FEC), | 411 // (4 media packets, 3 FEC packets), with 2 losses (one media and one FEC), |
412 // the loss configurations is: | 412 // the loss configurations is: |
413 // Media1 Media2 Media3 Media4 FEC1 FEC2 FEC3 | 413 // Media1 Media2 Media3 Media4 FEC1 FEC2 FEC3 |
414 // 0 0 1 0 0 1 0 | 414 // 0 0 1 0 0 1 0 |
415 for (int i = 1; i < num_loss_configurations; i++) { | 415 for (int i = 1; i < num_loss_configurations; i++) { |
416 // Counter for number of packets lost. | 416 // Counter for number of packets lost. |
417 int num_packets_lost = 0; | 417 int num_packets_lost = 0; |
418 // Counters for the number of media packets lost. | 418 // Counters for the number of media packets lost. |
419 int num_media_packets_lost = 0; | 419 int num_media_packets_lost = 0; |
420 | 420 |
421 // Map configuration number to a loss state. | 421 // Map configuration number to a loss state. |
422 for (int j = 0; j < tot_num_packets; j++) { | 422 for (int j = 0; j < tot_num_packets; j++) { |
423 state[j]=0; // Received state. | 423 state[j] = 0; // Received state. |
424 int bit_value = i >> (tot_num_packets - j - 1) & 1; | 424 int bit_value = i >> (tot_num_packets - j - 1) & 1; |
425 if (bit_value == 1) { | 425 if (bit_value == 1) { |
426 state[j] = 1; // Lost state. | 426 state[j] = 1; // Lost state. |
427 num_packets_lost++; | 427 num_packets_lost++; |
428 if (j < num_media_packets) { | 428 if (j < num_media_packets) { |
429 num_media_packets_lost++; | 429 num_media_packets_lost++; |
430 } | 430 } |
431 } | 431 } |
432 } // Done with loop over total number of packets. | 432 } // Done with loop over total number of packets. |
433 assert(num_media_packets_lost <= num_media_packets); | 433 assert(num_media_packets_lost <= num_media_packets); |
(...skipping 412 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
846 float loss_rate = loss_model_[k].average_loss_rate; | 846 float loss_rate = loss_model_[k].average_loss_rate; |
847 float protection_level = code_params_[code_index].protection_level; | 847 float protection_level = code_params_[code_index].protection_level; |
848 // Under these conditions we expect XOR to not be better than RS. | 848 // Under these conditions we expect XOR to not be better than RS. |
849 if (loss_model_[k].loss_type == kRandomLossModel && | 849 if (loss_model_[k].loss_type == kRandomLossModel && |
850 loss_rate <= protection_level) { | 850 loss_rate <= protection_level) { |
851 EXPECT_GE(kMetricsXorRandom[code_index].average_residual_loss[k], | 851 EXPECT_GE(kMetricsXorRandom[code_index].average_residual_loss[k], |
852 kMetricsReedSolomon[code_index].average_residual_loss[k]); | 852 kMetricsReedSolomon[code_index].average_residual_loss[k]); |
853 EXPECT_GE(kMetricsXorBursty[code_index].average_residual_loss[k], | 853 EXPECT_GE(kMetricsXorBursty[code_index].average_residual_loss[k], |
854 kMetricsReedSolomon[code_index].average_residual_loss[k]); | 854 kMetricsReedSolomon[code_index].average_residual_loss[k]); |
855 } | 855 } |
856 // TODO (marpan): There are some cases (for high loss rates and/or | 856 // TODO(marpan): There are some cases (for high loss rates and/or |
857 // burst loss models) where XOR is better than RS. Is there some pattern | 857 // burst loss models) where XOR is better than RS. Is there some pattern |
858 // we can identify and enforce as a constraint? | 858 // we can identify and enforce as a constraint? |
859 } | 859 } |
860 } | 860 } |
861 } | 861 } |
862 | 862 |
863 // Verify the trend (change) in the average residual loss, as a function of | 863 // Verify the trend (change) in the average residual loss, as a function of |
864 // loss rate, of the XOR code relative to the RS code. | 864 // loss rate, of the XOR code relative to the RS code. |
865 // The difference between XOR and RS should not get worse as we increase | 865 // The difference between XOR and RS should not get worse as we increase |
866 // the average loss rate. | 866 // the average loss rate. |
867 TEST_F(FecPacketMaskMetricsTest, FecTrendXorVsRsLossRate) { | 867 TEST_F(FecPacketMaskMetricsTest, FecTrendXorVsRsLossRate) { |
868 SetLossModels(); | 868 SetLossModels(); |
869 SetCodeParams(); | 869 SetCodeParams(); |
870 // TODO (marpan): Examine this further to see if the condition can be strictly | 870 // TODO(marpan): Examine this further to see if the condition can be strictly |
871 // satisfied (i.e., scale = 1.0) for all codes with different/better masks. | 871 // satisfied (i.e., scale = 1.0) for all codes with different/better masks. |
872 double scale = 0.90; | 872 double scale = 0.90; |
873 int num_loss_rates = sizeof(kAverageLossRate) / | 873 int num_loss_rates = sizeof(kAverageLossRate) / |
874 sizeof(*kAverageLossRate); | 874 sizeof(*kAverageLossRate); |
875 int num_burst_lengths = sizeof(kAverageBurstLength) / | 875 int num_burst_lengths = sizeof(kAverageBurstLength) / |
876 sizeof(*kAverageBurstLength); | 876 sizeof(*kAverageBurstLength); |
877 for (int code_index = 0; code_index < max_num_codes_; code_index++) { | 877 for (int code_index = 0; code_index < max_num_codes_; code_index++) { |
878 for (int i = 0; i < num_burst_lengths; i++) { | 878 for (int i = 0; i < num_burst_lengths; i++) { |
879 for (int j = 0; j < num_loss_rates - 1; j++) { | 879 for (int j = 0; j < num_loss_rates - 1; j++) { |
880 int k = num_loss_rates * i + j; | 880 int k = num_loss_rates * i + j; |
881 // For XOR random. | 881 // For XOR random. |
882 if (kMetricsXorRandom[code_index].average_residual_loss[k] > | 882 if (kMetricsXorRandom[code_index].average_residual_loss[k] > |
883 kMetricsReedSolomon[code_index].average_residual_loss[k]) { | 883 kMetricsReedSolomon[code_index].average_residual_loss[k]) { |
884 double diff_rs_xor_random_loss1 = | 884 double diff_rs_xor_random_loss1 = |
885 (kMetricsXorRandom[code_index].average_residual_loss[k] - | 885 (kMetricsXorRandom[code_index].average_residual_loss[k] - |
886 kMetricsReedSolomon[code_index].average_residual_loss[k]) / | 886 kMetricsReedSolomon[code_index].average_residual_loss[k]) / |
887 kMetricsXorRandom[code_index].average_residual_loss[k]; | 887 kMetricsXorRandom[code_index].average_residual_loss[k]; |
888 double diff_rs_xor_random_loss2 = | 888 double diff_rs_xor_random_loss2 = |
889 (kMetricsXorRandom[code_index].average_residual_loss[k+1] - | 889 (kMetricsXorRandom[code_index].average_residual_loss[k+1] - |
890 kMetricsReedSolomon[code_index].average_residual_loss[k+1]) / | 890 kMetricsReedSolomon[code_index].average_residual_loss[k+1]) / |
891 kMetricsXorRandom[code_index].average_residual_loss[k+1]; | 891 kMetricsXorRandom[code_index].average_residual_loss[k+1]; |
892 EXPECT_GE(diff_rs_xor_random_loss1, scale * diff_rs_xor_random_loss2); | 892 EXPECT_GE(diff_rs_xor_random_loss1, scale * diff_rs_xor_random_loss2); |
893 } | 893 } |
894 // TODO (marpan): Investigate the cases for the bursty mask where | 894 // TODO(marpan): Investigate the cases for the bursty mask where |
895 // this trend is not strictly satisfied. | 895 // this trend is not strictly satisfied. |
896 } | 896 } |
897 } | 897 } |
898 } | 898 } |
899 } | 899 } |
900 | 900 |
901 // Verify the average residual loss behavior via the protection level and | 901 // Verify the average residual loss behavior via the protection level and |
902 // the code length. The average residual loss for a given (k1,m1) code | 902 // the code length. The average residual loss for a given (k1,m1) code |
903 // should generally be higher than that of another code (k2,m2), which has | 903 // should generally be higher than that of another code (k2,m2), which has |
904 // either of the two conditions satisfied: | 904 // either of the two conditions satisfied: |
(...skipping 18 matching lines...) Expand all Loading... |
923 // models, this condition may be violated for some codes with equal or | 923 // models, this condition may be violated for some codes with equal or |
924 // very close protection levels. High loss rate case is excluded below. | 924 // very close protection levels. High loss rate case is excluded below. |
925 if ((protection_level2 > protection_level1 && length2 >= length1) || | 925 if ((protection_level2 > protection_level1 && length2 >= length1) || |
926 (protection_level2 == protection_level1 && length2 > length1)) { | 926 (protection_level2 == protection_level1 && length2 > length1)) { |
927 for (int k = 0; k < kNumLossModels; k++) { | 927 for (int k = 0; k < kNumLossModels; k++) { |
928 float loss_rate = loss_model_[k].average_loss_rate; | 928 float loss_rate = loss_model_[k].average_loss_rate; |
929 if (loss_rate < loss_rate_upper_threshold) { | 929 if (loss_rate < loss_rate_upper_threshold) { |
930 EXPECT_LT( | 930 EXPECT_LT( |
931 kMetricsReedSolomon[code_index2].average_residual_loss[k], | 931 kMetricsReedSolomon[code_index2].average_residual_loss[k], |
932 kMetricsReedSolomon[code_index1].average_residual_loss[k]); | 932 kMetricsReedSolomon[code_index1].average_residual_loss[k]); |
933 // TODO (marpan): There are some corner cases where this is not | 933 // TODO(marpan): There are some corner cases where this is not |
934 // satisfied with the current packet masks. Look into updating | 934 // satisfied with the current packet masks. Look into updating |
935 // these cases to see if this behavior should/can be satisfied, | 935 // these cases to see if this behavior should/can be satisfied, |
936 // with overall lower residual loss for those XOR codes. | 936 // with overall lower residual loss for those XOR codes. |
937 // EXPECT_LT( | 937 // EXPECT_LT( |
938 // kMetricsXorBursty[code_index2].average_residual_loss[k], | 938 // kMetricsXorBursty[code_index2].average_residual_loss[k], |
939 // kMetricsXorBursty[code_index1].average_residual_loss[k]); | 939 // kMetricsXorBursty[code_index1].average_residual_loss[k]); |
940 // EXPECT_LT( | 940 // EXPECT_LT( |
941 // kMetricsXorRandom[code_index2].average_residual_loss[k], | 941 // kMetricsXorRandom[code_index2].average_residual_loss[k], |
942 // kMetricsXorRandom[code_index1].average_residual_loss[k]); | 942 // kMetricsXorRandom[code_index1].average_residual_loss[k]); |
943 } | 943 } |
944 } | 944 } |
945 } | 945 } |
946 } | 946 } |
947 } | 947 } |
948 } | 948 } |
949 | 949 |
950 // Verify the beheavior of the variance of the XOR codes. | 950 // Verify the beheavior of the variance of the XOR codes. |
951 // The partial recovery of the XOR versus the all or nothing behavior of the RS | 951 // The partial recovery of the XOR versus the all or nothing behavior of the RS |
952 // code means that the variance of the residual loss for XOR should generally | 952 // code means that the variance of the residual loss for XOR should generally |
953 // not be worse than RS. | 953 // not be worse than RS. |
954 TEST_F(FecPacketMaskMetricsTest, FecVarianceBehaviorXorVsRs) { | 954 TEST_F(FecPacketMaskMetricsTest, FecVarianceBehaviorXorVsRs) { |
955 SetLossModels(); | 955 SetLossModels(); |
956 SetCodeParams(); | 956 SetCodeParams(); |
957 // The condition is not strictly satisfied with the current masks, | 957 // The condition is not strictly satisfied with the current masks, |
958 // i.e., for some codes, the variance of XOR may be slightly higher than RS. | 958 // i.e., for some codes, the variance of XOR may be slightly higher than RS. |
959 // TODO (marpan): Examine this further to see if the condition can be strictly | 959 // TODO(marpan): Examine this further to see if the condition can be strictly |
960 // satisfied (i.e., scale = 1.0) for all codes with different/better masks. | 960 // satisfied (i.e., scale = 1.0) for all codes with different/better masks. |
961 double scale = 0.95; | 961 double scale = 0.95; |
962 for (int code_index = 0; code_index < max_num_codes_; code_index++) { | 962 for (int code_index = 0; code_index < max_num_codes_; code_index++) { |
963 for (int k = 0; k < kNumLossModels; k++) { | 963 for (int k = 0; k < kNumLossModels; k++) { |
964 EXPECT_LE(scale * | 964 EXPECT_LE(scale * |
965 kMetricsXorRandom[code_index].variance_residual_loss[k], | 965 kMetricsXorRandom[code_index].variance_residual_loss[k], |
966 kMetricsReedSolomon[code_index].variance_residual_loss[k]); | 966 kMetricsReedSolomon[code_index].variance_residual_loss[k]); |
967 EXPECT_LE(scale * | 967 EXPECT_LE(scale * |
968 kMetricsXorBursty[code_index].variance_residual_loss[k], | 968 kMetricsXorBursty[code_index].variance_residual_loss[k], |
969 kMetricsReedSolomon[code_index].variance_residual_loss[k]); | 969 kMetricsReedSolomon[code_index].variance_residual_loss[k]); |
(...skipping 14 matching lines...) Expand all Loading... |
984 EXPECT_EQ(kMetricsXorBursty[code_index]. | 984 EXPECT_EQ(kMetricsXorBursty[code_index]. |
985 residual_loss_per_loss_gap[index], 0.0); | 985 residual_loss_per_loss_gap[index], 0.0); |
986 } | 986 } |
987 } | 987 } |
988 } | 988 } |
989 | 989 |
990 // The XOR codes with random mask type are generally better than the ones with | 990 // The XOR codes with random mask type are generally better than the ones with |
991 // bursty mask type, for random loss models at low loss rates. | 991 // bursty mask type, for random loss models at low loss rates. |
992 // The XOR codes with bursty mask types are generally better than the one with | 992 // The XOR codes with bursty mask types are generally better than the one with |
993 // random mask type, for bursty loss models and/or high loss rates. | 993 // random mask type, for bursty loss models and/or high loss rates. |
994 // TODO (marpan): Enable this test when some of the packet masks are updated. | 994 // TODO(marpan): Enable this test when some of the packet masks are updated. |
995 // Some isolated cases of the codes don't pass this currently. | 995 // Some isolated cases of the codes don't pass this currently. |
996 /* | 996 /* |
997 TEST_F(FecPacketMaskMetricsTest, FecXorRandomVsBursty) { | 997 TEST_F(FecPacketMaskMetricsTest, FecXorRandomVsBursty) { |
998 SetLossModels(); | 998 SetLossModels(); |
999 SetCodeParams(); | 999 SetCodeParams(); |
1000 for (int code_index = 0; code_index < max_num_codes_; code_index++) { | 1000 for (int code_index = 0; code_index < max_num_codes_; code_index++) { |
1001 double sum_residual_loss_random_mask_random_loss = 0.0; | 1001 double sum_residual_loss_random_mask_random_loss = 0.0; |
1002 double sum_residual_loss_bursty_mask_random_loss = 0.0; | 1002 double sum_residual_loss_bursty_mask_random_loss = 0.0; |
1003 double sum_residual_loss_random_mask_bursty_loss = 0.0; | 1003 double sum_residual_loss_random_mask_bursty_loss = 0.0; |
1004 double sum_residual_loss_bursty_mask_bursty_loss = 0.0; | 1004 double sum_residual_loss_bursty_mask_bursty_loss = 0.0; |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1072 recovery_rate_per_loss[loss_number], | 1072 recovery_rate_per_loss[loss_number], |
1073 kRecoveryRateXorRandom[2]); | 1073 kRecoveryRateXorRandom[2]); |
1074 EXPECT_GE(kMetricsXorBursty[code_index]. | 1074 EXPECT_GE(kMetricsXorBursty[code_index]. |
1075 recovery_rate_per_loss[loss_number], | 1075 recovery_rate_per_loss[loss_number], |
1076 kRecoveryRateXorBursty[2]); | 1076 kRecoveryRateXorBursty[2]); |
1077 } | 1077 } |
1078 } | 1078 } |
1079 } | 1079 } |
1080 | 1080 |
1081 } // namespace webrtc | 1081 } // namespace webrtc |
OLD | NEW |