1 /* 2 * Copyright 2010 The WebRTC Project Authors. All rights reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 #include "webrtc/sound/pulseaudiosoundsystem.h" 12 13 #ifdef HAVE_LIBPULSE 14 15 #include <algorithm> 16 #include <string> 17 18 #include "webrtc/base/arraysize.h" 19 #include "webrtc/base/common.h" 20 #include "webrtc/base/fileutils.h" // for GetApplicationName() 21 #include "webrtc/base/logging.h" 22 #include "webrtc/base/timeutils.h" 23 #include "webrtc/base/worker.h" 24 #include "webrtc/sound/sounddevicelocator.h" 25 #include "webrtc/sound/soundinputstreaminterface.h" 26 #include "webrtc/sound/soundoutputstreaminterface.h" 27 28 namespace rtc { 29 30 // First PulseAudio protocol version that supports PA_STREAM_ADJUST_LATENCY. 31 static const uint32_t kAdjustLatencyProtocolVersion = 13; 32 33 // Lookup table from the rtc format enum in soundsysteminterface.h to 34 // Pulse's enums. 35 static const pa_sample_format_t kCricketFormatToPulseFormatTable[] = { 36 // The order here must match the order in soundsysteminterface.h 37 PA_SAMPLE_S16LE, 38 }; 39 40 // Some timing constants for optimal operation. See 41 // https://tango.0pointer.de/pipermail/pulseaudio-discuss/2008-January/001170.html 42 // for a good explanation of some of the factors that go into this. 43 44 // Playback. 45 46 // For playback, there is a round-trip delay to fill the server-side playback 47 // buffer, so setting too low of a latency is a buffer underflow risk. We will 48 // automatically increase the latency if a buffer underflow does occur, but we 49 // also enforce a sane minimum at start-up time. Anything lower would be 50 // virtually guaranteed to underflow at least once, so there's no point in 51 // allowing lower latencies. 52 static const int kPlaybackLatencyMinimumMsecs = 20; 53 // Every time a playback stream underflows, we will reconfigure it with target 54 // latency that is greater by this amount. 55 static const int kPlaybackLatencyIncrementMsecs = 20; 56 // We also need to configure a suitable request size. Too small and we'd burn 57 // CPU from the overhead of transfering small amounts of data at once. Too large 58 // and the amount of data remaining in the buffer right before refilling it 59 // would be a buffer underflow risk. We set it to half of the buffer size. 60 static const int kPlaybackRequestFactor = 2; 61 62 // Capture. 63 64 // For capture, low latency is not a buffer overflow risk, but it makes us burn 65 // CPU from the overhead of transfering small amounts of data at once, so we set 66 // a recommended value that we use for the kLowLatency constant (but if the user 67 // explicitly requests something lower then we will honour it). 68 // 1ms takes about 6-7% CPU. 5ms takes about 5%. 10ms takes about 4.x%. 69 static const int kLowCaptureLatencyMsecs = 10; 70 // There is a round-trip delay to ack the data to the server, so the 71 // server-side buffer needs extra space to prevent buffer overflow. 20ms is 72 // sufficient, but there is no penalty to making it bigger, so we make it huge. 73 // (750ms is libpulse's default value for the _total_ buffer size in the 74 // kNoLatencyRequirements case.) 75 static const int kCaptureBufferExtraMsecs = 750; 76 77 static void FillPlaybackBufferAttr(int latency, 78 pa_buffer_attr *attr) { 79 attr->maxlength = latency; 80 attr->tlength = latency; 81 attr->minreq = latency / kPlaybackRequestFactor; 82 attr->prebuf = attr->tlength - attr->minreq; 83 LOG(LS_VERBOSE) << "Configuring latency = " << attr->tlength << ", minreq = " 84 << attr->minreq << ", minfill = " << attr->prebuf; 85 } 86 87 static pa_volume_t CricketVolumeToPulseVolume(int volume) { 88 // PA's volume space goes from 0% at PA_VOLUME_MUTED (value 0) to 100% at 89 // PA_VOLUME_NORM (value 0x10000). It can also go beyond 100% up to 90 // PA_VOLUME_MAX (value UINT32_MAX-1), but using that is probably unwise. 91 // We just linearly map the 0-255 scale of SoundSystemInterface onto 92 // PA_VOLUME_MUTED-PA_VOLUME_NORM. If the programmer exceeds kMaxVolume then 93 // they can access the over-100% features of PA. 94 return PA_VOLUME_MUTED + (PA_VOLUME_NORM - PA_VOLUME_MUTED) * 95 volume / SoundSystemInterface::kMaxVolume; 96 } 97 98 static int PulseVolumeToCricketVolume(pa_volume_t pa_volume) { 99 return SoundSystemInterface::kMinVolume + 100 (SoundSystemInterface::kMaxVolume - SoundSystemInterface::kMinVolume) * 101 pa_volume / PA_VOLUME_NORM; 102 } 103 104 static pa_volume_t MaxChannelVolume(pa_cvolume *channel_volumes) { 105 pa_volume_t pa_volume = PA_VOLUME_MUTED; // Minimum possible value. 106 for (int i = 0; i < channel_volumes->channels; ++i) { 107 if (pa_volume < channel_volumes->values[i]) { 108 pa_volume = channel_volumes->values[i]; 109 } 110 } 111 return pa_volume; 112 } 113 114 class PulseAudioDeviceLocator : public SoundDeviceLocator { 115 public: 116 PulseAudioDeviceLocator(const std::string &name, 117 const std::string &device_name) 118 : SoundDeviceLocator(name, device_name) { 119 } 120 121 virtual SoundDeviceLocator *Copy() const { 122 return new PulseAudioDeviceLocator(*this); 123 } 124 }; 125 126 // Functionality that is common to both PulseAudioInputStream and 127 // PulseAudioOutputStream. 128 class PulseAudioStream { 129 public: 130 PulseAudioStream(PulseAudioSoundSystem *pulse, pa_stream *stream, int flags) 131 : pulse_(pulse), stream_(stream), flags_(flags) { 132 } 133 134 ~PulseAudioStream() { 135 // Close() should have been called during the containing class's destructor. 136 ASSERT(stream_ == NULL); 137 } 138 139 // Must be called with the lock held. 140 bool Close() { 141 if (!IsClosed()) { 142 // Unset this here so that we don't get a TERMINATED callback. 143 symbol_table()->pa_stream_set_state_callback()(stream_, NULL, NULL); 144 if (symbol_table()->pa_stream_disconnect()(stream_) != 0) { 145 LOG(LS_ERROR) << "Can't disconnect stream"; 146 // Continue and return true anyways. 147 } 148 symbol_table()->pa_stream_unref()(stream_); 149 stream_ = NULL; 150 } 151 return true; 152 } 153 154 // Must be called with the lock held. 155 int LatencyUsecs() { 156 if (!(flags_ & SoundSystemInterface::FLAG_REPORT_LATENCY)) { 157 return 0; 158 } 159 160 pa_usec_t latency; 161 int negative; 162 Lock(); 163 int re = symbol_table()->pa_stream_get_latency()(stream_, &latency, 164 &negative); 165 Unlock(); 166 if (re != 0) { 167 LOG(LS_ERROR) << "Can't query latency"; 168 // We'd rather continue playout/capture with an incorrect delay than stop 169 // it altogether, so return a valid value. 170 return 0; 171 } 172 if (negative) { 173 // The delay can be negative for monitoring streams if the captured 174 // samples haven't been played yet. In such a case, "latency" contains the 175 // magnitude, so we must negate it to get the real value. 176 return -latency; 177 } else { 178 return latency; 179 } 180 } 181 182 PulseAudioSoundSystem *pulse() { 183 return pulse_; 184 } 185 186 PulseAudioSymbolTable *symbol_table() { 187 return &pulse()->symbol_table_; 188 } 189 190 pa_stream *stream() { 191 ASSERT(stream_ != NULL); 192 return stream_; 193 } 194 195 bool IsClosed() { 196 return stream_ == NULL; 197 } 198 199 void Lock() { 200 pulse()->Lock(); 201 } 202 203 void Unlock() { 204 pulse()->Unlock(); 205 } 206 207 private: 208 PulseAudioSoundSystem *pulse_; 209 pa_stream *stream_; 210 int flags_; 211 212 RTC_DISALLOW_COPY_AND_ASSIGN(PulseAudioStream); 213 }; 214 215 // Implementation of an input stream. See soundinputstreaminterface.h regarding 216 // thread-safety. 217 class PulseAudioInputStream : 218 public SoundInputStreamInterface, 219 private rtc::Worker { 220 public: 221 PulseAudioInputStream(PulseAudioSoundSystem *pulse, 222 pa_stream *stream, 223 int flags) 224 : stream_(pulse, stream, flags), 225 temp_sample_data_(NULL), 226 temp_sample_data_size_(0) { 227 // This callback seems to never be issued, but let's set it anyways. 228 symbol_table()->pa_stream_set_overflow_callback()(stream, &OverflowCallback, 229 NULL); 230 } 231 232 virtual ~PulseAudioInputStream() { 233 bool success = Close(); 234 // We need that to live. 235 VERIFY(success); 236 } 237 238 virtual bool StartReading() { 239 return StartWork(); 240 } 241 242 virtual bool StopReading() { 243 return StopWork(); 244 } 245 246 virtual bool GetVolume(int *volume) { 247 bool ret = false; 248 249 Lock(); 250 251 // Unlike output streams, input streams have no concept of a stream volume, 252 // only a device volume. So we have to retrieve the volume of the device 253 // itself. 254 255 pa_cvolume channel_volumes; 256 257 GetVolumeCallbackData data; 258 data.instance = this; 259 data.channel_volumes = &channel_volumes; 260 261 pa_operation *op = symbol_table()->pa_context_get_source_info_by_index()( 262 stream_.pulse()->context_, 263 symbol_table()->pa_stream_get_device_index()(stream_.stream()), 264 &GetVolumeCallbackThunk, 265 &data); 266 if (!stream_.pulse()->FinishOperation(op)) { 267 goto done; 268 } 269 270 if (data.channel_volumes) { 271 // This pointer was never unset by the callback, so we must have received 272 // an empty list of infos. This probably never happens, but we code for it 273 // anyway. 274 LOG(LS_ERROR) << "Did not receive GetVolumeCallback"; 275 goto done; 276 } 277 278 // We now have the volume for each channel. Each channel could have a 279 // different volume if, e.g., the user went and changed the volumes in the 280 // PA UI. To get a single volume for SoundSystemInterface we just take the 281 // maximum. Ideally we'd do so with pa_cvolume_max, but it doesn't exist in 282 // Hardy, so we do it manually. 283 pa_volume_t pa_volume; 284 pa_volume = MaxChannelVolume(&channel_volumes); 285 // Now map onto the SoundSystemInterface range. 286 *volume = PulseVolumeToCricketVolume(pa_volume); 287 288 ret = true; 289 done: 290 Unlock(); 291 return ret; 292 } 293 294 virtual bool SetVolume(int volume) { 295 bool ret = false; 296 pa_volume_t pa_volume = CricketVolumeToPulseVolume(volume); 297 298 Lock(); 299 300 // Unlike output streams, input streams have no concept of a stream volume, 301 // only a device volume. So we have to change the volume of the device 302 // itself. 303 304 // The device may have a different number of channels than the stream and 305 // their mapping may be different, so we don't want to use the channel count 306 // from our sample spec. We could use PA_CHANNELS_MAX to cover our bases, 307 // and the server allows that even if the device's channel count is lower, 308 // but some buggy PA clients don't like that (the pavucontrol on Hardy dies 309 // in an assert if the channel count is different). So instead we look up 310 // the actual number of channels that the device has. 311 312 uint8_t channels; 313 314 GetSourceChannelCountCallbackData data; 315 data.instance = this; 316 data.channels = &channels; 317 318 uint32_t device_index = symbol_table()->pa_stream_get_device_index()( 319 stream_.stream()); 320 321 pa_operation *op = symbol_table()->pa_context_get_source_info_by_index()( 322 stream_.pulse()->context_, 323 device_index, 324 &GetSourceChannelCountCallbackThunk, 325 &data); 326 if (!stream_.pulse()->FinishOperation(op)) { 327 goto done; 328 } 329 330 if (data.channels) { 331 // This pointer was never unset by the callback, so we must have received 332 // an empty list of infos. This probably never happens, but we code for it 333 // anyway. 334 LOG(LS_ERROR) << "Did not receive GetSourceChannelCountCallback"; 335 goto done; 336 } 337 338 pa_cvolume channel_volumes; 339 symbol_table()->pa_cvolume_set()(&channel_volumes, channels, pa_volume); 340 341 op = symbol_table()->pa_context_set_source_volume_by_index()( 342 stream_.pulse()->context_, 343 device_index, 344 &channel_volumes, 345 // This callback merely logs errors. 346 &SetVolumeCallback, 347 NULL); 348 if (!op) { 349 LOG(LS_ERROR) << "pa_context_set_source_volume_by_index()"; 350 goto done; 351 } 352 // Don't need to wait for this to complete. 353 symbol_table()->pa_operation_unref()(op); 354 355 ret = true; 356 done: 357 Unlock(); 358 return ret; 359 } 360 361 virtual bool Close() { 362 if (!StopReading()) { 363 return false; 364 } 365 bool ret = true; 366 if (!stream_.IsClosed()) { 367 Lock(); 368 ret = stream_.Close(); 369 Unlock(); 370 } 371 return ret; 372 } 373 374 virtual int LatencyUsecs() { 375 return stream_.LatencyUsecs(); 376 } 377 378 private: 379 struct GetVolumeCallbackData { 380 PulseAudioInputStream* instance; 381 pa_cvolume* channel_volumes; 382 }; 383 384 struct GetSourceChannelCountCallbackData { 385 PulseAudioInputStream* instance; 386 uint8_t* channels; 387 }; 388 389 void Lock() { 390 stream_.Lock(); 391 } 392 393 void Unlock() { 394 stream_.Unlock(); 395 } 396 397 PulseAudioSymbolTable *symbol_table() { 398 return stream_.symbol_table(); 399 } 400 401 void EnableReadCallback() { 402 symbol_table()->pa_stream_set_read_callback()( 403 stream_.stream(), 404 &ReadCallbackThunk, 405 this); 406 } 407 408 void DisableReadCallback() { 409 symbol_table()->pa_stream_set_read_callback()( 410 stream_.stream(), 411 NULL, 412 NULL); 413 } 414 415 static void ReadCallbackThunk(pa_stream *unused1, 416 size_t unused2, 417 void *userdata) { 418 PulseAudioInputStream *instance = 419 static_cast<PulseAudioInputStream *>(userdata); 420 instance->OnReadCallback(); 421 } 422 423 void OnReadCallback() { 424 // We get the data pointer and size now in order to save one Lock/Unlock 425 // on OnMessage. 426 if (symbol_table()->pa_stream_peek()(stream_.stream(), 427 &temp_sample_data_, 428 &temp_sample_data_size_) != 0) { 429 LOG(LS_ERROR) << "Can't read data!"; 430 return; 431 } 432 // Since we consume the data asynchronously on a different thread, we have 433 // to temporarily disable the read callback or else Pulse will call it 434 // continuously until we consume the data. We re-enable it below. 435 DisableReadCallback(); 436 HaveWork(); 437 } 438 439 // Inherited from Worker. 440 virtual void OnStart() { 441 Lock(); 442 EnableReadCallback(); 443 Unlock(); 444 } 445 446 // Inherited from Worker. 447 virtual void OnHaveWork() { 448 ASSERT(temp_sample_data_ && temp_sample_data_size_); 449 SignalSamplesRead(temp_sample_data_, 450 temp_sample_data_size_, 451 this); 452 temp_sample_data_ = NULL; 453 temp_sample_data_size_ = 0; 454 455 Lock(); 456 for (;;) { 457 // Ack the last thing we read. 458 if (symbol_table()->pa_stream_drop()(stream_.stream()) != 0) { 459 LOG(LS_ERROR) << "Can't ack read data"; 460 } 461 462 if (symbol_table()->pa_stream_readable_size()(stream_.stream()) <= 0) { 463 // Then that was all the data. 464 break; 465 } 466 467 // Else more data. 468 const void *sample_data; 469 size_t sample_data_size; 470 if (symbol_table()->pa_stream_peek()(stream_.stream(), 471 &sample_data, 472 &sample_data_size) != 0) { 473 LOG(LS_ERROR) << "Can't read data!"; 474 break; 475 } 476 477 // Drop lock for sigslot dispatch, which could take a while. 478 Unlock(); 479 SignalSamplesRead(sample_data, sample_data_size, this); 480 Lock(); 481 482 // Return to top of loop for the ack and the check for more data. 483 } 484 EnableReadCallback(); 485 Unlock(); 486 } 487 488 // Inherited from Worker. 489 virtual void OnStop() { 490 Lock(); 491 DisableReadCallback(); 492 Unlock(); 493 } 494 495 static void OverflowCallback(pa_stream *stream, 496 void *userdata) { 497 LOG(LS_WARNING) << "Buffer overflow on capture stream " << stream; 498 } 499 500 static void GetVolumeCallbackThunk(pa_context *unused, 501 const pa_source_info *info, 502 int eol, 503 void *userdata) { 504 GetVolumeCallbackData *data = 505 static_cast<GetVolumeCallbackData *>(userdata); 506 data->instance->OnGetVolumeCallback(info, eol, &data->channel_volumes); 507 } 508 509 void OnGetVolumeCallback(const pa_source_info *info, 510 int eol, 511 pa_cvolume **channel_volumes) { 512 if (eol) { 513 // List is over. Wake GetVolume(). 514 stream_.pulse()->Signal(); 515 return; 516 } 517 518 if (*channel_volumes) { 519 **channel_volumes = info->volume; 520 // Unset the pointer so that we know that we have have already copied the 521 // volume. 522 *channel_volumes = NULL; 523 } else { 524 // We have received an additional callback after the first one, which 525 // doesn't make sense for a single source. This probably never happens, 526 // but we code for it anyway. 527 LOG(LS_WARNING) << "Ignoring extra GetVolumeCallback"; 528 } 529 } 530 531 static void GetSourceChannelCountCallbackThunk(pa_context *unused, 532 const pa_source_info *info, 533 int eol, 534 void *userdata) { 535 GetSourceChannelCountCallbackData *data = 536 static_cast<GetSourceChannelCountCallbackData *>(userdata); 537 data->instance->OnGetSourceChannelCountCallback(info, eol, &data->channels); 538 } 539 540 void OnGetSourceChannelCountCallback(const pa_source_info *info, 541 int eol, 542 uint8_t **channels) { 543 if (eol) { 544 // List is over. Wake SetVolume(). 545 stream_.pulse()->Signal(); 546 return; 547 } 548 549 if (*channels) { 550 **channels = info->channel_map.channels; 551 // Unset the pointer so that we know that we have have already copied the 552 // channel count. 553 *channels = NULL; 554 } else { 555 // We have received an additional callback after the first one, which 556 // doesn't make sense for a single source. This probably never happens, 557 // but we code for it anyway. 558 LOG(LS_WARNING) << "Ignoring extra GetSourceChannelCountCallback"; 559 } 560 } 561 562 static void SetVolumeCallback(pa_context *unused1, 563 int success, 564 void *unused2) { 565 if (!success) { 566 LOG(LS_ERROR) << "Failed to change capture volume"; 567 } 568 } 569 570 PulseAudioStream stream_; 571 // Temporary storage for passing data between threads. 572 const void *temp_sample_data_; 573 size_t temp_sample_data_size_; 574 575 RTC_DISALLOW_COPY_AND_ASSIGN(PulseAudioInputStream); 576 }; 577 578 // Implementation of an output stream. See soundoutputstreaminterface.h 579 // regarding thread-safety. 580 class PulseAudioOutputStream : 581 public SoundOutputStreamInterface, 582 private rtc::Worker { 583 public: 584 PulseAudioOutputStream(PulseAudioSoundSystem *pulse, 585 pa_stream *stream, 586 int flags, 587 int latency) 588 : stream_(pulse, stream, flags), 589 configured_latency_(latency), 590 temp_buffer_space_(0) { 591 symbol_table()->pa_stream_set_underflow_callback()(stream, 592 &UnderflowCallbackThunk, 593 this); 594 } 595 596 virtual ~PulseAudioOutputStream() { 597 bool success = Close(); 598 // We need that to live. 599 VERIFY(success); 600 } 601 602 virtual bool EnableBufferMonitoring() { 603 return StartWork(); 604 } 605 606 virtual bool DisableBufferMonitoring() { 607 return StopWork(); 608 } 609 610 virtual bool WriteSamples(const void *sample_data, 611 size_t size) { 612 bool ret = true; 613 Lock(); 614 if (symbol_table()->pa_stream_write()(stream_.stream(), 615 sample_data, 616 size, 617 NULL, 618 0, 619 PA_SEEK_RELATIVE) != 0) { 620 LOG(LS_ERROR) << "Unable to write"; 621 ret = false; 622 } 623 Unlock(); 624 return ret; 625 } 626 627 virtual bool GetVolume(int *volume) { 628 bool ret = false; 629 630 Lock(); 631 632 pa_cvolume channel_volumes; 633 634 GetVolumeCallbackData data; 635 data.instance = this; 636 data.channel_volumes = &channel_volumes; 637 638 pa_operation *op = symbol_table()->pa_context_get_sink_input_info()( 639 stream_.pulse()->context_, 640 symbol_table()->pa_stream_get_index()(stream_.stream()), 641 &GetVolumeCallbackThunk, 642 &data); 643 if (!stream_.pulse()->FinishOperation(op)) { 644 goto done; 645 } 646 647 if (data.channel_volumes) { 648 // This pointer was never unset by the callback, so we must have received 649 // an empty list of infos. This probably never happens, but we code for it 650 // anyway. 651 LOG(LS_ERROR) << "Did not receive GetVolumeCallback"; 652 goto done; 653 } 654 655 // We now have the volume for each channel. Each channel could have a 656 // different volume if, e.g., the user went and changed the volumes in the 657 // PA UI. To get a single volume for SoundSystemInterface we just take the 658 // maximum. Ideally we'd do so with pa_cvolume_max, but it doesn't exist in 659 // Hardy, so we do it manually. 660 pa_volume_t pa_volume; 661 pa_volume = MaxChannelVolume(&channel_volumes); 662 // Now map onto the SoundSystemInterface range. 663 *volume = PulseVolumeToCricketVolume(pa_volume); 664 665 ret = true; 666 done: 667 Unlock(); 668 return ret; 669 } 670 671 virtual bool SetVolume(int volume) { 672 bool ret = false; 673 pa_volume_t pa_volume = CricketVolumeToPulseVolume(volume); 674 675 Lock(); 676 677 const pa_sample_spec *spec = symbol_table()->pa_stream_get_sample_spec()( 678 stream_.stream()); 679 if (!spec) { 680 LOG(LS_ERROR) << "pa_stream_get_sample_spec()"; 681 goto done; 682 } 683 684 pa_cvolume channel_volumes; 685 symbol_table()->pa_cvolume_set()(&channel_volumes, spec->channels, 686 pa_volume); 687 688 pa_operation *op; 689 op = symbol_table()->pa_context_set_sink_input_volume()( 690 stream_.pulse()->context_, 691 symbol_table()->pa_stream_get_index()(stream_.stream()), 692 &channel_volumes, 693 // This callback merely logs errors. 694 &SetVolumeCallback, 695 NULL); 696 if (!op) { 697 LOG(LS_ERROR) << "pa_context_set_sink_input_volume()"; 698 goto done; 699 } 700 // Don't need to wait for this to complete. 701 symbol_table()->pa_operation_unref()(op); 702 703 ret = true; 704 done: 705 Unlock(); 706 return ret; 707 } 708 709 virtual bool Close() { 710 if (!DisableBufferMonitoring()) { 711 return false; 712 } 713 bool ret = true; 714 if (!stream_.IsClosed()) { 715 Lock(); 716 symbol_table()->pa_stream_set_underflow_callback()(stream_.stream(), 717 NULL, 718 NULL); 719 ret = stream_.Close(); 720 Unlock(); 721 } 722 return ret; 723 } 724 725 virtual int LatencyUsecs() { 726 return stream_.LatencyUsecs(); 727 } 728 729 #if 0 730 // TODO(henrika): Versions 0.9.16 and later of Pulse have a new API for 731 // zero-copy writes, but Hardy is not new enough to have that so we can't 732 // rely on it. Perhaps auto-detect if it's present or not and use it if we 733 // can? 734 735 virtual bool GetWriteBuffer(void **buffer, size_t *size) { 736 bool ret = true; 737 Lock(); 738 if (symbol_table()->pa_stream_begin_write()(stream_.stream(), buffer, size) 739 != 0) { 740 LOG(LS_ERROR) << "Can't get write buffer"; 741 ret = false; 742 } 743 Unlock(); 744 return ret; 745 } 746 747 // Releases the caller's hold on the write buffer. "written" must be the 748 // amount of data that was written. 749 virtual bool ReleaseWriteBuffer(void *buffer, size_t written) { 750 bool ret = true; 751 Lock(); 752 if (written == 0) { 753 if (symbol_table()->pa_stream_cancel_write()(stream_.stream()) != 0) { 754 LOG(LS_ERROR) << "Can't cancel write"; 755 ret = false; 756 } 757 } else { 758 if (symbol_table()->pa_stream_write()(stream_.stream(), 759 buffer, 760 written, 761 NULL, 762 0, 763 PA_SEEK_RELATIVE) != 0) { 764 LOG(LS_ERROR) << "Unable to write"; 765 ret = false; 766 } 767 } 768 Unlock(); 769 return ret; 770 } 771 #endif 772 773 private: 774 struct GetVolumeCallbackData { 775 PulseAudioOutputStream* instance; 776 pa_cvolume* channel_volumes; 777 }; 778 779 void Lock() { 780 stream_.Lock(); 781 } 782 783 void Unlock() { 784 stream_.Unlock(); 785 } 786 787 PulseAudioSymbolTable *symbol_table() { 788 return stream_.symbol_table(); 789 } 790 791 void EnableWriteCallback() { 792 pa_stream_state_t state = symbol_table()->pa_stream_get_state()( 793 stream_.stream()); 794 if (state == PA_STREAM_READY) { 795 // May already have available space. Must check. 796 temp_buffer_space_ = symbol_table()->pa_stream_writable_size()( 797 stream_.stream()); 798 if (temp_buffer_space_ > 0) { 799 // Yup, there is already space available, so if we register a write 800 // callback then it will not receive any event. So dispatch one ourself 801 // instead. 802 HaveWork(); 803 return; 804 } 805 } 806 symbol_table()->pa_stream_set_write_callback()( 807 stream_.stream(), 808 &WriteCallbackThunk, 809 this); 810 } 811 812 void DisableWriteCallback() { 813 symbol_table()->pa_stream_set_write_callback()( 814 stream_.stream(), 815 NULL, 816 NULL); 817 } 818 819 static void WriteCallbackThunk(pa_stream *unused, 820 size_t buffer_space, 821 void *userdata) { 822 PulseAudioOutputStream *instance = 823 static_cast<PulseAudioOutputStream *>(userdata); 824 instance->OnWriteCallback(buffer_space); 825 } 826 827 void OnWriteCallback(size_t buffer_space) { 828 temp_buffer_space_ = buffer_space; 829 // Since we write the data asynchronously on a different thread, we have 830 // to temporarily disable the write callback or else Pulse will call it 831 // continuously until we write the data. We re-enable it below. 832 DisableWriteCallback(); 833 HaveWork(); 834 } 835 836 // Inherited from Worker. 837 virtual void OnStart() { 838 Lock(); 839 EnableWriteCallback(); 840 Unlock(); 841 } 842 843 // Inherited from Worker. 844 virtual void OnHaveWork() { 845 ASSERT(temp_buffer_space_ > 0); 846 847 SignalBufferSpace(temp_buffer_space_, this); 848 849 temp_buffer_space_ = 0; 850 Lock(); 851 EnableWriteCallback(); 852 Unlock(); 853 } 854 855 // Inherited from Worker. 856 virtual void OnStop() { 857 Lock(); 858 DisableWriteCallback(); 859 Unlock(); 860 } 861 862 static void UnderflowCallbackThunk(pa_stream *unused, 863 void *userdata) { 864 PulseAudioOutputStream *instance = 865 static_cast<PulseAudioOutputStream *>(userdata); 866 instance->OnUnderflowCallback(); 867 } 868 869 void OnUnderflowCallback() { 870 LOG(LS_WARNING) << "Buffer underflow on playback stream " 871 << stream_.stream(); 872 873 if (configured_latency_ == SoundSystemInterface::kNoLatencyRequirements) { 874 // We didn't configure a pa_buffer_attr before, so switching to one now 875 // would be questionable. 876 return; 877 } 878 879 // Otherwise reconfigure the stream with a higher target latency. 880 881 const pa_sample_spec *spec = symbol_table()->pa_stream_get_sample_spec()( 882 stream_.stream()); 883 if (!spec) { 884 LOG(LS_ERROR) << "pa_stream_get_sample_spec()"; 885 return; 886 } 887 888 size_t bytes_per_sec = symbol_table()->pa_bytes_per_second()(spec); 889 890 int new_latency = configured_latency_ + 891 bytes_per_sec * kPlaybackLatencyIncrementMsecs / 892 rtc::kNumMicrosecsPerSec; 893 894 pa_buffer_attr new_attr = {0}; 895 FillPlaybackBufferAttr(new_latency, &new_attr); 896 897 pa_operation *op = symbol_table()->pa_stream_set_buffer_attr()( 898 stream_.stream(), 899 &new_attr, 900 // No callback. 901 NULL, 902 NULL); 903 if (!op) { 904 LOG(LS_ERROR) << "pa_stream_set_buffer_attr()"; 905 return; 906 } 907 // Don't need to wait for this to complete. 908 symbol_table()->pa_operation_unref()(op); 909 910 // Save the new latency in case we underflow again. 911 configured_latency_ = new_latency; 912 } 913 914 static void GetVolumeCallbackThunk(pa_context *unused, 915 const pa_sink_input_info *info, 916 int eol, 917 void *userdata) { 918 GetVolumeCallbackData *data = 919 static_cast<GetVolumeCallbackData *>(userdata); 920 data->instance->OnGetVolumeCallback(info, eol, &data->channel_volumes); 921 } 922 923 void OnGetVolumeCallback(const pa_sink_input_info *info, 924 int eol, 925 pa_cvolume **channel_volumes) { 926 if (eol) { 927 // List is over. Wake GetVolume(). 928 stream_.pulse()->Signal(); 929 return; 930 } 931 932 if (*channel_volumes) { 933 **channel_volumes = info->volume; 934 // Unset the pointer so that we know that we have have already copied the 935 // volume. 936 *channel_volumes = NULL; 937 } else { 938 // We have received an additional callback after the first one, which 939 // doesn't make sense for a single sink input. This probably never 940 // happens, but we code for it anyway. 941 LOG(LS_WARNING) << "Ignoring extra GetVolumeCallback"; 942 } 943 } 944 945 static void SetVolumeCallback(pa_context *unused1, 946 int success, 947 void *unused2) { 948 if (!success) { 949 LOG(LS_ERROR) << "Failed to change playback volume"; 950 } 951 } 952 953 PulseAudioStream stream_; 954 int configured_latency_; 955 // Temporary storage for passing data between threads. 956 size_t temp_buffer_space_; 957 958 RTC_DISALLOW_COPY_AND_ASSIGN(PulseAudioOutputStream); 959 }; 960 961 PulseAudioSoundSystem::PulseAudioSoundSystem() 962 : mainloop_(NULL), context_(NULL) { 963 } 964 965 PulseAudioSoundSystem::~PulseAudioSoundSystem() { 966 Terminate(); 967 } 968 969 bool PulseAudioSoundSystem::Init() { 970 if (IsInitialized()) { 971 return true; 972 } 973 974 // Load libpulse. 975 if (!symbol_table_.Load()) { 976 // Most likely the Pulse library and sound server are not installed on 977 // this system. 978 LOG(LS_WARNING) << "Failed to load symbol table"; 979 return false; 980 } 981 982 // Now create and start the Pulse event thread. 983 mainloop_ = symbol_table_.pa_threaded_mainloop_new()(); 984 if (!mainloop_) { 985 LOG(LS_ERROR) << "Can't create mainloop"; 986 goto fail0; 987 } 988 989 if (symbol_table_.pa_threaded_mainloop_start()(mainloop_) != 0) { 990 LOG(LS_ERROR) << "Can't start mainloop"; 991 goto fail1; 992 } 993 994 Lock(); 995 context_ = CreateNewConnection(); 996 Unlock(); 997 998 if (!context_) { 999 goto fail2; 1000 } 1001 1002 // Otherwise we're now ready! 1003 return true; 1004 1005 fail2: 1006 symbol_table_.pa_threaded_mainloop_stop()(mainloop_); 1007 fail1: 1008 symbol_table_.pa_threaded_mainloop_free()(mainloop_); 1009 mainloop_ = NULL; 1010 fail0: 1011 return false; 1012 } 1013 1014 void PulseAudioSoundSystem::Terminate() { 1015 if (!IsInitialized()) { 1016 return; 1017 } 1018 1019 Lock(); 1020 symbol_table_.pa_context_disconnect()(context_); 1021 symbol_table_.pa_context_unref()(context_); 1022 Unlock(); 1023 context_ = NULL; 1024 symbol_table_.pa_threaded_mainloop_stop()(mainloop_); 1025 symbol_table_.pa_threaded_mainloop_free()(mainloop_); 1026 mainloop_ = NULL; 1027 1028 // We do not unload the symbol table because we may need it again soon if 1029 // Init() is called again. 1030 } 1031 1032 bool PulseAudioSoundSystem::EnumeratePlaybackDevices( 1033 SoundDeviceLocatorList *devices) { 1034 return EnumerateDevices<pa_sink_info>( 1035 devices, 1036 symbol_table_.pa_context_get_sink_info_list(), 1037 &EnumeratePlaybackDevicesCallbackThunk); 1038 } 1039 1040 bool PulseAudioSoundSystem::EnumerateCaptureDevices( 1041 SoundDeviceLocatorList *devices) { 1042 return EnumerateDevices<pa_source_info>( 1043 devices, 1044 symbol_table_.pa_context_get_source_info_list(), 1045 &EnumerateCaptureDevicesCallbackThunk); 1046 } 1047 1048 bool PulseAudioSoundSystem::GetDefaultPlaybackDevice( 1049 SoundDeviceLocator **device) { 1050 return GetDefaultDevice<&pa_server_info::default_sink_name>(device); 1051 } 1052 1053 bool PulseAudioSoundSystem::GetDefaultCaptureDevice( 1054 SoundDeviceLocator **device) { 1055 return GetDefaultDevice<&pa_server_info::default_source_name>(device); 1056 } 1057 1058 SoundOutputStreamInterface *PulseAudioSoundSystem::OpenPlaybackDevice( 1059 const SoundDeviceLocator *device, 1060 const OpenParams ¶ms) { 1061 return OpenDevice<SoundOutputStreamInterface>( 1062 device, 1063 params, 1064 "Playback", 1065 &PulseAudioSoundSystem::ConnectOutputStream); 1066 } 1067 1068 SoundInputStreamInterface *PulseAudioSoundSystem::OpenCaptureDevice( 1069 const SoundDeviceLocator *device, 1070 const OpenParams ¶ms) { 1071 return OpenDevice<SoundInputStreamInterface>( 1072 device, 1073 params, 1074 "Capture", 1075 &PulseAudioSoundSystem::ConnectInputStream); 1076 } 1077 1078 const char *PulseAudioSoundSystem::GetName() const { 1079 return "PulseAudio"; 1080 } 1081 1082 inline bool PulseAudioSoundSystem::IsInitialized() { 1083 return mainloop_ != NULL; 1084 } 1085 1086 struct ConnectToPulseCallbackData { 1087 PulseAudioSoundSystem *instance; 1088 bool connect_done; 1089 }; 1090 1091 void PulseAudioSoundSystem::ConnectToPulseCallbackThunk( 1092 pa_context *context, void *userdata) { 1093 ConnectToPulseCallbackData *data = 1094 static_cast<ConnectToPulseCallbackData *>(userdata); 1095 data->instance->OnConnectToPulseCallback(context, &data->connect_done); 1096 } 1097 1098 void PulseAudioSoundSystem::OnConnectToPulseCallback( 1099 pa_context *context, bool *connect_done) { 1100 pa_context_state_t state = symbol_table_.pa_context_get_state()(context); 1101 if (state == PA_CONTEXT_READY || 1102 state == PA_CONTEXT_FAILED || 1103 state == PA_CONTEXT_TERMINATED) { 1104 // Connection process has reached a terminal state. Wake ConnectToPulse(). 1105 *connect_done = true; 1106 Signal(); 1107 } 1108 } 1109 1110 // Must be called with the lock held. 1111 bool PulseAudioSoundSystem::ConnectToPulse(pa_context *context) { 1112 bool ret = true; 1113 ConnectToPulseCallbackData data; 1114 // Have to put this up here to satisfy the compiler. 1115 pa_context_state_t state; 1116 1117 data.instance = this; 1118 data.connect_done = false; 1119 1120 symbol_table_.pa_context_set_state_callback()(context, 1121 &ConnectToPulseCallbackThunk, 1122 &data); 1123 1124 // Connect to PulseAudio sound server. 1125 if (symbol_table_.pa_context_connect()( 1126 context, 1127 NULL, // Default server 1128 PA_CONTEXT_NOAUTOSPAWN, 1129 NULL) != 0) { // No special fork handling needed 1130 LOG(LS_ERROR) << "Can't start connection to PulseAudio sound server"; 1131 ret = false; 1132 goto done; 1133 } 1134 1135 // Wait for the connection state machine to reach a terminal state. 1136 do { 1137 Wait(); 1138 } while (!data.connect_done); 1139 1140 // Now check to see what final state we reached. 1141 state = symbol_table_.pa_context_get_state()(context); 1142 1143 if (state != PA_CONTEXT_READY) { 1144 if (state == PA_CONTEXT_FAILED) { 1145 LOG(LS_ERROR) << "Failed to connect to PulseAudio sound server"; 1146 } else if (state == PA_CONTEXT_TERMINATED) { 1147 LOG(LS_ERROR) << "PulseAudio connection terminated early"; 1148 } else { 1149 // Shouldn't happen, because we only signal on one of those three states. 1150 LOG(LS_ERROR) << "Unknown problem connecting to PulseAudio"; 1151 } 1152 ret = false; 1153 } 1154 1155 done: 1156 // We unset our callback for safety just in case the state might somehow 1157 // change later, because the pointer to "data" will be invalid after return 1158 // from this function. 1159 symbol_table_.pa_context_set_state_callback()(context, NULL, NULL); 1160 return ret; 1161 } 1162 1163 // Must be called with the lock held. 1164 pa_context *PulseAudioSoundSystem::CreateNewConnection() { 1165 // Create connection context. 1166 std::string app_name; 1167 // TODO(henrika): Pulse etiquette says this name should be localized. Do 1168 // we care? 1169 rtc::Filesystem::GetApplicationName(&app_name); 1170 pa_context *context = symbol_table_.pa_context_new()( 1171 symbol_table_.pa_threaded_mainloop_get_api()(mainloop_), 1172 app_name.c_str()); 1173 if (!context) { 1174 LOG(LS_ERROR) << "Can't create context"; 1175 goto fail0; 1176 } 1177 1178 // Now connect. 1179 if (!ConnectToPulse(context)) { 1180 goto fail1; 1181 } 1182 1183 // Otherwise the connection succeeded and is ready. 1184 return context; 1185 1186 fail1: 1187 symbol_table_.pa_context_unref()(context); 1188 fail0: 1189 return NULL; 1190 } 1191 1192 struct EnumerateDevicesCallbackData { 1193 PulseAudioSoundSystem *instance; 1194 SoundSystemInterface::SoundDeviceLocatorList *devices; 1195 }; 1196 1197 void PulseAudioSoundSystem::EnumeratePlaybackDevicesCallbackThunk( 1198 pa_context *unused, 1199 const pa_sink_info *info, 1200 int eol, 1201 void *userdata) { 1202 EnumerateDevicesCallbackData *data = 1203 static_cast<EnumerateDevicesCallbackData *>(userdata); 1204 data->instance->OnEnumeratePlaybackDevicesCallback(data->devices, info, eol); 1205 } 1206 1207 void PulseAudioSoundSystem::EnumerateCaptureDevicesCallbackThunk( 1208 pa_context *unused, 1209 const pa_source_info *info, 1210 int eol, 1211 void *userdata) { 1212 EnumerateDevicesCallbackData *data = 1213 static_cast<EnumerateDevicesCallbackData *>(userdata); 1214 data->instance->OnEnumerateCaptureDevicesCallback(data->devices, info, eol); 1215 } 1216 1217 void PulseAudioSoundSystem::OnEnumeratePlaybackDevicesCallback( 1218 SoundDeviceLocatorList *devices, 1219 const pa_sink_info *info, 1220 int eol) { 1221 if (eol) { 1222 // List is over. Wake EnumerateDevices(). 1223 Signal(); 1224 return; 1225 } 1226 1227 // Else this is the next device. 1228 devices->push_back( 1229 new PulseAudioDeviceLocator(info->description, info->name)); 1230 } 1231 1232 void PulseAudioSoundSystem::OnEnumerateCaptureDevicesCallback( 1233 SoundDeviceLocatorList *devices, 1234 const pa_source_info *info, 1235 int eol) { 1236 if (eol) { 1237 // List is over. Wake EnumerateDevices(). 1238 Signal(); 1239 return; 1240 } 1241 1242 if (info->monitor_of_sink != PA_INVALID_INDEX) { 1243 // We don't want to list monitor sources, since they are almost certainly 1244 // not what the user wants for voice conferencing. 1245 return; 1246 } 1247 1248 // Else this is the next device. 1249 devices->push_back( 1250 new PulseAudioDeviceLocator(info->description, info->name)); 1251 } 1252 1253 template <typename InfoStruct> 1254 bool PulseAudioSoundSystem::EnumerateDevices( 1255 SoundDeviceLocatorList *devices, 1256 pa_operation *(*enumerate_fn)( 1257 pa_context *c, 1258 void (*callback_fn)( 1259 pa_context *c, 1260 const InfoStruct *i, 1261 int eol, 1262 void *userdata), 1263 void *userdata), 1264 void (*callback_fn)( 1265 pa_context *c, 1266 const InfoStruct *i, 1267 int eol, 1268 void *userdata)) { 1269 ClearSoundDeviceLocatorList(devices); 1270 if (!IsInitialized()) { 1271 return false; 1272 } 1273 1274 EnumerateDevicesCallbackData data; 1275 data.instance = this; 1276 data.devices = devices; 1277 1278 Lock(); 1279 pa_operation *op = (*enumerate_fn)( 1280 context_, 1281 callback_fn, 1282 &data); 1283 bool ret = FinishOperation(op); 1284 Unlock(); 1285 return ret; 1286 } 1287 1288 struct GetDefaultDeviceCallbackData { 1289 PulseAudioSoundSystem *instance; 1290 SoundDeviceLocator **device; 1291 }; 1292 1293 template <const char *(pa_server_info::*field)> 1294 void PulseAudioSoundSystem::GetDefaultDeviceCallbackThunk( 1295 pa_context *unused, 1296 const pa_server_info *info, 1297 void *userdata) { 1298 GetDefaultDeviceCallbackData *data = 1299 static_cast<GetDefaultDeviceCallbackData *>(userdata); 1300 data->instance->OnGetDefaultDeviceCallback<field>(info, data->device); 1301 } 1302 1303 template <const char *(pa_server_info::*field)> 1304 void PulseAudioSoundSystem::OnGetDefaultDeviceCallback( 1305 const pa_server_info *info, 1306 SoundDeviceLocator **device) { 1307 if (info) { 1308 const char *dev = info->*field; 1309 if (dev) { 1310 *device = new PulseAudioDeviceLocator("Default device", dev); 1311 } 1312 } 1313 Signal(); 1314 } 1315 1316 template <const char *(pa_server_info::*field)> 1317 bool PulseAudioSoundSystem::GetDefaultDevice(SoundDeviceLocator **device) { 1318 if (!IsInitialized()) { 1319 return false; 1320 } 1321 bool ret; 1322 *device = NULL; 1323 GetDefaultDeviceCallbackData data; 1324 data.instance = this; 1325 data.device = device; 1326 Lock(); 1327 pa_operation *op = symbol_table_.pa_context_get_server_info()( 1328 context_, 1329 &GetDefaultDeviceCallbackThunk<field>, 1330 &data); 1331 ret = FinishOperation(op); 1332 Unlock(); 1333 return ret && (*device != NULL); 1334 } 1335 1336 void PulseAudioSoundSystem::StreamStateChangedCallbackThunk( 1337 pa_stream *stream, 1338 void *userdata) { 1339 PulseAudioSoundSystem *instance = 1340 static_cast<PulseAudioSoundSystem *>(userdata); 1341 instance->OnStreamStateChangedCallback(stream); 1342 } 1343 1344 void PulseAudioSoundSystem::OnStreamStateChangedCallback(pa_stream *stream) { 1345 pa_stream_state_t state = symbol_table_.pa_stream_get_state()(stream); 1346 if (state == PA_STREAM_READY) { 1347 LOG(LS_INFO) << "Pulse stream " << stream << " ready"; 1348 } else if (state == PA_STREAM_FAILED || 1349 state == PA_STREAM_TERMINATED || 1350 state == PA_STREAM_UNCONNECTED) { 1351 LOG(LS_ERROR) << "Pulse stream " << stream << " failed to connect: " 1352 << LastError(); 1353 } 1354 } 1355 1356 template <typename StreamInterface> 1357 StreamInterface *PulseAudioSoundSystem::OpenDevice( 1358 const SoundDeviceLocator *device, 1359 const OpenParams ¶ms, 1360 const char *stream_name, 1361 StreamInterface *(PulseAudioSoundSystem::*connect_fn)( 1362 pa_stream *stream, 1363 const char *dev, 1364 int flags, 1365 pa_stream_flags_t pa_flags, 1366 int latency, 1367 const pa_sample_spec &spec)) { 1368 if (!IsInitialized()) { 1369 return NULL; 1370 } 1371 1372 const char *dev = static_cast<const PulseAudioDeviceLocator *>(device)-> 1373 device_name().c_str(); 1374 1375 StreamInterface *stream_interface = NULL; 1376 1377 ASSERT(params.format < arraysize(kCricketFormatToPulseFormatTable)); 1378 1379 pa_sample_spec spec; 1380 spec.format = kCricketFormatToPulseFormatTable[params.format]; 1381 spec.rate = params.freq; 1382 spec.channels = params.channels; 1383 1384 int pa_flags = 0; 1385 if (params.flags & FLAG_REPORT_LATENCY) { 1386 pa_flags |= PA_STREAM_INTERPOLATE_TIMING | 1387 PA_STREAM_AUTO_TIMING_UPDATE; 1388 } 1389 1390 if (params.latency != kNoLatencyRequirements) { 1391 // If configuring a specific latency then we want to specify 1392 // PA_STREAM_ADJUST_LATENCY to make the server adjust parameters 1393 // automatically to reach that target latency. However, that flag doesn't 1394 // exist in Ubuntu 8.04 and many people still use that, so we have to check 1395 // the protocol version of libpulse. 1396 if (symbol_table_.pa_context_get_protocol_version()(context_) >= 1397 kAdjustLatencyProtocolVersion) { 1398 pa_flags |= PA_STREAM_ADJUST_LATENCY; 1399 } 1400 } 1401 1402 Lock(); 1403 1404 pa_stream *stream = symbol_table_.pa_stream_new()(context_, stream_name, 1405 &spec, NULL); 1406 if (!stream) { 1407 LOG(LS_ERROR) << "Can't create pa_stream"; 1408 goto done; 1409 } 1410 1411 // Set a state callback to log errors. 1412 symbol_table_.pa_stream_set_state_callback()(stream, 1413 &StreamStateChangedCallbackThunk, 1414 this); 1415 1416 stream_interface = (this->*connect_fn)( 1417 stream, 1418 dev, 1419 params.flags, 1420 static_cast<pa_stream_flags_t>(pa_flags), 1421 params.latency, 1422 spec); 1423 if (!stream_interface) { 1424 LOG(LS_ERROR) << "Can't connect stream to " << dev; 1425 symbol_table_.pa_stream_unref()(stream); 1426 } 1427 1428 done: 1429 Unlock(); 1430 return stream_interface; 1431 } 1432 1433 // Must be called with the lock held. 1434 SoundOutputStreamInterface *PulseAudioSoundSystem::ConnectOutputStream( 1435 pa_stream *stream, 1436 const char *dev, 1437 int flags, 1438 pa_stream_flags_t pa_flags, 1439 int latency, 1440 const pa_sample_spec &spec) { 1441 pa_buffer_attr attr = {0}; 1442 pa_buffer_attr *pattr = NULL; 1443 if (latency != kNoLatencyRequirements) { 1444 // kLowLatency is 0, so we treat it the same as a request for zero latency. 1445 ssize_t bytes_per_sec = symbol_table_.pa_bytes_per_second()(&spec); 1446 latency = std::max( 1447 latency, static_cast<int>(bytes_per_sec * kPlaybackLatencyMinimumMsecs / 1448 rtc::kNumMicrosecsPerSec)); 1449 FillPlaybackBufferAttr(latency, &attr); 1450 pattr = &attr; 1451 } 1452 if (symbol_table_.pa_stream_connect_playback()( 1453 stream, 1454 dev, 1455 pattr, 1456 pa_flags, 1457 // Let server choose volume 1458 NULL, 1459 // Not synchronized to any other playout 1460 NULL) != 0) { 1461 return NULL; 1462 } 1463 return new PulseAudioOutputStream(this, stream, flags, latency); 1464 } 1465 1466 // Must be called with the lock held. 1467 SoundInputStreamInterface *PulseAudioSoundSystem::ConnectInputStream( 1468 pa_stream *stream, 1469 const char *dev, 1470 int flags, 1471 pa_stream_flags_t pa_flags, 1472 int latency, 1473 const pa_sample_spec &spec) { 1474 pa_buffer_attr attr = {0}; 1475 pa_buffer_attr *pattr = NULL; 1476 if (latency != kNoLatencyRequirements) { 1477 size_t bytes_per_sec = symbol_table_.pa_bytes_per_second()(&spec); 1478 if (latency == kLowLatency) { 1479 latency = bytes_per_sec * kLowCaptureLatencyMsecs / 1480 rtc::kNumMicrosecsPerSec; 1481 } 1482 // Note: fragsize specifies a maximum transfer size, not a minimum, so it is 1483 // not possible to force a high latency setting, only a low one. 1484 attr.fragsize = latency; 1485 attr.maxlength = latency + bytes_per_sec * kCaptureBufferExtraMsecs / 1486 rtc::kNumMicrosecsPerSec; 1487 LOG(LS_VERBOSE) << "Configuring latency = " << attr.fragsize 1488 << ", maxlength = " << attr.maxlength; 1489 pattr = &attr; 1490 } 1491 if (symbol_table_.pa_stream_connect_record()(stream, 1492 dev, 1493 pattr, 1494 pa_flags) != 0) { 1495 return NULL; 1496 } 1497 return new PulseAudioInputStream(this, stream, flags); 1498 } 1499 1500 // Must be called with the lock held. 1501 bool PulseAudioSoundSystem::FinishOperation(pa_operation *op) { 1502 if (!op) { 1503 LOG(LS_ERROR) << "Failed to start operation"; 1504 return false; 1505 } 1506 1507 do { 1508 Wait(); 1509 } while (symbol_table_.pa_operation_get_state()(op) == PA_OPERATION_RUNNING); 1510 1511 symbol_table_.pa_operation_unref()(op); 1512 1513 return true; 1514 } 1515 1516 inline void PulseAudioSoundSystem::Lock() { 1517 symbol_table_.pa_threaded_mainloop_lock()(mainloop_); 1518 } 1519 1520 inline void PulseAudioSoundSystem::Unlock() { 1521 symbol_table_.pa_threaded_mainloop_unlock()(mainloop_); 1522 } 1523 1524 // Must be called with the lock held. 1525 inline void PulseAudioSoundSystem::Wait() { 1526 symbol_table_.pa_threaded_mainloop_wait()(mainloop_); 1527 } 1528 1529 // Must be called with the lock held. 1530 inline void PulseAudioSoundSystem::Signal() { 1531 symbol_table_.pa_threaded_mainloop_signal()(mainloop_, 0); 1532 } 1533 1534 // Must be called with the lock held. 1535 const char *PulseAudioSoundSystem::LastError() { 1536 return symbol_table_.pa_strerror()(symbol_table_.pa_context_errno()( 1537 context_)); 1538 } 1539 1540 } // namespace rtc 1541 1542 #endif // HAVE_LIBPULSE 1543