28
28
29
29
#include < libaudcore/i18n.h>
30
30
#include < libaudcore/plugin.h>
31
+ #include < libaudcore/ringbuf.h>
31
32
#include < libaudcore/runtime.h>
32
33
33
34
#if !PW_CHECK_VERSION(0, 3, 33)
34
- #define PW_KEY_NODE_RATE " node.rate"
35
+ #define PW_KEY_NODE_RATE " node.rate"
36
+ #endif
37
+
38
+ #if !PW_CHECK_VERSION(0, 3, 50)
39
+ static inline int pw_stream_get_time_n (struct pw_stream * stream,
40
+ struct pw_time * time, size_t size)
41
+ {
42
+ return pw_stream_get_time (stream, time );
43
+ }
44
+ #endif
45
+
46
+ #if !PW_CHECK_VERSION(1, 0, 4)
47
+ static uint64_t pw_stream_get_nsec (struct pw_stream * stream)
48
+ {
49
+ struct timespec ts;
50
+ clock_gettime (CLOCK_MONOTONIC, &ts);
51
+ return SPA_TIMESPEC_TO_NSEC (&ts);
52
+ }
35
53
#endif
36
54
37
55
class PipeWireOutput : public OutputPlugin
@@ -103,9 +121,8 @@ class PipeWireOutput : public OutputPlugin
103
121
int m_aud_format = 0 ;
104
122
int m_core_init_seq = 0 ;
105
123
106
- unsigned char * m_buffer = nullptr ;
107
- unsigned int m_buffer_at = 0 ;
108
- unsigned int m_buffer_size = 0 ;
124
+ RingBuf<unsigned char > m_buffer;
125
+ unsigned int m_pw_buffer_size = 0 ;
109
126
unsigned int m_frames = 0 ;
110
127
unsigned int m_stride = 0 ;
111
128
unsigned int m_rate = 0 ;
@@ -164,31 +181,57 @@ void PipeWireOutput::pause(bool pause)
164
181
165
182
int PipeWireOutput::get_delay ()
166
183
{
167
- return (m_buffer_at / m_stride + m_frames) * 1000 / m_rate;
184
+ int buff_time = ((m_buffer.len () / m_stride) * 1000 ) / m_rate;
185
+ int pw_buff_time = ((m_pw_buffer_size / m_stride) * 1000 ) / m_rate;
186
+ int time_diff = 0 ;
187
+ int add_delay = 0 ;
188
+
189
+ // Get time difference from updated time snapshot of the stream
190
+ struct pw_time time;
191
+ if (pw_stream_get_time_n (m_stream, &time , sizeof time ) == 0 )
192
+ {
193
+ time_diff = (pw_stream_get_nsec (m_stream) - time .now ) / SPA_NSEC_PER_MSEC;
194
+ time_diff = aud::clamp (time_diff, 0 , pw_buff_time);
195
+ add_delay = (time .buffered + time .queued ) * 1000 / m_rate;
196
+
197
+ if (time .rate .denom > 0 )
198
+ add_delay += time .delay * 1000 * time .rate .num / time .rate .denom ;
199
+ }
200
+
201
+ return buff_time + pw_buff_time - time_diff + add_delay;
168
202
}
169
203
170
204
void PipeWireOutput::drain ()
171
205
{
172
206
pw_thread_loop_lock (m_loop);
173
- if (m_buffer_at > 0 )
174
- pw_thread_loop_timed_wait (m_loop, 2 );
207
+
208
+ int buflen;
209
+ while ((buflen = m_buffer.len ()) > 0 )
210
+ {
211
+ pw_thread_loop_timed_wait (m_loop, 1 );
212
+ if (buflen <= m_buffer.len ())
213
+ {
214
+ AUDERR (" PipeWireOutput: buffer drain lock\n " );
215
+ break ;
216
+ }
217
+ }
175
218
176
219
pw_stream_flush (m_stream, true );
177
- pw_thread_loop_timed_wait (m_loop, 2 );
220
+ pw_thread_loop_timed_wait (m_loop, 1 ); // trigger on_drained() callback
178
221
pw_thread_loop_unlock (m_loop);
179
222
}
180
223
181
224
void PipeWireOutput::flush ()
182
225
{
183
226
pw_thread_loop_lock (m_loop);
184
- m_buffer_at = 0 ;
227
+ m_buffer. discard () ;
185
228
pw_thread_loop_unlock (m_loop);
186
229
pw_stream_flush (m_stream, false );
187
230
}
188
231
189
232
void PipeWireOutput::period_wait ()
190
233
{
191
- if (m_buffer_at != m_buffer_size )
234
+ if (m_buffer. space () )
192
235
return ;
193
236
194
237
pw_thread_loop_lock (m_loop);
@@ -200,12 +243,11 @@ int PipeWireOutput::write_audio(const void * data, int length)
200
243
{
201
244
pw_thread_loop_lock (m_loop);
202
245
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;
246
+ length = aud::min (length, m_buffer.space ());
247
+ m_buffer.copy_in (static_cast <const unsigned char *>(data), length);
206
248
207
249
pw_thread_loop_unlock (m_loop);
208
- return size ;
250
+ return length ;
209
251
}
210
252
211
253
void PipeWireOutput::close_audio ()
@@ -248,11 +290,7 @@ void PipeWireOutput::close_audio()
248
290
m_loop = nullptr ;
249
291
}
250
292
251
- if (m_buffer)
252
- {
253
- delete[] m_buffer;
254
- m_buffer = nullptr ;
255
- }
293
+ m_buffer.destroy ();
256
294
}
257
295
258
296
bool PipeWireOutput::open_audio (int format, int rate, int channels, String & error)
@@ -343,10 +381,9 @@ bool PipeWireOutput::init_core()
343
381
return false ;
344
382
}
345
383
384
+ m_frames = aud_get_int (" output_buffer_size" ) * m_rate / 1000 ;
346
385
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];
386
+ m_buffer.alloc (m_frames * m_stride);
350
387
351
388
return true ;
352
389
}
@@ -490,7 +527,7 @@ void PipeWireOutput::on_process(void * data)
490
527
struct spa_buffer * buf;
491
528
void * dst;
492
529
493
- if (!o->m_buffer_at )
530
+ if (!o->m_buffer . len () )
494
531
{
495
532
pw_thread_loop_signal (o->m_loop , false );
496
533
return ;
@@ -510,13 +547,12 @@ void PipeWireOutput::on_process(void * data)
510
547
return ;
511
548
}
512
549
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 );
550
+ auto size = aud::min<uint32_t >(buf->datas [0 ].maxsize , o->m_buffer .len ());
551
+ o->m_pw_buffer_size = size;
552
+ o->m_buffer .move_out (static_cast <unsigned char *>(dst), size);
517
553
518
554
b->buffer ->datas [0 ].chunk ->offset = 0 ;
519
- b->buffer ->datas [0 ].chunk ->size = o-> m_buffer_size ;
555
+ b->buffer ->datas [0 ].chunk ->size = size ;
520
556
b->buffer ->datas [0 ].chunk ->stride = o->m_stride ;
521
557
522
558
pw_stream_queue_buffer (o->m_stream , b);
@@ -570,15 +606,18 @@ void PipeWireOutput::set_channel_map(struct spa_audio_info_raw * info, int chann
570
606
info->position [8 ] = SPA_AUDIO_CHANNEL_RC;
571
607
// Fall through
572
608
case 8 :
609
+ case 7 :
573
610
info->position [6 ] = SPA_AUDIO_CHANNEL_FLC;
574
611
info->position [7 ] = SPA_AUDIO_CHANNEL_FRC;
575
612
// Fall through
576
613
case 6 :
614
+ case 5 :
577
615
info->position [4 ] = SPA_AUDIO_CHANNEL_RL;
578
616
info->position [5 ] = SPA_AUDIO_CHANNEL_RR;
579
617
// Fall through
580
618
case 4 :
581
- info->position [3 ] = SPA_AUDIO_CHANNEL_LFE;
619
+ if (channels != 5 && channels != 7 )
620
+ info->position [3 ] = SPA_AUDIO_CHANNEL_LFE;
582
621
// Fall through
583
622
case 3 :
584
623
info->position [2 ] = SPA_AUDIO_CHANNEL_FC;
0 commit comments