Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(35)

Side by Side Diff: services/media/audio/audio_track_impl.cc

Issue 2069873003: Motown: Define MediaRenderer and make it the way we identify renderers. (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Fix build break...audio_track_controller.* gone for good. Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « services/media/audio/audio_track_impl.h ('k') | services/media/factory_service/BUILD.gn » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 <algorithm> 5 #include <algorithm>
6 #include <limits> 6 #include <limits>
7 7
8 #include "base/logging.h" 8 #include "base/logging.h"
9 #include "mojo/services/media/common/cpp/linear_transform.h" 9 #include "mojo/services/media/common/cpp/linear_transform.h"
10 #include "mojo/services/media/common/cpp/timeline.h" 10 #include "mojo/services/media/common/cpp/timeline.h"
(...skipping 26 matching lines...) Expand all
37 }, 37 },
38 { 38 {
39 .sample_format = AudioSampleFormat::SIGNED_16, 39 .sample_format = AudioSampleFormat::SIGNED_16,
40 .min_channels = 1, 40 .min_channels = 1,
41 .max_channels = 2, 41 .max_channels = 2,
42 .min_frames_per_second = 1000, 42 .min_frames_per_second = 1000,
43 .max_frames_per_second = 48000, 43 .max_frames_per_second = 48000,
44 }, 44 },
45 }; 45 };
46 46
47 AudioTrackImpl::AudioTrackImpl(InterfaceRequest<AudioTrack> iface, 47 AudioTrackImpl::AudioTrackImpl(InterfaceRequest<AudioTrack> track_request,
48 InterfaceRequest<MediaRenderer> renderer_request,
48 AudioServerImpl* owner) 49 AudioServerImpl* owner)
49 : owner_(owner), 50 : owner_(owner),
50 binding_(this), 51 track_binding_(this, track_request.Pass()),
52 renderer_binding_(this, renderer_request.Pass()),
51 pipe_(this, owner) { 53 pipe_(this, owner) {
52 CHECK(nullptr != owner_); 54 CHECK(nullptr != owner_);
53 binding_.Bind(iface.Pass()); 55 track_binding_.set_connection_error_handler([this]() -> void {
54 binding_.set_connection_error_handler([this]() -> void { 56 if (!renderer_binding_.is_bound()) {
55 Shutdown(); 57 Shutdown();
58 }
59 });
60 renderer_binding_.set_connection_error_handler([this]() -> void {
61 if (!track_binding_.is_bound()) {
62 Shutdown();
63 }
56 }); 64 });
57 } 65 }
58 66
59 AudioTrackImpl::~AudioTrackImpl() { 67 AudioTrackImpl::~AudioTrackImpl() {
60 // assert that we have been cleanly shutdown already. 68 // assert that we have been cleanly shutdown already.
61 MOJO_DCHECK(!binding_.is_bound()); 69 MOJO_DCHECK(!track_binding_.is_bound());
70 MOJO_DCHECK(!renderer_binding_.is_bound());
62 } 71 }
63 72
64 AudioTrackImplPtr AudioTrackImpl::Create(InterfaceRequest<AudioTrack> iface, 73 AudioTrackImplPtr AudioTrackImpl::Create(
65 AudioServerImpl* owner) { 74 InterfaceRequest<AudioTrack> track_request,
66 AudioTrackImplPtr ret(new AudioTrackImpl(iface.Pass(), owner)); 75 InterfaceRequest<MediaRenderer> renderer_request,
76 AudioServerImpl* owner) {
77 AudioTrackImplPtr ret(
78 new AudioTrackImpl(track_request.Pass(), renderer_request.Pass(), owner));
67 ret->weak_this_ = ret; 79 ret->weak_this_ = ret;
68 return ret; 80 return ret;
69 } 81 }
70 82
71 void AudioTrackImpl::Shutdown() { 83 void AudioTrackImpl::Shutdown() {
84 if (track_binding_.is_bound()) {
85 track_binding_.set_connection_error_handler(mojo::Closure());
86 track_binding_.Close();
87 }
88
72 // If we are unbound, then we have already been shut down and are just waiting 89 // If we are unbound, then we have already been shut down and are just waiting
73 // for the service to destroy us. Run some DCHECK sanity checks and get out. 90 // for the service to destroy us. Run some DCHECK sanity checks and get out.
74 if (!binding_.is_bound()) { 91 if (!renderer_binding_.is_bound()) {
75 DCHECK(!pipe_.IsInitialized()); 92 DCHECK(!pipe_.IsInitialized());
76 DCHECK(!timeline_control_site_.is_bound()); 93 DCHECK(!timeline_control_site_.is_bound());
77 DCHECK(!outputs_.size()); 94 DCHECK(!outputs_.size());
78 return; 95 return;
79 } 96 }
80 97
81 // Close the connection to our client 98 // Close the connection to our client
82 binding_.set_connection_error_handler(mojo::Closure()); 99 renderer_binding_.set_connection_error_handler(mojo::Closure());
83 binding_.Close(); 100 renderer_binding_.Close();
84 101
85 // reset all of our internal state and close any other client connections in 102 // reset all of our internal state and close any other client connections in
86 // the process. 103 // the process.
87 pipe_.Reset(); 104 pipe_.Reset();
88 timeline_control_site_.Reset(); 105 timeline_control_site_.Reset();
89 outputs_.clear(); 106 outputs_.clear();
90 107
91 DCHECK(owner_); 108 DCHECK(owner_);
92 AudioTrackImplPtr thiz = weak_this_.lock(); 109 AudioTrackImplPtr thiz = weak_this_.lock();
93 owner_->RemoveTrack(thiz); 110 owner_->RemoveTrack(thiz);
94 } 111 }
95 112
96 void AudioTrackImpl::Describe(const DescribeCallback& cbk) { 113 void AudioTrackImpl::GetSupportedMediaTypes(
114 const GetSupportedMediaTypesCallback& cbk) {
97 // Build a minimal descriptor 115 // Build a minimal descriptor
98 // 116 //
99 // TODO(johngro): one day, we need to make this description much more rich and 117 // TODO(johngro): one day, we need to make this description much more rich and
100 // fully describe our capabilities, based on things like what outputs are 118 // fully describe our capabilities, based on things like what outputs are
101 // available, the class of hardware we are on, and what options we were 119 // available, the class of hardware we are on, and what options we were
102 // compiled with. 120 // compiled with.
103 // 121 //
104 // For now, it would be nice to just be able to have a static const tree of 122 // For now, it would be nice to just be able to have a static const tree of
105 // capabilities in this translational unit which we could use to construct our 123 // capabilities in this translational unit which we could use to construct our
106 // message, but the nature of the structures generated by the C++ bindings 124 // message, but the nature of the structures generated by the C++ bindings
107 // make this difficult. For now, we just create a trivial descriptor entierly 125 // make this difficult. For now, we just create a trivial descriptor entierly
108 // by hand. 126 // by hand.
109 AudioTrackDescriptorPtr desc(AudioTrackDescriptor::New()); 127 Array<MediaTypeSetPtr> supported_media_types =
110
111 desc->supported_media_types =
112 Array<MediaTypeSetPtr>::New(arraysize(kSupportedAudioTypeSets)); 128 Array<MediaTypeSetPtr>::New(arraysize(kSupportedAudioTypeSets));
113 129
114 for (size_t i = 0; i < desc->supported_media_types.size(); ++i) { 130 for (size_t i = 0; i < supported_media_types.size(); ++i) {
115 const MediaTypeSetPtr& mts = 131 const MediaTypeSetPtr& mts =
116 (desc->supported_media_types[i] = MediaTypeSet::New()); 132 (supported_media_types[i] = MediaTypeSet::New());
117 133
118 mts->medium = MediaTypeMedium::AUDIO; 134 mts->medium = MediaTypeMedium::AUDIO;
119 mts->encodings = Array<String>::New(1); 135 mts->encodings = Array<String>::New(1);
120 mts->details = MediaTypeSetDetails::New(); 136 mts->details = MediaTypeSetDetails::New();
121 137
122 mts->encodings[0] = MediaType::kAudioEncodingLpcm; 138 mts->encodings[0] = MediaType::kAudioEncodingLpcm;
123 139
124 const auto& s = kSupportedAudioTypeSets[i]; 140 const auto& s = kSupportedAudioTypeSets[i];
125 AudioMediaTypeSetDetailsPtr audio_detail = AudioMediaTypeSetDetails::New(); 141 AudioMediaTypeSetDetailsPtr audio_detail = AudioMediaTypeSetDetails::New();
126 142
127 audio_detail->sample_format = s.sample_format; 143 audio_detail->sample_format = s.sample_format;
128 audio_detail->min_channels = s.min_channels; 144 audio_detail->min_channels = s.min_channels;
129 audio_detail->max_channels = s.max_channels; 145 audio_detail->max_channels = s.max_channels;
130 audio_detail->min_frames_per_second = s.min_frames_per_second; 146 audio_detail->min_frames_per_second = s.min_frames_per_second;
131 audio_detail->max_frames_per_second = s.max_frames_per_second; 147 audio_detail->max_frames_per_second = s.max_frames_per_second;
132 mts->details->set_audio(audio_detail.Pass()); 148 mts->details->set_audio(audio_detail.Pass());
133 } 149 }
134 150
135 cbk.Run(desc.Pass()); 151 cbk.Run(supported_media_types.Pass());
136 } 152 }
137 153
138 void AudioTrackImpl::Configure(AudioTrackConfigurationPtr configuration, 154 void AudioTrackImpl::SetMediaType(MediaTypePtr media_type) {
139 InterfaceRequest<MediaConsumer> req) {
140 // Are we already configured? 155 // Are we already configured?
141 if (pipe_.IsInitialized()) { 156 if (pipe_.IsInitialized()) {
142 LOG(ERROR) << "Attempting to reconfigure a configured audio track."; 157 LOG(ERROR) << "Attempting to reconfigure a configured audio track.";
143 Shutdown(); 158 Shutdown();
144 return; 159 return;
145 } 160 }
146 161
147 // Check the requested configuration. 162 // Check the requested configuration.
148 if ((configuration->media_type->medium != MediaTypeMedium::AUDIO) || 163 if ((media_type->medium != MediaTypeMedium::AUDIO) ||
149 (configuration->media_type->encoding != MediaType::kAudioEncodingLpcm) || 164 (media_type->encoding != MediaType::kAudioEncodingLpcm) ||
150 (!configuration->media_type->details->is_audio())) { 165 (!media_type->details->is_audio())) {
151 LOG(ERROR) << "Unsupported configuration requested in " 166 LOG(ERROR) << "Unsupported configuration requested in "
152 "AudioTrack::Configure. Media type must be LPCM audio."; 167 "AudioTrack::Configure. Media type must be LPCM audio.";
153 Shutdown(); 168 Shutdown();
154 return; 169 return;
155 } 170 }
156 171
157 // Search our supported configuration sets to find one compatible with this 172 // Search our supported configuration sets to find one compatible with this
158 // request. 173 // request.
159 auto& cfg = configuration->media_type->details->get_audio(); 174 auto& cfg = media_type->details->get_audio();
160 size_t i; 175 size_t i;
161 for (i = 0; i < arraysize(kSupportedAudioTypeSets); ++i) { 176 for (i = 0; i < arraysize(kSupportedAudioTypeSets); ++i) {
162 const auto& cfg_set = kSupportedAudioTypeSets[i]; 177 const auto& cfg_set = kSupportedAudioTypeSets[i];
163 178
164 if ((cfg->sample_format == cfg_set.sample_format) && 179 if ((cfg->sample_format == cfg_set.sample_format) &&
165 (cfg->channels >= cfg_set.min_channels) && 180 (cfg->channels >= cfg_set.min_channels) &&
166 (cfg->channels <= cfg_set.max_channels) && 181 (cfg->channels <= cfg_set.max_channels) &&
167 (cfg->frames_per_second >= cfg_set.min_frames_per_second) && 182 (cfg->frames_per_second >= cfg_set.min_frames_per_second) &&
168 (cfg->frames_per_second <= cfg_set.max_frames_per_second)) { 183 (cfg->frames_per_second <= cfg_set.max_frames_per_second)) {
169 break; 184 break;
170 } 185 }
171 } 186 }
172 187
173 if (i >= arraysize(kSupportedAudioTypeSets)) { 188 if (i >= arraysize(kSupportedAudioTypeSets)) {
174 LOG(ERROR) << "Unsupported LPCM configuration requested in " 189 LOG(ERROR) << "Unsupported LPCM configuration requested in "
175 "AudioTrack::Configure. " 190 "AudioTrack::Configure. "
176 << "(format = " << cfg->sample_format 191 << "(format = " << cfg->sample_format
177 << ", channels = " 192 << ", channels = "
178 << static_cast<uint32_t>(cfg->channels) 193 << static_cast<uint32_t>(cfg->channels)
179 << ", frames_per_second = " << cfg->frames_per_second 194 << ", frames_per_second = " << cfg->frames_per_second
180 << ")"; 195 << ")";
181 Shutdown(); 196 Shutdown();
182 return; 197 return;
183 } 198 }
184 199
185 // Sanity check the ratio which relates audio frames to media time.
186 uint32_t numerator =
187 static_cast<uint32_t>(configuration->audio_frame_ratio);
188 uint32_t denominator =
189 static_cast<uint32_t>(configuration->media_time_ratio);
190 if ((numerator < 1) || (denominator < 1)) {
191 LOG(ERROR) << "Invalid (audio frames:media time ticks) ratio ("
192 << numerator << "/" << denominator << ")";
193 Shutdown();
194 return;
195 }
196
197 frames_per_ns_ = 200 frames_per_ns_ =
198 TimelineRate(cfg->frames_per_second, Timeline::ns_from_seconds(1)); 201 TimelineRate(cfg->frames_per_second, Timeline::ns_from_seconds(1));
199 202
200 // Figure out the rate we need to scale by in order to produce our fixed 203 // Figure out the rate we need to scale by in order to produce our fixed
201 // point timestamps. 204 // point timestamps.
202 LinearTransform::Ratio frac_scale(1 << PTS_FRACTIONAL_BITS, 1); 205 LinearTransform::Ratio frac_scale(1 << PTS_FRACTIONAL_BITS, 1);
203 LinearTransform::Ratio frame_scale(LinearTransform::Ratio(numerator, 206 LinearTransform::Ratio frame_scale(LinearTransform::Ratio(1, 1));
204 denominator));
205 bool no_loss = LinearTransform::Ratio::Compose(frac_scale, 207 bool no_loss = LinearTransform::Ratio::Compose(frac_scale,
206 frame_scale, 208 frame_scale,
207 &frame_to_media_ratio_); 209 &frame_to_media_ratio_);
208 if (!no_loss) { 210 if (!no_loss) {
209 LOG(ERROR) << "Invalid (audio frames:media time ticks) ratio (" 211 LOG(ERROR) << "Invalid (audio frames:media time ticks) ratio (1/1)";
210 << numerator << "/" << denominator << ")";
211 Shutdown(); 212 Shutdown();
212 return; 213 return;
213 } 214 }
214 215
215 // Figure out how many bytes we need to hold the requested number of nSec of 216 // Figure out how many bytes we need to hold the requested number of nSec of
216 // audio. 217 // audio.
217 switch (cfg->sample_format) { 218 switch (cfg->sample_format) {
218 case AudioSampleFormat::UNSIGNED_8: 219 case AudioSampleFormat::UNSIGNED_8:
219 bytes_per_frame_ = 1; 220 bytes_per_frame_ = 1;
220 break; 221 break;
221 222
222 case AudioSampleFormat::SIGNED_16: 223 case AudioSampleFormat::SIGNED_16:
223 bytes_per_frame_ = 2; 224 bytes_per_frame_ = 2;
224 break; 225 break;
225 226
226 case AudioSampleFormat::SIGNED_24_IN_32: 227 case AudioSampleFormat::SIGNED_24_IN_32:
227 bytes_per_frame_ = 4; 228 bytes_per_frame_ = 4;
228 break; 229 break;
229 230
230 default: 231 default:
231 DCHECK(false); 232 DCHECK(false);
232 bytes_per_frame_ = 2; 233 bytes_per_frame_ = 2;
233 break; 234 break;
234 } 235 }
235 bytes_per_frame_ *= cfg->channels; 236 bytes_per_frame_ *= cfg->channels;
236 237
237 // Bind our pipe to the interface request.
238 if (pipe_.Init(req.Pass()) != MOJO_RESULT_OK) {
239 LOG(ERROR) << "Failed to media pipe to interface request.";
240 Shutdown();
241 return;
242 }
243
244 // Stash our configuration. 238 // Stash our configuration.
245 format_ = cfg.Pass(); 239 format_ = cfg.Pass();
246 240
247 // Have the audio output manager initialize our set of outputs. Note; there 241 // Have the audio output manager initialize our set of outputs. Note; there
248 // is currently no need for a lock here. Methods called from our user-facing 242 // is currently no need for a lock here. Methods called from our user-facing
249 // interfaces are seriailzed by nature of the mojo framework, and none of the 243 // interfaces are seriailzed by nature of the mojo framework, and none of the
250 // output manager's threads should ever need to manipulate the set. Cleanup 244 // output manager's threads should ever need to manipulate the set. Cleanup
251 // of outputs which have gone away is currently handled in a lazy fashion when 245 // of outputs which have gone away is currently handled in a lazy fashion when
252 // the track fails to promote its weak reference during an operation involving 246 // the track fails to promote its weak reference during an operation involving
253 // its outputs. 247 // its outputs.
254 // 248 //
255 // TODO(johngro): someday, we will need to deal with recalculating properties 249 // TODO(johngro): someday, we will need to deal with recalculating properties
256 // which depend on a track's current set of outputs (for example, the minimum 250 // which depend on a track's current set of outputs (for example, the minimum
257 // latency). This will probably be done using a dirty flag in the track 251 // latency). This will probably be done using a dirty flag in the track
258 // implementations, and scheduling a job to recalculate the properties for the 252 // implementations, and scheduling a job to recalculate the properties for the
259 // dirty tracks and notify the users as appropriate. 253 // dirty tracks and notify the users as appropriate.
260 254
261 // If we cannot promote our own weak pointer, something is seriously wrong. 255 // If we cannot promote our own weak pointer, something is seriously wrong.
262 AudioTrackImplPtr strong_this(weak_this_.lock()); 256 AudioTrackImplPtr strong_this(weak_this_.lock());
263 DCHECK(strong_this); 257 DCHECK(strong_this);
264 DCHECK(owner_); 258 DCHECK(owner_);
265 owner_->GetOutputManager().SelectOutputsForTrack(strong_this); 259 owner_->GetOutputManager().SelectOutputsForTrack(strong_this);
266 } 260 }
267 261
262 void AudioTrackImpl::GetConsumer(
263 InterfaceRequest<MediaConsumer> consumer_request) {
264 // Bind our pipe to the interface request.
265 if (pipe_.Init(consumer_request.Pass()) != MOJO_RESULT_OK) {
266 LOG(ERROR) << "Failed to media pipe to interface request.";
267 Shutdown();
268 return;
269 }
270 }
271
268 void AudioTrackImpl::GetTimelineControlSite( 272 void AudioTrackImpl::GetTimelineControlSite(
269 InterfaceRequest<MediaTimelineControlSite> req) { 273 InterfaceRequest<MediaTimelineControlSite> req) {
270 timeline_control_site_.Bind(req.Pass()); 274 timeline_control_site_.Bind(req.Pass());
271 } 275 }
272 276
273 void AudioTrackImpl::SetGain(float db_gain) { 277 void AudioTrackImpl::SetGain(float db_gain) {
274 if (db_gain >= AudioTrack::kMaxGain) { 278 if (db_gain >= AudioTrack::kMaxGain) {
275 LOG(ERROR) << "Gain value too large (" << db_gain << ") for audio track."; 279 LOG(ERROR) << "Gain value too large (" << db_gain << ") for audio track.";
276 Shutdown(); 280 Shutdown();
277 return; 281 return;
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
344 DCHECK(output); 348 DCHECK(output);
345 output->FlushPendingQueue(); 349 output->FlushPendingQueue();
346 } 350 }
347 cbk.Run(); 351 cbk.Run();
348 return true; 352 return true;
349 } 353 }
350 354
351 } // namespace audio 355 } // namespace audio
352 } // namespace media 356 } // namespace media
353 } // namespace mojo 357 } // namespace mojo
OLDNEW
« no previous file with comments | « services/media/audio/audio_track_impl.h ('k') | services/media/factory_service/BUILD.gn » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698