1 // Copyright (c) 2012 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 #include "media/base/media_log.h"
6
7 #include <utility>
8
9 #include "base/atomic_sequence_num.h"
10 #include "base/json/json_writer.h"
11 #include "base/memory/ptr_util.h"
12 #include "base/strings/string_util.h"
13 #include "base/values.h"
14
15 namespace media {
16
17 const char MediaLog::kEventKey[] = "event";
18 const char MediaLog::kStatusText[] = "pipeline_error";
19
20 // A count of all MediaLogs created in the current process. Used to generate
21 // unique IDs.
22 static base::AtomicSequenceNumber g_media_log_count;
23
MediaLog()24 MediaLog::MediaLog() : MediaLog(new ParentLogRecord(this)) {}
25
MediaLog(scoped_refptr<ParentLogRecord> parent_log_record)26 MediaLog::MediaLog(scoped_refptr<ParentLogRecord> parent_log_record)
27 : parent_log_record_(std::move(parent_log_record)) {}
28
~MediaLog()29 MediaLog::~MediaLog() {
30 // If we are the underlying log, then somebody should have called
31 // InvalidateLog before now. Otherwise, there could be concurrent calls into
32 // this after we're destroyed. Note that calling it here isn't really much
33 // better, since there could be concurrent calls into the now destroyed
34 // derived class.
35 //
36 // However, we can't DCHECK on it, since lots of folks create a base Medialog
37 // implementation temporarily. So, the best we can do is invalidate the log.
38 // We could get around this if we introduce a new NullMediaLog that handles
39 // log invalidation, so we could dcheck here. However, that seems like a lot
40 // of boilerplate.
41 InvalidateLog();
42 }
43
44 // Default *Locked implementations
AddLogRecordLocked(std::unique_ptr<MediaLogRecord> event)45 void MediaLog::AddLogRecordLocked(std::unique_ptr<MediaLogRecord> event) {}
46
GetErrorMessageLocked()47 std::string MediaLog::GetErrorMessageLocked() {
48 return "";
49 }
50
AddMessage(MediaLogMessageLevel level,std::string message)51 void MediaLog::AddMessage(MediaLogMessageLevel level, std::string message) {
52 std::unique_ptr<MediaLogRecord> record(
53 CreateRecord(MediaLogRecord::Type::kMessage));
54 record->params.SetStringPath(MediaLogMessageLevelToString(level),
55 std::move(message));
56 AddLogRecord(std::move(record));
57 }
58
NotifyError(PipelineStatus status)59 void MediaLog::NotifyError(PipelineStatus status) {
60 std::unique_ptr<MediaLogRecord> record(
61 CreateRecord(MediaLogRecord::Type::kMediaStatus));
62 record->params.SetIntPath(MediaLog::kStatusText, status);
63 AddLogRecord(std::move(record));
64 }
65
NotifyError(Status status)66 void MediaLog::NotifyError(Status status) {
67 DCHECK(!status.is_ok());
68 std::string output_str;
69 base::JSONWriter::Write(MediaSerialize(status), &output_str);
70 AddMessage(MediaLogMessageLevel::kERROR, output_str);
71 }
72
OnWebMediaPlayerDestroyedLocked()73 void MediaLog::OnWebMediaPlayerDestroyedLocked() {}
OnWebMediaPlayerDestroyed()74 void MediaLog::OnWebMediaPlayerDestroyed() {
75 AddEvent<MediaLogEvent::kWebMediaPlayerDestroyed>();
76 base::AutoLock auto_lock(parent_log_record_->lock);
77 // Forward to the parent log's implementation.
78 if (parent_log_record_->media_log)
79 parent_log_record_->media_log->OnWebMediaPlayerDestroyedLocked();
80 }
81
GetErrorMessage()82 std::string MediaLog::GetErrorMessage() {
83 base::AutoLock auto_lock(parent_log_record_->lock);
84 // Forward to the parent log's implementation.
85 if (parent_log_record_->media_log)
86 return parent_log_record_->media_log->GetErrorMessageLocked();
87
88 return "";
89 }
90
Clone()91 std::unique_ptr<MediaLog> MediaLog::Clone() {
92 // Protected ctor, so we can't use std::make_unique.
93 return base::WrapUnique(new MediaLog(parent_log_record_));
94 }
95
AddLogRecord(std::unique_ptr<MediaLogRecord> record)96 void MediaLog::AddLogRecord(std::unique_ptr<MediaLogRecord> record) {
97 base::AutoLock auto_lock(parent_log_record_->lock);
98 // Forward to the parent log's implementation.
99 if (parent_log_record_->media_log)
100 parent_log_record_->media_log->AddLogRecordLocked(std::move(record));
101 }
102
CreateRecord(MediaLogRecord::Type type)103 std::unique_ptr<MediaLogRecord> MediaLog::CreateRecord(
104 MediaLogRecord::Type type) {
105 auto record = std::make_unique<MediaLogRecord>();
106 record->id = id();
107 record->type = type;
108 record->time = base::TimeTicks::Now();
109 return record;
110 }
111
InvalidateLog()112 void MediaLog::InvalidateLog() {
113 base::AutoLock auto_lock(parent_log_record_->lock);
114 // Do nothing if this log didn't create the record, i.e.
115 // it's not the parent log. The parent log should invalidate itself.
116 if (parent_log_record_->media_log == this)
117 parent_log_record_->media_log = nullptr;
118 // Keep |parent_log_record_| around, since the lock must keep working.
119 }
120
ParentLogRecord(MediaLog * log)121 MediaLog::ParentLogRecord::ParentLogRecord(MediaLog* log)
122 : id(g_media_log_count.GetNext()), media_log(log) {}
123 MediaLog::ParentLogRecord::~ParentLogRecord() = default;
124
LogHelper(MediaLogMessageLevel level,MediaLog * media_log)125 LogHelper::LogHelper(MediaLogMessageLevel level, MediaLog* media_log)
126 : level_(level), media_log_(media_log) {
127 DCHECK(media_log_);
128 }
129
LogHelper(MediaLogMessageLevel level,const std::unique_ptr<MediaLog> & media_log)130 LogHelper::LogHelper(MediaLogMessageLevel level,
131 const std::unique_ptr<MediaLog>& media_log)
132 : LogHelper(level, media_log.get()) {}
133
~LogHelper()134 LogHelper::~LogHelper() {
135 media_log_->AddMessage(level_, stream_.str());
136 }
137
138 } //namespace media
139