• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // libjingle
2 // Copyright 2004--2005, Google Inc.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are met:
6 //
7 //  1. Redistributions of source code must retain the above copyright notice,
8 //     this list of conditions and the following disclaimer.
9 //  2. Redistributions in binary form must reproduce the above copyright notice,
10 //     this list of conditions and the following disclaimer in the documentation
11 //     and/or other materials provided with the distribution.
12 //  3. The name of the author may not be used to endorse or promote products
13 //     derived from this software without specific prior written permission.
14 //
15 // THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
16 // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
17 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
18 // EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21 // OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22 // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23 // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
24 // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 
26 #include "talk/session/phone/filemediaengine.h"
27 
28 #include <climits>
29 
30 #include "talk/base/buffer.h"
31 #include "talk/base/event.h"
32 #include "talk/base/logging.h"
33 #include "talk/base/pathutils.h"
34 #include "talk/base/stream.h"
35 #include "talk/session/phone/rtpdump.h"
36 
37 namespace cricket {
38 
39 ///////////////////////////////////////////////////////////////////////////
40 // Implementation of FileMediaEngine.
41 ///////////////////////////////////////////////////////////////////////////
GetCapabilities()42 int FileMediaEngine::GetCapabilities() {
43   int capabilities = 0;
44   if (!voice_input_filename_.empty()) {
45     capabilities |= MediaEngine::AUDIO_SEND;
46   }
47   if (!voice_output_filename_.empty()) {
48     capabilities |= MediaEngine::AUDIO_RECV;
49   }
50   if (!video_input_filename_.empty()) {
51     capabilities |= MediaEngine::VIDEO_SEND;
52   }
53   if (!video_output_filename_.empty()) {
54     capabilities |= MediaEngine::VIDEO_RECV;
55   }
56   return capabilities;
57 }
58 
CreateChannel()59 VoiceMediaChannel* FileMediaEngine::CreateChannel() {
60   if (!voice_input_filename_.empty() || !voice_output_filename_.empty()) {
61     return new FileVoiceChannel(voice_input_filename_, voice_output_filename_);
62   } else {
63     return NULL;
64   }
65 }
66 
CreateVideoChannel(VoiceMediaChannel * voice_ch)67 VideoMediaChannel* FileMediaEngine::CreateVideoChannel(
68     VoiceMediaChannel* voice_ch) {
69   if (!video_input_filename_.empty() || !video_output_filename_.empty()) {
70     return new FileVideoChannel(video_input_filename_, video_output_filename_);
71   } else {
72     return NULL;
73   }
74 }
75 
76 ///////////////////////////////////////////////////////////////////////////
77 // Definition of RtpSenderReceiver.
78 ///////////////////////////////////////////////////////////////////////////
79 class RtpSenderReceiver
80     : public talk_base::Thread, public talk_base::MessageHandler {
81  public:
82   RtpSenderReceiver(MediaChannel* channel, const std::string& in_file,
83                     const std::string& out_file);
84 
85   // Called by media channel. Context: media channel thread.
86   bool SetSend(bool send);
87   void OnPacketReceived(talk_base::Buffer* packet);
88 
89   // Override virtual method of parent MessageHandler. Context: Worker Thread.
90   virtual void OnMessage(talk_base::Message* pmsg);
91 
92  private:
93   // Read the next RTP dump packet, whose RTP SSRC is the same as first_ssrc_.
94   // Return true if successful.
95   bool ReadNextPacket(RtpDumpPacket* packet);
96   // Send a RTP packet to the network. The input parameter data points to the
97   // start of the RTP packet and len is the packet size. Return true if the sent
98   // size is equal to len.
99   bool SendRtpPacket(const void* data, size_t len);
100 
101   MediaChannel* media_channel_;
102   talk_base::scoped_ptr<talk_base::StreamInterface> input_stream_;
103   talk_base::scoped_ptr<talk_base::StreamInterface> output_stream_;
104   talk_base::scoped_ptr<RtpDumpLoopReader> rtp_dump_reader_;
105   talk_base::scoped_ptr<RtpDumpWriter> rtp_dump_writer_;
106   // RTP dump packet read from the input stream.
107   RtpDumpPacket rtp_dump_packet_;
108   uint32 start_send_time_;
109   bool sending_;
110   bool first_packet_;
111   uint32 first_ssrc_;
112 
113   DISALLOW_COPY_AND_ASSIGN(RtpSenderReceiver);
114 };
115 
116 ///////////////////////////////////////////////////////////////////////////
117 // Implementation of RtpSenderReceiver.
118 ///////////////////////////////////////////////////////////////////////////
RtpSenderReceiver(MediaChannel * channel,const std::string & in_file,const std::string & out_file)119 RtpSenderReceiver::RtpSenderReceiver(MediaChannel* channel,
120                                      const std::string& in_file,
121                                      const std::string& out_file)
122     : media_channel_(channel),
123       sending_(false),
124       first_packet_(true) {
125   input_stream_.reset(talk_base::Filesystem::OpenFile(
126       talk_base::Pathname(in_file), "rb"));
127   if (input_stream_.get()) {
128     rtp_dump_reader_.reset(new RtpDumpLoopReader(input_stream_.get()));
129     // Start the sender thread, which reads rtp dump records, waits based on
130     // the record timestamps, and sends the RTP packets to the network.
131     Thread::Start();
132   }
133 
134   // Create a rtp dump writer for the output RTP dump stream.
135   output_stream_.reset(talk_base::Filesystem::OpenFile(
136       talk_base::Pathname(out_file), "wb"));
137   if (output_stream_.get()) {
138     rtp_dump_writer_.reset(new RtpDumpWriter(output_stream_.get()));
139   }
140 }
141 
SetSend(bool send)142 bool RtpSenderReceiver::SetSend(bool send) {
143   bool was_sending = sending_;
144   sending_ = send;
145   if (!was_sending && sending_) {
146     PostDelayed(0, this);  // Wake up the send thread.
147     start_send_time_ = talk_base::Time();
148   }
149   return true;
150 }
151 
OnPacketReceived(talk_base::Buffer * packet)152 void RtpSenderReceiver::OnPacketReceived(talk_base::Buffer* packet) {
153   if (rtp_dump_writer_.get()) {
154     rtp_dump_writer_->WriteRtpPacket(packet->data(), packet->length());
155   }
156 }
157 
OnMessage(talk_base::Message * pmsg)158 void RtpSenderReceiver::OnMessage(talk_base::Message* pmsg) {
159   if (!sending_) {
160     // If the sender thread is not sending, ignore this message. The thread goes
161     // to sleep until SetSend(true) wakes it up.
162     return;
163   }
164 
165   if (!first_packet_) {
166     // Send the previously read packet.
167     SendRtpPacket(&rtp_dump_packet_.data[0], rtp_dump_packet_.data.size());
168   }
169 
170   if (ReadNextPacket(&rtp_dump_packet_)) {
171     int wait = talk_base::TimeUntil(
172         start_send_time_ + rtp_dump_packet_.elapsed_time);
173     wait = talk_base::_max(0, wait);
174     PostDelayed(wait, this);
175   } else {
176     Quit();
177   }
178 }
179 
ReadNextPacket(RtpDumpPacket * packet)180 bool RtpSenderReceiver::ReadNextPacket(RtpDumpPacket* packet) {
181   while (talk_base::SR_SUCCESS == rtp_dump_reader_->ReadPacket(packet)) {
182     uint32 ssrc;
183     if (!packet->GetRtpSsrc(&ssrc)) {
184       return false;
185     }
186     if (first_packet_) {
187       first_packet_ = false;
188       first_ssrc_ = ssrc;
189     }
190     if (ssrc == first_ssrc_) {
191       return true;
192     }
193   }
194   return false;
195 }
196 
SendRtpPacket(const void * data,size_t len)197 bool RtpSenderReceiver::SendRtpPacket(const void* data, size_t len) {
198   if (!media_channel_ || !media_channel_->network_interface()) {
199     return false;
200   }
201 
202   talk_base::Buffer packet(data, len, kMaxRtpPacketLen);
203   return media_channel_->network_interface()->SendPacket(&packet);
204 }
205 
206 ///////////////////////////////////////////////////////////////////////////
207 // Implementation of FileVoiceChannel.
208 ///////////////////////////////////////////////////////////////////////////
FileVoiceChannel(const std::string & in_file,const std::string & out_file)209 FileVoiceChannel::FileVoiceChannel(const std::string& in_file,
210                                    const std::string& out_file)
211     : rtp_sender_receiver_(new RtpSenderReceiver(this, in_file, out_file)) {
212 }
213 
~FileVoiceChannel()214 FileVoiceChannel::~FileVoiceChannel() {}
215 
SetSendCodecs(const std::vector<AudioCodec> & codecs)216 bool FileVoiceChannel::SetSendCodecs(const std::vector<AudioCodec>& codecs) {
217   // TODO: Check the format of RTP dump input.
218   return true;
219 }
220 
SetSend(SendFlags flag)221 bool FileVoiceChannel::SetSend(SendFlags flag) {
222   return rtp_sender_receiver_->SetSend(flag != SEND_NOTHING);
223 }
224 
OnPacketReceived(talk_base::Buffer * packet)225 void FileVoiceChannel::OnPacketReceived(talk_base::Buffer* packet) {
226   rtp_sender_receiver_->OnPacketReceived(packet);
227 }
228 
229 ///////////////////////////////////////////////////////////////////////////
230 // Implementation of FileVideoChannel.
231 ///////////////////////////////////////////////////////////////////////////
FileVideoChannel(const std::string & in_file,const std::string & out_file)232 FileVideoChannel::FileVideoChannel(const std::string& in_file,
233                                    const std::string& out_file)
234     : rtp_sender_receiver_(new RtpSenderReceiver(this, in_file, out_file)) {
235 }
236 
~FileVideoChannel()237 FileVideoChannel::~FileVideoChannel() {}
238 
SetSendCodecs(const std::vector<VideoCodec> & codecs)239 bool FileVideoChannel::SetSendCodecs(const std::vector<VideoCodec>& codecs) {
240   // TODO: Check the format of RTP dump input.
241   return true;
242 }
243 
SetSend(bool send)244 bool FileVideoChannel::SetSend(bool send) {
245   return rtp_sender_receiver_->SetSend(send);
246 }
247 
OnPacketReceived(talk_base::Buffer * packet)248 void FileVideoChannel::OnPacketReceived(talk_base::Buffer* packet) {
249   rtp_sender_receiver_->OnPacketReceived(packet);
250 }
251 
252 }  // namespace cricket
253