Index: webrtc/call/rtc_event_log_unittest.cc |
diff --git a/webrtc/call/rtc_event_log_unittest.cc b/webrtc/call/rtc_event_log_unittest.cc |
index 0779f8e013138e4036aac94d0892fc7585bc44eb..067c44123b925fae0d6085217d62ba98e853d3b3 100644 |
--- a/webrtc/call/rtc_event_log_unittest.cc |
+++ b/webrtc/call/rtc_event_log_unittest.cc |
@@ -22,6 +22,8 @@ |
#include "webrtc/base/random.h" |
#include "webrtc/call.h" |
#include "webrtc/call/rtc_event_log.h" |
+#include "webrtc/call/rtc_event_log_parser.h" |
+#include "webrtc/call/rtc_event_log_unittest_helper.h" |
#include "webrtc/modules/rtp_rtcp/source/rtcp_packet.h" |
#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/sender_report.h" |
#include "webrtc/modules/rtp_rtcp/source/rtp_sender.h" |
@@ -53,249 +55,50 @@ const char* kExtensionNames[] = {RtpExtension::kTOffset, |
RtpExtension::kTransportSequenceNumber}; |
const size_t kNumExtensions = 5; |
-} // namespace |
- |
-// TODO(terelius): Place this definition with other parsing functions? |
-MediaType GetRuntimeMediaType(rtclog::MediaType media_type) { |
- switch (media_type) { |
- case rtclog::MediaType::ANY: |
- return MediaType::ANY; |
- case rtclog::MediaType::AUDIO: |
- return MediaType::AUDIO; |
- case rtclog::MediaType::VIDEO: |
- return MediaType::VIDEO; |
- case rtclog::MediaType::DATA: |
- return MediaType::DATA; |
- } |
- RTC_NOTREACHED(); |
- return MediaType::ANY; |
-} |
- |
-// Checks that the event has a timestamp, a type and exactly the data field |
-// corresponding to the type. |
-::testing::AssertionResult IsValidBasicEvent(const rtclog::Event& event) { |
- if (!event.has_timestamp_us()) |
- return ::testing::AssertionFailure() << "Event has no timestamp"; |
- if (!event.has_type()) |
- return ::testing::AssertionFailure() << "Event has no event type"; |
- rtclog::Event_EventType type = event.type(); |
- if ((type == rtclog::Event::RTP_EVENT) != event.has_rtp_packet()) |
- return ::testing::AssertionFailure() |
- << "Event of type " << type << " has " |
- << (event.has_rtp_packet() ? "" : "no ") << "RTP packet"; |
- if ((type == rtclog::Event::RTCP_EVENT) != event.has_rtcp_packet()) |
- return ::testing::AssertionFailure() |
- << "Event of type " << type << " has " |
- << (event.has_rtcp_packet() ? "" : "no ") << "RTCP packet"; |
- if ((type == rtclog::Event::AUDIO_PLAYOUT_EVENT) != |
- event.has_audio_playout_event()) |
- return ::testing::AssertionFailure() |
- << "Event of type " << type << " has " |
- << (event.has_audio_playout_event() ? "" : "no ") |
- << "audio_playout event"; |
- if ((type == rtclog::Event::VIDEO_RECEIVER_CONFIG_EVENT) != |
- event.has_video_receiver_config()) |
- return ::testing::AssertionFailure() |
- << "Event of type " << type << " has " |
- << (event.has_video_receiver_config() ? "" : "no ") |
- << "receiver config"; |
- if ((type == rtclog::Event::VIDEO_SENDER_CONFIG_EVENT) != |
- event.has_video_sender_config()) |
- return ::testing::AssertionFailure() |
- << "Event of type " << type << " has " |
- << (event.has_video_sender_config() ? "" : "no ") << "sender config"; |
- if ((type == rtclog::Event::AUDIO_RECEIVER_CONFIG_EVENT) != |
- event.has_audio_receiver_config()) { |
- return ::testing::AssertionFailure() |
- << "Event of type " << type << " has " |
- << (event.has_audio_receiver_config() ? "" : "no ") |
- << "audio receiver config"; |
- } |
- if ((type == rtclog::Event::AUDIO_SENDER_CONFIG_EVENT) != |
- event.has_audio_sender_config()) { |
- return ::testing::AssertionFailure() |
- << "Event of type " << type << " has " |
- << (event.has_audio_sender_config() ? "" : "no ") |
- << "audio sender config"; |
- } |
- return ::testing::AssertionSuccess(); |
-} |
- |
-void VerifyReceiveStreamConfig(const rtclog::Event& event, |
- const VideoReceiveStream::Config& config) { |
- ASSERT_TRUE(IsValidBasicEvent(event)); |
- ASSERT_EQ(rtclog::Event::VIDEO_RECEIVER_CONFIG_EVENT, event.type()); |
- const rtclog::VideoReceiveConfig& receiver_config = |
- event.video_receiver_config(); |
- // Check SSRCs. |
- ASSERT_TRUE(receiver_config.has_remote_ssrc()); |
- EXPECT_EQ(config.rtp.remote_ssrc, receiver_config.remote_ssrc()); |
- ASSERT_TRUE(receiver_config.has_local_ssrc()); |
- EXPECT_EQ(config.rtp.local_ssrc, receiver_config.local_ssrc()); |
- // Check RTCP settings. |
- ASSERT_TRUE(receiver_config.has_rtcp_mode()); |
- if (config.rtp.rtcp_mode == RtcpMode::kCompound) |
- EXPECT_EQ(rtclog::VideoReceiveConfig::RTCP_COMPOUND, |
- receiver_config.rtcp_mode()); |
- else |
- EXPECT_EQ(rtclog::VideoReceiveConfig::RTCP_REDUCEDSIZE, |
- receiver_config.rtcp_mode()); |
- ASSERT_TRUE(receiver_config.has_remb()); |
- EXPECT_EQ(config.rtp.remb, receiver_config.remb()); |
- // Check RTX map. |
- ASSERT_EQ(static_cast<int>(config.rtp.rtx.size()), |
- receiver_config.rtx_map_size()); |
- for (const rtclog::RtxMap& rtx_map : receiver_config.rtx_map()) { |
- ASSERT_TRUE(rtx_map.has_payload_type()); |
- ASSERT_TRUE(rtx_map.has_config()); |
- EXPECT_EQ(1u, config.rtp.rtx.count(rtx_map.payload_type())); |
- const rtclog::RtxConfig& rtx_config = rtx_map.config(); |
- const VideoReceiveStream::Config::Rtp::Rtx& rtx = |
- config.rtp.rtx.at(rtx_map.payload_type()); |
- ASSERT_TRUE(rtx_config.has_rtx_ssrc()); |
- ASSERT_TRUE(rtx_config.has_rtx_payload_type()); |
- EXPECT_EQ(rtx.ssrc, rtx_config.rtx_ssrc()); |
- EXPECT_EQ(rtx.payload_type, rtx_config.rtx_payload_type()); |
- } |
- // Check header extensions. |
- ASSERT_EQ(static_cast<int>(config.rtp.extensions.size()), |
- receiver_config.header_extensions_size()); |
- for (int i = 0; i < receiver_config.header_extensions_size(); i++) { |
- ASSERT_TRUE(receiver_config.header_extensions(i).has_name()); |
- ASSERT_TRUE(receiver_config.header_extensions(i).has_id()); |
- const std::string& name = receiver_config.header_extensions(i).name(); |
- int id = receiver_config.header_extensions(i).id(); |
- EXPECT_EQ(config.rtp.extensions[i].id, id); |
- EXPECT_EQ(config.rtp.extensions[i].name, name); |
- } |
- // Check decoders. |
- ASSERT_EQ(static_cast<int>(config.decoders.size()), |
- receiver_config.decoders_size()); |
- for (int i = 0; i < receiver_config.decoders_size(); i++) { |
- ASSERT_TRUE(receiver_config.decoders(i).has_name()); |
- ASSERT_TRUE(receiver_config.decoders(i).has_payload_type()); |
- const std::string& decoder_name = receiver_config.decoders(i).name(); |
- int decoder_type = receiver_config.decoders(i).payload_type(); |
- EXPECT_EQ(config.decoders[i].payload_name, decoder_name); |
- EXPECT_EQ(config.decoders[i].payload_type, decoder_type); |
- } |
-} |
- |
-void VerifySendStreamConfig(const rtclog::Event& event, |
- const VideoSendStream::Config& config) { |
- ASSERT_TRUE(IsValidBasicEvent(event)); |
- ASSERT_EQ(rtclog::Event::VIDEO_SENDER_CONFIG_EVENT, event.type()); |
- const rtclog::VideoSendConfig& sender_config = event.video_sender_config(); |
- // Check SSRCs. |
- ASSERT_EQ(static_cast<int>(config.rtp.ssrcs.size()), |
- sender_config.ssrcs_size()); |
- for (int i = 0; i < sender_config.ssrcs_size(); i++) { |
- EXPECT_EQ(config.rtp.ssrcs[i], sender_config.ssrcs(i)); |
- } |
- // Check header extensions. |
- ASSERT_EQ(static_cast<int>(config.rtp.extensions.size()), |
- sender_config.header_extensions_size()); |
- for (int i = 0; i < sender_config.header_extensions_size(); i++) { |
- ASSERT_TRUE(sender_config.header_extensions(i).has_name()); |
- ASSERT_TRUE(sender_config.header_extensions(i).has_id()); |
- const std::string& name = sender_config.header_extensions(i).name(); |
- int id = sender_config.header_extensions(i).id(); |
- EXPECT_EQ(config.rtp.extensions[i].id, id); |
- EXPECT_EQ(config.rtp.extensions[i].name, name); |
+void PrintActualEvents(const ParsedRtcEventLog& parsed_log) { |
+ std::map<int, size_t> actual_event_counts; |
+ for (size_t i = 0; i < parsed_log.GetNumberOfEvents(); i++) { |
+ actual_event_counts[parsed_log.GetEventType(i)]++; |
} |
- // Check RTX settings. |
- ASSERT_EQ(static_cast<int>(config.rtp.rtx.ssrcs.size()), |
- sender_config.rtx_ssrcs_size()); |
- for (int i = 0; i < sender_config.rtx_ssrcs_size(); i++) { |
- EXPECT_EQ(config.rtp.rtx.ssrcs[i], sender_config.rtx_ssrcs(i)); |
+ printf("Actual events: "); |
+ for (auto kv : actual_event_counts) { |
+ printf("%d_count = %zu, ", kv.first, kv.second); |
} |
- if (sender_config.rtx_ssrcs_size() > 0) { |
- ASSERT_TRUE(sender_config.has_rtx_payload_type()); |
- EXPECT_EQ(config.rtp.rtx.payload_type, sender_config.rtx_payload_type()); |
+ printf("\n"); |
+ for (size_t i = 0; i < parsed_log.GetNumberOfEvents(); i++) { |
+ printf("%4d ", parsed_log.GetEventType(i)); |
} |
- // Check encoder. |
- ASSERT_TRUE(sender_config.has_encoder()); |
- ASSERT_TRUE(sender_config.encoder().has_name()); |
- ASSERT_TRUE(sender_config.encoder().has_payload_type()); |
- EXPECT_EQ(config.encoder_settings.payload_name, |
- sender_config.encoder().name()); |
- EXPECT_EQ(config.encoder_settings.payload_type, |
- sender_config.encoder().payload_type()); |
+ printf("\n"); |
} |
-void VerifyRtpEvent(const rtclog::Event& event, |
- PacketDirection direction, |
- MediaType media_type, |
- const uint8_t* header, |
- size_t header_size, |
- size_t total_size) { |
- ASSERT_TRUE(IsValidBasicEvent(event)); |
- ASSERT_EQ(rtclog::Event::RTP_EVENT, event.type()); |
- const rtclog::RtpPacket& rtp_packet = event.rtp_packet(); |
- ASSERT_TRUE(rtp_packet.has_incoming()); |
- EXPECT_EQ(direction == kIncomingPacket, rtp_packet.incoming()); |
- ASSERT_TRUE(rtp_packet.has_type()); |
- EXPECT_EQ(media_type, GetRuntimeMediaType(rtp_packet.type())); |
- ASSERT_TRUE(rtp_packet.has_packet_length()); |
- EXPECT_EQ(total_size, rtp_packet.packet_length()); |
- ASSERT_TRUE(rtp_packet.has_header()); |
- ASSERT_EQ(header_size, rtp_packet.header().size()); |
- for (size_t i = 0; i < header_size; i++) { |
- EXPECT_EQ(header[i], static_cast<uint8_t>(rtp_packet.header()[i])); |
- } |
-} |
- |
-void VerifyRtcpEvent(const rtclog::Event& event, |
- PacketDirection direction, |
- MediaType media_type, |
- const uint8_t* packet, |
- size_t total_size) { |
- ASSERT_TRUE(IsValidBasicEvent(event)); |
- ASSERT_EQ(rtclog::Event::RTCP_EVENT, event.type()); |
- const rtclog::RtcpPacket& rtcp_packet = event.rtcp_packet(); |
- ASSERT_TRUE(rtcp_packet.has_incoming()); |
- EXPECT_EQ(direction == kIncomingPacket, rtcp_packet.incoming()); |
- ASSERT_TRUE(rtcp_packet.has_type()); |
- EXPECT_EQ(media_type, GetRuntimeMediaType(rtcp_packet.type())); |
- ASSERT_TRUE(rtcp_packet.has_packet_data()); |
- ASSERT_EQ(total_size, rtcp_packet.packet_data().size()); |
- for (size_t i = 0; i < total_size; i++) { |
- EXPECT_EQ(packet[i], static_cast<uint8_t>(rtcp_packet.packet_data()[i])); |
+void PrintExpectedEvents(size_t rtp_count, |
+ size_t rtcp_count, |
+ size_t playout_count, |
+ size_t bwe_loss_count) { |
+ printf( |
+ "Expected events: rtp_count = %zu, rtcp_count = %zu," |
+ "playout_count = %zu, bwe_loss_count = %zu\n", |
+ rtp_count, rtcp_count, playout_count, bwe_loss_count); |
+ size_t rtcp_index = 1, playout_index = 1, bwe_loss_index = 1; |
+ printf("strt cfg cfg "); |
+ for (size_t i = 1; i <= rtp_count; i++) { |
+ printf(" rtp "); |
+ if (i * rtcp_count >= rtcp_index * rtp_count) { |
+ printf("rtcp "); |
+ rtcp_index++; |
+ } |
+ if (i * playout_count >= playout_index * rtp_count) { |
+ printf("play "); |
+ playout_index++; |
+ } |
+ if (i * bwe_loss_count >= bwe_loss_index * rtp_count) { |
+ printf("loss "); |
+ bwe_loss_index++; |
+ } |
} |
+ printf("end \n"); |
} |
- |
-void VerifyPlayoutEvent(const rtclog::Event& event, uint32_t ssrc) { |
- ASSERT_TRUE(IsValidBasicEvent(event)); |
- ASSERT_EQ(rtclog::Event::AUDIO_PLAYOUT_EVENT, event.type()); |
- const rtclog::AudioPlayoutEvent& playout_event = event.audio_playout_event(); |
- ASSERT_TRUE(playout_event.has_local_ssrc()); |
- EXPECT_EQ(ssrc, playout_event.local_ssrc()); |
-} |
- |
-void VerifyBweLossEvent(const rtclog::Event& event, |
- int32_t bitrate, |
- uint8_t fraction_loss, |
- int32_t total_packets) { |
- ASSERT_TRUE(IsValidBasicEvent(event)); |
- ASSERT_EQ(rtclog::Event::BWE_PACKET_LOSS_EVENT, event.type()); |
- const rtclog::BwePacketLossEvent& bwe_event = event.bwe_packet_loss_event(); |
- ASSERT_TRUE(bwe_event.has_bitrate()); |
- EXPECT_EQ(bitrate, bwe_event.bitrate()); |
- ASSERT_TRUE(bwe_event.has_fraction_loss()); |
- EXPECT_EQ(fraction_loss, bwe_event.fraction_loss()); |
- ASSERT_TRUE(bwe_event.has_total_packets()); |
- EXPECT_EQ(total_packets, bwe_event.total_packets()); |
-} |
- |
-void VerifyLogStartEvent(const rtclog::Event& event) { |
- ASSERT_TRUE(IsValidBasicEvent(event)); |
- EXPECT_EQ(rtclog::Event::LOG_START, event.type()); |
-} |
- |
-void VerifyLogEndEvent(const rtclog::Event& event) { |
- ASSERT_TRUE(IsValidBasicEvent(event)); |
- EXPECT_EQ(rtclog::Event::LOG_END, event.type()); |
-} |
+} // namespace |
/* |
* Bit number i of extension_bitvector is set to indicate the |
@@ -523,90 +326,58 @@ void LogSessionAndReadBack(size_t rtp_count, |
} |
// Read the generated file from disk. |
- rtclog::EventStream parsed_stream; |
+ ParsedRtcEventLog parsed_log; |
- ASSERT_TRUE(RtcEventLog::ParseRtcEventLog(temp_filename, &parsed_stream)); |
+ ASSERT_TRUE(parsed_log.ParseFile(temp_filename)); |
// Verify that what we read back from the event log is the same as |
// what we wrote down. For RTCP we log the full packets, but for |
// RTP we should only log the header. |
- const int event_count = config_count + playout_count + bwe_loss_count + |
- rtcp_count + rtp_count + 2; |
- EXPECT_GE(1000, event_count); // The events must fit in the message queue. |
- EXPECT_EQ(event_count, parsed_stream.stream_size()); |
- if (event_count != parsed_stream.stream_size()) { |
+ const size_t event_count = config_count + playout_count + bwe_loss_count + |
+ rtcp_count + rtp_count + 2; |
+ EXPECT_GE(1000u, event_count); // The events must fit in the message queue. |
+ EXPECT_EQ(event_count, parsed_log.GetNumberOfEvents()); |
+ if (event_count != parsed_log.GetNumberOfEvents()) { |
// Print the expected and actual event types for easier debugging. |
- std::map<int, size_t> actual_event_counts; |
- for (size_t i = 0; i < static_cast<size_t>(parsed_stream.stream_size()); |
- i++) { |
- actual_event_counts[parsed_stream.stream(i).type()]++; |
- } |
- printf("Actual events: "); |
- for (auto kv : actual_event_counts) { |
- printf("%d_count = %zu, ", kv.first, kv.second); |
- } |
- printf("\n"); |
- for (size_t i = 0; i < static_cast<size_t>(parsed_stream.stream_size()); |
- i++) { |
- printf("%4d ", parsed_stream.stream(i).type()); |
- } |
- printf("\n"); |
- printf( |
- "Expected events: rtp_count = %zu, rtcp_count = %zu," |
- "playout_count = %zu, bwe_loss_count = %zu\n", |
- rtp_count, rtcp_count, playout_count, bwe_loss_count); |
- size_t rtcp_index = 1, playout_index = 1, bwe_loss_index = 1; |
- printf("strt cfg cfg "); |
- for (size_t i = 1; i <= rtp_count; i++) { |
- printf(" rtp "); |
- if (i * rtcp_count >= rtcp_index * rtp_count) { |
- printf("rtcp "); |
- rtcp_index++; |
- } |
- if (i * playout_count >= playout_index * rtp_count) { |
- printf("play "); |
- playout_index++; |
- } |
- if (i * bwe_loss_count >= bwe_loss_index * rtp_count) { |
- printf("loss "); |
- bwe_loss_index++; |
- } |
- } |
- printf("\n"); |
+ PrintActualEvents(parsed_log); |
+ PrintExpectedEvents(rtp_count, rtcp_count, playout_count, bwe_loss_count); |
} |
- VerifyLogStartEvent(parsed_stream.stream(0)); |
- VerifyReceiveStreamConfig(parsed_stream.stream(1), receiver_config); |
- VerifySendStreamConfig(parsed_stream.stream(2), sender_config); |
+ RtcEventLogTestHelper::VerifyLogStartEvent(parsed_log, 0); |
+ RtcEventLogTestHelper::VerifyReceiveStreamConfig(parsed_log, 1, |
+ receiver_config); |
+ RtcEventLogTestHelper::VerifySendStreamConfig(parsed_log, 2, sender_config); |
size_t event_index = config_count + 1; |
size_t rtcp_index = 1; |
size_t playout_index = 1; |
size_t bwe_loss_index = 1; |
for (size_t i = 1; i <= rtp_count; i++) { |
- VerifyRtpEvent(parsed_stream.stream(event_index), |
- (i % 2 == 0) ? kIncomingPacket : kOutgoingPacket, |
- (i % 3 == 0) ? MediaType::AUDIO : MediaType::VIDEO, |
- rtp_packets[i - 1].data(), rtp_header_sizes[i - 1], |
- rtp_packets[i - 1].size()); |
+ RtcEventLogTestHelper::VerifyRtpEvent( |
+ parsed_log, event_index, |
+ (i % 2 == 0) ? kIncomingPacket : kOutgoingPacket, |
+ (i % 3 == 0) ? MediaType::AUDIO : MediaType::VIDEO, |
+ rtp_packets[i - 1].data(), rtp_header_sizes[i - 1], |
+ rtp_packets[i - 1].size()); |
event_index++; |
if (i * rtcp_count >= rtcp_index * rtp_count) { |
- VerifyRtcpEvent(parsed_stream.stream(event_index), |
- (rtcp_index % 2 == 0) ? kIncomingPacket : kOutgoingPacket, |
- rtcp_index % 3 == 0 ? MediaType::AUDIO : MediaType::VIDEO, |
- rtcp_packets[rtcp_index - 1].data(), |
- rtcp_packets[rtcp_index - 1].size()); |
+ RtcEventLogTestHelper::VerifyRtcpEvent( |
+ parsed_log, event_index, |
+ rtcp_index % 2 == 0 ? kIncomingPacket : kOutgoingPacket, |
+ rtcp_index % 3 == 0 ? MediaType::AUDIO : MediaType::VIDEO, |
+ rtcp_packets[rtcp_index - 1].data(), |
+ rtcp_packets[rtcp_index - 1].size()); |
event_index++; |
rtcp_index++; |
} |
if (i * playout_count >= playout_index * rtp_count) { |
- VerifyPlayoutEvent(parsed_stream.stream(event_index), |
- playout_ssrcs[playout_index - 1]); |
+ RtcEventLogTestHelper::VerifyPlayoutEvent( |
+ parsed_log, event_index, playout_ssrcs[playout_index - 1]); |
event_index++; |
playout_index++; |
} |
if (i * bwe_loss_count >= bwe_loss_index * rtp_count) { |
- VerifyBweLossEvent(parsed_stream.stream(event_index), |
- bwe_loss_updates[bwe_loss_index - 1].first, |
- bwe_loss_updates[bwe_loss_index - 1].second, i); |
+ RtcEventLogTestHelper::VerifyBweLossEvent( |
+ parsed_log, event_index, bwe_loss_updates[bwe_loss_index - 1].first, |
+ bwe_loss_updates[bwe_loss_index - 1].second, i); |
event_index++; |
bwe_loss_index++; |
} |
@@ -683,22 +454,24 @@ TEST(RtcEventLogTest, LogEventAndReadBack) { |
log_dumper->StopLogging(); |
// Read the generated file from disk. |
- rtclog::EventStream parsed_stream; |
- ASSERT_TRUE(RtcEventLog::ParseRtcEventLog(temp_filename, &parsed_stream)); |
+ ParsedRtcEventLog parsed_log; |
+ ASSERT_TRUE(parsed_log.ParseFile(temp_filename)); |
// Verify that what we read back from the event log is the same as |
// what we wrote down. |
- EXPECT_EQ(4, parsed_stream.stream_size()); |
+ EXPECT_EQ(4u, parsed_log.GetNumberOfEvents()); |
- VerifyLogStartEvent(parsed_stream.stream(0)); |
+ RtcEventLogTestHelper::VerifyLogStartEvent(parsed_log, 0); |
- VerifyRtpEvent(parsed_stream.stream(1), kIncomingPacket, MediaType::VIDEO, |
- rtp_packet.data(), header_size, rtp_packet.size()); |
+ RtcEventLogTestHelper::VerifyRtpEvent(parsed_log, 1, kIncomingPacket, |
+ MediaType::VIDEO, rtp_packet.data(), |
+ header_size, rtp_packet.size()); |
- VerifyRtcpEvent(parsed_stream.stream(2), kOutgoingPacket, MediaType::VIDEO, |
- rtcp_packet.data(), rtcp_packet.size()); |
+ RtcEventLogTestHelper::VerifyRtcpEvent(parsed_log, 2, kOutgoingPacket, |
+ MediaType::VIDEO, rtcp_packet.data(), |
+ rtcp_packet.size()); |
- VerifyLogEndEvent(parsed_stream.stream(3)); |
+ RtcEventLogTestHelper::VerifyLogEndEvent(parsed_log, 3); |
// Clean up temporary file - can be pretty slow. |
remove(temp_filename.c_str()); |