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