Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2014 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 "chromecast/media/cma/base/balanced_media_task_runner_factory.h" | |
| 6 | |
| 7 #include <map> | |
| 8 | |
| 9 #include "base/bind.h" | |
| 10 #include "base/callback_helpers.h" | |
| 11 #include "base/logging.h" | |
| 12 #include "base/single_thread_task_runner.h" | |
| 13 #include "chromecast/media/cma/base/media_task_runner.h" | |
| 14 #include "media/base/buffers.h" | |
| 15 | |
| 16 namespace chromecast { | |
| 17 namespace media { | |
| 18 | |
| 19 // MediaTaskRunnerWithNotification - | |
| 20 // Media task runner which also behaves as a media task runner observer. | |
| 21 class MediaTaskRunnerWithNotification | |
| 22 : public MediaTaskRunner { | |
|
xhwang
2014/09/03 17:06:39
fit in one line?
damienv1
2014/09/03 22:01:03
Done.
| |
| 23 public: | |
| 24 MediaTaskRunnerWithNotification( | |
| 25 const scoped_refptr<MediaTaskRunner>& media_task_runner, | |
| 26 const base::Closure new_task_cb, | |
| 27 const base::Closure shutdown_cb); | |
|
xhwang
2014/09/03 17:06:39
Document what the two callbacks are and when they
damienv1
2014/09/03 22:01:03
Good catch. That's an unwilling mistake on my side
| |
| 28 | |
| 29 // MediaTaskRunner implementation. | |
| 30 virtual bool PostMediaTask( | |
| 31 const tracked_objects::Location& from_here, | |
| 32 const base::Closure& task, | |
| 33 base::TimeDelta timestamp) OVERRIDE; | |
| 34 | |
| 35 private: | |
| 36 virtual ~MediaTaskRunnerWithNotification(); | |
| 37 | |
| 38 scoped_refptr<MediaTaskRunner> const media_task_runner_; | |
| 39 | |
| 40 const base::Closure new_task_cb_; | |
| 41 const base::Closure shutdown_cb_; | |
| 42 | |
| 43 DISALLOW_COPY_AND_ASSIGN(MediaTaskRunnerWithNotification); | |
| 44 }; | |
| 45 | |
| 46 MediaTaskRunnerWithNotification::MediaTaskRunnerWithNotification( | |
| 47 const scoped_refptr<MediaTaskRunner>& media_task_runner, | |
| 48 const base::Closure new_task_cb, | |
| 49 const base::Closure shutdown_cb) | |
| 50 : media_task_runner_(media_task_runner), | |
| 51 new_task_cb_(new_task_cb), | |
| 52 shutdown_cb_(shutdown_cb) { | |
| 53 } | |
| 54 | |
| 55 MediaTaskRunnerWithNotification::~MediaTaskRunnerWithNotification() { | |
| 56 shutdown_cb_.Run(); | |
| 57 } | |
| 58 | |
| 59 bool MediaTaskRunnerWithNotification::PostMediaTask( | |
| 60 const tracked_objects::Location& from_here, | |
| 61 const base::Closure& task, | |
| 62 base::TimeDelta timestamp) { | |
| 63 bool may_run_in_future = | |
| 64 media_task_runner_->PostMediaTask(from_here, task, timestamp); | |
| 65 if (may_run_in_future) | |
| 66 new_task_cb_.Run(); | |
| 67 return may_run_in_future; | |
| 68 } | |
| 69 | |
| 70 | |
| 71 // BalancedMediaTaskRunner - | |
| 72 // Run media tasks whose timestamp is less or equal to a max timestamp. | |
| 73 // | |
| 74 // Restrictions of BalancedMediaTaskRunner: | |
| 75 // - Can have at most one task in the queue. | |
| 76 // - Tasks should be given by increasing timestamps. | |
| 77 class BalancedMediaTaskRunner | |
| 78 : public MediaTaskRunner { | |
| 79 public: | |
| 80 explicit BalancedMediaTaskRunner( | |
| 81 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner); | |
| 82 | |
| 83 // Schedule tasks whose timestamp is less than or equal to |max_timestamp|. | |
| 84 void ScheduleWork(base::TimeDelta max_timestamp); | |
| 85 | |
| 86 // Return the timestamp of the last media task. | |
| 87 // Return ::media::kNoTimestamp() if no media task has been posted. | |
| 88 base::TimeDelta GetMediaTimestamp() const; | |
| 89 | |
| 90 // MediaTaskRunner implementation. | |
| 91 virtual bool PostMediaTask( | |
| 92 const tracked_objects::Location& from_here, | |
| 93 const base::Closure& task, | |
| 94 base::TimeDelta timestamp) OVERRIDE; | |
| 95 | |
| 96 private: | |
| 97 virtual ~BalancedMediaTaskRunner(); | |
| 98 | |
| 99 scoped_refptr<base::SingleThreadTaskRunner> const task_runner_; | |
| 100 | |
| 101 // Protects the following variables. | |
| 102 mutable base::Lock lock_; | |
| 103 | |
| 104 // Possible pending media task. | |
| 105 tracked_objects::Location from_here_; | |
| 106 base::Closure pending_task_; | |
| 107 | |
| 108 // Timestamp of the last posted task. | |
| 109 // Is initialized to ::media::kNoTimestamp(). | |
| 110 base::TimeDelta last_timestamp_; | |
| 111 | |
| 112 DISALLOW_COPY_AND_ASSIGN(BalancedMediaTaskRunner); | |
| 113 }; | |
| 114 | |
| 115 BalancedMediaTaskRunner::BalancedMediaTaskRunner( | |
| 116 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) | |
| 117 : task_runner_(task_runner), | |
| 118 last_timestamp_(::media::kNoTimestamp()) { | |
| 119 } | |
| 120 | |
| 121 BalancedMediaTaskRunner::~BalancedMediaTaskRunner() { | |
| 122 } | |
| 123 | |
| 124 void BalancedMediaTaskRunner::ScheduleWork(base::TimeDelta max_media_time) { | |
| 125 base::Closure task; | |
| 126 { | |
| 127 base::AutoLock auto_lock(lock_); | |
| 128 if (pending_task_.is_null()) | |
| 129 return; | |
| 130 | |
| 131 if (last_timestamp_ != ::media::kNoTimestamp() && | |
| 132 last_timestamp_ >= max_media_time) { | |
| 133 return; | |
| 134 } | |
| 135 | |
| 136 task = base::ResetAndReturn(&pending_task_); | |
| 137 } | |
| 138 task_runner_->PostTask(from_here_, task); | |
| 139 } | |
| 140 | |
| 141 base::TimeDelta BalancedMediaTaskRunner::GetMediaTimestamp() const { | |
| 142 base::AutoLock auto_lock(lock_); | |
| 143 return last_timestamp_; | |
| 144 } | |
| 145 | |
| 146 bool BalancedMediaTaskRunner::PostMediaTask( | |
| 147 const tracked_objects::Location& from_here, | |
| 148 const base::Closure& task, | |
| 149 base::TimeDelta timestamp) { | |
| 150 DCHECK(!task.is_null()); | |
| 151 | |
| 152 // Pass through for a task with no timestamp. | |
| 153 if (timestamp == ::media::kNoTimestamp()) { | |
| 154 return task_runner_->PostTask(from_here, task); | |
| 155 } | |
| 156 | |
| 157 base::AutoLock auto_lock(lock_); | |
| 158 | |
| 159 // Timestamps must be in order. | |
| 160 // Any task that does not meet that condition is simply discarded. | |
| 161 if (last_timestamp_ != ::media::kNoTimestamp() && | |
| 162 timestamp < last_timestamp_) { | |
| 163 return false; | |
| 164 } | |
| 165 | |
| 166 // Only support one pending task at a time. | |
| 167 DCHECK(pending_task_.is_null()); | |
| 168 from_here_ = from_here; | |
| 169 pending_task_ = task; | |
| 170 last_timestamp_ = timestamp; | |
| 171 | |
| 172 return true; | |
| 173 } | |
| 174 | |
| 175 | |
| 176 BalancedMediaTaskRunnerFactory::BalancedMediaTaskRunnerFactory( | |
| 177 base::TimeDelta max_delta) | |
| 178 : max_delta_(max_delta) { | |
| 179 } | |
| 180 | |
| 181 BalancedMediaTaskRunnerFactory::~BalancedMediaTaskRunnerFactory() { | |
| 182 } | |
| 183 | |
| 184 scoped_refptr<MediaTaskRunner> | |
| 185 BalancedMediaTaskRunnerFactory::CreateMediaTaskRunner( | |
| 186 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) { | |
| 187 scoped_refptr<BalancedMediaTaskRunner> media_task_runner( | |
| 188 new BalancedMediaTaskRunner(task_runner)); | |
| 189 scoped_refptr<MediaTaskRunnerWithNotification> media_task_runner_wrapper( | |
| 190 new MediaTaskRunnerWithNotification( | |
| 191 media_task_runner, | |
| 192 base::Bind(&BalancedMediaTaskRunnerFactory::OnNewTask, this), | |
| 193 base::Bind( | |
| 194 &BalancedMediaTaskRunnerFactory::UnregisterMediaTaskRunner, | |
| 195 this, media_task_runner))); | |
| 196 base::AutoLock auto_lock(lock_); | |
| 197 task_runners_.insert(media_task_runner); | |
| 198 return media_task_runner_wrapper; | |
| 199 } | |
| 200 | |
| 201 void BalancedMediaTaskRunnerFactory::OnNewTask() { | |
| 202 typedef | |
| 203 std::multimap<base::TimeDelta, scoped_refptr<BalancedMediaTaskRunner> > | |
| 204 TaskRunnerMap; | |
| 205 TaskRunnerMap runnable_task_runner; | |
| 206 | |
| 207 base::AutoLock auto_lock(lock_); | |
| 208 | |
| 209 // Get the minimum timestamp among all streams. | |
| 210 for (MediaTaskRunnerSet::const_iterator it = task_runners_.begin(); | |
| 211 it != task_runners_.end(); ++it) { | |
| 212 base::TimeDelta timestamp((*it)->GetMediaTimestamp()); | |
| 213 if (timestamp == ::media::kNoTimestamp()) | |
| 214 continue; | |
| 215 runnable_task_runner.insert( | |
| 216 std::pair<base::TimeDelta, scoped_refptr<BalancedMediaTaskRunner> >( | |
| 217 timestamp, *it)); | |
| 218 } | |
| 219 | |
| 220 // If there is no media task, just returns. | |
| 221 if (runnable_task_runner.empty()) | |
| 222 return; | |
| 223 | |
| 224 // Run tasks which meet the balancing criteria. | |
| 225 base::TimeDelta min_timestamp(runnable_task_runner.begin()->first); | |
| 226 base::TimeDelta max_timestamp = min_timestamp + max_delta_; | |
| 227 for (TaskRunnerMap::iterator it = runnable_task_runner.begin(); | |
| 228 it != runnable_task_runner.end(); ++it) { | |
| 229 (*it).second->ScheduleWork(max_timestamp); | |
| 230 } | |
| 231 } | |
| 232 | |
| 233 void BalancedMediaTaskRunnerFactory::UnregisterMediaTaskRunner( | |
| 234 const scoped_refptr<BalancedMediaTaskRunner>& media_task_runner) { | |
| 235 base::AutoLock auto_lock(lock_); | |
| 236 task_runners_.erase(media_task_runner); | |
| 237 } | |
| 238 | |
| 239 } // namespace media | |
| 240 } // namespace chromecast | |
| OLD | NEW |