Skip to content

Commit c44c41e

Browse files
pipewire: Revise plugin code. Closes: #1401
- Use RingBuf from audcore - Respect output_buffer_size setting - Improve get_delay() and drain() functions - Add support for 5 and 7 channels Co-authored-by: Thomas Lange <[email protected]>
1 parent d306f1a commit c44c41e

File tree

1 file changed

+53
-27
lines changed

1 file changed

+53
-27
lines changed

src/pipewire/pipewire.cc

+53-27
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828

2929
#include <libaudcore/i18n.h>
3030
#include <libaudcore/plugin.h>
31+
#include <libaudcore/ringbuf.h>
3132
#include <libaudcore/runtime.h>
3233

3334
#if !PW_CHECK_VERSION(0, 3, 33)
@@ -103,8 +104,9 @@ class PipeWireOutput : public OutputPlugin
103104
int m_aud_format = 0;
104105
int m_core_init_seq = 0;
105106

106-
unsigned char * m_buffer = nullptr;
107-
unsigned int m_buffer_at = 0;
107+
timespec m_time {};
108+
109+
RingBuf<unsigned char> m_buffer;
108110
unsigned int m_buffer_size = 0;
109111
unsigned int m_frames = 0;
110112
unsigned int m_stride = 0;
@@ -159,36 +161,61 @@ void PipeWireOutput::pause(bool pause)
159161
{
160162
pw_thread_loop_lock(m_loop);
161163
pw_stream_set_active(m_stream, !pause);
164+
clock_gettime(CLOCK_REALTIME, &m_time);
162165
pw_thread_loop_unlock(m_loop);
163166
}
164167

165168
int PipeWireOutput::get_delay()
166169
{
167-
return (m_buffer_at / m_stride + m_frames) * 1000 / m_rate;
170+
int buff_time = (((m_buffer.len() + m_buffer_size) / m_stride) * 1000) / m_rate;
171+
172+
// Get time difference from last buffer fill
173+
timespec time_now {};
174+
clock_gettime(CLOCK_REALTIME, &time_now);
175+
176+
int time_diff =
177+
(((time_now.tv_sec - m_time.tv_sec) * 1000000000) +
178+
(time_now.tv_nsec - m_time.tv_nsec)) / 1000000;
179+
180+
if (time_diff < 0)
181+
time_diff = 0;
182+
if (time_diff > buff_time)
183+
time_diff = buff_time;
184+
185+
return buff_time - time_diff;
168186
}
169187

170188
void PipeWireOutput::drain()
171189
{
172190
pw_thread_loop_lock(m_loop);
173-
if (m_buffer_at > 0)
174-
pw_thread_loop_timed_wait(m_loop, 2);
191+
192+
int buflen;
193+
while ((buflen = m_buffer.len()) > 0)
194+
{
195+
pw_thread_loop_timed_wait(m_loop, 1);
196+
if (buflen <= m_buffer.len())
197+
{
198+
AUDERR("PipeWireOutput: buffer drain lock\n");
199+
break;
200+
}
201+
}
175202

176203
pw_stream_flush(m_stream, true);
177-
pw_thread_loop_timed_wait(m_loop, 2);
204+
pw_thread_loop_timed_wait(m_loop, 1);
178205
pw_thread_loop_unlock(m_loop);
179206
}
180207

181208
void PipeWireOutput::flush()
182209
{
183210
pw_thread_loop_lock(m_loop);
184-
m_buffer_at = 0;
211+
m_buffer.discard();
185212
pw_thread_loop_unlock(m_loop);
186213
pw_stream_flush(m_stream, false);
187214
}
188215

189216
void PipeWireOutput::period_wait()
190217
{
191-
if (m_buffer_at != m_buffer_size)
218+
if (m_buffer.space())
192219
return;
193220

194221
pw_thread_loop_lock(m_loop);
@@ -200,12 +227,11 @@ int PipeWireOutput::write_audio(const void * data, int length)
200227
{
201228
pw_thread_loop_lock(m_loop);
202229

203-
auto size = aud::min<size_t>(m_buffer_size - m_buffer_at, length);
204-
memcpy(m_buffer + m_buffer_at, data, size);
205-
m_buffer_at += size;
230+
length = aud::min(length, m_buffer.space());
231+
m_buffer.copy_in(static_cast<const unsigned char *>(data), length);
206232

207233
pw_thread_loop_unlock(m_loop);
208-
return size;
234+
return length;
209235
}
210236

211237
void PipeWireOutput::close_audio()
@@ -248,11 +274,7 @@ void PipeWireOutput::close_audio()
248274
m_loop = nullptr;
249275
}
250276

