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