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