Line data Source code
1 : /* 2 : * Copyright (C) 2004-2024 Savoir-faire Linux Inc. 3 : * 4 : * This program is free software: you can redistribute it and/or modify 5 : * it under the terms of the GNU General Public License as published by 6 : * the Free Software Foundation, either version 3 of the License, or 7 : * (at your option) any later version. 8 : * 9 : * This program is distributed in the hope that it will be useful, 10 : * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 : * GNU General Public License for more details. 13 : * 14 : * You should have received a copy of the GNU General Public License 15 : * along with this program. If not, see <https://www.gnu.org/licenses/>. 16 : */ 17 : #pragma once 18 : 19 : #include "noncopyable.h" 20 : #include "pulselayer.h" 21 : 22 : #include <pulse/pulseaudio.h> 23 : #include <string> 24 : 25 : namespace jami { 26 : 27 : inline AVSampleFormat 28 0 : sampleFormatFromPulse(pa_sample_format_t format) { 29 0 : switch (format) 30 : { 31 0 : case PA_SAMPLE_S16LE: 32 : case PA_SAMPLE_S16BE: 33 0 : return AV_SAMPLE_FMT_S16; 34 0 : case PA_SAMPLE_FLOAT32LE: 35 : case PA_SAMPLE_FLOAT32BE: 36 0 : return AV_SAMPLE_FMT_FLT; 37 0 : case PA_SAMPLE_S32LE: 38 : case PA_SAMPLE_S32BE: 39 0 : return AV_SAMPLE_FMT_S32; 40 0 : default: 41 0 : return AV_SAMPLE_FMT_S16; 42 : } 43 : } 44 : 45 : inline pa_sample_format_t 46 0 : pulseSampleFormatFromAv(AVSampleFormat format) { 47 0 : switch (format) 48 : { 49 0 : case AV_SAMPLE_FMT_S16: 50 0 : return PA_SAMPLE_S16LE; 51 0 : case AV_SAMPLE_FMT_FLT: 52 0 : return PA_SAMPLE_FLOAT32LE; 53 0 : case AV_SAMPLE_FMT_S32: 54 0 : return PA_SAMPLE_S32LE; 55 0 : default: 56 0 : return PA_SAMPLE_S16LE; 57 : } 58 : } 59 : 60 : class AudioStream 61 : { 62 : public: 63 : using OnReady = std::function<void()>; 64 : using OnData = std::function<void(size_t)>; 65 : 66 : /** 67 : * Constructor 68 : * 69 : * @param context pulseaudio's application context. 70 : * @param mainloop pulseaudio's main loop 71 : * @param description 72 : * @param types 73 : * @param audio sampling rate 74 : * @param pointer to pa_source_info or pa_sink_info (depending on type). 75 : * @param true if echo cancelling should be used with this stream 76 : */ 77 : AudioStream(pa_context*, 78 : pa_threaded_mainloop*, 79 : const char*, 80 : AudioDeviceType, 81 : unsigned, 82 : pa_sample_format_t, 83 : const PaDeviceInfos&, 84 : bool, 85 : OnReady onReady, 86 : OnData onData); 87 : 88 : ~AudioStream(); 89 : 90 : void start(); 91 : void stop(); 92 : 93 : /** 94 : * Accessor: Get the pulseaudio stream object 95 : * @return pa_stream* The stream 96 : */ 97 0 : pa_stream* stream() { return audiostream_; } 98 : 99 0 : const pa_sample_spec* sampleSpec() const { return pa_stream_get_sample_spec(audiostream_); } 100 : 101 : inline size_t sampleSize() const { return pa_sample_size(sampleSpec()); } 102 0 : inline size_t frameSize() const { return pa_frame_size(sampleSpec()); } 103 : 104 : inline uint8_t channels() const { return sampleSpec()->channels; } 105 : 106 0 : inline AudioFormat format() const 107 : { 108 0 : auto s = sampleSpec(); 109 0 : return AudioFormat(s->rate, s->channels, sampleFormatFromPulse(s->format)); 110 : } 111 : 112 0 : inline std::string getDeviceName() const 113 : { 114 0 : auto res = pa_stream_get_device_name(audiostream_); 115 0 : if (res == reinterpret_cast<decltype(res)>(-PA_ERR_NOTSUPPORTED) or !res) 116 0 : return {}; 117 0 : return res; 118 : } 119 : 120 : bool isReady(); 121 : 122 0 : void setEchoCancelCb(std::function<void(bool)>&& cb) { echoCancelCb = cb; } 123 : 124 : private: 125 : NON_COPYABLE(AudioStream); 126 : 127 : OnReady onReady_; 128 : OnData onData_; 129 : 130 : /** 131 : * Mandatory asynchronous callback on the audio stream state 132 : */ 133 : void stateChanged(pa_stream* s); 134 : void moved(pa_stream* s); 135 : void opEnded(pa_operation* s); 136 : 137 : /** 138 : * The pulse audio object 139 : */ 140 : pa_stream* audiostream_; 141 : 142 : /** 143 : * A pointer to the opaque threaded main loop object 144 : */ 145 : pa_threaded_mainloop* mainloop_; 146 : 147 : /** 148 : * The type of this audio stream 149 : */ 150 : AudioDeviceType audioType_; 151 : 152 : /** 153 : * Function called whenever the stream is moved and we check for an echo canceller 154 : */ 155 : std::function<void(bool)> echoCancelCb; 156 : 157 : std::mutex mutex_; 158 : std::condition_variable cond_; 159 : std::set<pa_operation*> ongoing_ops; 160 : }; 161 : 162 : } // namespace jami