🛠️🐜 Antkeeper superbuild with dependencies included https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1528 lines
52 KiB

  1. /**
  2. * OpenAL cross platform audio library
  3. * Copyright (C) 2009 by Konstantinos Natsakis <konstantinos.natsakis@gmail.com>
  4. * Copyright (C) 2010 by Chris Robinson <chris.kcat@gmail.com>
  5. * This library is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU Library General Public
  7. * License as published by the Free Software Foundation; either
  8. * version 2 of the License, or (at your option) any later version.
  9. *
  10. * This library is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. * Library General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Library General Public
  16. * License along with this library; if not, write to the
  17. * Free Software Foundation, Inc.,
  18. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  19. * Or go to http://www.gnu.org/copyleft/lgpl.html
  20. */
  21. #include "config.h"
  22. #include "backends/pulseaudio.h"
  23. #include <poll.h>
  24. #include <cstring>
  25. #include <array>
  26. #include <string>
  27. #include <vector>
  28. #include <atomic>
  29. #include <thread>
  30. #include <algorithm>
  31. #include <condition_variable>
  32. #include "alMain.h"
  33. #include "alu.h"
  34. #include "alconfig.h"
  35. #include "compat.h"
  36. #include "alexcpt.h"
  37. #include <pulse/pulseaudio.h>
  38. namespace {
  39. #ifdef HAVE_DYNLOAD
  40. #define PULSE_FUNCS(MAGIC) \
  41. MAGIC(pa_mainloop_new); \
  42. MAGIC(pa_mainloop_free); \
  43. MAGIC(pa_mainloop_set_poll_func); \
  44. MAGIC(pa_mainloop_run); \
  45. MAGIC(pa_mainloop_get_api); \
  46. MAGIC(pa_context_new); \
  47. MAGIC(pa_context_unref); \
  48. MAGIC(pa_context_get_state); \
  49. MAGIC(pa_context_disconnect); \
  50. MAGIC(pa_context_set_state_callback); \
  51. MAGIC(pa_context_errno); \
  52. MAGIC(pa_context_connect); \
  53. MAGIC(pa_context_get_server_info); \
  54. MAGIC(pa_context_get_sink_info_by_name); \
  55. MAGIC(pa_context_get_sink_info_list); \
  56. MAGIC(pa_context_get_source_info_by_name); \
  57. MAGIC(pa_context_get_source_info_list); \
  58. MAGIC(pa_stream_new); \
  59. MAGIC(pa_stream_unref); \
  60. MAGIC(pa_stream_drop); \
  61. MAGIC(pa_stream_get_state); \
  62. MAGIC(pa_stream_peek); \
  63. MAGIC(pa_stream_write); \
  64. MAGIC(pa_stream_connect_record); \
  65. MAGIC(pa_stream_connect_playback); \
  66. MAGIC(pa_stream_readable_size); \
  67. MAGIC(pa_stream_writable_size); \
  68. MAGIC(pa_stream_is_corked); \
  69. MAGIC(pa_stream_cork); \
  70. MAGIC(pa_stream_is_suspended); \
  71. MAGIC(pa_stream_get_device_name); \
  72. MAGIC(pa_stream_get_latency); \
  73. MAGIC(pa_stream_set_write_callback); \
  74. MAGIC(pa_stream_set_buffer_attr); \
  75. MAGIC(pa_stream_get_buffer_attr); \
  76. MAGIC(pa_stream_get_sample_spec); \
  77. MAGIC(pa_stream_get_time); \
  78. MAGIC(pa_stream_set_read_callback); \
  79. MAGIC(pa_stream_set_state_callback); \
  80. MAGIC(pa_stream_set_moved_callback); \
  81. MAGIC(pa_stream_set_underflow_callback); \
  82. MAGIC(pa_stream_new_with_proplist); \
  83. MAGIC(pa_stream_disconnect); \
  84. MAGIC(pa_stream_set_buffer_attr_callback); \
  85. MAGIC(pa_stream_begin_write); \
  86. MAGIC(pa_channel_map_init_auto); \
  87. MAGIC(pa_channel_map_parse); \
  88. MAGIC(pa_channel_map_snprint); \
  89. MAGIC(pa_channel_map_equal); \
  90. MAGIC(pa_channel_map_superset); \
  91. MAGIC(pa_operation_get_state); \
  92. MAGIC(pa_operation_unref); \
  93. MAGIC(pa_sample_spec_valid); \
  94. MAGIC(pa_frame_size); \
  95. MAGIC(pa_strerror); \
  96. MAGIC(pa_path_get_filename); \
  97. MAGIC(pa_get_binary_name); \
  98. MAGIC(pa_xmalloc); \
  99. MAGIC(pa_xfree);
  100. void *pulse_handle;
  101. #define MAKE_FUNC(x) decltype(x) * p##x
  102. PULSE_FUNCS(MAKE_FUNC)
  103. #undef MAKE_FUNC
  104. #ifndef IN_IDE_PARSER
  105. #define pa_mainloop_new ppa_mainloop_new
  106. #define pa_mainloop_free ppa_mainloop_free
  107. #define pa_mainloop_set_poll_func ppa_mainloop_set_poll_func
  108. #define pa_mainloop_run ppa_mainloop_run
  109. #define pa_mainloop_get_api ppa_mainloop_get_api
  110. #define pa_context_new ppa_context_new
  111. #define pa_context_unref ppa_context_unref
  112. #define pa_context_get_state ppa_context_get_state
  113. #define pa_context_disconnect ppa_context_disconnect
  114. #define pa_context_set_state_callback ppa_context_set_state_callback
  115. #define pa_context_errno ppa_context_errno
  116. #define pa_context_connect ppa_context_connect
  117. #define pa_context_get_server_info ppa_context_get_server_info
  118. #define pa_context_get_sink_info_by_name ppa_context_get_sink_info_by_name
  119. #define pa_context_get_sink_info_list ppa_context_get_sink_info_list
  120. #define pa_context_get_source_info_by_name ppa_context_get_source_info_by_name
  121. #define pa_context_get_source_info_list ppa_context_get_source_info_list
  122. #define pa_stream_new ppa_stream_new
  123. #define pa_stream_unref ppa_stream_unref
  124. #define pa_stream_disconnect ppa_stream_disconnect
  125. #define pa_stream_drop ppa_stream_drop
  126. #define pa_stream_set_write_callback ppa_stream_set_write_callback
  127. #define pa_stream_set_buffer_attr ppa_stream_set_buffer_attr
  128. #define pa_stream_get_buffer_attr ppa_stream_get_buffer_attr
  129. #define pa_stream_get_sample_spec ppa_stream_get_sample_spec
  130. #define pa_stream_get_time ppa_stream_get_time
  131. #define pa_stream_set_read_callback ppa_stream_set_read_callback
  132. #define pa_stream_set_state_callback ppa_stream_set_state_callback
  133. #define pa_stream_set_moved_callback ppa_stream_set_moved_callback
  134. #define pa_stream_set_underflow_callback ppa_stream_set_underflow_callback
  135. #define pa_stream_connect_record ppa_stream_connect_record
  136. #define pa_stream_connect_playback ppa_stream_connect_playback
  137. #define pa_stream_readable_size ppa_stream_readable_size
  138. #define pa_stream_writable_size ppa_stream_writable_size
  139. #define pa_stream_is_corked ppa_stream_is_corked
  140. #define pa_stream_cork ppa_stream_cork
  141. #define pa_stream_is_suspended ppa_stream_is_suspended
  142. #define pa_stream_get_device_name ppa_stream_get_device_name
  143. #define pa_stream_get_latency ppa_stream_get_latency
  144. #define pa_stream_set_buffer_attr_callback ppa_stream_set_buffer_attr_callback
  145. #define pa_stream_begin_write ppa_stream_begin_write*/
  146. #define pa_channel_map_init_auto ppa_channel_map_init_auto
  147. #define pa_channel_map_parse ppa_channel_map_parse
  148. #define pa_channel_map_snprint ppa_channel_map_snprint
  149. #define pa_channel_map_equal ppa_channel_map_equal
  150. #define pa_channel_map_superset ppa_channel_map_superset
  151. #define pa_operation_get_state ppa_operation_get_state
  152. #define pa_operation_unref ppa_operation_unref
  153. #define pa_sample_spec_valid ppa_sample_spec_valid
  154. #define pa_frame_size ppa_frame_size
  155. #define pa_strerror ppa_strerror
  156. #define pa_stream_get_state ppa_stream_get_state
  157. #define pa_stream_peek ppa_stream_peek
  158. #define pa_stream_write ppa_stream_write
  159. #define pa_xfree ppa_xfree
  160. #define pa_path_get_filename ppa_path_get_filename
  161. #define pa_get_binary_name ppa_get_binary_name
  162. #define pa_xmalloc ppa_xmalloc
  163. #endif /* IN_IDE_PARSER */
  164. #endif
  165. constexpr pa_channel_map MonoChanMap{
  166. 1, {PA_CHANNEL_POSITION_MONO}
  167. }, StereoChanMap{
  168. 2, {PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT}
  169. }, QuadChanMap{
  170. 4, {
  171. PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
  172. PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT
  173. }
  174. }, X51ChanMap{
  175. 6, {
  176. PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
  177. PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE,
  178. PA_CHANNEL_POSITION_SIDE_LEFT, PA_CHANNEL_POSITION_SIDE_RIGHT
  179. }
  180. }, X51RearChanMap{
  181. 6, {
  182. PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
  183. PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE,
  184. PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT
  185. }
  186. }, X61ChanMap{
  187. 7, {
  188. PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
  189. PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE,
  190. PA_CHANNEL_POSITION_REAR_CENTER,
  191. PA_CHANNEL_POSITION_SIDE_LEFT, PA_CHANNEL_POSITION_SIDE_RIGHT
  192. }
  193. }, X71ChanMap{
  194. 8, {
  195. PA_CHANNEL_POSITION_FRONT_LEFT, PA_CHANNEL_POSITION_FRONT_RIGHT,
  196. PA_CHANNEL_POSITION_FRONT_CENTER, PA_CHANNEL_POSITION_LFE,
  197. PA_CHANNEL_POSITION_REAR_LEFT, PA_CHANNEL_POSITION_REAR_RIGHT,
  198. PA_CHANNEL_POSITION_SIDE_LEFT, PA_CHANNEL_POSITION_SIDE_RIGHT
  199. }
  200. };
  201. size_t ChannelFromPulse(pa_channel_position_t chan)
  202. {
  203. switch(chan)
  204. {
  205. case PA_CHANNEL_POSITION_INVALID: break;
  206. case PA_CHANNEL_POSITION_MONO: return FrontCenter;
  207. case PA_CHANNEL_POSITION_FRONT_LEFT: return FrontLeft;
  208. case PA_CHANNEL_POSITION_FRONT_RIGHT: return FrontRight;
  209. case PA_CHANNEL_POSITION_FRONT_CENTER: return FrontCenter;
  210. case PA_CHANNEL_POSITION_REAR_CENTER: return BackCenter;
  211. case PA_CHANNEL_POSITION_REAR_LEFT: return BackLeft;
  212. case PA_CHANNEL_POSITION_REAR_RIGHT: return BackRight;
  213. case PA_CHANNEL_POSITION_LFE: return LFE;
  214. case PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER: break;
  215. case PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER: break;
  216. case PA_CHANNEL_POSITION_SIDE_LEFT: return SideLeft;
  217. case PA_CHANNEL_POSITION_SIDE_RIGHT: return SideRight;
  218. case PA_CHANNEL_POSITION_AUX0: return Aux0;
  219. case PA_CHANNEL_POSITION_AUX1: return Aux1;
  220. case PA_CHANNEL_POSITION_AUX2: return Aux2;
  221. case PA_CHANNEL_POSITION_AUX3: return Aux3;
  222. case PA_CHANNEL_POSITION_AUX4: return Aux4;
  223. case PA_CHANNEL_POSITION_AUX5: return Aux5;
  224. case PA_CHANNEL_POSITION_AUX6: return Aux6;
  225. case PA_CHANNEL_POSITION_AUX7: return Aux7;
  226. case PA_CHANNEL_POSITION_AUX8: return Aux8;
  227. case PA_CHANNEL_POSITION_AUX9: return Aux9;
  228. case PA_CHANNEL_POSITION_AUX10: return Aux10;
  229. case PA_CHANNEL_POSITION_AUX11: return Aux11;
  230. case PA_CHANNEL_POSITION_AUX12: return Aux12;
  231. case PA_CHANNEL_POSITION_AUX13: return Aux13;
  232. case PA_CHANNEL_POSITION_AUX14: return Aux14;
  233. case PA_CHANNEL_POSITION_AUX15: return Aux15;
  234. case PA_CHANNEL_POSITION_AUX16: break;
  235. case PA_CHANNEL_POSITION_AUX17: break;
  236. case PA_CHANNEL_POSITION_AUX18: break;
  237. case PA_CHANNEL_POSITION_AUX19: break;
  238. case PA_CHANNEL_POSITION_AUX20: break;
  239. case PA_CHANNEL_POSITION_AUX21: break;
  240. case PA_CHANNEL_POSITION_AUX22: break;
  241. case PA_CHANNEL_POSITION_AUX23: break;
  242. case PA_CHANNEL_POSITION_AUX24: break;
  243. case PA_CHANNEL_POSITION_AUX25: break;
  244. case PA_CHANNEL_POSITION_AUX26: break;
  245. case PA_CHANNEL_POSITION_AUX27: break;
  246. case PA_CHANNEL_POSITION_AUX28: break;
  247. case PA_CHANNEL_POSITION_AUX29: break;
  248. case PA_CHANNEL_POSITION_AUX30: break;
  249. case PA_CHANNEL_POSITION_AUX31: break;
  250. case PA_CHANNEL_POSITION_TOP_CENTER: break;
  251. case PA_CHANNEL_POSITION_TOP_FRONT_LEFT: return UpperFrontLeft;
  252. case PA_CHANNEL_POSITION_TOP_FRONT_RIGHT: return UpperFrontRight;
  253. case PA_CHANNEL_POSITION_TOP_FRONT_CENTER: break;
  254. case PA_CHANNEL_POSITION_TOP_REAR_LEFT: return UpperBackLeft;
  255. case PA_CHANNEL_POSITION_TOP_REAR_RIGHT: return UpperBackRight;
  256. case PA_CHANNEL_POSITION_TOP_REAR_CENTER: break;
  257. case PA_CHANNEL_POSITION_MAX: break;
  258. }
  259. throw al::backend_exception{ALC_INVALID_VALUE, "Unexpected channel enum %d", chan};
  260. }
  261. void SetChannelOrderFromMap(ALCdevice *device, const pa_channel_map &chanmap)
  262. {
  263. device->RealOut.ChannelIndex.fill(-1);
  264. for(int i{0};i < chanmap.channels;++i)
  265. device->RealOut.ChannelIndex[ChannelFromPulse(chanmap.map[i])] = i;
  266. }
  267. /* *grumble* Don't use enums for bitflags. */
  268. inline pa_stream_flags_t operator|(pa_stream_flags_t lhs, pa_stream_flags_t rhs)
  269. { return pa_stream_flags_t(int(lhs) | int(rhs)); }
  270. inline pa_stream_flags_t& operator|=(pa_stream_flags_t &lhs, pa_stream_flags_t rhs)
  271. {
  272. lhs = pa_stream_flags_t(int(lhs) | int(rhs));
  273. return lhs;
  274. }
  275. inline pa_context_flags_t& operator|=(pa_context_flags_t &lhs, pa_context_flags_t rhs)
  276. {
  277. lhs = pa_context_flags_t(int(lhs) | int(rhs));
  278. return lhs;
  279. }
  280. inline pa_stream_flags_t& operator&=(pa_stream_flags_t &lhs, int rhs)
  281. {
  282. lhs = pa_stream_flags_t(int(lhs) & rhs);
  283. return lhs;
  284. }
  285. /* Global flags and properties */
  286. pa_context_flags_t pulse_ctx_flags;
  287. pa_mainloop *pulse_mainloop{nullptr};
  288. std::mutex pulse_lock;
  289. std::condition_variable pulse_condvar;
  290. int pulse_poll_func(struct pollfd *ufds, unsigned long nfds, int timeout, void *userdata)
  291. {
  292. auto plock = static_cast<std::unique_lock<std::mutex>*>(userdata);
  293. plock->unlock();
  294. int r{poll(ufds, nfds, timeout)};
  295. plock->lock();
  296. return r;
  297. }
  298. int pulse_mainloop_thread()
  299. {
  300. SetRTPriority();
  301. std::unique_lock<std::mutex> plock{pulse_lock};
  302. pulse_mainloop = pa_mainloop_new();
  303. pa_mainloop_set_poll_func(pulse_mainloop, pulse_poll_func, &plock);
  304. pulse_condvar.notify_all();
  305. int ret{};
  306. pa_mainloop_run(pulse_mainloop, &ret);
  307. pa_mainloop_free(pulse_mainloop);
  308. pulse_mainloop = nullptr;
  309. return ret;
  310. }
  311. /* PulseAudio Event Callbacks */
  312. void context_state_callback(pa_context *context, void* /*pdata*/)
  313. {
  314. pa_context_state_t state{pa_context_get_state(context)};
  315. if(state == PA_CONTEXT_READY || !PA_CONTEXT_IS_GOOD(state))
  316. pulse_condvar.notify_all();
  317. }
  318. void stream_state_callback(pa_stream *stream, void* /*pdata*/)
  319. {
  320. pa_stream_state_t state{pa_stream_get_state(stream)};
  321. if(state == PA_STREAM_READY || !PA_STREAM_IS_GOOD(state))
  322. pulse_condvar.notify_all();
  323. }
  324. void stream_success_callback(pa_stream* /*stream*/, int /*success*/, void* /*pdata*/)
  325. {
  326. pulse_condvar.notify_all();
  327. }
  328. void wait_for_operation(pa_operation *op, std::unique_lock<std::mutex> &plock)
  329. {
  330. if(op)
  331. {
  332. while(pa_operation_get_state(op) == PA_OPERATION_RUNNING)
  333. pulse_condvar.wait(plock);
  334. pa_operation_unref(op);
  335. }
  336. }
  337. pa_context *connect_context(std::unique_lock<std::mutex> &plock)
  338. {
  339. const char *name{"OpenAL Soft"};
  340. const PathNamePair &binname = GetProcBinary();
  341. if(!binname.fname.empty())
  342. name = binname.fname.c_str();
  343. if(UNLIKELY(!pulse_mainloop))
  344. {
  345. std::thread{pulse_mainloop_thread}.detach();
  346. while(!pulse_mainloop)
  347. pulse_condvar.wait(plock);
  348. }
  349. pa_context *context{pa_context_new(pa_mainloop_get_api(pulse_mainloop), name)};
  350. if(!context) throw al::backend_exception{ALC_OUT_OF_MEMORY, "pa_context_new() failed"};
  351. pa_context_set_state_callback(context, context_state_callback, nullptr);
  352. int err;
  353. if((err=pa_context_connect(context, nullptr, pulse_ctx_flags, nullptr)) >= 0)
  354. {
  355. pa_context_state_t state;
  356. while((state=pa_context_get_state(context)) != PA_CONTEXT_READY)
  357. {
  358. if(!PA_CONTEXT_IS_GOOD(state))
  359. {
  360. err = pa_context_errno(context);
  361. if(err > 0) err = -err;
  362. break;
  363. }
  364. pulse_condvar.wait(plock);
  365. }
  366. }
  367. pa_context_set_state_callback(context, nullptr, nullptr);
  368. if(err < 0)
  369. {
  370. pa_context_unref(context);
  371. throw al::backend_exception{ALC_INVALID_VALUE, "Context did not connect (%s)",
  372. pa_strerror(err)};
  373. }
  374. return context;
  375. }
  376. void pulse_close(pa_context *context, pa_stream *stream)
  377. {
  378. std::lock_guard<std::mutex> _{pulse_lock};
  379. if(stream)
  380. {
  381. pa_stream_set_state_callback(stream, nullptr, nullptr);
  382. pa_stream_set_moved_callback(stream, nullptr, nullptr);
  383. pa_stream_set_write_callback(stream, nullptr, nullptr);
  384. pa_stream_set_buffer_attr_callback(stream, nullptr, nullptr);
  385. pa_stream_disconnect(stream);
  386. pa_stream_unref(stream);
  387. }
  388. pa_context_disconnect(context);
  389. pa_context_unref(context);
  390. }
  391. struct DevMap {
  392. std::string name;
  393. std::string device_name;
  394. };
  395. bool checkName(const al::vector<DevMap> &list, const std::string &name)
  396. {
  397. return std::find_if(list.cbegin(), list.cend(),
  398. [&name](const DevMap &entry) -> bool
  399. { return entry.name == name; }
  400. ) != list.cend();
  401. }
  402. al::vector<DevMap> PlaybackDevices;
  403. al::vector<DevMap> CaptureDevices;
  404. pa_stream *pulse_connect_stream(const char *device_name, std::unique_lock<std::mutex> &plock,
  405. pa_context *context, pa_stream_flags_t flags, pa_buffer_attr *attr, pa_sample_spec *spec,
  406. pa_channel_map *chanmap, BackendType type)
  407. {
  408. const char *stream_id{(type==BackendType::Playback) ? "Playback Stream" : "Capture Stream"};
  409. pa_stream *stream{pa_stream_new(context, stream_id, spec, chanmap)};
  410. if(!stream)
  411. throw al::backend_exception{ALC_OUT_OF_MEMORY, "pa_stream_new() failed (%s)",
  412. pa_strerror(pa_context_errno(context))};
  413. pa_stream_set_state_callback(stream, stream_state_callback, nullptr);
  414. int err{(type==BackendType::Playback) ?
  415. pa_stream_connect_playback(stream, device_name, attr, flags, nullptr, nullptr) :
  416. pa_stream_connect_record(stream, device_name, attr, flags)};
  417. if(err < 0)
  418. {
  419. pa_stream_unref(stream);
  420. throw al::backend_exception{ALC_INVALID_VALUE, "%s did not connect (%s)", stream_id,
  421. pa_strerror(err)};
  422. }
  423. pa_stream_state_t state;
  424. while((state=pa_stream_get_state(stream)) != PA_STREAM_READY)
  425. {
  426. if(!PA_STREAM_IS_GOOD(state))
  427. {
  428. int err{pa_context_errno(context)};
  429. pa_stream_unref(stream);
  430. throw al::backend_exception{ALC_INVALID_VALUE, "%s did not get ready (%s)", stream_id,
  431. pa_strerror(err)};
  432. }
  433. pulse_condvar.wait(plock);
  434. }
  435. pa_stream_set_state_callback(stream, nullptr, nullptr);
  436. return stream;
  437. }
  438. void device_sink_callback(pa_context *UNUSED(context), const pa_sink_info *info, int eol, void* /*pdata*/)
  439. {
  440. if(eol)
  441. {
  442. pulse_condvar.notify_all();
  443. return;
  444. }
  445. /* Skip this device is if it's already in the list. */
  446. if(std::find_if(PlaybackDevices.cbegin(), PlaybackDevices.cend(),
  447. [info](const DevMap &entry) -> bool
  448. { return entry.device_name == info->name; }
  449. ) != PlaybackDevices.cend())
  450. return;
  451. /* Make sure the display name (description) is unique. Append a number
  452. * counter as needed.
  453. */
  454. int count{1};
  455. std::string newname{info->description};
  456. while(checkName(PlaybackDevices, newname))
  457. {
  458. newname = info->description;
  459. newname += " #";
  460. newname += std::to_string(++count);
  461. }
  462. PlaybackDevices.emplace_back(DevMap{std::move(newname), info->name});
  463. DevMap &newentry = PlaybackDevices.back();
  464. TRACE("Got device \"%s\", \"%s\"\n", newentry.name.c_str(), newentry.device_name.c_str());
  465. }
  466. void probePlaybackDevices()
  467. {
  468. PlaybackDevices.clear();
  469. try {
  470. std::unique_lock<std::mutex> plock{pulse_lock};
  471. pa_context *context{connect_context(plock)};
  472. const pa_stream_flags_t flags{PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE |
  473. PA_STREAM_FIX_CHANNELS | PA_STREAM_DONT_MOVE};
  474. pa_sample_spec spec{};
  475. spec.format = PA_SAMPLE_S16NE;
  476. spec.rate = 44100;
  477. spec.channels = 2;
  478. pa_stream *stream{pulse_connect_stream(nullptr, plock, context, flags, nullptr, &spec,
  479. nullptr, BackendType::Playback)};
  480. pa_operation *op{pa_context_get_sink_info_by_name(context,
  481. pa_stream_get_device_name(stream), device_sink_callback, nullptr)};
  482. wait_for_operation(op, plock);
  483. pa_stream_disconnect(stream);
  484. pa_stream_unref(stream);
  485. stream = nullptr;
  486. op = pa_context_get_sink_info_list(context, device_sink_callback, nullptr);
  487. wait_for_operation(op, plock);
  488. pa_context_disconnect(context);
  489. pa_context_unref(context);
  490. }
  491. catch(std::exception &e) {
  492. ERR("Error enumerating devices: %s\n", e.what());
  493. }
  494. }
  495. void device_source_callback(pa_context *UNUSED(context), const pa_source_info *info, int eol, void* /*pdata*/)
  496. {
  497. if(eol)
  498. {
  499. pulse_condvar.notify_all();
  500. return;
  501. }
  502. /* Skip this device is if it's already in the list. */
  503. if(std::find_if(CaptureDevices.cbegin(), CaptureDevices.cend(),
  504. [info](const DevMap &entry) -> bool
  505. { return entry.device_name == info->name; }
  506. ) != CaptureDevices.cend())
  507. return;
  508. /* Make sure the display name (description) is unique. Append a number
  509. * counter as needed.
  510. */
  511. int count{1};
  512. std::string newname{info->description};
  513. while(checkName(CaptureDevices, newname))
  514. {
  515. newname = info->description;
  516. newname += " #";
  517. newname += std::to_string(++count);
  518. }
  519. CaptureDevices.emplace_back(DevMap{std::move(newname), info->name});
  520. DevMap &newentry = CaptureDevices.back();
  521. TRACE("Got device \"%s\", \"%s\"\n", newentry.name.c_str(), newentry.device_name.c_str());
  522. }
  523. void probeCaptureDevices()
  524. {
  525. CaptureDevices.clear();
  526. try {
  527. std::unique_lock<std::mutex> plock{pulse_lock};
  528. pa_context *context{connect_context(plock)};
  529. const pa_stream_flags_t flags{PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE |
  530. PA_STREAM_FIX_CHANNELS | PA_STREAM_DONT_MOVE};
  531. pa_sample_spec spec{};
  532. spec.format = PA_SAMPLE_S16NE;
  533. spec.rate = 44100;
  534. spec.channels = 1;
  535. pa_stream *stream{pulse_connect_stream(nullptr, plock, context, flags, nullptr, &spec, nullptr,
  536. BackendType::Capture)};
  537. pa_operation *op{pa_context_get_source_info_by_name(context,
  538. pa_stream_get_device_name(stream), device_source_callback, nullptr)};
  539. wait_for_operation(op, plock);
  540. pa_stream_disconnect(stream);
  541. pa_stream_unref(stream);
  542. stream = nullptr;
  543. op = pa_context_get_source_info_list(context, device_source_callback, nullptr);
  544. wait_for_operation(op, plock);
  545. pa_context_disconnect(context);
  546. pa_context_unref(context);
  547. }
  548. catch(std::exception &e) {
  549. ERR("Error enumerating devices: %s\n", e.what());
  550. }
  551. }
  552. struct PulsePlayback final : public BackendBase {
  553. PulsePlayback(ALCdevice *device) noexcept : BackendBase{device} { }
  554. ~PulsePlayback() override;
  555. static void bufferAttrCallbackC(pa_stream *stream, void *pdata);
  556. void bufferAttrCallback(pa_stream *stream);
  557. static void contextStateCallbackC(pa_context *context, void *pdata);
  558. void contextStateCallback(pa_context *context);
  559. static void streamStateCallbackC(pa_stream *stream, void *pdata);
  560. void streamStateCallback(pa_stream *stream);
  561. static void streamWriteCallbackC(pa_stream *stream, size_t nbytes, void *pdata);
  562. void streamWriteCallback(pa_stream *stream, size_t nbytes);
  563. static void sinkInfoCallbackC(pa_context *context, const pa_sink_info *info, int eol, void *pdata);
  564. void sinkInfoCallback(pa_context *context, const pa_sink_info *info, int eol);
  565. static void sinkNameCallbackC(pa_context *context, const pa_sink_info *info, int eol, void *pdata);
  566. void sinkNameCallback(pa_context *context, const pa_sink_info *info, int eol);
  567. static void streamMovedCallbackC(pa_stream *stream, void *pdata);
  568. void streamMovedCallback(pa_stream *stream);
  569. ALCenum open(const ALCchar *name) override;
  570. ALCboolean reset() override;
  571. ALCboolean start() override;
  572. void stop() override;
  573. ClockLatency getClockLatency() override;
  574. void lock() override;
  575. void unlock() override;
  576. std::string mDeviceName;
  577. pa_buffer_attr mAttr;
  578. pa_sample_spec mSpec;
  579. pa_stream *mStream{nullptr};
  580. pa_context *mContext{nullptr};
  581. ALuint mFrameSize{0u};
  582. static constexpr inline const char *CurrentPrefix() noexcept { return "PulsePlayback::"; }
  583. DEF_NEWDEL(PulsePlayback)
  584. };
  585. PulsePlayback::~PulsePlayback()
  586. {
  587. if(!mContext)
  588. return;
  589. pulse_close(mContext, mStream);
  590. mContext = nullptr;
  591. mStream = nullptr;
  592. }
  593. void PulsePlayback::bufferAttrCallbackC(pa_stream *stream, void *pdata)
  594. { static_cast<PulsePlayback*>(pdata)->bufferAttrCallback(stream); }
  595. void PulsePlayback::bufferAttrCallback(pa_stream *stream)
  596. {
  597. /* FIXME: Update the device's UpdateSize (and/or BufferSize) using the new
  598. * buffer attributes? Changing UpdateSize will change the ALC_REFRESH
  599. * property, which probably shouldn't change between device resets. But
  600. * leaving it alone means ALC_REFRESH will be off.
  601. */
  602. mAttr = *(pa_stream_get_buffer_attr(stream));
  603. TRACE("minreq=%d, tlength=%d, prebuf=%d\n", mAttr.minreq, mAttr.tlength, mAttr.prebuf);
  604. }
  605. void PulsePlayback::contextStateCallbackC(pa_context *context, void *pdata)
  606. { static_cast<PulsePlayback*>(pdata)->contextStateCallback(context); }
  607. void PulsePlayback::contextStateCallback(pa_context *context)
  608. {
  609. if(pa_context_get_state(context) == PA_CONTEXT_FAILED)
  610. {
  611. ERR("Received context failure!\n");
  612. aluHandleDisconnect(mDevice, "Playback state failure");
  613. }
  614. pulse_condvar.notify_all();
  615. }
  616. void PulsePlayback::streamStateCallbackC(pa_stream *stream, void *pdata)
  617. { static_cast<PulsePlayback*>(pdata)->streamStateCallback(stream); }
  618. void PulsePlayback::streamStateCallback(pa_stream *stream)
  619. {
  620. if(pa_stream_get_state(stream) == PA_STREAM_FAILED)
  621. {
  622. ERR("Received stream failure!\n");
  623. aluHandleDisconnect(mDevice, "Playback stream failure");
  624. }
  625. pulse_condvar.notify_all();
  626. }
  627. void PulsePlayback::streamWriteCallbackC(pa_stream *stream, size_t nbytes, void *pdata)
  628. { static_cast<PulsePlayback*>(pdata)->streamWriteCallback(stream, nbytes); }
  629. void PulsePlayback::streamWriteCallback(pa_stream *stream, size_t nbytes)
  630. {
  631. void *buf{pa_xmalloc(nbytes)};
  632. aluMixData(mDevice, buf, nbytes/mFrameSize);
  633. int ret{pa_stream_write(stream, buf, nbytes, pa_xfree, 0, PA_SEEK_RELATIVE)};
  634. if(UNLIKELY(ret != PA_OK))
  635. ERR("Failed to write to stream: %d, %s\n", ret, pa_strerror(ret));
  636. }
  637. void PulsePlayback::sinkInfoCallbackC(pa_context *context, const pa_sink_info *info, int eol, void *pdata)
  638. { static_cast<PulsePlayback*>(pdata)->sinkInfoCallback(context, info, eol); }
  639. void PulsePlayback::sinkInfoCallback(pa_context* UNUSED(context), const pa_sink_info *info, int eol)
  640. {
  641. struct ChannelMap {
  642. DevFmtChannels chans;
  643. pa_channel_map map;
  644. };
  645. static constexpr std::array<ChannelMap,7> chanmaps{{
  646. { DevFmtX71, X71ChanMap },
  647. { DevFmtX61, X61ChanMap },
  648. { DevFmtX51, X51ChanMap },
  649. { DevFmtX51Rear, X51RearChanMap },
  650. { DevFmtQuad, QuadChanMap },
  651. { DevFmtStereo, StereoChanMap },
  652. { DevFmtMono, MonoChanMap }
  653. }};
  654. if(eol)
  655. {
  656. pulse_condvar.notify_all();
  657. return;
  658. }
  659. auto chanmap = std::find_if(chanmaps.cbegin(), chanmaps.cend(),
  660. [info](const ChannelMap &chanmap) -> bool
  661. { return pa_channel_map_superset(&info->channel_map, &chanmap.map); }
  662. );
  663. if(chanmap != chanmaps.cend())
  664. {
  665. if(!(mDevice->Flags&DEVICE_CHANNELS_REQUEST))
  666. mDevice->FmtChans = chanmap->chans;
  667. }
  668. else
  669. {
  670. char chanmap_str[PA_CHANNEL_MAP_SNPRINT_MAX]{};
  671. pa_channel_map_snprint(chanmap_str, sizeof(chanmap_str), &info->channel_map);
  672. WARN("Failed to find format for channel map:\n %s\n", chanmap_str);
  673. }
  674. if(info->active_port)
  675. TRACE("Active port: %s (%s)\n", info->active_port->name, info->active_port->description);
  676. mDevice->IsHeadphones = (mDevice->FmtChans == DevFmtStereo &&
  677. info->active_port && strcmp(info->active_port->name, "analog-output-headphones") == 0);
  678. }
  679. void PulsePlayback::sinkNameCallbackC(pa_context *context, const pa_sink_info *info, int eol, void *pdata)
  680. { static_cast<PulsePlayback*>(pdata)->sinkNameCallback(context, info, eol); }
  681. void PulsePlayback::sinkNameCallback(pa_context* UNUSED(context), const pa_sink_info *info, int eol)
  682. {
  683. if(eol)
  684. {
  685. pulse_condvar.notify_all();
  686. return;
  687. }
  688. mDevice->DeviceName = info->description;
  689. }
  690. void PulsePlayback::streamMovedCallbackC(pa_stream *stream, void *pdata)
  691. { static_cast<PulsePlayback*>(pdata)->streamMovedCallback(stream); }
  692. void PulsePlayback::streamMovedCallback(pa_stream *stream)
  693. {
  694. mDeviceName = pa_stream_get_device_name(stream);
  695. TRACE("Stream moved to %s\n", mDeviceName.c_str());
  696. }
  697. ALCenum PulsePlayback::open(const ALCchar *name)
  698. {
  699. const char *pulse_name{nullptr};
  700. const char *dev_name{nullptr};
  701. if(name)
  702. {
  703. if(PlaybackDevices.empty())
  704. probePlaybackDevices();
  705. auto iter = std::find_if(PlaybackDevices.cbegin(), PlaybackDevices.cend(),
  706. [name](const DevMap &entry) -> bool
  707. { return entry.name == name; }
  708. );
  709. if(iter == PlaybackDevices.cend())
  710. throw al::backend_exception{ALC_INVALID_VALUE, "Device name \"%s\" not found", name};
  711. pulse_name = iter->device_name.c_str();
  712. dev_name = iter->name.c_str();
  713. }
  714. std::unique_lock<std::mutex> plock{pulse_lock};
  715. mContext = connect_context(plock);
  716. pa_context_set_state_callback(mContext, &PulsePlayback::contextStateCallbackC, this);
  717. pa_stream_flags_t flags{PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE | PA_STREAM_FIX_CHANNELS};
  718. if(!GetConfigValueBool(nullptr, "pulse", "allow-moves", 1))
  719. flags |= PA_STREAM_DONT_MOVE;
  720. pa_sample_spec spec{};
  721. spec.format = PA_SAMPLE_S16NE;
  722. spec.rate = 44100;
  723. spec.channels = 2;
  724. if(!pulse_name)
  725. {
  726. pulse_name = getenv("ALSOFT_PULSE_DEFAULT");
  727. if(pulse_name && !pulse_name[0]) pulse_name = nullptr;
  728. }
  729. TRACE("Connecting to \"%s\"\n", pulse_name ? pulse_name : "(default)");
  730. mStream = pulse_connect_stream(pulse_name, plock, mContext, flags, nullptr, &spec, nullptr,
  731. BackendType::Playback);
  732. pa_stream_set_moved_callback(mStream, &PulsePlayback::streamMovedCallbackC, this);
  733. mFrameSize = pa_frame_size(pa_stream_get_sample_spec(mStream));
  734. mDeviceName = pa_stream_get_device_name(mStream);
  735. if(!dev_name)
  736. {
  737. pa_operation *op{pa_context_get_sink_info_by_name(mContext, mDeviceName.c_str(),
  738. &PulsePlayback::sinkNameCallbackC, this)};
  739. wait_for_operation(op, plock);
  740. }
  741. else
  742. mDevice->DeviceName = dev_name;
  743. return ALC_NO_ERROR;
  744. }
  745. ALCboolean PulsePlayback::reset()
  746. {
  747. std::unique_lock<std::mutex> plock{pulse_lock};
  748. if(mStream)
  749. {
  750. pa_stream_set_state_callback(mStream, nullptr, nullptr);
  751. pa_stream_set_moved_callback(mStream, nullptr, nullptr);
  752. pa_stream_set_write_callback(mStream, nullptr, nullptr);
  753. pa_stream_set_buffer_attr_callback(mStream, nullptr, nullptr);
  754. pa_stream_disconnect(mStream);
  755. pa_stream_unref(mStream);
  756. mStream = nullptr;
  757. }
  758. pa_operation *op{pa_context_get_sink_info_by_name(mContext, mDeviceName.c_str(),
  759. &PulsePlayback::sinkInfoCallbackC, this)};
  760. wait_for_operation(op, plock);
  761. pa_stream_flags_t flags{PA_STREAM_START_CORKED | PA_STREAM_INTERPOLATE_TIMING |
  762. PA_STREAM_AUTO_TIMING_UPDATE | PA_STREAM_EARLY_REQUESTS};
  763. if(!GetConfigValueBool(nullptr, "pulse", "allow-moves", 1))
  764. flags |= PA_STREAM_DONT_MOVE;
  765. if(GetConfigValueBool(mDevice->DeviceName.c_str(), "pulse", "adjust-latency", 0))
  766. {
  767. /* ADJUST_LATENCY can't be specified with EARLY_REQUESTS, for some
  768. * reason. So if the user wants to adjust the overall device latency,
  769. * we can't ask to get write signals as soon as minreq is reached.
  770. */
  771. flags &= ~PA_STREAM_EARLY_REQUESTS;
  772. flags |= PA_STREAM_ADJUST_LATENCY;
  773. }
  774. if(GetConfigValueBool(mDevice->DeviceName.c_str(), "pulse", "fix-rate", 0) ||
  775. !(mDevice->Flags&DEVICE_FREQUENCY_REQUEST))
  776. flags |= PA_STREAM_FIX_RATE;
  777. pa_channel_map chanmap{};
  778. switch(mDevice->FmtChans)
  779. {
  780. case DevFmtMono:
  781. chanmap = MonoChanMap;
  782. break;
  783. case DevFmtAmbi3D:
  784. mDevice->FmtChans = DevFmtStereo;
  785. /*fall-through*/
  786. case DevFmtStereo:
  787. chanmap = StereoChanMap;
  788. break;
  789. case DevFmtQuad:
  790. chanmap = QuadChanMap;
  791. break;
  792. case DevFmtX51:
  793. chanmap = X51ChanMap;
  794. break;
  795. case DevFmtX51Rear:
  796. chanmap = X51RearChanMap;
  797. break;
  798. case DevFmtX61:
  799. chanmap = X61ChanMap;
  800. break;
  801. case DevFmtX71:
  802. chanmap = X71ChanMap;
  803. break;
  804. }
  805. SetChannelOrderFromMap(mDevice, chanmap);
  806. switch(mDevice->FmtType)
  807. {
  808. case DevFmtByte:
  809. mDevice->FmtType = DevFmtUByte;
  810. /* fall-through */
  811. case DevFmtUByte:
  812. mSpec.format = PA_SAMPLE_U8;
  813. break;
  814. case DevFmtUShort:
  815. mDevice->FmtType = DevFmtShort;
  816. /* fall-through */
  817. case DevFmtShort:
  818. mSpec.format = PA_SAMPLE_S16NE;
  819. break;
  820. case DevFmtUInt:
  821. mDevice->FmtType = DevFmtInt;
  822. /* fall-through */
  823. case DevFmtInt:
  824. mSpec.format = PA_SAMPLE_S32NE;
  825. break;
  826. case DevFmtFloat:
  827. mSpec.format = PA_SAMPLE_FLOAT32NE;
  828. break;
  829. }
  830. mSpec.rate = mDevice->Frequency;
  831. mSpec.channels = mDevice->channelsFromFmt();
  832. if(pa_sample_spec_valid(&mSpec) == 0)
  833. throw al::backend_exception{ALC_INVALID_VALUE, "Invalid sample spec"};
  834. mAttr.maxlength = -1;
  835. mAttr.tlength = mDevice->BufferSize * pa_frame_size(&mSpec);
  836. mAttr.prebuf = 0;
  837. mAttr.minreq = mDevice->UpdateSize * pa_frame_size(&mSpec);
  838. mAttr.fragsize = -1;
  839. mStream = pulse_connect_stream(mDeviceName.c_str(), plock, mContext, flags, &mAttr, &mSpec,
  840. &chanmap, BackendType::Playback);
  841. pa_stream_set_state_callback(mStream, &PulsePlayback::streamStateCallbackC, this);
  842. pa_stream_set_moved_callback(mStream, &PulsePlayback::streamMovedCallbackC, this);
  843. mSpec = *(pa_stream_get_sample_spec(mStream));
  844. mFrameSize = pa_frame_size(&mSpec);
  845. if(mDevice->Frequency != mSpec.rate)
  846. {
  847. /* Server updated our playback rate, so modify the buffer attribs
  848. * accordingly.
  849. */
  850. const auto scale = static_cast<double>(mSpec.rate) / mDevice->Frequency;
  851. const ALuint perlen{static_cast<ALuint>(clampd(scale*mDevice->UpdateSize + 0.5, 64.0,
  852. 8192.0))};
  853. const ALuint buflen{static_cast<ALuint>(clampd(scale*mDevice->BufferSize + 0.5, perlen*2,
  854. std::numeric_limits<int>::max()/mFrameSize))};
  855. mAttr.maxlength = -1;
  856. mAttr.tlength = buflen * mFrameSize;
  857. mAttr.prebuf = 0;
  858. mAttr.minreq = perlen * mFrameSize;
  859. op = pa_stream_set_buffer_attr(mStream, &mAttr, stream_success_callback, nullptr);
  860. wait_for_operation(op, plock);
  861. mDevice->Frequency = mSpec.rate;
  862. }
  863. pa_stream_set_buffer_attr_callback(mStream, &PulsePlayback::bufferAttrCallbackC, this);
  864. bufferAttrCallback(mStream);
  865. mDevice->BufferSize = mAttr.tlength / mFrameSize;
  866. mDevice->UpdateSize = mAttr.minreq / mFrameSize;
  867. /* HACK: prebuf should be 0 as that's what we set it to. However on some
  868. * systems it comes back as non-0, so we have to make sure the device will
  869. * write enough audio to start playback. The lack of manual start control
  870. * may have unintended consequences, but it's better than not starting at
  871. * all.
  872. */
  873. if(mAttr.prebuf != 0)
  874. {
  875. ALuint len{mAttr.prebuf / mFrameSize};
  876. if(len <= mDevice->BufferSize)
  877. ERR("Non-0 prebuf, %u samples (%u bytes), device has %u samples\n",
  878. len, mAttr.prebuf, mDevice->BufferSize);
  879. }
  880. return ALC_TRUE;
  881. }
  882. ALCboolean PulsePlayback::start()
  883. {
  884. std::unique_lock<std::mutex> plock{pulse_lock};
  885. pa_stream_set_write_callback(mStream, &PulsePlayback::streamWriteCallbackC, this);
  886. pa_operation *op{pa_stream_cork(mStream, 0, stream_success_callback, nullptr)};
  887. wait_for_operation(op, plock);
  888. return ALC_TRUE;
  889. }
  890. void PulsePlayback::stop()
  891. {
  892. std::unique_lock<std::mutex> plock{pulse_lock};
  893. pa_stream_set_write_callback(mStream, nullptr, nullptr);
  894. pa_operation *op{pa_stream_cork(mStream, 1, stream_success_callback, nullptr)};
  895. wait_for_operation(op, plock);
  896. }
  897. ClockLatency PulsePlayback::getClockLatency()
  898. {
  899. ClockLatency ret;
  900. pa_usec_t latency;
  901. int neg, err;
  902. { std::lock_guard<std::mutex> _{pulse_lock};
  903. ret.ClockTime = GetDeviceClockTime(mDevice);
  904. err = pa_stream_get_latency(mStream, &latency, &neg);
  905. }
  906. if(UNLIKELY(err != 0))
  907. {
  908. /* FIXME: if err = -PA_ERR_NODATA, it means we were called too soon
  909. * after starting the stream and no timing info has been received from
  910. * the server yet. Should we wait, possibly stalling the app, or give a
  911. * dummy value? Either way, it shouldn't be 0. */
  912. if(err != -PA_ERR_NODATA)
  913. ERR("Failed to get stream latency: 0x%x\n", err);
  914. latency = 0;
  915. neg = 0;
  916. }
  917. else if(UNLIKELY(neg))
  918. latency = 0;
  919. ret.Latency = std::chrono::microseconds{latency};
  920. return ret;
  921. }
  922. void PulsePlayback::lock()
  923. { pulse_lock.lock(); }
  924. void PulsePlayback::unlock()
  925. { pulse_lock.unlock(); }
  926. struct PulseCapture final : public BackendBase {
  927. PulseCapture(ALCdevice *device) noexcept : BackendBase{device} { }
  928. ~PulseCapture() override;
  929. static void contextStateCallbackC(pa_context *context, void *pdata);
  930. void contextStateCallback(pa_context *context);
  931. static void streamStateCallbackC(pa_stream *stream, void *pdata);
  932. void streamStateCallback(pa_stream *stream);
  933. static void sourceNameCallbackC(pa_context *context, const pa_source_info *info, int eol, void *pdata);
  934. void sourceNameCallback(pa_context *context, const pa_source_info *info, int eol);
  935. static void streamMovedCallbackC(pa_stream *stream, void *pdata);
  936. void streamMovedCallback(pa_stream *stream);
  937. ALCenum open(const ALCchar *name) override;
  938. ALCboolean start() override;
  939. void stop() override;
  940. ALCenum captureSamples(ALCvoid *buffer, ALCuint samples) override;
  941. ALCuint availableSamples() override;
  942. ClockLatency getClockLatency() override;
  943. void lock() override;
  944. void unlock() override;
  945. std::string mDeviceName;
  946. const void *mCapStore{nullptr};
  947. size_t mCapLen{0u};
  948. size_t mCapRemain{0u};
  949. ALCuint mLastReadable{0u};
  950. pa_buffer_attr mAttr{};
  951. pa_sample_spec mSpec{};
  952. pa_stream *mStream{nullptr};
  953. pa_context *mContext{nullptr};
  954. static constexpr inline const char *CurrentPrefix() noexcept { return "PulseCapture::"; }
  955. DEF_NEWDEL(PulseCapture)
  956. };
  957. PulseCapture::~PulseCapture()
  958. {
  959. if(!mContext)
  960. return;
  961. pulse_close(mContext, mStream);
  962. mContext = nullptr;
  963. mStream = nullptr;
  964. }
  965. void PulseCapture::contextStateCallbackC(pa_context *context, void *pdata)
  966. { static_cast<PulseCapture*>(pdata)->contextStateCallback(context); }
  967. void PulseCapture::contextStateCallback(pa_context *context)
  968. {
  969. if(pa_context_get_state(context) == PA_CONTEXT_FAILED)
  970. {
  971. ERR("Received context failure!\n");
  972. aluHandleDisconnect(mDevice, "Capture state failure");
  973. }
  974. pulse_condvar.notify_all();
  975. }
  976. void PulseCapture::streamStateCallbackC(pa_stream *stream, void *pdata)
  977. { static_cast<PulseCapture*>(pdata)->streamStateCallback(stream); }
  978. void PulseCapture::streamStateCallback(pa_stream *stream)
  979. {
  980. if(pa_stream_get_state(stream) == PA_STREAM_FAILED)
  981. {
  982. ERR("Received stream failure!\n");
  983. aluHandleDisconnect(mDevice, "Capture stream failure");
  984. }
  985. pulse_condvar.notify_all();
  986. }
  987. void PulseCapture::sourceNameCallbackC(pa_context *context, const pa_source_info *info, int eol, void *pdata)
  988. { static_cast<PulseCapture*>(pdata)->sourceNameCallback(context, info, eol); }
  989. void PulseCapture::sourceNameCallback(pa_context* UNUSED(context), const pa_source_info *info, int eol)
  990. {
  991. if(eol)
  992. {
  993. pulse_condvar.notify_all();
  994. return;
  995. }
  996. mDevice->DeviceName = info->description;
  997. }
  998. void PulseCapture::streamMovedCallbackC(pa_stream *stream, void *pdata)
  999. { static_cast<PulseCapture*>(pdata)->streamMovedCallback(stream); }
  1000. void PulseCapture::streamMovedCallback(pa_stream *stream)
  1001. {
  1002. mDeviceName = pa_stream_get_device_name(stream);
  1003. TRACE("Stream moved to %s\n", mDeviceName.c_str());
  1004. }
  1005. ALCenum PulseCapture::open(const ALCchar *name)
  1006. {
  1007. const char *pulse_name{nullptr};
  1008. if(name)
  1009. {
  1010. if(CaptureDevices.empty())
  1011. probeCaptureDevices();
  1012. auto iter = std::find_if(CaptureDevices.cbegin(), CaptureDevices.cend(),
  1013. [name](const DevMap &entry) -> bool
  1014. { return entry.name == name; }
  1015. );
  1016. if(iter == CaptureDevices.cend())
  1017. throw al::backend_exception{ALC_INVALID_VALUE, "Device name \"%s\" not found", name};
  1018. pulse_name = iter->device_name.c_str();
  1019. mDevice->DeviceName = iter->name;
  1020. }
  1021. std::unique_lock<std::mutex> plock{pulse_lock};
  1022. mContext = connect_context(plock);
  1023. pa_context_set_state_callback(mContext, &PulseCapture::contextStateCallbackC, this);
  1024. pa_channel_map chanmap{};
  1025. switch(mDevice->FmtChans)
  1026. {
  1027. case DevFmtMono:
  1028. chanmap = MonoChanMap;
  1029. break;
  1030. case DevFmtStereo:
  1031. chanmap = StereoChanMap;
  1032. break;
  1033. case DevFmtQuad:
  1034. chanmap = QuadChanMap;
  1035. break;
  1036. case DevFmtX51:
  1037. chanmap = X51ChanMap;
  1038. break;
  1039. case DevFmtX51Rear:
  1040. chanmap = X51RearChanMap;
  1041. break;
  1042. case DevFmtX61:
  1043. chanmap = X61ChanMap;
  1044. break;
  1045. case DevFmtX71:
  1046. chanmap = X71ChanMap;
  1047. break;
  1048. case DevFmtAmbi3D:
  1049. throw al::backend_exception{ALC_INVALID_VALUE, "%s capture samples not supported",
  1050. DevFmtChannelsString(mDevice->FmtChans)};
  1051. }
  1052. SetChannelOrderFromMap(mDevice, chanmap);
  1053. switch(mDevice->FmtType)
  1054. {
  1055. case DevFmtUByte:
  1056. mSpec.format = PA_SAMPLE_U8;
  1057. break;
  1058. case DevFmtShort:
  1059. mSpec.format = PA_SAMPLE_S16NE;
  1060. break;
  1061. case DevFmtInt:
  1062. mSpec.format = PA_SAMPLE_S32NE;
  1063. break;
  1064. case DevFmtFloat:
  1065. mSpec.format = PA_SAMPLE_FLOAT32NE;
  1066. break;
  1067. case DevFmtByte:
  1068. case DevFmtUShort:
  1069. case DevFmtUInt:
  1070. throw al::backend_exception{ALC_INVALID_VALUE, "%s capture samples not supported",
  1071. DevFmtTypeString(mDevice->FmtType)};
  1072. }
  1073. mSpec.rate = mDevice->Frequency;
  1074. mSpec.channels = mDevice->channelsFromFmt();
  1075. if(pa_sample_spec_valid(&mSpec) == 0)
  1076. throw al::backend_exception{ALC_INVALID_VALUE, "Invalid sample format"};
  1077. ALuint samples{mDevice->BufferSize};
  1078. samples = maxu(samples, 100 * mDevice->Frequency / 1000);
  1079. mAttr.minreq = -1;
  1080. mAttr.prebuf = -1;
  1081. mAttr.maxlength = samples * pa_frame_size(&mSpec);
  1082. mAttr.tlength = -1;
  1083. mAttr.fragsize = minu(samples, 50*mDevice->Frequency/1000) * pa_frame_size(&mSpec);
  1084. pa_stream_flags_t flags{PA_STREAM_START_CORKED | PA_STREAM_ADJUST_LATENCY};
  1085. if(!GetConfigValueBool(nullptr, "pulse", "allow-moves", 1))
  1086. flags |= PA_STREAM_DONT_MOVE;
  1087. TRACE("Connecting to \"%s\"\n", pulse_name ? pulse_name : "(default)");
  1088. mStream = pulse_connect_stream(pulse_name, plock, mContext, flags, &mAttr, &mSpec, &chanmap,
  1089. BackendType::Capture);
  1090. pa_stream_set_moved_callback(mStream, &PulseCapture::streamMovedCallbackC, this);
  1091. pa_stream_set_state_callback(mStream, &PulseCapture::streamStateCallbackC, this);
  1092. mDeviceName = pa_stream_get_device_name(mStream);
  1093. if(mDevice->DeviceName.empty())
  1094. {
  1095. pa_operation *op{pa_context_get_source_info_by_name(mContext, mDeviceName.c_str(),
  1096. &PulseCapture::sourceNameCallbackC, this)};
  1097. wait_for_operation(op, plock);
  1098. }
  1099. return ALC_NO_ERROR;
  1100. }
  1101. ALCboolean PulseCapture::start()
  1102. {
  1103. std::unique_lock<std::mutex> plock{pulse_lock};
  1104. pa_operation *op{pa_stream_cork(mStream, 0, stream_success_callback, nullptr)};
  1105. wait_for_operation(op, plock);
  1106. return ALC_TRUE;
  1107. }
  1108. void PulseCapture::stop()
  1109. {
  1110. std::unique_lock<std::mutex> plock{pulse_lock};
  1111. pa_operation *op{pa_stream_cork(mStream, 1, stream_success_callback, nullptr)};
  1112. wait_for_operation(op, plock);
  1113. }
  1114. ALCenum PulseCapture::captureSamples(ALCvoid *buffer, ALCuint samples)
  1115. {
  1116. ALCuint todo{samples * static_cast<ALCuint>(pa_frame_size(&mSpec))};
  1117. /* Capture is done in fragment-sized chunks, so we loop until we get all
  1118. * that's available */
  1119. mLastReadable -= todo;
  1120. std::lock_guard<std::mutex> _{pulse_lock};
  1121. while(todo > 0)
  1122. {
  1123. if(mCapLen == 0)
  1124. {
  1125. if(UNLIKELY(!mDevice->Connected.load(std::memory_order_acquire)))
  1126. break;
  1127. const pa_stream_state_t state{pa_stream_get_state(mStream)};
  1128. if(UNLIKELY(!PA_STREAM_IS_GOOD(state)))
  1129. {
  1130. aluHandleDisconnect(mDevice, "Bad capture state: %u", state);
  1131. break;
  1132. }
  1133. if(UNLIKELY(pa_stream_peek(mStream, &mCapStore, &mCapLen) < 0))
  1134. {
  1135. aluHandleDisconnect(mDevice, "Failed retrieving capture samples: %s",
  1136. pa_strerror(pa_context_errno(mContext)));
  1137. break;
  1138. }
  1139. if(mCapLen == 0) break;
  1140. mCapRemain = mCapLen;
  1141. }
  1142. const size_t rem{minz(todo, mCapRemain)};
  1143. if(LIKELY(mCapStore))
  1144. memcpy(buffer, mCapStore, rem);
  1145. else
  1146. memset(buffer, ((mDevice->FmtType==DevFmtUByte) ? 0x80 : 0), rem);
  1147. buffer = static_cast<ALbyte*>(buffer) + rem;
  1148. todo -= rem;
  1149. if(LIKELY(mCapStore))
  1150. mCapStore = reinterpret_cast<const ALbyte*>(mCapStore) + rem;
  1151. mCapRemain -= rem;
  1152. if(mCapRemain == 0)
  1153. {
  1154. pa_stream_drop(mStream);
  1155. mCapLen = 0;
  1156. }
  1157. }
  1158. if(todo > 0)
  1159. memset(buffer, ((mDevice->FmtType==DevFmtUByte) ? 0x80 : 0), todo);
  1160. return ALC_NO_ERROR;
  1161. }
  1162. ALCuint PulseCapture::availableSamples()
  1163. {
  1164. size_t readable{mCapRemain};
  1165. if(mDevice->Connected.load(std::memory_order_acquire))
  1166. {
  1167. std::lock_guard<std::mutex> _{pulse_lock};
  1168. size_t got{pa_stream_readable_size(mStream)};
  1169. if(static_cast<ssize_t>(got) < 0)
  1170. {
  1171. ERR("pa_stream_readable_size() failed: %s\n", pa_strerror(got));
  1172. aluHandleDisconnect(mDevice, "Failed getting readable size: %s", pa_strerror(got));
  1173. }
  1174. else if(got > mCapLen)
  1175. readable += got - mCapLen;
  1176. }
  1177. if(mLastReadable < readable)
  1178. mLastReadable = readable;
  1179. return mLastReadable / pa_frame_size(&mSpec);
  1180. }
  1181. ClockLatency PulseCapture::getClockLatency()
  1182. {
  1183. ClockLatency ret;
  1184. pa_usec_t latency;
  1185. int neg, err;
  1186. { std::lock_guard<std::mutex> _{pulse_lock};
  1187. ret.ClockTime = GetDeviceClockTime(mDevice);
  1188. err = pa_stream_get_latency(mStream, &latency, &neg);
  1189. }
  1190. if(UNLIKELY(err != 0))
  1191. {
  1192. ERR("Failed to get stream latency: 0x%x\n", err);
  1193. latency = 0;
  1194. neg = 0;
  1195. }
  1196. else if(UNLIKELY(neg))
  1197. latency = 0;
  1198. ret.Latency = std::chrono::microseconds{latency};
  1199. return ret;
  1200. }
  1201. void PulseCapture::lock()
  1202. { pulse_lock.lock(); }
  1203. void PulseCapture::unlock()
  1204. { pulse_lock.unlock(); }
  1205. } // namespace
  1206. bool PulseBackendFactory::init()
  1207. {
  1208. #ifdef HAVE_DYNLOAD
  1209. if(!pulse_handle)
  1210. {
  1211. bool ret{true};
  1212. std::string missing_funcs;
  1213. #ifdef _WIN32
  1214. #define PALIB "libpulse-0.dll"
  1215. #elif defined(__APPLE__) && defined(__MACH__)
  1216. #define PALIB "libpulse.0.dylib"
  1217. #else
  1218. #define PALIB "libpulse.so.0"
  1219. #endif
  1220. pulse_handle = LoadLib(PALIB);
  1221. if(!pulse_handle)
  1222. {
  1223. WARN("Failed to load %s\n", PALIB);
  1224. return false;
  1225. }
  1226. #define LOAD_FUNC(x) do { \
  1227. p##x = reinterpret_cast<decltype(p##x)>(GetSymbol(pulse_handle, #x)); \
  1228. if(!(p##x)) { \
  1229. ret = false; \
  1230. missing_funcs += "\n" #x; \
  1231. } \
  1232. } while(0)
  1233. PULSE_FUNCS(LOAD_FUNC)
  1234. #undef LOAD_FUNC
  1235. if(!ret)
  1236. {
  1237. WARN("Missing expected functions:%s\n", missing_funcs.c_str());
  1238. CloseLib(pulse_handle);
  1239. pulse_handle = nullptr;
  1240. return false;
  1241. }
  1242. }
  1243. #endif /* HAVE_DYNLOAD */
  1244. pulse_ctx_flags = PA_CONTEXT_NOFLAGS;
  1245. if(!GetConfigValueBool(nullptr, "pulse", "spawn-server", 1))
  1246. pulse_ctx_flags |= PA_CONTEXT_NOAUTOSPAWN;
  1247. try {
  1248. std::unique_lock<std::mutex> plock{pulse_lock};
  1249. pa_context *context{connect_context(plock)};
  1250. pa_context_disconnect(context);
  1251. pa_context_unref(context);
  1252. return true;
  1253. }
  1254. catch(...) {
  1255. return false;
  1256. }
  1257. }
  1258. bool PulseBackendFactory::querySupport(BackendType type)
  1259. { return type == BackendType::Playback || type == BackendType::Capture; }
  1260. void PulseBackendFactory::probe(DevProbe type, std::string *outnames)
  1261. {
  1262. auto add_device = [outnames](const DevMap &entry) -> void
  1263. {
  1264. /* +1 to also append the null char (to ensure a null-separated list and
  1265. * double-null terminated list).
  1266. */
  1267. outnames->append(entry.name.c_str(), entry.name.length()+1);
  1268. };
  1269. switch(type)
  1270. {
  1271. case DevProbe::Playback:
  1272. probePlaybackDevices();
  1273. std::for_each(PlaybackDevices.cbegin(), PlaybackDevices.cend(), add_device);
  1274. break;
  1275. case DevProbe::Capture:
  1276. probeCaptureDevices();
  1277. std::for_each(CaptureDevices.cbegin(), CaptureDevices.cend(), add_device);
  1278. break;
  1279. }
  1280. }
  1281. BackendPtr PulseBackendFactory::createBackend(ALCdevice *device, BackendType type)
  1282. {
  1283. if(type == BackendType::Playback)
  1284. return BackendPtr{new PulsePlayback{device}};
  1285. if(type == BackendType::Capture)
  1286. return BackendPtr{new PulseCapture{device}};
  1287. return nullptr;
  1288. }
  1289. BackendFactory &PulseBackendFactory::getFactory()
  1290. {
  1291. static PulseBackendFactory factory{};
  1292. return factory;
  1293. }