[WPE][GTK] Bump minimum versions of GLib, GTK, libsoup, ATK, GStreamer, and Cairo
[WebKit-https.git] / Source / WebCore / platform / mediastream / gstreamer / MockGStreamerAudioCaptureSource.cpp
1 /*
2  * Copyright (C) 2018 Metrological Group B.V.
3  * Author: Thibault Saunier <tsaunier@igalia.com>
4  * Author: Alejandro G. Castro  <alex@igalia.com>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library 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 GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public License
17  * aint with this library; see the file COPYING.LIB.  If not, write to
18  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  */
21
22 #include "config.h"
23
24 #if ENABLE(MEDIA_STREAM) && USE(LIBWEBRTC) && USE(GSTREAMER)
25 #include "MockGStreamerAudioCaptureSource.h"
26
27 #include "GStreamerAudioStreamDescription.h"
28 #include "MockRealtimeAudioSource.h"
29
30 #include <gst/app/gstappsrc.h>
31
32 namespace WebCore {
33
34 static const double s_Tau = 2 * M_PI;
35 static const double s_BipBopDuration = 0.07;
36 static const double s_BipBopVolume = 0.5;
37 static const double s_BipFrequency = 1500;
38 static const double s_BopFrequency = 500;
39 static const double s_HumFrequency = 150;
40 static const double s_HumVolume = 0.1;
41
42 class WrappedMockRealtimeAudioSource : public MockRealtimeAudioSource {
43 public:
44     WrappedMockRealtimeAudioSource(String&& deviceID, String&& name, String&& hashSalt)
45         : MockRealtimeAudioSource(WTFMove(deviceID), WTFMove(name), WTFMove(hashSalt))
46         , m_src(nullptr)
47     {
48     }
49
50     void start(GRefPtr<GstElement> src)
51     {
52         m_src = src;
53         if (m_streamFormat)
54             gst_app_src_set_caps(GST_APP_SRC(m_src.get()), m_streamFormat->caps());
55         MockRealtimeAudioSource::start();
56     }
57
58     void addHum(float amplitude, float frequency, float sampleRate, uint64_t start, float *p, uint64_t count)
59     {
60         float humPeriod = sampleRate / frequency;
61         for (uint64_t i = start, end = start + count; i < end; ++i) {
62             float a = amplitude * sin(i * s_Tau / humPeriod);
63             a += *p;
64             *p++ = a;
65         }
66     }
67
68     void render(Seconds delta)
69     {
70         ASSERT(m_src);
71
72         uint32_t totalFrameCount = GST_ROUND_UP_16(static_cast<size_t>(delta.seconds() * sampleRate()));
73         uint32_t frameCount = std::min(totalFrameCount, m_maximiumFrameCount);
74         while (frameCount) {
75             uint32_t bipBopStart = m_samplesRendered % m_bipBopBuffer.size();
76             uint32_t bipBopRemain = m_bipBopBuffer.size() - bipBopStart;
77             uint32_t bipBopCount = std::min(frameCount, bipBopRemain);
78
79             GstBuffer* buffer = gst_buffer_new_allocate(nullptr, bipBopCount * m_streamFormat->bytesPerFrame(), nullptr);
80             {
81                 auto map = GstMappedBuffer::create(buffer, GST_MAP_WRITE);
82
83                 if (!muted()) {
84                     memcpy(map->data(), &m_bipBopBuffer[bipBopStart], sizeof(float) * bipBopCount);
85                     addHum(s_HumVolume, s_HumFrequency, sampleRate(), m_samplesRendered, (float*)map->data(), bipBopCount);
86                 } else
87                     memset(map->data(), 0, sizeof(float) * bipBopCount);
88             }
89
90             gst_app_src_push_buffer(GST_APP_SRC(m_src.get()), buffer);
91             m_samplesRendered += bipBopCount;
92             totalFrameCount -= bipBopCount;
93             frameCount = std::min(totalFrameCount, m_maximiumFrameCount);
94         }
95     }
96
97     void settingsDidChange(OptionSet<RealtimeMediaSourceSettings::Flag> settings)
98     {
99         if (settings.contains(RealtimeMediaSourceSettings::Flag::SampleRate)) {
100             GstAudioInfo info;
101             auto rate = sampleRate();
102             size_t sampleCount = 2 * rate;
103
104             m_maximiumFrameCount = WTF::roundUpToPowerOfTwo(renderInterval().seconds() * sampleRate());
105             gst_audio_info_set_format(&info, GST_AUDIO_FORMAT_F32LE, rate, 1, nullptr);
106             m_streamFormat = GStreamerAudioStreamDescription(info);
107
108             if (m_src)
109                 gst_app_src_set_caps(GST_APP_SRC(m_src.get()), m_streamFormat->caps());
110
111             m_bipBopBuffer.grow(sampleCount);
112             m_bipBopBuffer.fill(0);
113
114             size_t bipBopSampleCount = ceil(s_BipBopDuration * rate);
115             size_t bipStart = 0;
116             size_t bopStart = rate;
117
118             addHum(s_BipBopVolume, s_BipFrequency, rate, 0, static_cast<float*>(m_bipBopBuffer.data() + bipStart), bipBopSampleCount);
119             addHum(s_BipBopVolume, s_BopFrequency, rate, 0, static_cast<float*>(m_bipBopBuffer.data() + bopStart), bipBopSampleCount);
120         }
121
122         MockRealtimeAudioSource::settingsDidChange(settings);
123     }
124
125     GRefPtr<GstElement> m_src;
126     Optional<GStreamerAudioStreamDescription> m_streamFormat;
127     Vector<float> m_bipBopBuffer;
128     uint32_t m_maximiumFrameCount;
129     uint64_t m_samplesEmitted { 0 };
130     uint64_t m_samplesRendered { 0 };
131 };
132
133 CaptureSourceOrError MockRealtimeAudioSource::create(String&& deviceID,
134     String&& name, String&& hashSalt, const MediaConstraints* constraints)
135 {
136     auto source = adoptRef(*new MockGStreamerAudioCaptureSource(WTFMove(deviceID), WTFMove(name), WTFMove(hashSalt)));
137
138     if (constraints && source->applyConstraints(*constraints))
139         return { };
140
141     return CaptureSourceOrError(WTFMove(source));
142 }
143
144 Optional<RealtimeMediaSource::ApplyConstraintsError> MockGStreamerAudioCaptureSource::applyConstraints(const MediaConstraints& constraints)
145 {
146     m_wrappedSource->applyConstraints(constraints);
147     return GStreamerAudioCaptureSource::applyConstraints(constraints);
148 }
149
150 void MockGStreamerAudioCaptureSource::applyConstraints(const MediaConstraints& constraints, ApplyConstraintsHandler&& completionHandler)
151 {
152     m_wrappedSource->applyConstraints(constraints, WTFMove(completionHandler));
153 }
154
155 MockGStreamerAudioCaptureSource::MockGStreamerAudioCaptureSource(String&& deviceID, String&& name, String&& hashSalt)
156     : GStreamerAudioCaptureSource(String { deviceID }, String { name }, String { hashSalt })
157     , m_wrappedSource(std::make_unique<WrappedMockRealtimeAudioSource>(WTFMove(deviceID), WTFMove(name), WTFMove(hashSalt)))
158 {
159     m_wrappedSource->addObserver(*this);
160 }
161
162 MockGStreamerAudioCaptureSource::~MockGStreamerAudioCaptureSource()
163 {
164     m_wrappedSource->removeObserver(*this);
165 }
166
167 void MockGStreamerAudioCaptureSource::stopProducingData()
168 {
169     m_wrappedSource->stop();
170
171     GStreamerAudioCaptureSource::stopProducingData();
172 }
173
174 void MockGStreamerAudioCaptureSource::startProducingData()
175 {
176     GStreamerAudioCaptureSource::startProducingData();
177     static_cast<WrappedMockRealtimeAudioSource*>(m_wrappedSource.get())->start(capturer()->source());
178 }
179
180 const RealtimeMediaSourceSettings& MockGStreamerAudioCaptureSource::settings()
181 {
182     return m_wrappedSource->settings();
183 }
184
185 const RealtimeMediaSourceCapabilities& MockGStreamerAudioCaptureSource::capabilities()
186 {
187     m_capabilities = m_wrappedSource->capabilities();
188     m_currentSettings = m_wrappedSource->settings();
189     return m_wrappedSource->capabilities();
190 }
191
192 void MockGStreamerAudioCaptureSource::captureFailed()
193 {
194     stop();
195     RealtimeMediaSource::captureFailed();
196 }
197
198 } // namespace WebCore
199
200 #endif // ENABLE(MEDIA_STREAM) && USE(LIBWEBRTC) && USE(GSTREAMER)