blob: 54610420f67916bcafed233be7af6d2b4925a72f [file] [log] [blame]
andrew@webrtc.orga7b57da2012-10-22 18:19:23 +00001/*
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3 *
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
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include "video_engine/vie_file_recorder.h"
12
13#include "modules/utility/interface/file_player.h"
14#include "modules/utility/interface/file_recorder.h"
15#include "system_wrappers/interface/critical_section_wrapper.h"
16#include "system_wrappers/interface/tick_util.h"
17#include "system_wrappers/interface/trace.h"
18#include "video_engine/vie_defines.h"
19
20namespace webrtc {
21
22ViEFileRecorder::ViEFileRecorder(int instanceID)
23 : recorder_cs_(CriticalSectionWrapper::CreateCriticalSection()),
24 file_recorder_(NULL),
25 is_first_frame_recorded_(false),
26 is_out_stream_started_(false),
27 instance_id_(instanceID),
28 frame_delay_(0),
29 audio_channel_(-1),
30 audio_source_(NO_AUDIO),
31 voe_file_interface_(NULL) {
32}
33
34ViEFileRecorder::~ViEFileRecorder() {
35 StopRecording();
36 delete recorder_cs_;
37}
38
39int ViEFileRecorder::StartRecording(const char* file_nameUTF8,
40 const VideoCodec& codec_inst,
41 AudioSource audio_source,
42 int audio_channel,
43 const CodecInst& audio_codec_inst,
44 VoiceEngine* voe_ptr,
45 const FileFormats file_format) {
46 CriticalSectionScoped lock(recorder_cs_);
47
48 if (file_recorder_) {
49 WEBRTC_TRACE(kTraceError, kTraceVideo, instance_id_,
50 "ViEFileRecorder::StartRecording() - already recording.");
51 return -1;
52 }
53 file_recorder_ = FileRecorder::CreateFileRecorder(instance_id_, file_format);
54 if (!file_recorder_) {
55 WEBRTC_TRACE(kTraceError, kTraceVideo, instance_id_,
56 "ViEFileRecorder::StartRecording() failed to create recoder.");
57 return -1;
58 }
59
60 int error = file_recorder_->StartRecordingVideoFile(file_nameUTF8,
61 audio_codec_inst,
62 codec_inst,
63 AMRFileStorage,
64 audio_source == NO_AUDIO);
65 if (error) {
66 WEBRTC_TRACE(kTraceError, kTraceVideo, instance_id_,
67 "ViEFileRecorder::StartRecording() failed to "
68 "StartRecordingVideoFile.");
69 FileRecorder::DestroyFileRecorder(file_recorder_);
70 file_recorder_ = NULL;
71 return -1;
72 }
73
74 audio_source_ = audio_source;
75 if (voe_ptr && audio_source != NO_AUDIO) {
76 // VoE interface has been provided and we want to record audio.
77 voe_file_interface_ = VoEFile::GetInterface(voe_ptr);
78 if (!voe_file_interface_) {
79 WEBRTC_TRACE(kTraceError, kTraceVideo, instance_id_,
80 "ViEFileRecorder::StartRecording() failed to get VEFile "
81 "interface");
82 return -1;
83 }
84
85 // Always L16.
86 CodecInst engine_audio_codec_inst = {96, "L16", audio_codec_inst.plfreq,
87 audio_codec_inst.plfreq / 100, 1,
88 audio_codec_inst.plfreq * 16 };
89
90 switch (audio_source) {
91 // case NO_AUDIO is checked above.
92 case MICROPHONE:
93 error = voe_file_interface_->StartRecordingMicrophone(
94 this, &engine_audio_codec_inst);
95 break;
96 case PLAYOUT:
97 error = voe_file_interface_->StartRecordingPlayout(
98 audio_channel, this, &engine_audio_codec_inst);
99 break;
100 default:
101 assert(false && "Unknown audio_source");
102 }
103 if (error != 0) {
104 WEBRTC_TRACE(kTraceError, kTraceVideo, instance_id_,
105 "ViEFileRecorder::StartRecording() failed to start recording"
106 " audio");
107 FileRecorder::DestroyFileRecorder(file_recorder_);
108 file_recorder_ = NULL;
109 return -1;
110 }
111 is_out_stream_started_ = true;
112 audio_channel_ = audio_channel;
113 }
114 is_first_frame_recorded_ = false;
115 return 0;
116}
117
118int ViEFileRecorder::StopRecording() {
119 int error = 0;
120 // We can not hold the ptr_cs_ while accessing VoE functions. It might cause
121 // deadlock in Write.
122 if (voe_file_interface_) {
123 switch (audio_source_) {
124 case MICROPHONE:
125 error = voe_file_interface_->StopRecordingMicrophone();
126 break;
127 case PLAYOUT:
128 error = voe_file_interface_->StopRecordingPlayout(audio_channel_);
129 break;
130 case NO_AUDIO:
131 break;
132 default:
133 assert(false && "Unknown audio_source");
134 }
135 if (error != 0) {
136 WEBRTC_TRACE(kTraceError, kTraceVideo, instance_id_,
137 "ViEFileRecorder::StopRecording() failed to stop recording "
138 "audio");
139 }
140 }
141 CriticalSectionScoped lock(recorder_cs_);
142 if (voe_file_interface_) {
143 voe_file_interface_->Release();
144 voe_file_interface_ = NULL;
145 }
146
147 if (file_recorder_) {
148 if (file_recorder_->IsRecording()) {
149 int error = file_recorder_->StopRecording();
150 if (error) {
151 return -1;
152 }
153 }
154 FileRecorder::DestroyFileRecorder(file_recorder_);
155 file_recorder_ = NULL;
156 }
157 is_first_frame_recorded_ = false;
158 is_out_stream_started_ = false;
159 return 0;
160}
161
162void ViEFileRecorder::SetFrameDelay(int frame_delay) {
163 CriticalSectionScoped lock(recorder_cs_);
164 frame_delay_ = frame_delay;
165}
166
167bool ViEFileRecorder::RecordingStarted() {
168 CriticalSectionScoped lock(recorder_cs_);
169 return file_recorder_ && file_recorder_->IsRecording();
170}
171
172bool ViEFileRecorder::FirstFrameRecorded() {
173 CriticalSectionScoped lock(recorder_cs_);
174 return is_first_frame_recorded_;
175}
176
177bool ViEFileRecorder::IsRecordingFileFormat(const FileFormats file_format) {
178 CriticalSectionScoped lock(recorder_cs_);
179 return (file_recorder_->RecordingFileFormat() == file_format) ? true : false;
180}
181
mikhal@webrtc.orgdc7e6cf2012-10-24 18:33:04 +0000182void ViEFileRecorder::RecordVideoFrame(const I420VideoFrame& video_frame) {
andrew@webrtc.orga7b57da2012-10-22 18:19:23 +0000183 CriticalSectionScoped lock(recorder_cs_);
184
185 if (file_recorder_ && file_recorder_->IsRecording()) {
186 if (!IsRecordingFileFormat(kFileFormatAviFile))
187 return;
188
189 // Compensate for frame delay in order to get audio/video sync when
190 // recording local video.
mikhal@webrtc.orgdc7e6cf2012-10-24 18:33:04 +0000191 const WebRtc_UWord32 time_stamp = video_frame.timestamp();
192 const WebRtc_Word64 render_time_stamp = video_frame.render_time_ms();
193 I420VideoFrame& unconst_video_frame =
194 const_cast<I420VideoFrame&>(video_frame);
195 unconst_video_frame.set_timestamp(time_stamp - 90 * frame_delay_);
196 unconst_video_frame.set_render_time_ms(render_time_stamp - frame_delay_);
andrew@webrtc.orga7b57da2012-10-22 18:19:23 +0000197
198 file_recorder_->RecordVideoToFile(unconst_video_frame);
199
mikhal@webrtc.orgdc7e6cf2012-10-24 18:33:04 +0000200 unconst_video_frame.set_render_time_ms(render_time_stamp);
201 unconst_video_frame.set_timestamp(time_stamp);
andrew@webrtc.orga7b57da2012-10-22 18:19:23 +0000202 }
203}
204
205bool ViEFileRecorder::Write(const void* buf, int len) {
206 if (!is_out_stream_started_)
207 return true;
208
209 // Always 10 ms L16 from VoE.
210 if (len % (2 * 80)) {
211 // Not 2 bytes 80 samples.
212 WEBRTC_TRACE(kTraceError, kTraceVideo, audio_channel_,
213 "Audio length not supported: %d.", len);
214 return true;
215 }
216
217 AudioFrame audio_frame;
218 WebRtc_UWord16 length_in_samples = len / 2;
219 audio_frame.UpdateFrame(audio_channel_, 0,
220 static_cast<const WebRtc_Word16*>(buf),
221 length_in_samples, length_in_samples * 100,
222 AudioFrame::kUndefined,
223 AudioFrame::kVadUnknown);
224
225 CriticalSectionScoped lock(recorder_cs_);
226 if (file_recorder_ && file_recorder_->IsRecording()) {
227 TickTime tick_time = TickTime::Now();
228 file_recorder_->RecordAudioToFile(audio_frame, &tick_time);
229 }
230
231 // Always return true to continue recording.
232 return true;
233}
234
235int ViEFileRecorder::Rewind() {
236 // Not supported!
237 return -1;
238}
239
240} // namespace webrtc