OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 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 "media/audio/pulse/pulse_util.h" | 5 #include "media/audio/pulse/pulse_util.h" |
6 | 6 |
7 #include <stdint.h> | 7 #include <stdint.h> |
8 | 8 |
| 9 #include "base/files/file_path.h" |
9 #include "base/logging.h" | 10 #include "base/logging.h" |
10 #include "base/macros.h" | 11 #include "base/macros.h" |
| 12 #include "base/memory/ptr_util.h" |
11 #include "media/audio/audio_device_description.h" | 13 #include "media/audio/audio_device_description.h" |
12 #include "media/base/audio_parameters.h" | 14 #include "media/base/audio_parameters.h" |
13 #include "media/base/audio_timestamp_helper.h" | 15 #include "media/base/audio_timestamp_helper.h" |
14 | 16 |
| 17 #if defined(DLOPEN_PULSEAUDIO) |
| 18 #include "media/audio/pulse/pulse_stubs.h" |
| 19 |
| 20 using media_audio_pulse::kModulePulse; |
| 21 using media_audio_pulse::InitializeStubs; |
| 22 using media_audio_pulse::StubPathMap; |
| 23 #endif // defined(DLOPEN_PULSEAUDIO) |
| 24 |
15 namespace media { | 25 namespace media { |
16 | 26 |
17 namespace pulse { | 27 namespace pulse { |
18 | 28 |
19 namespace { | 29 namespace { |
20 | 30 |
21 #if defined(GOOGLE_CHROME_BUILD) | 31 #if defined(GOOGLE_CHROME_BUILD) |
22 static const char kBrowserDisplayName[] = "google-chrome"; | 32 static const char kBrowserDisplayName[] = "google-chrome"; |
23 #else | 33 #else |
24 static const char kBrowserDisplayName[] = "chromium-browser"; | 34 static const char kBrowserDisplayName[] = "chromium-browser"; |
25 #endif | 35 #endif |
26 | 36 |
| 37 #if defined(DLOPEN_PULSEAUDIO) |
| 38 static const base::FilePath::CharType kPulseLib[] = |
| 39 FILE_PATH_LITERAL("libpulse.so.0"); |
| 40 #endif |
| 41 |
| 42 void DestroyMainloop(pa_threaded_mainloop* mainloop) { |
| 43 pa_threaded_mainloop_stop(mainloop); |
| 44 pa_threaded_mainloop_free(mainloop); |
| 45 } |
| 46 |
| 47 void DestroyContext(pa_context* context) { |
| 48 pa_context_set_state_callback(context, NULL, NULL); |
| 49 pa_context_disconnect(context); |
| 50 pa_context_unref(context); |
| 51 } |
| 52 |
27 pa_channel_position ChromiumToPAChannelPosition(Channels channel) { | 53 pa_channel_position ChromiumToPAChannelPosition(Channels channel) { |
28 switch (channel) { | 54 switch (channel) { |
29 // PulseAudio does not differentiate between left/right and | 55 // PulseAudio does not differentiate between left/right and |
30 // stereo-left/stereo-right, both translate to front-left/front-right. | 56 // stereo-left/stereo-right, both translate to front-left/front-right. |
31 case LEFT: | 57 case LEFT: |
32 return PA_CHANNEL_POSITION_FRONT_LEFT; | 58 return PA_CHANNEL_POSITION_FRONT_LEFT; |
33 case RIGHT: | 59 case RIGHT: |
34 return PA_CHANNEL_POSITION_FRONT_RIGHT; | 60 return PA_CHANNEL_POSITION_FRONT_RIGHT; |
35 case CENTER: | 61 case CENTER: |
36 return PA_CHANNEL_POSITION_FRONT_CENTER; | 62 return PA_CHANNEL_POSITION_FRONT_CENTER; |
(...skipping 26 matching lines...) Expand all Loading... |
63 | 89 |
64 pa_proplist* get() const { return property_list_; } | 90 pa_proplist* get() const { return property_list_; } |
65 | 91 |
66 private: | 92 private: |
67 pa_proplist* property_list_; | 93 pa_proplist* property_list_; |
68 DISALLOW_COPY_AND_ASSIGN(ScopedPropertyList); | 94 DISALLOW_COPY_AND_ASSIGN(ScopedPropertyList); |
69 }; | 95 }; |
70 | 96 |
71 } // namespace | 97 } // namespace |
72 | 98 |
| 99 bool InitPulse(pa_threaded_mainloop** mainloop, pa_context** context) { |
| 100 #if defined(DLOPEN_PULSEAUDIO) |
| 101 StubPathMap paths; |
| 102 |
| 103 // Check if the pulse library is avialbale. |
| 104 paths[kModulePulse].push_back(kPulseLib); |
| 105 if (!InitializeStubs(paths)) { |
| 106 VLOG(1) << "Failed on loading the Pulse library and symbols"; |
| 107 return false; |
| 108 } |
| 109 #endif // defined(DLOPEN_PULSEAUDIO) |
| 110 |
| 111 // Create a mainloop API and connect to the default server. |
| 112 // The mainloop is the internal asynchronous API event loop. |
| 113 pa_threaded_mainloop* pa_mainloop = pa_threaded_mainloop_new(); |
| 114 if (!pa_mainloop) |
| 115 return false; |
| 116 |
| 117 // Start the threaded mainloop. |
| 118 if (pa_threaded_mainloop_start(pa_mainloop)) { |
| 119 pa_threaded_mainloop_free(pa_mainloop); |
| 120 return false; |
| 121 } |
| 122 |
| 123 // Lock the event loop object, effectively blocking the event loop thread |
| 124 // from processing events. This is necessary. |
| 125 auto mainloop_lock = base::MakeUnique<AutoPulseLock>(pa_mainloop); |
| 126 |
| 127 pa_mainloop_api* pa_mainloop_api = pa_threaded_mainloop_get_api(pa_mainloop); |
| 128 pa_context* pa_context = pa_context_new(pa_mainloop_api, "Chrome input"); |
| 129 if (!pa_context) { |
| 130 mainloop_lock.reset(); |
| 131 DestroyMainloop(pa_mainloop); |
| 132 return false; |
| 133 } |
| 134 |
| 135 pa_context_set_state_callback(pa_context, &pulse::ContextStateCallback, |
| 136 pa_mainloop); |
| 137 if (pa_context_connect(pa_context, NULL, PA_CONTEXT_NOAUTOSPAWN, NULL)) { |
| 138 VLOG(1) << "Failed to connect to the context. Error: " |
| 139 << pa_strerror(pa_context_errno(pa_context)); |
| 140 pa_context_set_state_callback(pa_context, NULL, NULL); |
| 141 pa_context_unref(pa_context); |
| 142 mainloop_lock.reset(); |
| 143 DestroyMainloop(pa_mainloop); |
| 144 return false; |
| 145 } |
| 146 |
| 147 // Wait until |pa_context| is ready. pa_threaded_mainloop_wait() must be |
| 148 // called after pa_context_get_state() in case the context is already ready, |
| 149 // otherwise pa_threaded_mainloop_wait() will hang indefinitely. |
| 150 while (true) { |
| 151 pa_context_state_t context_state = pa_context_get_state(pa_context); |
| 152 if (!PA_CONTEXT_IS_GOOD(context_state)) { |
| 153 DestroyContext(pa_context); |
| 154 mainloop_lock.reset(); |
| 155 DestroyMainloop(pa_mainloop); |
| 156 return false; |
| 157 } |
| 158 if (context_state == PA_CONTEXT_READY) |
| 159 break; |
| 160 pa_threaded_mainloop_wait(pa_mainloop); |
| 161 } |
| 162 |
| 163 *mainloop = pa_mainloop; |
| 164 *context = pa_context; |
| 165 return true; |
| 166 } |
| 167 |
| 168 void DestroyPulse(pa_threaded_mainloop* mainloop, pa_context* context) { |
| 169 DCHECK(mainloop); |
| 170 DCHECK(context); |
| 171 |
| 172 { |
| 173 AutoPulseLock auto_lock(mainloop); |
| 174 DestroyContext(context); |
| 175 } |
| 176 |
| 177 DestroyMainloop(mainloop); |
| 178 } |
| 179 |
73 // static, pa_stream_success_cb_t | 180 // static, pa_stream_success_cb_t |
74 void StreamSuccessCallback(pa_stream* s, int error, void* mainloop) { | 181 void StreamSuccessCallback(pa_stream* s, int error, void* mainloop) { |
75 pa_threaded_mainloop* pa_mainloop = | 182 pa_threaded_mainloop* pa_mainloop = |
76 static_cast<pa_threaded_mainloop*>(mainloop); | 183 static_cast<pa_threaded_mainloop*>(mainloop); |
77 pa_threaded_mainloop_signal(pa_mainloop, 0); | 184 pa_threaded_mainloop_signal(pa_mainloop, 0); |
78 } | 185 } |
79 | 186 |
80 // |pa_context| and |pa_stream| state changed cb. | 187 // |pa_context| and |pa_stream| state changed cb. |
81 void ContextStateCallback(pa_context* context, void* mainloop) { | 188 void ContextStateCallback(pa_context* context, void* mainloop) { |
82 pa_threaded_mainloop* pa_mainloop = | 189 pa_threaded_mainloop* pa_mainloop = |
(...skipping 275 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
358 } | 465 } |
359 | 466 |
360 return true; | 467 return true; |
361 } | 468 } |
362 | 469 |
363 #undef RETURN_ON_FAILURE | 470 #undef RETURN_ON_FAILURE |
364 | 471 |
365 } // namespace pulse | 472 } // namespace pulse |
366 | 473 |
367 } // namespace media | 474 } // namespace media |
OLD | NEW |