251-
if (m_buffer)
252-
{
253-
delete[] m_buffer;
254-
m_buffer = nullptr;
255-
}
277+
m_buffer.destroy();
256278
}
257279

258280
bool PipeWireOutput::open_audio(int format, int rate, int channels, String & error)
@@ -267,6 +289,7 @@ bool PipeWireOutput::open_audio(int format, int rate, int channels, String & err
267289
return false;
268290
}
269291

292+
clock_gettime(CLOCK_REALTIME, &m_time);
270293
return true;
271294
}
272295

@@ -343,10 +366,9 @@ bool PipeWireOutput::init_core()
343366
return false;
344367
}
345368

369+
m_frames = aud_get_int("output_buffer_size") * m_rate / 1000;
346370
m_stride = FMT_SIZEOF(m_aud_format) * m_channels;
347-
m_frames = aud::clamp<int>(64, ceilf(2048 * m_rate / 48000.0f), 8192);
348-
m_buffer_size = m_frames * m_stride;
349-
m_buffer = new unsigned char[m_buffer_size];
371+
m_buffer.alloc(m_frames * m_stride);
350372

351373
return true;
352374
}
@@ -490,7 +512,9 @@ void PipeWireOutput::on_process(void * data)
490512
struct spa_buffer * buf;
491513
void * dst;
492514

493-
if (!o->m_buffer_at)
515+
clock_gettime(CLOCK_REALTIME, &o->m_time);
516+
517+
if (!o->m_buffer.len())
494518
{
495519
pw_thread_loop_signal(o->m_loop, false);
496520
return;
@@ -510,13 +534,12 @@ void PipeWireOutput::on_process(void * data)
510534
return;
511535
}
512536

513-
auto size = aud::min<uint32_t>(buf->datas[0].maxsize, o->m_buffer_at);
514-
memcpy(dst, o->m_buffer, size);
515-
o->m_buffer_at -= size;
516-
memmove(o->m_buffer, o->m_buffer + size, o->m_buffer_at);
537+
auto size = aud::min<uint32_t>(buf->datas[0].maxsize, o->m_buffer.len());
538+
o->m_buffer_size = size;
539+
o->m_buffer.move_out(static_cast<unsigned char *>(dst), size);
517540

518541
b->buffer->datas[0].chunk->offset = 0;
519-
b->buffer->datas[0].chunk->size = o->m_buffer_size;
542+
b->buffer->datas[0].chunk->size = size;
520543
b->buffer->datas[0].chunk->stride = o->m_stride;
521544

522545
pw_stream_queue_buffer(o->m_stream, b);
@@ -570,15 +593,18 @@ void PipeWireOutput::set_channel_map(struct spa_audio_info_raw * info, int chann
570593
info->position[8] = SPA_AUDIO_CHANNEL_RC;
571594
// Fall through
572595
case 8:
596+
case 7:
573597
info->position[6] = SPA_AUDIO_CHANNEL_FLC;
574598
info->position[7] = SPA_AUDIO_CHANNEL_FRC;
575599
// Fall through
576600
case 6:
601+
case 5:
577602
info->position[4] = SPA_AUDIO_CHANNEL_RL;
578603
info->position[5] = SPA_AUDIO_CHANNEL_RR;
579604
// Fall through
580605
case 4:
581-
info->position[3] = SPA_AUDIO_CHANNEL_LFE;
606+
if (channels != 5 && channels != 7)
607+
info->position[3] = SPA_AUDIO_CHANNEL_LFE;
582608
// Fall through
583609
case 3:
584610
info->position[2] = SPA_AUDIO_CHANNEL_FC;

0 commit comments

Comments
 (0)