| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <limits> | 5 #include <limits> |
| 6 | 6 |
| 7 #include "base/logging.h" | 7 #include "base/logging.h" |
| 8 #include "services/media/audio/audio_track_impl.h" | 8 #include "services/media/audio/audio_track_impl.h" |
| 9 #include "services/media/audio/audio_track_to_output_link.h" | 9 #include "services/media/audio/audio_track_to_output_link.h" |
| 10 #include "services/media/audio/platform/generic/mixer.h" | 10 #include "services/media/audio/platform/generic/mixer.h" |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 71 | 71 |
| 72 // As long as our implementation wants to mix more and has not run into a | 72 // As long as our implementation wants to mix more and has not run into a |
| 73 // problem trying to finish the mix job, mix some more. | 73 // problem trying to finish the mix job, mix some more. |
| 74 do { | 74 do { |
| 75 ::memset(&cur_mix_job_, 0, sizeof(cur_mix_job_)); | 75 ::memset(&cur_mix_job_, 0, sizeof(cur_mix_job_)); |
| 76 | 76 |
| 77 if (!StartMixJob(&cur_mix_job_, now)) { | 77 if (!StartMixJob(&cur_mix_job_, now)) { |
| 78 break; | 78 break; |
| 79 } | 79 } |
| 80 | 80 |
| 81 // If we have a mix job, then we must have an output formatter, and an |
| 82 // intermediate buffer allocated, and it must be large enough for the mix |
| 83 // job we were given. |
| 84 DCHECK(mix_buf_); |
| 85 DCHECK(output_formatter_); |
| 86 DCHECK_LE(cur_mix_job_.buf_frames, mix_buf_frames_); |
| 87 |
| 88 // Fill the intermediate buffer with silence. |
| 89 size_t bytes_to_zero = sizeof(*mix_buf_) |
| 90 * cur_mix_job_.buf_frames |
| 91 * output_formatter_->channels(); |
| 92 ::memset(mix_buf_.get(), 0, bytes_to_zero); |
| 93 |
| 94 // Mix each track into the intermediate buffer, then clip/format into the |
| 95 // final buffer. |
| 81 ForeachTrack(setup_mix_, process_mix_); | 96 ForeachTrack(setup_mix_, process_mix_); |
| 97 output_formatter_->ProduceOutput(mix_buf_.get(), |
| 98 cur_mix_job_.buf, |
| 99 cur_mix_job_.buf_frames); |
| 100 |
| 82 mixed = true; | 101 mixed = true; |
| 83 } while (FinishMixJob(cur_mix_job_)); | 102 } while (FinishMixJob(cur_mix_job_)); |
| 84 } | 103 } |
| 85 | 104 |
| 86 if (!next_sched_time_known_) { | 105 if (!next_sched_time_known_) { |
| 87 // TODO(johngro): log this as an error. | 106 // TODO(johngro): log this as an error. |
| 88 ShutdownSelf(); | 107 ShutdownSelf(); |
| 89 return; | 108 return; |
| 90 } | 109 } |
| 91 | 110 |
| (...skipping 20 matching lines...) Expand all Loading... |
| 112 | 131 |
| 113 // We should never fail to allocate our bookkeeping. The only way this can | 132 // We should never fail to allocate our bookkeeping. The only way this can |
| 114 // happen is if we have a badly behaved implementation. | 133 // happen is if we have a badly behaved implementation. |
| 115 if (!bk) { return MediaResult::INTERNAL_ERROR; } | 134 if (!bk) { return MediaResult::INTERNAL_ERROR; } |
| 116 | 135 |
| 117 // We cannot proceed if our track has somehow managed to go away already. | 136 // We cannot proceed if our track has somehow managed to go away already. |
| 118 AudioTrackImplPtr track = link->GetTrack(); | 137 AudioTrackImplPtr track = link->GetTrack(); |
| 119 if (!track) { return MediaResult::INVALID_ARGUMENT; } | 138 if (!track) { return MediaResult::INVALID_ARGUMENT; } |
| 120 | 139 |
| 121 // Pick a mixer based on the input and output formats. | 140 // Pick a mixer based on the input and output formats. |
| 122 bk->mixer = Mixer::Select(track->Format(), output_format_); | 141 bk->mixer = Mixer::Select(track->Format(), output_formatter_ |
| 142 ? &output_formatter_->format() |
| 143 : nullptr); |
| 123 if (bk->mixer == nullptr) { return MediaResult::UNSUPPORTED_CONFIG; } | 144 if (bk->mixer == nullptr) { return MediaResult::UNSUPPORTED_CONFIG; } |
| 124 | 145 |
| 125 // Looks like things went well. Stash a reference to our bookkeeping and get | 146 // Looks like things went well. Stash a reference to our bookkeeping and get |
| 126 // out. | 147 // out. |
| 127 link->output_bookkeeping() = std::move(ref); | 148 link->output_bookkeeping() = std::move(ref); |
| 128 return MediaResult::OK; | 149 return MediaResult::OK; |
| 129 } | 150 } |
| 130 | 151 |
| 131 StandardOutputBase::TrackBookkeeping* StandardOutputBase::AllocBookkeeping() { | 152 StandardOutputBase::TrackBookkeeping* StandardOutputBase::AllocBookkeeping() { |
| 132 return new TrackBookkeeping(); | 153 return new TrackBookkeeping(); |
| 133 } | 154 } |
| 134 | 155 |
| 156 void StandardOutputBase::SetupMixBuffer(uint32_t max_mix_frames) { |
| 157 DCHECK_GT(output_formatter_->channels(), 0u); |
| 158 DCHECK_GT(max_mix_frames, 0u); |
| 159 DCHECK_LE(max_mix_frames, std::numeric_limits<uint32_t>::max() / |
| 160 output_formatter_->channels()); |
| 161 |
| 162 mix_buf_frames_ = max_mix_frames; |
| 163 mix_buf_.reset(new int32_t[mix_buf_frames_ * output_formatter_->channels()]); |
| 164 } |
| 165 |
| 135 void StandardOutputBase::ForeachTrack(const TrackSetupTask& setup, | 166 void StandardOutputBase::ForeachTrack(const TrackSetupTask& setup, |
| 136 const TrackProcessTask& process) { | 167 const TrackProcessTask& process) { |
| 137 for (auto iter = links_.begin(); iter != links_.end(); ) { | 168 for (auto iter = links_.begin(); iter != links_.end(); ) { |
| 138 if (shutting_down()) { return; } | 169 if (shutting_down()) { return; } |
| 139 | 170 |
| 140 // Is the track still around? If so, process it. Otherwise, remove the | 171 // Is the track still around? If so, process it. Otherwise, remove the |
| 141 // track entry and move on. | 172 // track entry and move on. |
| 142 const AudioTrackToOutputLinkPtr& link = *iter; | 173 const AudioTrackToOutputLinkPtr& link = *iter; |
| 143 AudioTrackImplPtr track(link->GetTrack()); | 174 AudioTrackImplPtr track(link->GetTrack()); |
| 144 | 175 |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 211 | 242 |
| 212 bool StandardOutputBase::ProcessMix( | 243 bool StandardOutputBase::ProcessMix( |
| 213 const AudioTrackImplPtr& track, | 244 const AudioTrackImplPtr& track, |
| 214 TrackBookkeeping* info, | 245 TrackBookkeeping* info, |
| 215 const AudioPipe::AudioPacketRefPtr& packet) { | 246 const AudioPipe::AudioPacketRefPtr& packet) { |
| 216 // Sanity check our parameters. | 247 // Sanity check our parameters. |
| 217 DCHECK(info); | 248 DCHECK(info); |
| 218 DCHECK(packet); | 249 DCHECK(packet); |
| 219 | 250 |
| 220 // We had better have a valid job, or why are we here? | 251 // We had better have a valid job, or why are we here? |
| 221 DCHECK(cur_mix_job_.buf); | |
| 222 DCHECK(cur_mix_job_.buf_frames); | 252 DCHECK(cur_mix_job_.buf_frames); |
| 223 DCHECK(cur_mix_job_.frames_produced <= cur_mix_job_.buf_frames); | 253 DCHECK(cur_mix_job_.frames_produced <= cur_mix_job_.buf_frames); |
| 224 | 254 |
| 225 // We also must have selected a mixer, or we are in trouble. | 255 // We also must have selected a mixer, or we are in trouble. |
| 226 DCHECK(info->mixer); | 256 DCHECK(info->mixer); |
| 227 Mixer& mixer = *(info->mixer); | 257 Mixer& mixer = *(info->mixer); |
| 228 | 258 |
| 229 // If this track is currently paused (or being sampled extremely slowly), our | 259 // If this track is currently paused (or being sampled extremely slowly), our |
| 230 // step size will be zero. We know that this packet will be relevant at some | 260 // step size will be zero. We know that this packet will be relevant at some |
| 231 // point in the future, but right now it contributes nothing. Tell the | 261 // point in the future, but right now it contributes nothing. Tell the |
| 232 // ForeachTrack loop that we are done and to hold onto this packet for now. | 262 // ForeachTrack loop that we are done and to hold onto this packet for now. |
| 233 if (!info->step_size) { | 263 if (!info->step_size) { |
| 234 return false; | 264 return false; |
| 235 } | 265 } |
| 236 | 266 |
| 237 // Have we produced all that we are supposed to? If so, hold the current | 267 // Have we produced all that we are supposed to? If so, hold the current |
| 238 // packet and move on to the next track. | 268 // packet and move on to the next track. |
| 239 if (cur_mix_job_.frames_produced >= cur_mix_job_.buf_frames) { | 269 if (cur_mix_job_.frames_produced >= cur_mix_job_.buf_frames) { |
| 240 return false; | 270 return false; |
| 241 } | 271 } |
| 242 | 272 |
| 243 uint32_t frames_left = cur_mix_job_.buf_frames - cur_mix_job_.frames_produced; | 273 uint32_t frames_left = cur_mix_job_.buf_frames - cur_mix_job_.frames_produced; |
| 244 void* buf = static_cast<uint8_t*>(cur_mix_job_.buf) | 274 int32_t* buf = mix_buf_.get() |
| 245 + (cur_mix_job_.frames_produced * output_bytes_per_frame_); | 275 + (cur_mix_job_.frames_produced * output_formatter_->channels()); |
| 246 | 276 |
| 247 // Figure out where the first and last sampling points of this job are, | 277 // Figure out where the first and last sampling points of this job are, |
| 248 // expressed in fractional track frames. | 278 // expressed in fractional track frames. |
| 249 int64_t first_sample_ftf; | 279 int64_t first_sample_ftf; |
| 250 bool good = info->out_frames_to_track_frames.DoForwardTransform( | 280 bool good = info->out_frames_to_track_frames.DoForwardTransform( |
| 251 cur_mix_job_.start_pts_of + cur_mix_job_.frames_produced, | 281 cur_mix_job_.start_pts_of + cur_mix_job_.frames_produced, |
| 252 &first_sample_ftf); | 282 &first_sample_ftf); |
| 253 DCHECK(good); | 283 DCHECK(good); |
| 254 | 284 |
| 255 DCHECK(frames_left); | 285 DCHECK(frames_left); |
| (...skipping 242 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 498 step_size = static_cast<uint32_t>(tmp_step_size); | 528 step_size = static_cast<uint32_t>(tmp_step_size); |
| 499 } | 529 } |
| 500 | 530 |
| 501 // Done, update our generation. | 531 // Done, update our generation. |
| 502 out_frames_to_track_frames_gen = job.local_to_output_gen; | 532 out_frames_to_track_frames_gen = job.local_to_output_gen; |
| 503 } | 533 } |
| 504 | 534 |
| 505 } // namespace audio | 535 } // namespace audio |
| 506 } // namespace media | 536 } // namespace media |
| 507 } // namespace mojo | 537 } // namespace mojo |
| OLD | NEW |