OLD | NEW |
---|---|
(Empty) | |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 #include <string> | |
6 | |
7 #include "services/media/audio/audio_output.h" | |
8 #include "services/media/audio/audio_output_manager.h" | |
9 #include "services/media/audio/audio_server_impl.h" | |
10 #include "services/media/audio/audio_track_to_output_link.h" | |
11 #include "services/media/audio/platform/generic/throttle_output.h" | |
12 | |
13 namespace mojo { | |
14 namespace media { | |
15 namespace audio { | |
16 | |
17 static constexpr size_t THREAD_POOL_SZ = 2; | |
18 static const std::string THREAD_PREFIX("AudioMixer"); | |
19 | |
20 AudioOutputManager::AudioOutputManager(AudioServerImpl* server) | |
21 : server_(server) { | |
22 } | |
23 | |
24 AudioOutputManager::~AudioOutputManager() { | |
25 Shutdown(); | |
26 DCHECK_EQ(outputs_.size(), 0u); | |
27 DCHECK(!thread_pool_); | |
28 } | |
29 | |
30 MediaResult AudioOutputManager::Init() { | |
31 // Step #1: Initialize the mixing thread pool. | |
32 // | |
33 // TODO(johngro): make the thread pool size proportional to the maximum | |
34 // number of cores available in the system. | |
35 // | |
36 // TODO(johngro): make sure that the threads are executed at an elevated | |
37 // priority, not the default priority. | |
38 thread_pool_ = new base::SequencedWorkerPool(THREAD_POOL_SZ, THREAD_PREFIX); | |
39 | |
40 // Step #2: Instantiate all of the built-in audio output devices. | |
41 // | |
42 // TODO(johngro): Come up with a better way of doing this based on our | |
43 // platform. Right now, we just create some hardcoded default outputs and | |
44 // leave it at that. | |
45 outputs_.emplace(audio::ThrottleOutput::New(this)); | |
46 | |
47 // Step #3: Being monitoring for plug/unplug events for pluggable audio | |
48 // output devices. | |
49 // | |
50 // TODO(johngro): Implement step #3. Right now, the details are behind | |
51 // hot-plug monitoring are TBD, so the feature is not implemented. | |
52 | |
53 // Step #4: Attempt to initialize each of the audio outputs we have created, | |
54 // then kick off the callback engine for each of them. | |
55 for (auto iter = outputs_.begin(); iter != outputs_.end(); ) { | |
56 const AudioOutputPtr& output = *iter; | |
57 auto tmp = iter++; | |
58 DCHECK(output); | |
59 | |
60 // Create a sequenced task runner for this output. It will be used by the | |
61 // output to schedule jobs (such as mixing) on the thread pool. | |
62 scoped_refptr<base::SequencedTaskRunner> task_runner = | |
63 thread_pool_->GetSequencedTaskRunnerWithShutdownBehavior( | |
64 thread_pool_->GetSequenceToken(), | |
65 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN); | |
66 | |
67 MediaResult res = output->Init(output, task_runner); | |
68 if (res != MediaResult::OK) { | |
69 // TODO(johngro): Probably should log something about this, assuming that | |
jeffbrown
2015/11/04 23:43:33
Another approach would be to handle this symmetric
johngro
2015/11/06 02:20:24
Perhaps, but I do not feel that there is ever a go
| |
70 // the output has not already. | |
71 outputs_.erase(tmp); | |
72 } | |
73 } | |
74 | |
75 return MediaResult::OK; | |
76 } | |
77 | |
78 void AudioOutputManager::Shutdown() { | |
79 // Are we already shutdown (or were we never successfully initialized?) | |
80 if (thread_pool_ == nullptr) { | |
81 DCHECK_EQ(outputs_.size(), 0u); | |
82 return; | |
83 } | |
84 | |
85 // Step #1: Stop monitoringing plug/unplug events. We are shutting down and | |
86 // no longer care about outputs coming and going. | |
87 // | |
88 // TODO(johngro): Implement step #1. Right now, the details are behind | |
89 // hot-plug monitoring are TBD, so the feature is not implemented. | |
90 | |
91 // Step #2: Shut down each currently active output in the system. It is | |
92 // possible for this to take a bit of time as outputs release their hardware, | |
93 // but it should not take long. | |
jeffbrown
2015/11/04 23:43:33
Famous last words. :)
johngro
2015/11/06 02:20:24
See above. Hopefully not, but we will adapt if th
| |
94 for (const auto& output_ptr : outputs_) { | |
95 output_ptr->Shutdown(); | |
96 } | |
97 outputs_.clear(); | |
98 | |
99 // Step #3: Shutdown and release our thread pool. Since we have shut down all | |
100 // of our outputs, any pending tasks left in the task runner are now no-ops, | |
101 // so it does not matter that the task runner is going to cancel them all | |
102 // (instead of blocking) when we shut it down. | |
103 thread_pool_->Shutdown(); | |
104 thread_pool_ = nullptr; | |
105 } | |
106 | |
107 void AudioOutputManager::ShutdownOutput(AudioOutputPtr output) { | |
108 // No one should be calling this method if we have been shut down (or never | |
109 // successfully started). | |
110 DCHECK(thread_pool_); | |
111 | |
112 auto iter = outputs_.find(output); | |
113 if (iter != outputs_.end()) { | |
114 output->Shutdown(); | |
115 outputs_.erase(iter); | |
116 } | |
117 } | |
118 | |
119 void AudioOutputManager::SelectOutputsForTrack(AudioTrackImplPtr track) { | |
120 // TODO(johngro): Someday, base this on policy. For now, every track gets | |
121 // assigned to every output in the system. | |
122 DCHECK(track); | |
123 | |
124 // TODO(johngro): Add some way to assert that we are executing on the main | |
125 // message loop thread. | |
126 | |
127 for (auto output : outputs_) { | |
128 auto link = AudioTrackToOutputLink::New(track, output); | |
129 DCHECK(output); | |
130 DCHECK(link); | |
131 | |
132 // If we cannot add this link to the output, it's because the output is in | |
133 // the process of shutting down (we didn't want to hang out with that guy | |
134 // anyway) | |
135 if (output->AddTrackLink(link) == MediaResult::OK) { | |
136 track->AddOutput(link); | |
137 } | |
138 } | |
139 } | |
140 | |
141 void AudioOutputManager::ScheduleMessageLoopTask( | |
142 const tracked_objects::Location& from_here, | |
143 const base::Closure& task) { | |
144 DCHECK(server_); | |
145 server_->ScheduleMessageLoopTask(from_here, task); | |
146 } | |
147 | |
148 } // namespace audio | |
149 } // namespace media | |
150 } // namespace mojo | |
OLD | NEW |