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