1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef CHROME_BROWSER_MEDIA_WEBRTC_WEBRTC_RTP_DUMP_WRITER_H_
6 #define CHROME_BROWSER_MEDIA_WEBRTC_WEBRTC_RTP_DUMP_WRITER_H_
7 
8 #include <stddef.h>
9 #include <stdint.h>
10 
11 #include <memory>
12 
13 #include "base/callback.h"
14 #include "base/files/file_path.h"
15 #include "base/macros.h"
16 #include "base/memory/weak_ptr.h"
17 #include "base/sequence_checker.h"
18 #include "base/sequenced_task_runner.h"
19 #include "base/time/time.h"
20 #include "chrome/browser/media/webrtc/rtp_dump_type.h"
21 
22 // This class is responsible for creating the compressed RTP header dump file:
23 // - Adds the RTP headers to an in-memory buffer.
24 // - When the in-memory buffer is full, compresses it, and writes it to the
25 //   disk.
26 // - Notifies the caller when the on-disk file size reaches the max limit.
27 // - The uncompressed dump follows the standard RTPPlay format
28 //   (http://www.cs.columbia.edu/irt/software/rtptools/).
29 // - The caller is always responsible for cleaning up the dump file in all
30 //   cases.
31 // - WebRtcRtpDumpWriter does not stop writing to the dump after the max size
32 //   limit is reached. The caller must stop calling WriteRtpPacket instead.
33 //
34 // This object must run on the IO thread.
35 class WebRtcRtpDumpWriter {
36  public:
37   typedef base::OnceCallback<void(bool incoming_succeeded,
38                                   bool outgoing_succeeded)>
39       EndDumpCallback;
40 
41   // |incoming_dump_path| and |outgoing_dump_path| are the file paths of the
42   // compressed dump files for incoming and outgoing packets respectively.
43   // |max_dump_size| is the max size of the compressed dump file in bytes.
44   // |max_dump_size_reached_callback| will be called when the on-disk file size
45   // reaches |max_dump_size|.
46   WebRtcRtpDumpWriter(const base::FilePath& incoming_dump_path,
47                       const base::FilePath& outgoing_dump_path,
48                       size_t max_dump_size,
49                       base::RepeatingClosure max_dump_size_reached_callback);
50 
51   virtual ~WebRtcRtpDumpWriter();
52 
53   // Adds a RTP packet to the dump. The caller must make sure it's a valid RTP
54   // packet. No validation is done by this method.
55   virtual void WriteRtpPacket(const uint8_t* packet_header,
56                               size_t header_length,
57                               size_t packet_length,
58                               bool incoming);
59 
60   // Flushes the in-memory buffer to the disk and ends the dump. The caller must
61   // make sure the dump has not already been ended.
62   // |finished_callback| will be called to indicate whether the dump is valid.
63   // If this object is destroyed before the operation is finished, the callback
64   // will be canceled and the dump files will be deleted.
65   virtual void EndDump(RtpDumpType type, EndDumpCallback finished_callback);
66 
67   size_t max_dump_size() const;
68 
background_task_runner()69   const scoped_refptr<base::SequencedTaskRunner>& background_task_runner()
70       const {
71     return background_task_runner_;
72   }
73 
74  private:
75   enum FlushResult {
76     // Flushing has succeeded and the dump size is under the max limit.
77     FLUSH_RESULT_SUCCESS,
78     // Nothing has been written to disk and the dump is empty.
79     FLUSH_RESULT_NO_DATA,
80     // Flushing has failed for other reasons.
81     FLUSH_RESULT_FAILURE
82   };
83 
84   class FileWorker;
85 
86   typedef base::OnceCallback<void(bool)> FlushDoneCallback;
87 
88   // Used by EndDump to cache the input and intermediate results.
89   struct EndDumpContext {
90     EndDumpContext(RtpDumpType type, EndDumpCallback callback);
91     EndDumpContext(EndDumpContext&& other);
92     ~EndDumpContext();
93 
94     RtpDumpType type;
95     bool incoming_succeeded;
96     bool outgoing_succeeded;
97     EndDumpCallback callback;
98   };
99 
100   // Flushes the in-memory buffer to disk. If |incoming| is true, the incoming
101   // buffer will be flushed; otherwise, the outgoing buffer will be flushed.
102   // The dump file will be ended if |end_stream| is true. |callback| will be
103   // called when flushing is done.
104   void FlushBuffer(bool incoming, bool end_stream, FlushDoneCallback callback);
105 
106   // Called when FlushBuffer finishes. Checks the max dump size limit and
107   // maybe calls the |max_dump_size_reached_callback_|. Also calls |callback|
108   // with the flush result.
109   void OnFlushDone(FlushDoneCallback callback,
110                    const std::unique_ptr<FlushResult>& result,
111                    const std::unique_ptr<size_t>& bytes_written);
112 
113   // Called when one type of dump has been ended. It continues to end the other
114   // dump if needed based on |context| and |incoming|, or calls the callback in
115   // |context| if no more dump needs to be ended.
116   void OnDumpEnded(EndDumpContext context, bool incoming, bool success);
117 
118   // The max limit on the total size of incoming and outgoing dumps on disk.
119   const size_t max_dump_size_;
120 
121   // The callback to call when the max size limit is reached.
122   const base::RepeatingClosure max_dump_size_reached_callback_;
123 
124   // The in-memory buffers for the uncompressed dumps.
125   std::vector<uint8_t> incoming_buffer_;
126   std::vector<uint8_t> outgoing_buffer_;
127 
128   // The time when the first packet is dumped.
129   base::TimeTicks start_time_;
130 
131   // The total on-disk size of the compressed incoming and outgoing dumps.
132   size_t total_dump_size_on_disk_;
133 
134   // File workers must be called and deleted on the backround task runner.
135   scoped_refptr<base::SequencedTaskRunner> background_task_runner_;
136   std::unique_ptr<FileWorker> incoming_file_thread_worker_;
137   std::unique_ptr<FileWorker> outgoing_file_thread_worker_;
138 
139   SEQUENCE_CHECKER(sequence_checker_);
140 
141   base::WeakPtrFactory<WebRtcRtpDumpWriter> weak_ptr_factory_{this};
142 
143   DISALLOW_COPY_AND_ASSIGN(WebRtcRtpDumpWriter);
144 };
145 
146 #endif  // CHROME_BROWSER_MEDIA_WEBRTC_WEBRTC_RTP_DUMP_WRITER_H_
147