blob: c2f8fa0ed66fae0ed47e97b869d369e1d18f7129 [file] [log] [blame]
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "video_engine/vie_file_recorder.h"
#include "modules/utility/interface/file_player.h"
#include "modules/utility/interface/file_recorder.h"
#include "system_wrappers/interface/critical_section_wrapper.h"
#include "system_wrappers/interface/tick_util.h"
#include "system_wrappers/interface/trace.h"
#include "video_engine/vie_defines.h"
namespace webrtc {
ViEFileRecorder::ViEFileRecorder(int instanceID)
: recorder_cs_(CriticalSectionWrapper::CreateCriticalSection()),
file_recorder_(NULL),
is_first_frame_recorded_(false),
is_out_stream_started_(false),
instance_id_(instanceID),
frame_delay_(0),
audio_channel_(-1),
audio_source_(NO_AUDIO),
voe_file_interface_(NULL) {
}
ViEFileRecorder::~ViEFileRecorder() {
StopRecording();
delete recorder_cs_;
}
int ViEFileRecorder::StartRecording(const char* file_nameUTF8,
const VideoCodec& codec_inst,
AudioSource audio_source,
int audio_channel,
const CodecInst& audio_codec_inst,
VoiceEngine* voe_ptr,
const FileFormats file_format) {
CriticalSectionScoped lock(*recorder_cs_);
if (file_recorder_) {
WEBRTC_TRACE(kTraceError, kTraceVideo, instance_id_,
"ViEFileRecorder::StartRecording() - already recording.");
return -1;
}
file_recorder_ = FileRecorder::CreateFileRecorder(instance_id_, file_format);
if (!file_recorder_) {
WEBRTC_TRACE(kTraceError, kTraceVideo, instance_id_,
"ViEFileRecorder::StartRecording() failed to create recoder.");
return -1;
}
int error = file_recorder_->StartRecordingVideoFile(file_nameUTF8,
audio_codec_inst,
codec_inst,
AMRFileStorage,
audio_source == NO_AUDIO);
if (error) {
WEBRTC_TRACE(kTraceError, kTraceVideo, instance_id_,
"ViEFileRecorder::StartRecording() failed to "
"StartRecordingVideoFile.");
FileRecorder::DestroyFileRecorder(file_recorder_);
file_recorder_ = NULL;
return -1;
}
audio_source_ = audio_source;
if (voe_ptr && audio_source != NO_AUDIO) {
// VoE interface has been provided and we want to record audio.
voe_file_interface_ = VoEFile::GetInterface(voe_ptr);
if (!voe_file_interface_) {
WEBRTC_TRACE(kTraceError, kTraceVideo, instance_id_,
"ViEFileRecorder::StartRecording() failed to get VEFile "
"interface");
return -1;
}
// Always L16.
CodecInst engine_audio_codec_inst = {96, "L16", audio_codec_inst.plfreq,
audio_codec_inst.plfreq / 100, 1,
audio_codec_inst.plfreq * 16 };
switch (audio_source) {
// case NO_AUDIO is checked above.
case MICROPHONE:
error = voe_file_interface_->StartRecordingMicrophone(
this, &engine_audio_codec_inst);
break;
case PLAYOUT:
error = voe_file_interface_->StartRecordingPlayout(
audio_channel, this, &engine_audio_codec_inst);
break;
default:
assert(!"Unknown audio_source");
}
if (error != 0) {
WEBRTC_TRACE(kTraceError, kTraceVideo, instance_id_,
"ViEFileRecorder::StartRecording() failed to start recording"
" audio");
FileRecorder::DestroyFileRecorder(file_recorder_);
file_recorder_ = NULL;
return -1;
}
is_out_stream_started_ = true;
audio_channel_ = audio_channel;
}
is_first_frame_recorded_ = false;
return 0;
}
int ViEFileRecorder::StopRecording() {
int error = 0;
// We can not hold the ptr_cs_ while accessing VoE functions. It might cause
// deadlock in Write.
if (voe_file_interface_) {
switch (audio_source_) {
case MICROPHONE:
error = voe_file_interface_->StopRecordingMicrophone();
break;
case PLAYOUT:
error = voe_file_interface_->StopRecordingPlayout(audio_channel_);
break;
case NO_AUDIO:
break;
default:
assert(!"Unknown audio_source");
}
if (error != 0) {
WEBRTC_TRACE(kTraceError, kTraceVideo, instance_id_,
"ViEFileRecorder::StopRecording() failed to stop recording "
"audio");
}
}
CriticalSectionScoped lock(*recorder_cs_);
if (voe_file_interface_) {
voe_file_interface_->Release();
voe_file_interface_ = NULL;
}
if (file_recorder_) {
if (file_recorder_->IsRecording()) {
int error = file_recorder_->StopRecording();
if (error) {
return -1;
}
}
FileRecorder::DestroyFileRecorder(file_recorder_);
file_recorder_ = NULL;
}
is_first_frame_recorded_ = false;
is_out_stream_started_ = false;
return 0;
}
void ViEFileRecorder::SetFrameDelay(int frame_delay) {
CriticalSectionScoped lock(*recorder_cs_);
frame_delay_ = frame_delay;
}
bool ViEFileRecorder::RecordingStarted() {
CriticalSectionScoped lock(*recorder_cs_);
return file_recorder_ && file_recorder_->IsRecording();
}
bool ViEFileRecorder::FirstFrameRecorded() {
CriticalSectionScoped lock(*recorder_cs_);
return is_first_frame_recorded_;
}
bool ViEFileRecorder::IsRecordingFileFormat(const FileFormats file_format) {
CriticalSectionScoped lock(*recorder_cs_);
return (file_recorder_->RecordingFileFormat() == file_format) ? true : false;
}
void ViEFileRecorder::RecordVideoFrame(const VideoFrame& video_frame) {
CriticalSectionScoped lock(*recorder_cs_);
if (file_recorder_ && file_recorder_->IsRecording()) {
if (!IsRecordingFileFormat(kFileFormatAviFile))
return;
// Compensate for frame delay in order to get audio/video sync when
// recording local video.
const WebRtc_UWord32 time_stamp = video_frame.TimeStamp();
const WebRtc_Word64 render_time_stamp = video_frame.RenderTimeMs();
VideoFrame& unconst_video_frame = const_cast<VideoFrame&>(video_frame);
unconst_video_frame.SetTimeStamp(time_stamp - 90 * frame_delay_);
unconst_video_frame.SetRenderTime(render_time_stamp - frame_delay_);
file_recorder_->RecordVideoToFile(unconst_video_frame);
unconst_video_frame.SetRenderTime(render_time_stamp);
unconst_video_frame.SetTimeStamp(time_stamp);
}
}
bool ViEFileRecorder::Write(const void* buf, int len) {
if (!is_out_stream_started_)
return true;
// Always 10 ms L16 from VoE.
if (len % (2 * 80)) {
// Not 2 bytes 80 samples.
WEBRTC_TRACE(kTraceError, kTraceVideo, audio_channel_,
"Audio length not supported: %d.", len);
return true;
}
AudioFrame audio_frame;
WebRtc_UWord16 length_in_samples = len / 2;
audio_frame.UpdateFrame(audio_channel_, 0,
static_cast<const WebRtc_Word16*>(buf),
length_in_samples, length_in_samples * 100,
AudioFrame::kUndefined,
AudioFrame::kVadUnknown);
CriticalSectionScoped lock(*recorder_cs_);
if (file_recorder_ && file_recorder_->IsRecording()) {
TickTime tick_time = TickTime::Now();
file_recorder_->RecordAudioToFile(audio_frame, &tick_time);
}
// Always return true to continue recording.
return true;
}
int ViEFileRecorder::Rewind() {
// Not supported!
return -1;
}
} // namespace webrtc