1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::{borrow::Cow, future::Future, sync::atomic};
4
5use glib::{subclass::prelude::*, translate::*};
6
7use super::prelude::*;
8use crate::{
9 prelude::*, Element, Event, PadTemplate, QueryRef, StateChange, StateChangeError,
10 StateChangeReturn, StateChangeSuccess,
11};
12
13#[derive(Debug, Clone)]
14pub struct ElementMetadata {
15 long_name: Cow<'static, str>,
16 classification: Cow<'static, str>,
17 description: Cow<'static, str>,
18 author: Cow<'static, str>,
19 additional: Cow<'static, [(Cow<'static, str>, Cow<'static, str>)]>,
20}
21
22impl ElementMetadata {
23 pub fn new(long_name: &str, classification: &str, description: &str, author: &str) -> Self {
24 Self {
25 long_name: Cow::Owned(long_name.into()),
26 classification: Cow::Owned(classification.into()),
27 description: Cow::Owned(description.into()),
28 author: Cow::Owned(author.into()),
29 additional: Cow::Borrowed(&[]),
30 }
31 }
32
33 pub fn with_additional(
34 long_name: &str,
35 classification: &str,
36 description: &str,
37 author: &str,
38 additional: &[(&str, &str)],
39 ) -> Self {
40 Self {
41 long_name: Cow::Owned(long_name.into()),
42 classification: Cow::Owned(classification.into()),
43 description: Cow::Owned(description.into()),
44 author: Cow::Owned(author.into()),
45 additional: additional
46 .iter()
47 .copied()
48 .map(|(key, value)| (Cow::Owned(key.into()), Cow::Owned(value.into())))
49 .collect(),
50 }
51 }
52
53 pub const fn with_cow(
54 long_name: Cow<'static, str>,
55 classification: Cow<'static, str>,
56 description: Cow<'static, str>,
57 author: Cow<'static, str>,
58 additional: Cow<'static, [(Cow<'static, str>, Cow<'static, str>)]>,
59 ) -> Self {
60 Self {
61 long_name,
62 classification,
63 description,
64 author,
65 additional,
66 }
67 }
68}
69
70pub trait ElementImpl: ElementImplExt + GstObjectImpl + Send + Sync {
71 fn metadata() -> Option<&'static ElementMetadata> {
72 None
73 }
74
75 fn pad_templates() -> &'static [PadTemplate] {
76 &[]
77 }
78
79 fn change_state(
80 &self,
81 transition: StateChange,
82 ) -> Result<StateChangeSuccess, StateChangeError> {
83 self.parent_change_state(transition)
84 }
85
86 fn request_new_pad(
87 &self,
88 templ: &crate::PadTemplate,
89 name: Option<&str>,
90 caps: Option<&crate::Caps>,
91 ) -> Option<crate::Pad> {
92 self.parent_request_new_pad(templ, name, caps)
93 }
94
95 fn release_pad(&self, pad: &crate::Pad) {
96 self.parent_release_pad(pad)
97 }
98
99 fn send_event(&self, event: Event) -> bool {
100 self.parent_send_event(event)
101 }
102
103 fn query(&self, query: &mut QueryRef) -> bool {
104 self.parent_query(query)
105 }
106
107 fn set_context(&self, context: &crate::Context) {
108 self.parent_set_context(context)
109 }
110
111 fn set_clock(&self, clock: Option<&crate::Clock>) -> bool {
112 self.parent_set_clock(clock)
113 }
114
115 fn provide_clock(&self) -> Option<crate::Clock> {
116 self.parent_provide_clock()
117 }
118
119 fn post_message(&self, msg: crate::Message) -> bool {
120 self.parent_post_message(msg)
121 }
122}
123
124mod sealed {
125 pub trait Sealed {}
126 impl<T: super::ElementImplExt> Sealed for T {}
127}
128
129pub trait ElementImplExt: sealed::Sealed + ObjectSubclass {
130 fn parent_change_state(
131 &self,
132 transition: StateChange,
133 ) -> Result<StateChangeSuccess, StateChangeError> {
134 unsafe {
135 let data = Self::type_data();
136 let parent_class = data.as_ref().parent_class() as *mut ffi::GstElementClass;
137
138 let f = (*parent_class)
139 .change_state
140 .expect("Missing parent function `change_state`");
141 try_from_glib(f(
142 self.obj().unsafe_cast_ref::<Element>().to_glib_none().0,
143 transition.into_glib(),
144 ))
145 }
146 }
147
148 fn parent_request_new_pad(
149 &self,
150 templ: &crate::PadTemplate,
151 name: Option<&str>,
152 caps: Option<&crate::Caps>,
153 ) -> Option<crate::Pad> {
154 unsafe {
155 let data = Self::type_data();
156 let parent_class = data.as_ref().parent_class() as *mut ffi::GstElementClass;
157
158 (*parent_class)
159 .request_new_pad
160 .map(|f| {
161 from_glib_none(f(
162 self.obj().unsafe_cast_ref::<Element>().to_glib_none().0,
163 templ.to_glib_none().0,
164 name.to_glib_full(),
165 caps.to_glib_none().0,
166 ))
167 })
168 .unwrap_or(None)
169 }
170 }
171
172 fn parent_release_pad(&self, pad: &crate::Pad) {
173 unsafe {
174 let data = Self::type_data();
175 let parent_class = data.as_ref().parent_class() as *mut ffi::GstElementClass;
176
177 (*parent_class)
178 .release_pad
179 .map(|f| {
180 f(
181 self.obj().unsafe_cast_ref::<Element>().to_glib_none().0,
182 pad.to_glib_none().0,
183 )
184 })
185 .unwrap_or(())
186 }
187 }
188
189 fn parent_send_event(&self, event: Event) -> bool {
190 unsafe {
191 let data = Self::type_data();
192 let parent_class = data.as_ref().parent_class() as *mut ffi::GstElementClass;
193
194 (*parent_class)
195 .send_event
196 .map(|f| {
197 from_glib(f(
198 self.obj().unsafe_cast_ref::<Element>().to_glib_none().0,
199 event.into_glib_ptr(),
200 ))
201 })
202 .unwrap_or(false)
203 }
204 }
205
206 fn parent_query(&self, query: &mut QueryRef) -> bool {
207 unsafe {
208 let data = Self::type_data();
209 let parent_class = data.as_ref().parent_class() as *mut ffi::GstElementClass;
210
211 (*parent_class)
212 .query
213 .map(|f| {
214 from_glib(f(
215 self.obj().unsafe_cast_ref::<Element>().to_glib_none().0,
216 query.as_mut_ptr(),
217 ))
218 })
219 .unwrap_or(false)
220 }
221 }
222
223 fn parent_set_context(&self, context: &crate::Context) {
224 unsafe {
225 let data = Self::type_data();
226 let parent_class = data.as_ref().parent_class() as *mut ffi::GstElementClass;
227
228 (*parent_class)
229 .set_context
230 .map(|f| {
231 f(
232 self.obj().unsafe_cast_ref::<Element>().to_glib_none().0,
233 context.to_glib_none().0,
234 )
235 })
236 .unwrap_or(())
237 }
238 }
239
240 fn parent_set_clock(&self, clock: Option<&crate::Clock>) -> bool {
241 unsafe {
242 let data = Self::type_data();
243 let parent_class = data.as_ref().parent_class() as *mut ffi::GstElementClass;
244
245 (*parent_class)
246 .set_clock
247 .map(|f| {
248 from_glib(f(
249 self.obj().unsafe_cast_ref::<Element>().to_glib_none().0,
250 clock.to_glib_none().0,
251 ))
252 })
253 .unwrap_or(false)
254 }
255 }
256
257 fn parent_provide_clock(&self) -> Option<crate::Clock> {
258 unsafe {
259 let data = Self::type_data();
260 let parent_class = data.as_ref().parent_class() as *mut ffi::GstElementClass;
261
262 (*parent_class)
263 .provide_clock
264 .map(|f| {
265 from_glib_none(f(self.obj().unsafe_cast_ref::<Element>().to_glib_none().0))
266 })
267 .unwrap_or(None)
268 }
269 }
270
271 fn parent_post_message(&self, msg: crate::Message) -> bool {
272 unsafe {
273 let data = Self::type_data();
274 let parent_class = data.as_ref().parent_class() as *mut ffi::GstElementClass;
275
276 if let Some(f) = (*parent_class).post_message {
277 from_glib(f(
278 self.obj().unsafe_cast_ref::<Element>().to_glib_none().0,
279 msg.into_glib_ptr(),
280 ))
281 } else {
282 false
283 }
284 }
285 }
286
287 #[inline(never)]
288 fn panicked(&self) -> &atomic::AtomicBool {
289 self.instance_data::<atomic::AtomicBool>(crate::Element::static_type())
290 .expect("instance not initialized correctly")
291 }
292
293 fn catch_panic<R, F: FnOnce(&Self) -> R, G: FnOnce() -> R>(&self, fallback: G, f: F) -> R {
294 panic_to_error!(self, fallback(), { f(self) })
295 }
296
297 fn catch_panic_future<R, F: FnOnce() -> R, G: Future<Output = R>>(
298 &self,
299 fallback: F,
300 fut: G,
301 ) -> CatchPanic<Self, F, G> {
302 CatchPanic {
303 self_: self.ref_counted().downgrade(),
304 fallback: Some(fallback),
305 fut,
306 }
307 }
308
309 fn catch_panic_pad_function<R, F: FnOnce(&Self) -> R, G: FnOnce() -> R>(
310 parent: Option<&crate::Object>,
311 fallback: G,
312 f: F,
313 ) -> R {
314 let element = parent.unwrap().dynamic_cast_ref::<Self::Type>().unwrap();
315 let imp = element.imp();
316
317 panic_to_error!(imp, fallback(), { f(imp) })
318 }
319
320 fn post_error_message(&self, msg: crate::ErrorMessage) {
321 unsafe {
322 self.obj()
323 .unsafe_cast_ref::<Element>()
324 .post_error_message(msg)
325 }
326 }
327}
328
329impl<T: ElementImpl> ElementImplExt for T {}
330
331pin_project_lite::pin_project! {
332 #[must_use = "futures do nothing unless you `.await` or poll them"]
333 pub struct CatchPanic<T: glib::subclass::types::ObjectSubclass, F, G> {
334 self_: glib::subclass::ObjectImplWeakRef<T>,
335 fallback: Option<F>,
336 #[pin]
337 fut: G,
338 }
339}
340
341impl<R, T: ElementImpl, F: FnOnce() -> R, G: Future<Output = R>> Future for CatchPanic<T, F, G> {
342 type Output = R;
343
344 fn poll(
345 self: std::pin::Pin<&mut Self>,
346 cx: &mut std::task::Context<'_>,
347 ) -> std::task::Poll<Self::Output> {
348 let this = self.project();
349
350 let Some(self_) = this.self_.upgrade() else {
351 return std::task::Poll::Ready((this
352 .fallback
353 .take()
354 .expect("Future polled after resolving"))(
355 ));
356 };
357
358 panic_to_error!(
359 &*self_,
360 std::task::Poll::Ready(this.fallback.take().expect("Future polled after resolving")()),
361 {
362 let fut = this.fut;
363 fut.poll(cx)
364 }
365 )
366 }
367}
368
369unsafe impl<T: ElementImpl> IsSubclassable<T> for Element {
370 fn class_init(klass: &mut glib::Class<Self>) {
371 Self::parent_class_init::<T>(klass);
372 let klass = klass.as_mut();
373 klass.change_state = Some(element_change_state::<T>);
374 klass.request_new_pad = Some(element_request_new_pad::<T>);
375 klass.release_pad = Some(element_release_pad::<T>);
376 klass.send_event = Some(element_send_event::<T>);
377 klass.query = Some(element_query::<T>);
378 klass.set_context = Some(element_set_context::<T>);
379 klass.set_clock = Some(element_set_clock::<T>);
380 klass.provide_clock = Some(element_provide_clock::<T>);
381 klass.post_message = Some(element_post_message::<T>);
382
383 unsafe {
384 for pad_template in T::pad_templates() {
385 ffi::gst_element_class_add_pad_template(klass, pad_template.to_glib_none().0);
386 }
387
388 if let Some(metadata) = T::metadata() {
389 ffi::gst_element_class_set_metadata(
390 klass,
391 metadata.long_name.to_glib_none().0,
392 metadata.classification.to_glib_none().0,
393 metadata.description.to_glib_none().0,
394 metadata.author.to_glib_none().0,
395 );
396
397 for (key, value) in &metadata.additional[..] {
398 ffi::gst_element_class_add_metadata(
399 klass,
400 key.to_glib_none().0,
401 value.to_glib_none().0,
402 );
403 }
404 }
405 }
406 }
407
408 fn instance_init(instance: &mut glib::subclass::InitializingObject<T>) {
409 Self::parent_instance_init::<T>(instance);
410
411 instance.set_instance_data(Self::static_type(), atomic::AtomicBool::new(false));
412 }
413}
414
415unsafe extern "C" fn element_change_state<T: ElementImpl>(
416 ptr: *mut ffi::GstElement,
417 transition: ffi::GstStateChange,
418) -> ffi::GstStateChangeReturn {
419 let instance: &::Instance = &*(ptr as *mut T::Instance);
420 let imp: &T = instance.imp();
421
422 // *Never* fail downwards state changes, this causes bugs in GStreamer
423 // and leads to crashes and deadlocks.
424 let transition: StateChange = from_glib(val:transition);
425 let fallback: StateChangeReturn = match transition {
426 StateChange::PlayingToPaused | StateChange::PausedToReady | StateChange::ReadyToNull => {
427 StateChangeReturn::Success
428 }
429 _ => StateChangeReturn::Failure,
430 };
431
432 panic_to_error!(imp, fallback, { imp.change_state(transition).into() }).into_glib()
433}
434
435unsafe extern "C" fn element_request_new_pad<T: ElementImpl>(
436 ptr: *mut ffi::GstElement,
437 templ: *mut ffi::GstPadTemplate,
438 name: *const libc::c_char,
439 caps: *const ffi::GstCaps,
440) -> *mut ffi::GstPad {
441 let instance = &*(ptr as *mut T::Instance);
442 let imp = instance.imp();
443
444 let caps = Option::<crate::Caps>::from_glib_borrow(caps);
445 let name = Option::<String>::from_glib_none(name);
446
447 // XXX: This is effectively unsafe but the best we can do
448 // See https://bugzilla.gnome.org/show_bug.cgi?id=791193
449 let pad = panic_to_error!(imp, None, {
450 imp.request_new_pad(
451 &from_glib_borrow(templ),
452 name.as_deref(),
453 caps.as_ref().as_ref(),
454 )
455 });
456
457 // Ensure that the pad is owned by the element now, if a pad was returned
458 if let Some(ref pad) = pad {
459 assert_eq!(
460 pad.parent().as_ref(),
461 Some(&*crate::Object::from_glib_borrow(
462 ptr as *mut ffi::GstObject
463 ))
464 );
465 }
466
467 pad.to_glib_none().0
468}
469
470unsafe extern "C" fn element_release_pad<T: ElementImpl>(
471 ptr: *mut ffi::GstElement,
472 pad: *mut ffi::GstPad,
473) {
474 let instance: &::Instance = &*(ptr as *mut T::Instance);
475 let imp: &T = instance.imp();
476
477 // If we get a floating reference passed simply return here. It can't be stored inside this
478 // element, and if we continued to use it we would take ownership of this floating reference.
479 if glib::gobject_ffi::g_object_is_floating(object:pad as *mut glib::gobject_ffi::GObject)
480 != glib::ffi::GFALSE
481 {
482 return;
483 }
484
485 panic_to_error!(imp, (), { imp.release_pad(&from_glib_none(pad)) })
486}
487
488unsafe extern "C" fn element_send_event<T: ElementImpl>(
489 ptr: *mut ffi::GstElement,
490 event: *mut ffi::GstEvent,
491) -> glib::ffi::gboolean {
492 let instance: &::Instance = &*(ptr as *mut T::Instance);
493 let imp: &T = instance.imp();
494
495 panic_to_error!(imp, false, { imp.send_event(from_glib_full(event)) }).into_glib()
496}
497
498unsafe extern "C" fn element_query<T: ElementImpl>(
499 ptr: *mut ffi::GstElement,
500 query: *mut ffi::GstQuery,
501) -> glib::ffi::gboolean {
502 let instance: &::Instance = &*(ptr as *mut T::Instance);
503 let imp: &T = instance.imp();
504 let query: &mut QueryRef = QueryRef::from_mut_ptr(query);
505
506 panic_to_error!(imp, false, { imp.query(query) }).into_glib()
507}
508
509unsafe extern "C" fn element_set_context<T: ElementImpl>(
510 ptr: *mut ffi::GstElement,
511 context: *mut ffi::GstContext,
512) {
513 let instance: &::Instance = &*(ptr as *mut T::Instance);
514 let imp: &T = instance.imp();
515
516 panic_to_error!(imp, (), { imp.set_context(&from_glib_borrow(context)) })
517}
518
519unsafe extern "C" fn element_set_clock<T: ElementImpl>(
520 ptr: *mut ffi::GstElement,
521 clock: *mut ffi::GstClock,
522) -> glib::ffi::gboolean {
523 let instance: &::Instance = &*(ptr as *mut T::Instance);
524 let imp: &T = instance.imp();
525
526 let clock: Borrowed> = Option::<crate::Clock>::from_glib_borrow(_ptr:clock);
527
528 panic_to_error!(imp, false, { imp.set_clock(clock.as_ref().as_ref()) }).into_glib()
529}
530
531unsafe extern "C" fn element_provide_clock<T: ElementImpl>(
532 ptr: *mut ffi::GstElement,
533) -> *mut ffi::GstClock {
534 let instance: &::Instance = &*(ptr as *mut T::Instance);
535 let imp: &T = instance.imp();
536
537 panic_to_error!(imp, None, { imp.provide_clock() }).into_glib_ptr()
538}
539
540unsafe extern "C" fn element_post_message<T: ElementImpl>(
541 ptr: *mut ffi::GstElement,
542 msg: *mut ffi::GstMessage,
543) -> glib::ffi::gboolean {
544 let instance: &::Instance = &*(ptr as *mut T::Instance);
545 let imp: &T = instance.imp();
546
547 // Can't catch panics here as posting the error message would cause
548 // this code to be called again recursively forever.
549 imp.post_message(msg:from_glib_full(ptr:msg)).into_glib()
550}
551
552#[cfg(test)]
553mod tests {
554 use std::sync::atomic;
555
556 use super::*;
557 use crate::ElementFactory;
558
559 pub mod imp {
560 use super::*;
561
562 pub struct TestElement {
563 pub(super) srcpad: crate::Pad,
564 pub(super) sinkpad: crate::Pad,
565 pub(super) n_buffers: atomic::AtomicU32,
566 pub(super) reached_playing: atomic::AtomicBool,
567 }
568
569 impl TestElement {
570 fn sink_chain(
571 &self,
572 _pad: &crate::Pad,
573 buffer: crate::Buffer,
574 ) -> Result<crate::FlowSuccess, crate::FlowError> {
575 self.n_buffers.fetch_add(1, atomic::Ordering::SeqCst);
576 self.srcpad.push(buffer)
577 }
578
579 fn sink_event(&self, _pad: &crate::Pad, event: crate::Event) -> bool {
580 self.srcpad.push_event(event)
581 }
582
583 fn sink_query(&self, _pad: &crate::Pad, query: &mut crate::QueryRef) -> bool {
584 self.srcpad.peer_query(query)
585 }
586
587 fn src_event(&self, _pad: &crate::Pad, event: crate::Event) -> bool {
588 self.sinkpad.push_event(event)
589 }
590
591 fn src_query(&self, _pad: &crate::Pad, query: &mut crate::QueryRef) -> bool {
592 self.sinkpad.peer_query(query)
593 }
594 }
595
596 #[glib::object_subclass]
597 impl ObjectSubclass for TestElement {
598 const NAME: &'static str = "TestElement";
599 type Type = super::TestElement;
600 type ParentType = Element;
601
602 fn with_class(klass: &Self::Class) -> Self {
603 let templ = klass.pad_template("sink").unwrap();
604 let sinkpad = crate::Pad::builder_from_template(&templ)
605 .chain_function(|pad, parent, buffer| {
606 TestElement::catch_panic_pad_function(
607 parent,
608 || Err(crate::FlowError::Error),
609 |identity| identity.sink_chain(pad, buffer),
610 )
611 })
612 .event_function(|pad, parent, event| {
613 TestElement::catch_panic_pad_function(
614 parent,
615 || false,
616 |identity| identity.sink_event(pad, event),
617 )
618 })
619 .query_function(|pad, parent, query| {
620 TestElement::catch_panic_pad_function(
621 parent,
622 || false,
623 |identity| identity.sink_query(pad, query),
624 )
625 })
626 .build();
627
628 let templ = klass.pad_template("src").unwrap();
629 let srcpad = crate::Pad::builder_from_template(&templ)
630 .event_function(|pad, parent, event| {
631 TestElement::catch_panic_pad_function(
632 parent,
633 || false,
634 |identity| identity.src_event(pad, event),
635 )
636 })
637 .query_function(|pad, parent, query| {
638 TestElement::catch_panic_pad_function(
639 parent,
640 || false,
641 |identity| identity.src_query(pad, query),
642 )
643 })
644 .build();
645
646 Self {
647 n_buffers: atomic::AtomicU32::new(0),
648 reached_playing: atomic::AtomicBool::new(false),
649 srcpad,
650 sinkpad,
651 }
652 }
653 }
654
655 impl ObjectImpl for TestElement {
656 fn constructed(&self) {
657 self.parent_constructed();
658
659 let element = self.obj();
660 element.add_pad(&self.sinkpad).unwrap();
661 element.add_pad(&self.srcpad).unwrap();
662 }
663 }
664
665 impl GstObjectImpl for TestElement {}
666
667 impl ElementImpl for TestElement {
668 fn metadata() -> Option<&'static ElementMetadata> {
669 use glib::once_cell::sync::Lazy;
670 static ELEMENT_METADATA: Lazy<ElementMetadata> = Lazy::new(|| {
671 ElementMetadata::new(
672 "Test Element",
673 "Generic",
674 "Does nothing",
675 "Sebastian Dröge <sebastian@centricular.com>",
676 )
677 });
678
679 Some(&*ELEMENT_METADATA)
680 }
681
682 fn pad_templates() -> &'static [PadTemplate] {
683 use glib::once_cell::sync::Lazy;
684 static PAD_TEMPLATES: Lazy<Vec<PadTemplate>> = Lazy::new(|| {
685 let caps = crate::Caps::new_any();
686 vec![
687 PadTemplate::new(
688 "src",
689 crate::PadDirection::Src,
690 crate::PadPresence::Always,
691 &caps,
692 )
693 .unwrap(),
694 PadTemplate::new(
695 "sink",
696 crate::PadDirection::Sink,
697 crate::PadPresence::Always,
698 &caps,
699 )
700 .unwrap(),
701 ]
702 });
703
704 PAD_TEMPLATES.as_ref()
705 }
706
707 fn change_state(
708 &self,
709 transition: crate::StateChange,
710 ) -> Result<crate::StateChangeSuccess, crate::StateChangeError> {
711 let res = self.parent_change_state(transition)?;
712
713 if transition == crate::StateChange::PausedToPlaying {
714 self.reached_playing.store(true, atomic::Ordering::SeqCst);
715 }
716
717 Ok(res)
718 }
719 }
720 }
721
722 glib::wrapper! {
723 pub struct TestElement(ObjectSubclass<imp::TestElement>) @extends Element, crate::Object;
724 }
725
726 impl TestElement {
727 pub fn new(name: Option<&str>) -> Self {
728 glib::Object::builder().property("name", name).build()
729 }
730 }
731
732 #[test]
733 fn test_element_subclass() {
734 crate::init().unwrap();
735
736 let element = TestElement::new(Some("test"));
737
738 assert_eq!(element.name(), "test");
739
740 assert_eq!(
741 element.metadata(crate::ELEMENT_METADATA_LONGNAME),
742 Some("Test Element")
743 );
744
745 let pipeline = crate::Pipeline::new();
746 let src = ElementFactory::make("fakesrc")
747 .property("num-buffers", 100i32)
748 .build()
749 .unwrap();
750 let sink = ElementFactory::make("fakesink").build().unwrap();
751
752 pipeline
753 .add_many([&src, element.upcast_ref(), &sink])
754 .unwrap();
755 Element::link_many([&src, element.upcast_ref(), &sink]).unwrap();
756
757 pipeline.set_state(crate::State::Playing).unwrap();
758 let bus = pipeline.bus().unwrap();
759
760 let eos = bus.timed_pop_filtered(crate::ClockTime::NONE, &[crate::MessageType::Eos]);
761 assert!(eos.is_some());
762
763 pipeline.set_state(crate::State::Null).unwrap();
764
765 let imp = element.imp();
766 assert_eq!(imp.n_buffers.load(atomic::Ordering::SeqCst), 100);
767 assert!(imp.reached_playing.load(atomic::Ordering::SeqCst));
768 }
769}
770