| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2010 The WebRTC Project Authors. All rights reserved. | 2 * Copyright 2010 The WebRTC Project Authors. All rights reserved. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license | 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 | 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 | 6 * tree. An additional intellectual property rights grant can be found |
| 7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
| 8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
| 9 */ | 9 */ |
| 10 | 10 |
| 11 #include "webrtc/sound/pulseaudiosoundsystem.h" | 11 #include "webrtc/sound/pulseaudiosoundsystem.h" |
| 12 | 12 |
| 13 #ifdef HAVE_LIBPULSE | 13 #ifdef HAVE_LIBPULSE |
| 14 | 14 |
| 15 #include <algorithm> | 15 #include <algorithm> |
| 16 #include <string> |
| 16 | 17 |
| 17 #include "webrtc/base/arraysize.h" | 18 #include "webrtc/base/arraysize.h" |
| 18 #include "webrtc/base/common.h" | 19 #include "webrtc/base/common.h" |
| 19 #include "webrtc/base/fileutils.h" // for GetApplicationName() | 20 #include "webrtc/base/fileutils.h" // for GetApplicationName() |
| 20 #include "webrtc/base/logging.h" | 21 #include "webrtc/base/logging.h" |
| 21 #include "webrtc/base/timeutils.h" | 22 #include "webrtc/base/timeutils.h" |
| 22 #include "webrtc/base/worker.h" | 23 #include "webrtc/base/worker.h" |
| 23 #include "webrtc/sound/sounddevicelocator.h" | 24 #include "webrtc/sound/sounddevicelocator.h" |
| 24 #include "webrtc/sound/soundinputstreaminterface.h" | 25 #include "webrtc/sound/soundinputstreaminterface.h" |
| 25 #include "webrtc/sound/soundoutputstreaminterface.h" | 26 #include "webrtc/sound/soundoutputstreaminterface.h" |
| (...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 209 int flags_; | 210 int flags_; |
| 210 | 211 |
| 211 RTC_DISALLOW_COPY_AND_ASSIGN(PulseAudioStream); | 212 RTC_DISALLOW_COPY_AND_ASSIGN(PulseAudioStream); |
| 212 }; | 213 }; |
| 213 | 214 |
| 214 // Implementation of an input stream. See soundinputstreaminterface.h regarding | 215 // Implementation of an input stream. See soundinputstreaminterface.h regarding |
| 215 // thread-safety. | 216 // thread-safety. |
| 216 class PulseAudioInputStream : | 217 class PulseAudioInputStream : |
| 217 public SoundInputStreamInterface, | 218 public SoundInputStreamInterface, |
| 218 private rtc::Worker { | 219 private rtc::Worker { |
| 219 | |
| 220 struct GetVolumeCallbackData { | |
| 221 PulseAudioInputStream *instance; | |
| 222 pa_cvolume *channel_volumes; | |
| 223 }; | |
| 224 | |
| 225 struct GetSourceChannelCountCallbackData { | |
| 226 PulseAudioInputStream *instance; | |
| 227 uint8_t *channels; | |
| 228 }; | |
| 229 | |
| 230 public: | 220 public: |
| 231 PulseAudioInputStream(PulseAudioSoundSystem *pulse, | 221 PulseAudioInputStream(PulseAudioSoundSystem *pulse, |
| 232 pa_stream *stream, | 222 pa_stream *stream, |
| 233 int flags) | 223 int flags) |
| 234 : stream_(pulse, stream, flags), | 224 : stream_(pulse, stream, flags), |
| 235 temp_sample_data_(NULL), | 225 temp_sample_data_(NULL), |
| 236 temp_sample_data_size_(0) { | 226 temp_sample_data_size_(0) { |
| 237 // This callback seems to never be issued, but let's set it anyways. | 227 // This callback seems to never be issued, but let's set it anyways. |
| 238 symbol_table()->pa_stream_set_overflow_callback()(stream, &OverflowCallback, | 228 symbol_table()->pa_stream_set_overflow_callback()(stream, &OverflowCallback, |
| 239 NULL); | 229 NULL); |
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 379 Unlock(); | 369 Unlock(); |
| 380 } | 370 } |
| 381 return ret; | 371 return ret; |
| 382 } | 372 } |
| 383 | 373 |
| 384 virtual int LatencyUsecs() { | 374 virtual int LatencyUsecs() { |
| 385 return stream_.LatencyUsecs(); | 375 return stream_.LatencyUsecs(); |
| 386 } | 376 } |
| 387 | 377 |
| 388 private: | 378 private: |
| 379 struct GetVolumeCallbackData { |
| 380 PulseAudioInputStream* instance; |
| 381 pa_cvolume* channel_volumes; |
| 382 }; |
| 383 |
| 384 struct GetSourceChannelCountCallbackData { |
| 385 PulseAudioInputStream* instance; |
| 386 uint8_t* channels; |
| 387 }; |
| 388 |
| 389 void Lock() { | 389 void Lock() { |
| 390 stream_.Lock(); | 390 stream_.Lock(); |
| 391 } | 391 } |
| 392 | 392 |
| 393 void Unlock() { | 393 void Unlock() { |
| 394 stream_.Unlock(); | 394 stream_.Unlock(); |
| 395 } | 395 } |
| 396 | 396 |
| 397 PulseAudioSymbolTable *symbol_table() { | 397 PulseAudioSymbolTable *symbol_table() { |
| 398 return stream_.symbol_table(); | 398 return stream_.symbol_table(); |
| (...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 573 size_t temp_sample_data_size_; | 573 size_t temp_sample_data_size_; |
| 574 | 574 |
| 575 RTC_DISALLOW_COPY_AND_ASSIGN(PulseAudioInputStream); | 575 RTC_DISALLOW_COPY_AND_ASSIGN(PulseAudioInputStream); |
| 576 }; | 576 }; |
| 577 | 577 |
| 578 // Implementation of an output stream. See soundoutputstreaminterface.h | 578 // Implementation of an output stream. See soundoutputstreaminterface.h |
| 579 // regarding thread-safety. | 579 // regarding thread-safety. |
| 580 class PulseAudioOutputStream : | 580 class PulseAudioOutputStream : |
| 581 public SoundOutputStreamInterface, | 581 public SoundOutputStreamInterface, |
| 582 private rtc::Worker { | 582 private rtc::Worker { |
| 583 | |
| 584 struct GetVolumeCallbackData { | |
| 585 PulseAudioOutputStream *instance; | |
| 586 pa_cvolume *channel_volumes; | |
| 587 }; | |
| 588 | |
| 589 public: | 583 public: |
| 590 PulseAudioOutputStream(PulseAudioSoundSystem *pulse, | 584 PulseAudioOutputStream(PulseAudioSoundSystem *pulse, |
| 591 pa_stream *stream, | 585 pa_stream *stream, |
| 592 int flags, | 586 int flags, |
| 593 int latency) | 587 int latency) |
| 594 : stream_(pulse, stream, flags), | 588 : stream_(pulse, stream, flags), |
| 595 configured_latency_(latency), | 589 configured_latency_(latency), |
| 596 temp_buffer_space_(0) { | 590 temp_buffer_space_(0) { |
| 597 symbol_table()->pa_stream_set_underflow_callback()(stream, | 591 symbol_table()->pa_stream_set_underflow_callback()(stream, |
| 598 &UnderflowCallbackThunk, | 592 &UnderflowCallbackThunk, |
| (...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 726 Unlock(); | 720 Unlock(); |
| 727 } | 721 } |
| 728 return ret; | 722 return ret; |
| 729 } | 723 } |
| 730 | 724 |
| 731 virtual int LatencyUsecs() { | 725 virtual int LatencyUsecs() { |
| 732 return stream_.LatencyUsecs(); | 726 return stream_.LatencyUsecs(); |
| 733 } | 727 } |
| 734 | 728 |
| 735 #if 0 | 729 #if 0 |
| 736 // TODO: Versions 0.9.16 and later of Pulse have a new API for | 730 // TODO(henrika): Versions 0.9.16 and later of Pulse have a new API for |
| 737 // zero-copy writes, but Hardy is not new enough to have that so we can't | 731 // zero-copy writes, but Hardy is not new enough to have that so we can't |
| 738 // rely on it. Perhaps auto-detect if it's present or not and use it if we | 732 // rely on it. Perhaps auto-detect if it's present or not and use it if we |
| 739 // can? | 733 // can? |
| 740 | 734 |
| 741 virtual bool GetWriteBuffer(void **buffer, size_t *size) { | 735 virtual bool GetWriteBuffer(void **buffer, size_t *size) { |
| 742 bool ret = true; | 736 bool ret = true; |
| 743 Lock(); | 737 Lock(); |
| 744 if (symbol_table()->pa_stream_begin_write()(stream_.stream(), buffer, size) | 738 if (symbol_table()->pa_stream_begin_write()(stream_.stream(), buffer, size) |
| 745 != 0) { | 739 != 0) { |
| 746 LOG(LS_ERROR) << "Can't get write buffer"; | 740 LOG(LS_ERROR) << "Can't get write buffer"; |
| (...skipping 23 matching lines...) Expand all Loading... |
| 770 LOG(LS_ERROR) << "Unable to write"; | 764 LOG(LS_ERROR) << "Unable to write"; |
| 771 ret = false; | 765 ret = false; |
| 772 } | 766 } |
| 773 } | 767 } |
| 774 Unlock(); | 768 Unlock(); |
| 775 return ret; | 769 return ret; |
| 776 } | 770 } |
| 777 #endif | 771 #endif |
| 778 | 772 |
| 779 private: | 773 private: |
| 774 struct GetVolumeCallbackData { |
| 775 PulseAudioOutputStream* instance; |
| 776 pa_cvolume* channel_volumes; |
| 777 }; |
| 778 |
| 780 void Lock() { | 779 void Lock() { |
| 781 stream_.Lock(); | 780 stream_.Lock(); |
| 782 } | 781 } |
| 783 | 782 |
| 784 void Unlock() { | 783 void Unlock() { |
| 785 stream_.Unlock(); | 784 stream_.Unlock(); |
| 786 } | 785 } |
| 787 | 786 |
| 788 PulseAudioSymbolTable *symbol_table() { | 787 PulseAudioSymbolTable *symbol_table() { |
| 789 return stream_.symbol_table(); | 788 return stream_.symbol_table(); |
| (...skipping 368 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1158 // change later, because the pointer to "data" will be invalid after return | 1157 // change later, because the pointer to "data" will be invalid after return |
| 1159 // from this function. | 1158 // from this function. |
| 1160 symbol_table_.pa_context_set_state_callback()(context, NULL, NULL); | 1159 symbol_table_.pa_context_set_state_callback()(context, NULL, NULL); |
| 1161 return ret; | 1160 return ret; |
| 1162 } | 1161 } |
| 1163 | 1162 |
| 1164 // Must be called with the lock held. | 1163 // Must be called with the lock held. |
| 1165 pa_context *PulseAudioSoundSystem::CreateNewConnection() { | 1164 pa_context *PulseAudioSoundSystem::CreateNewConnection() { |
| 1166 // Create connection context. | 1165 // Create connection context. |
| 1167 std::string app_name; | 1166 std::string app_name; |
| 1168 // TODO: Pulse etiquette says this name should be localized. Do | 1167 // TODO(henrika): Pulse etiquette says this name should be localized. Do |
| 1169 // we care? | 1168 // we care? |
| 1170 rtc::Filesystem::GetApplicationName(&app_name); | 1169 rtc::Filesystem::GetApplicationName(&app_name); |
| 1171 pa_context *context = symbol_table_.pa_context_new()( | 1170 pa_context *context = symbol_table_.pa_context_new()( |
| 1172 symbol_table_.pa_threaded_mainloop_get_api()(mainloop_), | 1171 symbol_table_.pa_threaded_mainloop_get_api()(mainloop_), |
| 1173 app_name.c_str()); | 1172 app_name.c_str()); |
| 1174 if (!context) { | 1173 if (!context) { |
| 1175 LOG(LS_ERROR) << "Can't create context"; | 1174 LOG(LS_ERROR) << "Can't create context"; |
| 1176 goto fail0; | 1175 goto fail0; |
| 1177 } | 1176 } |
| 1178 | 1177 |
| (...skipping 355 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1534 | 1533 |
| 1535 // Must be called with the lock held. | 1534 // Must be called with the lock held. |
| 1536 const char *PulseAudioSoundSystem::LastError() { | 1535 const char *PulseAudioSoundSystem::LastError() { |
| 1537 return symbol_table_.pa_strerror()(symbol_table_.pa_context_errno()( | 1536 return symbol_table_.pa_strerror()(symbol_table_.pa_context_errno()( |
| 1538 context_)); | 1537 context_)); |
| 1539 } | 1538 } |
| 1540 | 1539 |
| 1541 } // namespace rtc | 1540 } // namespace rtc |
| 1542 | 1541 |
| 1543 #endif // HAVE_LIBPULSE | 1542 #endif // HAVE_LIBPULSE |
| OLD | NEW |