objc2-av-foundation 0.3.2

Bindings to the AVFoundation framework
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
//! This file has been automatically generated by `objc2`'s `header-translator`.
//! DO NOT EDIT
use core::ffi::*;
use core::ptr::NonNull;
use objc2::__framework_prelude::*;
#[cfg(feature = "objc2-core-media")]
use objc2_core_media::*;
use objc2_foundation::*;

use crate::*;

/// Describes why an AVCoordinatedPlaybackParticipant is not currently available to participate in coordinated playback.
///
/// See also [Apple's documentation](https://developer.apple.com/documentation/avfoundation/avcoordinatedplaybacksuspensionreason?language=objc)
// NS_TYPED_EXTENSIBLE_ENUM
pub type AVCoordinatedPlaybackSuspensionReason = NSString;

extern "C" {
    /// The participant's audio session was interrupted.
    ///
    /// See also [Apple's documentation](https://developer.apple.com/documentation/avfoundation/avcoordinatedplaybacksuspensionreasonaudiosessioninterrupted?language=objc)
    pub static AVCoordinatedPlaybackSuspensionReasonAudioSessionInterrupted:
        &'static AVCoordinatedPlaybackSuspensionReason;
}

extern "C" {
    /// The player is buffering data after a stall.
    ///
    /// See also [Apple's documentation](https://developer.apple.com/documentation/avfoundation/avcoordinatedplaybacksuspensionreasonstallrecovery?language=objc)
    pub static AVCoordinatedPlaybackSuspensionReasonStallRecovery:
        &'static AVCoordinatedPlaybackSuspensionReason;
}

extern "C" {
    /// The participant is presented with interstitial content instead of the main player.
    ///
    /// See also [Apple's documentation](https://developer.apple.com/documentation/avfoundation/avcoordinatedplaybacksuspensionreasonplayinginterstitial?language=objc)
    pub static AVCoordinatedPlaybackSuspensionReasonPlayingInterstitial:
        &'static AVCoordinatedPlaybackSuspensionReason;
}

extern "C" {
    /// The participant cannot participate in coordinated playback.
    ///
    /// See also [Apple's documentation](https://developer.apple.com/documentation/avfoundation/avcoordinatedplaybacksuspensionreasoncoordinatedplaybacknotpossible?language=objc)
    pub static AVCoordinatedPlaybackSuspensionReasonCoordinatedPlaybackNotPossible:
        &'static AVCoordinatedPlaybackSuspensionReason;
}

extern "C" {
    /// The participant's playback object is in a state that requires manual intervention by the user to resume playback.
    ///
    /// See also [Apple's documentation](https://developer.apple.com/documentation/avfoundation/avcoordinatedplaybacksuspensionreasonuseractionrequired?language=objc)
    pub static AVCoordinatedPlaybackSuspensionReasonUserActionRequired:
        &'static AVCoordinatedPlaybackSuspensionReason;
}

extern "C" {
    /// The participant is actively changing current time.
    ///
    /// See also [Apple's documentation](https://developer.apple.com/documentation/avfoundation/avcoordinatedplaybacksuspensionreasonuserischangingcurrenttime?language=objc)
    pub static AVCoordinatedPlaybackSuspensionReasonUserIsChangingCurrentTime:
        &'static AVCoordinatedPlaybackSuspensionReason;
}

extern_class!(
    /// A representation of a temporary break in participation.
    ///
    /// Subclasses of this type that are used from Swift must fulfill the requirements of a Sendable type.
    ///
    /// - NOTE: See AVPlaybackCoordinator's beginSuspensionForReason: method for details on use.
    ///
    /// See also [Apple's documentation](https://developer.apple.com/documentation/avfoundation/avcoordinatedplaybacksuspension?language=objc)
    #[unsafe(super(NSObject))]
    #[derive(Debug, PartialEq, Eq, Hash)]
    pub struct AVCoordinatedPlaybackSuspension;
);

extern_conformance!(
    unsafe impl NSObjectProtocol for AVCoordinatedPlaybackSuspension {}
);

impl AVCoordinatedPlaybackSuspension {
    extern_methods!(
        #[unsafe(method(init))]
        #[unsafe(method_family = init)]
        pub unsafe fn init(this: Allocated<Self>) -> Retained<Self>;

        #[unsafe(method(new))]
        #[unsafe(method_family = new)]
        pub unsafe fn new() -> Retained<Self>;

        /// The reason for the suspension. This will be communicated to other participants while coordination is suspended.
        #[unsafe(method(reason))]
        #[unsafe(method_family = none)]
        pub unsafe fn reason(&self) -> Retained<AVCoordinatedPlaybackSuspensionReason>;

        /// The begin time of the suspension.
        #[unsafe(method(beginDate))]
        #[unsafe(method_family = none)]
        pub unsafe fn beginDate(&self) -> Retained<NSDate>;

        /// Ends the suspension.
        ///
        /// If this is the last suspension, the coordinator will adjust timing of its playback object to match the group.
        /// Also see endProposingNewTime: for a way to end a suspension and simultaneously proposing a new time to the group.
        #[unsafe(method(end))]
        #[unsafe(method_family = none)]
        pub unsafe fn end(&self);

        #[cfg(feature = "objc2-core-media")]
        /// Ends the suspension and proposes a new time that everyone should seek to.
        ///
        /// If this is the last suspension, the coordinator will propose the new time to the group without changing the groups playback rate.
        /// If this is not the last suspension, the time will be ignored.
        /// If the time is not numeric, this will behave like a call to [suspension end].
        #[unsafe(method(endProposingNewTime:))]
        #[unsafe(method_family = none)]
        pub unsafe fn endProposingNewTime(&self, time: CMTime);
    );
}

extern "C" {
    /// Posted by the playback coordinator when its otherParticipants property changes.
    ///
    /// See also [Apple's documentation](https://developer.apple.com/documentation/avfoundation/avplaybackcoordinatorotherparticipantsdidchangenotification?language=objc)
    pub static AVPlaybackCoordinatorOtherParticipantsDidChangeNotification:
        &'static NSNotificationName;
}

extern "C" {
    /// Posted by the playback coordinator when its suspensionReasons property changes.
    ///
    /// See also [Apple's documentation](https://developer.apple.com/documentation/avfoundation/avplaybackcoordinatorsuspensionreasonsdidchangenotification?language=objc)
    pub static AVPlaybackCoordinatorSuspensionReasonsDidChangeNotification:
        &'static NSNotificationName;
}

extern_class!(
    /// The playback coordinator negotiates playback state between a player, such as AVPlayer or a custom playback object represented by an implementation of the AVPlaybackCoordinatorPlaybackControlDelegate protocol, and a group of other connected players.
    ///
    /// AVPlaybackCoordinator will match rate and time of all connected players. This means that a local rate change or seek will be reflected in all connected players. Equally, a rate change or seek in any of the connected players will be reflected locally.
    /// AVPlaybackCoordinator does not manage the items in the play queue of the connected players, so it is up to player's owner to share and match the play queue across participants.
    /// The coordinator does, however, keep track of the identity of items enqueued in each player. This means that for one player's current time and rate to be applied on another player, both players must be playing the same item. If two players are playing different items, they each have independent playback states. When one of the two players transitions to the other's item later, it will match the time and rate of that other player.
    ///
    /// See also [Apple's documentation](https://developer.apple.com/documentation/avfoundation/avplaybackcoordinator?language=objc)
    #[unsafe(super(NSObject))]
    #[derive(Debug, PartialEq, Eq, Hash)]
    pub struct AVPlaybackCoordinator;
);

extern_conformance!(
    unsafe impl NSObjectProtocol for AVPlaybackCoordinator {}
);

impl AVPlaybackCoordinator {
    extern_methods!(
        #[unsafe(method(init))]
        #[unsafe(method_family = init)]
        pub unsafe fn init(this: Allocated<Self>) -> Retained<Self>;

        #[unsafe(method(new))]
        #[unsafe(method_family = new)]
        pub unsafe fn new() -> Retained<Self>;

        /// The playback states of the other participants in the group.
        ///
        /// Use this property to create UI informing the local user about the state of other participants in the group.
        ///
        /// - NOTE: The coordinator posts AVPlaybackCoordinatorOtherParticipantsDidChangeNotification when the contents of the array changes.
        #[unsafe(method(otherParticipants))]
        #[unsafe(method_family = none)]
        pub unsafe fn otherParticipants(
            &self,
        ) -> Retained<NSArray<AVCoordinatedPlaybackParticipant>>;

        /// Describes why the coordinator is currently not able to participate in group playback.
        ///
        /// If the list of reasons is non-empty, the coordinator will not react to any changes of group playback state.
        #[unsafe(method(suspensionReasons))]
        #[unsafe(method_family = none)]
        pub unsafe fn suspensionReasons(
            &self,
        ) -> Retained<NSArray<AVCoordinatedPlaybackSuspensionReason>>;

        /// Informs the coordinator that its playback object is detached from the group for some reason and should not receive any playback commands from the coordinator.
        ///
        /// Use this to tell the coordinator that its player cannot, or should not, participate in coordinated playback temporarily.
        /// The coordinator will not respond to playback commands coming from the group and it will also not send any commands to the group.
        /// To resume in group playback, end a suspension by calling one of the suspension's end methods.
        ///
        /// - Parameter suspensionReason: Indicates the reason for the suspension that is shared with other participants. Can be a system-defined reason (see AVCoordinatedPlaybackSuspensionReason*) or a custom string.
        ///
        /// - NOTE: See the description of AVPlaybackCoordinator subclasses for suspensions automatically begun on behalf of their playback objects, if any.
        #[unsafe(method(beginSuspensionForReason:))]
        #[unsafe(method_family = none)]
        pub unsafe fn beginSuspensionForReason(
            &self,
            suspension_reason: &AVCoordinatedPlaybackSuspensionReason,
        ) -> Retained<AVCoordinatedPlaybackSuspension>;

        #[cfg(feature = "objc2-core-media")]
        /// Returns the item time (for the current item) that the coordinator expects to be playing at a given host clock time.
        ///
        /// This method is useful to decide if it is appropriate to end a suspension, e.g. a suspension with AVCoordinatedPlaybackSuspensionReasonStallRecovery, while other participants are continuing playback.
        #[unsafe(method(expectedItemTimeAtHostTime:))]
        #[unsafe(method_family = none)]
        pub unsafe fn expectedItemTimeAtHostTime(&self, host_clock_time: CMTime) -> CMTime;
    );
}

extern_class!(
    /// A participant in a coordinated playback group connected through AVPlaybackCoordinator.
    ///
    /// Subclasses of this type that are used from Swift must fulfill the requirements of a Sendable type.
    ///
    /// See also [Apple's documentation](https://developer.apple.com/documentation/avfoundation/avcoordinatedplaybackparticipant?language=objc)
    #[unsafe(super(NSObject))]
    #[derive(Debug, PartialEq, Eq, Hash)]
    pub struct AVCoordinatedPlaybackParticipant;
);

unsafe impl Send for AVCoordinatedPlaybackParticipant {}

unsafe impl Sync for AVCoordinatedPlaybackParticipant {}

extern_conformance!(
    unsafe impl NSObjectProtocol for AVCoordinatedPlaybackParticipant {}
);

impl AVCoordinatedPlaybackParticipant {
    extern_methods!(
        /// The reason, if any, this participant is currently not participating in coordinated playback.
        ///
        /// This property is not atomic.
        ///
        /// # Safety
        ///
        /// This might not be thread-safe.
        #[unsafe(method(suspensionReasons))]
        #[unsafe(method_family = none)]
        pub unsafe fn suspensionReasons(
            &self,
        ) -> Retained<NSArray<AVCoordinatedPlaybackSuspensionReason>>;

        /// YES if the participant is ready to play.
        ///
        /// This property is not atomic.
        ///
        /// # Safety
        ///
        /// This might not be thread-safe.
        #[unsafe(method(isReadyToPlay))]
        #[unsafe(method_family = none)]
        pub unsafe fn isReadyToPlay(&self) -> bool;

        /// A unique id for the participant.
        ///
        /// Use this identifier to distinguish participants.
        ///
        /// This property is not atomic.
        ///
        /// # Safety
        ///
        /// This might not be thread-safe.
        #[unsafe(method(identifier))]
        #[unsafe(method_family = none)]
        pub unsafe fn identifier(&self) -> Retained<NSUUID>;
    );
}

/// Methods declared on superclass `NSObject`.
impl AVCoordinatedPlaybackParticipant {
    extern_methods!(
        #[unsafe(method(init))]
        #[unsafe(method_family = init)]
        pub unsafe fn init(this: Allocated<Self>) -> Retained<Self>;

        #[unsafe(method(new))]
        #[unsafe(method_family = new)]
        pub unsafe fn new() -> Retained<Self>;
    );
}

/// AVCoordinatedPlaybackPolicies.
///
/// Policies used by AVPlaybackCoordinator to determine how to interact with the group.
impl AVPlaybackCoordinator {
    extern_methods!(
        /// Sets the amount of participants that can join a group before the coordinator stops waiting for this particular suspension reason.
        ///
        /// This allows additional configuration for suspension reasons in the suspensionReasonsThatTriggerWaiting array.
        /// When the coordinator decides whether one participant's suspensions should cause others to wait, it will also consider this limit of participants currently in the group.
        #[unsafe(method(setParticipantLimit:forWaitingOutSuspensionsWithReason:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setParticipantLimit_forWaitingOutSuspensionsWithReason(
            &self,
            participant_limit: NSInteger,
            reason: &AVCoordinatedPlaybackSuspensionReason,
        );

        /// Returns the maximum number of participants that can be in a group before the coordinator stops waiting out this particular suspensions reason. Default value is NSIntegerMax.
        #[unsafe(method(participantLimitForWaitingOutSuspensionsWithReason:))]
        #[unsafe(method_family = none)]
        pub unsafe fn participantLimitForWaitingOutSuspensionsWithReason(
            &self,
            reason: &AVCoordinatedPlaybackSuspensionReason,
        ) -> NSInteger;

        /// If the coordinator decides to delay playback to wait for others, it will wait out these reasons, but not others.
        #[unsafe(method(suspensionReasonsThatTriggerWaiting))]
        #[unsafe(method_family = none)]
        pub unsafe fn suspensionReasonsThatTriggerWaiting(
            &self,
        ) -> Retained<NSArray<AVCoordinatedPlaybackSuspensionReason>>;

        /// Setter for [`suspensionReasonsThatTriggerWaiting`][Self::suspensionReasonsThatTriggerWaiting].
        ///
        /// This is [copied][objc2_foundation::NSCopying::copy] when set.
        #[unsafe(method(setSuspensionReasonsThatTriggerWaiting:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setSuspensionReasonsThatTriggerWaiting(
            &self,
            suspension_reasons_that_trigger_waiting: &NSArray<
                AVCoordinatedPlaybackSuspensionReason,
            >,
        );

        /// Determines if participants should mirror the originator's stop time when pausing.
        ///
        /// If YES, all participants will seek to the originator's stop time after they pause. Use this if it is desirable to counteract any network delay incurred by communicating the originator's pause to the other participants.
        /// If NO, it's acceptable for participants to stop at slightly different offsets and a pause will not cause other participants' time to jump back.
        #[unsafe(method(pauseSnapsToMediaTimeOfOriginator))]
        #[unsafe(method_family = none)]
        pub unsafe fn pauseSnapsToMediaTimeOfOriginator(&self) -> bool;

        /// Setter for [`pauseSnapsToMediaTimeOfOriginator`][Self::pauseSnapsToMediaTimeOfOriginator].
        #[unsafe(method(setPauseSnapsToMediaTimeOfOriginator:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setPauseSnapsToMediaTimeOfOriginator(
            &self,
            pause_snaps_to_media_time_of_originator: bool,
        );
    );
}

extern_class!(
    /// An AVPlaybackCoordinator subclass for controlling an AVPlayer
    ///
    /// While the coordinator is connected to other participants, it will intercept rate changes and seeks issued to the player to share these with other participants if appropriate.
    /// Clients of AVPlayer can thus use the AVPlayer interfaces to modify the playback state of connected participants. When appropriate, the coordinator will also impose rate changes and seeks from other participants on the player. If this occurs, the corresponding notifications will carry an originating participant in their payload.
    /// See AVPlayer's playbackCoordinator property for more details about player behavior changes.
    /// AVPlayerPlaybackCoordinator may begin suspensions on behalf of the player when the player's timeControlStatus changes from AVPlayerTimeControlStatusPlaying to AVPlayerTimeControlStatusWaitingToPlayAtSpecifiedRate or AVPlayerTimeControlStatusPaused. These suspensions will end when the player's timeControlStatus changes back to AVPlayerTimeControlStatusPlaying. This means that a suspension that begun because the player entered a waiting state, will end automatically when the player is done waiting. A suspension that begun because the player paused, will only end once the player's rate changes back to non-zero.
    ///
    /// See also [Apple's documentation](https://developer.apple.com/documentation/avfoundation/avplayerplaybackcoordinator?language=objc)
    #[unsafe(super(AVPlaybackCoordinator, NSObject))]
    #[derive(Debug, PartialEq, Eq, Hash)]
    pub struct AVPlayerPlaybackCoordinator;
);

extern_conformance!(
    unsafe impl NSObjectProtocol for AVPlayerPlaybackCoordinator {}
);

impl AVPlayerPlaybackCoordinator {
    extern_methods!(
        #[unsafe(method(init))]
        #[unsafe(method_family = init)]
        pub unsafe fn init(this: Allocated<Self>) -> Retained<Self>;

        #[unsafe(method(new))]
        #[unsafe(method_family = new)]
        pub unsafe fn new() -> Retained<Self>;

        #[cfg(feature = "AVPlayer")]
        /// The AVPlayer this coordinator is controlling.
        #[unsafe(method(player))]
        #[unsafe(method_family = none)]
        pub unsafe fn player(&self, mtm: MainThreadMarker) -> Option<Retained<AVPlayer>>;

        /// An object implementing the AVPlaybackCoordinatorDelegate protocol.
        #[unsafe(method(delegate))]
        #[unsafe(method_family = none)]
        pub unsafe fn delegate(
            &self,
        ) -> Option<Retained<ProtocolObject<dyn AVPlayerPlaybackCoordinatorDelegate>>>;

        /// Setter for [`delegate`][Self::delegate].
        ///
        /// This is a [weak property][objc2::topics::weak_property].
        #[unsafe(method(setDelegate:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setDelegate(
            &self,
            delegate: Option<&ProtocolObject<dyn AVPlayerPlaybackCoordinatorDelegate>>,
        );
    );
}

/// AVPlaybackCoordinationMediumSupport.
impl AVPlayerPlaybackCoordinator {
    extern_methods!(
        #[cfg(feature = "AVPlaybackCoordinationMedium")]
        /// Connects the playback coordinator to the coordination medium
        ///
        /// This connects the playback coordinator to a coordination medium to enable sending and receiving messages from other connected playback coordinators.
        /// If the coordination medium is non-NULL, this will connect the playback coordinator to the specified coordination medium.
        /// If the coordination medium is set to NULL, this will disconnect the playback coordinator from the playback coordination medium. The player will no longer be coordinated with the other players connected to the coordination medium.
        /// The playback coordinator can either only coordinate with local players through an AVPlaybackCoordinationMedium or coordinate with a remote group session through the `coordinateWithSession` API. If the client attempts to connect to an AVPlaybackCoordinationMedium while already connected to a group session, this method will populate the outError parameter
        /// If the playback coordinator successfully connects to the coordination medium or disconnects from a coordination medium, the `outError` parameter will be nil. If the playback coordinator fails to connect to the specified coordination medium, the `outError` parameter will describe what went wrong.
        ///
        /// - Parameter coordinationMedium: The coordination medium the playback coordinator connects to. If NULL, the playback coordinator disconnects from any existing coordination medium.
        /// - Parameter outError: A pointer to an NSError object that will be populated with failure information if connecting to or disconnecting from the coordination medium fails.
        #[unsafe(method(coordinateUsingCoordinationMedium:error:_))]
        #[unsafe(method_family = none)]
        pub unsafe fn coordinateUsingCoordinationMedium_error(
            &self,
            coordination_medium: Option<&AVPlaybackCoordinationMedium>,
        ) -> Result<(), Retained<NSError>>;

        #[cfg(feature = "AVPlaybackCoordinationMedium")]
        /// The AVPlaybackCoordinationMedium this playback coordinator is connected to.
        ///
        /// This is the AVPlaybackCoordinationMedium the playback coordinator is connected to.
        /// If not NULL, the playback coordinator is connected to the specified coordination medium. The playback coordinator is not available to coordinate with a group session.
        /// If NULL, the playback coordinator is not connected to any playback coordination medium. The playback coordinator is available to coordinate with a group session through the `coordinateWithSession` API.
        #[unsafe(method(playbackCoordinationMedium))]
        #[unsafe(method_family = none)]
        pub unsafe fn playbackCoordinationMedium(
            &self,
        ) -> Option<Retained<AVPlaybackCoordinationMedium>>;
    );
}

extern_protocol!(
    /// Delegate protocol for AVPlayerPlaybackCoordinator.
    ///
    /// See also [Apple's documentation](https://developer.apple.com/documentation/avfoundation/avplayerplaybackcoordinatordelegate?language=objc)
    pub unsafe trait AVPlayerPlaybackCoordinatorDelegate:
        NSObjectProtocol + Send + Sync
    {
        #[cfg(feature = "AVPlayerItem")]
        /// Called by the coordinator to identify AVPlayerItems played by the coordinator's AVPlayer.
        ///
        /// Implementing this method allows the coordinator to establish identity of two items created from different URLs, e.g., because one participant is using a local cache and the other a remote URL.
        /// If the method is not implemented, the coordinator will derive the identifier from the item's asset.
        #[optional]
        #[unsafe(method(playbackCoordinator:identifierForPlayerItem:))]
        #[unsafe(method_family = none)]
        unsafe fn playbackCoordinator_identifierForPlayerItem(
            &self,
            coordinator: &AVPlayerPlaybackCoordinator,
            player_item: &AVPlayerItem,
        ) -> Retained<NSString>;

        #[cfg(feature = "AVPlayerItem")]
        /// Called by the coordinator to obtain time ranges in the AVPlayerItem that do not correspond to the primary content.
        ///
        /// Implement this method to provide the coordinator a list of sample accurate time ranges that represent interstitials in the player item.
        /// The coordinator would use this along with the waiting policy for the playingInterstitial suspension to coordinate playback across the group.
        /// If the playingInterstitial suspension is part of AVPlaybackCoordinator.suspensionReasonsThatTriggerWaiting, then the coordinator would wait for other participants to complete the interstitial before proceeding with playback.
        /// And if the playingInterstitial suspension is not a part of AVPlaybackCoordinator.suspensionReasonsThatTriggerWaiting then the coordinator will not wait for the participant playing the interstitial.
        /// Instead, that participant would jump to catch up with the rest of the group when they finish playing the interstitial.
        /// This delegate method is expected to return an array of NSValues with each value containing a CMTimeRange that represents the interstitial.
        /// If the method is not implemented, the coordinator would assume that the entire item corresponds to the primary content.
        #[optional]
        #[unsafe(method(playbackCoordinator:interstitialTimeRangesForPlayerItem:))]
        #[unsafe(method_family = none)]
        unsafe fn playbackCoordinator_interstitialTimeRangesForPlayerItem(
            &self,
            coordinator: &AVPlayerPlaybackCoordinator,
            player_item: &AVPlayerItem,
        ) -> Retained<NSArray<NSValue>>;
    }
);

/// Configuration for a call to [AVDelegatingPlaybackCoordinator coordinateRateChangeToRate:options:].
///
/// See also [Apple's documentation](https://developer.apple.com/documentation/avfoundation/avdelegatingplaybackcoordinatorratechangeoptions?language=objc)
// NS_OPTIONS
#[repr(transparent)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct AVDelegatingPlaybackCoordinatorRateChangeOptions(pub NSUInteger);
bitflags::bitflags! {
    impl AVDelegatingPlaybackCoordinatorRateChangeOptions: NSUInteger {
/// Requests that the coordinator begin playback as soon as possible and ignore other participant's readiness and suspensions.
        #[doc(alias = "AVDelegatingPlaybackCoordinatorRateChangeOptionPlayImmediately")]
        const PlayImmediately = 1<<0;
    }
}

unsafe impl Encode for AVDelegatingPlaybackCoordinatorRateChangeOptions {
    const ENCODING: Encoding = NSUInteger::ENCODING;
}

unsafe impl RefEncode for AVDelegatingPlaybackCoordinatorRateChangeOptions {
    const ENCODING_REF: Encoding = Encoding::Pointer(&Self::ENCODING);
}

/// Configuration for a call to [AVDelegatingPlaybackCoordinator coordinateSeekToTime:options:].
///
/// See also [Apple's documentation](https://developer.apple.com/documentation/avfoundation/avdelegatingplaybackcoordinatorseekoptions?language=objc)
// NS_OPTIONS
#[repr(transparent)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct AVDelegatingPlaybackCoordinatorSeekOptions(pub NSUInteger);
bitflags::bitflags! {
    impl AVDelegatingPlaybackCoordinatorSeekOptions: NSUInteger {
/// Requests that the coordinator resume playback as soon as possible after the seek is complete and ignore other participant's readiness and suspensions.
        #[doc(alias = "AVDelegatingPlaybackCoordinatorSeekOptionResumeImmediately")]
        const ResumeImmediately = 1<<0;
    }
}

unsafe impl Encode for AVDelegatingPlaybackCoordinatorSeekOptions {
    const ENCODING: Encoding = NSUInteger::ENCODING;
}

unsafe impl RefEncode for AVDelegatingPlaybackCoordinatorSeekOptions {
    const ENCODING_REF: Encoding = Encoding::Pointer(&Self::ENCODING);
}

extern_class!(
    /// An AVPlaybackCoordinator subclass for controlling a custom playback object.
    ///
    /// - NOTE: Use AVPlayer's playbackCoordinator property to get an AVPlaybackCoordinator for an AVPlayer.
    ///
    /// See also [Apple's documentation](https://developer.apple.com/documentation/avfoundation/avdelegatingplaybackcoordinator?language=objc)
    #[unsafe(super(AVPlaybackCoordinator, NSObject))]
    #[derive(Debug, PartialEq, Eq, Hash)]
    pub struct AVDelegatingPlaybackCoordinator;
);

extern_conformance!(
    unsafe impl NSObjectProtocol for AVDelegatingPlaybackCoordinator {}
);

impl AVDelegatingPlaybackCoordinator {
    extern_methods!(
        /// Creates an AVPlaybackCoordinator for a custom playback object.
        ///
        /// Use this to create an AVPlaybackCoordinator when playback is not driven by an AVPlayer.
        ///
        /// - Parameter playbackControlDelegate: An object conforming to the AVPlaybackCoordinatorPlaybackControlDelegate protocol representing a custom playback object. The coordinator will only hold a weak reference to its delegate.
        ///
        /// - NOTE: See AVPlayer's playbackCoordinator property to get an AVPlaybackCoordinator for an AVPlayer.
        #[unsafe(method(initWithPlaybackControlDelegate:))]
        #[unsafe(method_family = init)]
        pub unsafe fn initWithPlaybackControlDelegate(
            this: Allocated<Self>,
            playback_control_delegate: &ProtocolObject<
                dyn AVPlaybackCoordinatorPlaybackControlDelegate,
            >,
        ) -> Retained<Self>;

        /// The custom player implementation controlled by the coordinator.
        #[unsafe(method(playbackControlDelegate))]
        #[unsafe(method_family = none)]
        pub unsafe fn playbackControlDelegate(
            &self,
        ) -> Option<Retained<ProtocolObject<dyn AVPlaybackCoordinatorPlaybackControlDelegate>>>;

        /// Coordinaties a rate change across the group of connected participants, waiting for other participants to become ready if necessary.
        ///
        /// The coordinator will request a coordinated rate change from all other connected participants.
        /// When changing the rate from zero to non-zero, it may also wait out other participant's suspensions as configured by the suspensionReasonsThatTriggerWaiting property.
        ///
        /// This method should not be called when the rate change should not affect the group, or the group should not have control over local playback temporarily, e.g. a pause because of an audio session interruption.
        /// In those cases, the coordinator should be informed by beginning a suspension with the appropriate reason instead. If other participants pause is dependent on the coordinator's configuration.
        /// The suspension will stop the coordinator from issuing further commands to its playbackControlDelegate. After beginning the suspension, the playback object can be reconfigured as necessary.
        ///
        /// - Parameter rate: The playback rate the group should be using.
        /// - Parameter options: Additional configuration of the rate change. For details see AVDelegatingPlaybackCoordinatorRateChangeOptions.
        ///
        /// - NOTE: Calling this method while the coordinator is suspended affects only the local playback object. The group state will not be affected, even after the suspension ends.
        #[unsafe(method(coordinateRateChangeToRate:options:))]
        #[unsafe(method_family = none)]
        pub unsafe fn coordinateRateChangeToRate_options(
            &self,
            rate: c_float,
            options: AVDelegatingPlaybackCoordinatorRateChangeOptions,
        );

        #[cfg(feature = "objc2-core-media")]
        /// Triggers a seek to the requested time for all connected participants.
        ///
        /// For behavior around resuming playback after the seek is complete and suspensions, see the discussion of coordinateRateChangeToRate:options.
        ///
        /// - Parameter time: The time the group should seek to when the command ends.
        /// - Parameter options: Additional configuration of the seek. For details see AVDelegatingPlaybackCoordinatorSeekOptions.
        ///
        /// - NOTE: Calling this method while the coordinator is suspended affects only the local playback object. The group state will not be affected, even after the suspension ends.
        /// To end a suspension and also affect the group timing see -[AVCoordinatedPlaybackSuspension endProposingNewTime:]
        #[unsafe(method(coordinateSeekToTime:options:))]
        #[unsafe(method_family = none)]
        pub unsafe fn coordinateSeekToTime_options(
            &self,
            time: CMTime,
            options: AVDelegatingPlaybackCoordinatorSeekOptions,
        );

        #[cfg(feature = "objc2-core-media")]
        /// Informs the coordinator to transition to a new current item.
        ///
        /// The coordinator will stop sending commands for any previous item identifier and begin sending commands for the new identifier.
        /// The proposed timing will either be used as the new referece timing for the group, or it will be compared to an already existing reference timing.
        /// If the proposed timing doesn't match such an existing reference timing, the coordinator will use the playbackControlDelegate to issue appropriate commands to match up the timing.
        ///
        /// - Parameter itemIdentifier: The identifier for the new current item. May be nil if nothing is playing.
        /// - Parameter snapshotTimebase: A timebase used to communicate the initial playback state of the new item. If NULL, the coordinator will assume that playback is paused at kCMTimeZero. An appropriate timebase to pass to the completion handler may be retreived from AVFoundation playback objects such as AVSampleBufferRenderSynchronizer. It can also be created manually using CMTimebaseCreateWithSourceClock. The timebase will only be used to take a snapshot of its immediate timing. It will not be observed further.
        ///
        /// - NOTE: This is not a way to affect the play queue of other participants. All other participants must do this independently, e.g. as a side-effect of an automatic item transition or an out-of-band communication requesting a similar item change.
        #[unsafe(method(transitionToItemWithIdentifier:proposingInitialTimingBasedOnTimebase:))]
        #[unsafe(method_family = none)]
        pub unsafe fn transitionToItemWithIdentifier_proposingInitialTimingBasedOnTimebase(
            &self,
            item_identifier: Option<&NSString>,
            snapshot_timebase: Option<&CMTimebase>,
        );

        /// The item identifier of the current item. Previously set by a call to transitionToItemWithIdentifier:proposingInitialTimingBasedOnTimebase:
        #[unsafe(method(currentItemIdentifier))]
        #[unsafe(method_family = none)]
        pub unsafe fn currentItemIdentifier(&self) -> Option<Retained<NSString>>;

        /// Instructs the coordinator to re-issue commands to synchronize the current item back to the state of the other participants.
        ///
        /// Use this method when the playback object is in a state that doesn't match the group for some reason and should be re-synchronized.
        #[unsafe(method(reapplyCurrentItemStateToPlaybackControlDelegate))]
        #[unsafe(method_family = none)]
        pub unsafe fn reapplyCurrentItemStateToPlaybackControlDelegate(&self);
    );
}

/// Methods declared on superclass `AVPlaybackCoordinator`.
impl AVDelegatingPlaybackCoordinator {
    extern_methods!(
        #[unsafe(method(init))]
        #[unsafe(method_family = init)]
        pub unsafe fn init(this: Allocated<Self>) -> Retained<Self>;

        #[unsafe(method(new))]
        #[unsafe(method_family = new)]
        pub unsafe fn new() -> Retained<Self>;
    );
}

extern_protocol!(
    /// A custom player implementation
    ///
    /// See also [Apple's documentation](https://developer.apple.com/documentation/avfoundation/avplaybackcoordinatorplaybackcontroldelegate?language=objc)
    pub unsafe trait AVPlaybackCoordinatorPlaybackControlDelegate:
        NSObjectProtocol + Send + Sync
    {
        #[cfg(feature = "block2")]
        /// Called by the coordinator to match the playback rate of the control delegate to the group, when the target rate is non-zero.
        ///
        /// The coordinator issues this command when the desired playback timeline has changed. This may mean that the rate has changed, but it can also mean that the anchor time has changed.
        /// Play commands are only issued when the desired playback rate is non-zero.
        ///
        /// - Parameter coordinator: The coordinator requesting a change in playback rate.
        /// - Parameter playCommand: A play command object. See AVDelegatingPlaybackCoordinatorPlayCommand. The receiver should verify that the command is still valid by inspecting the expectedCurrentItemIdentifier property before applying the command.
        /// - Parameter completionHandler: The receiver must call the completion handler when done, either when the command has been handled succesfully or when the receiver has indicated its inability to handle the command by beginning a suspension with an appropriate reason.
        ///
        /// # Safety
        ///
        /// `completion_handler` block must be sendable.
        #[unsafe(method(playbackCoordinator:didIssuePlayCommand:completionHandler:))]
        #[unsafe(method_family = none)]
        unsafe fn playbackCoordinator_didIssuePlayCommand_completionHandler(
            &self,
            coordinator: &AVDelegatingPlaybackCoordinator,
            play_command: &AVDelegatingPlaybackCoordinatorPlayCommand,
            completion_handler: &block2::DynBlock<dyn Fn()>,
        );

        #[cfg(feature = "block2")]
        /// Called by the coordinator to pause playback.
        ///
        /// - Parameter coordinator: The coordinator requesting playback to pause.
        /// - Parameter pauseCommand: A pause command object. See AVDelegatingPlaybackCoordinatorPauseCommand. The receiver should verify that the command is still valid by inspecting the expectedCurrentItemIdentifier property before applying the command.
        /// - Parameter completionHandler: The receiver must call the completion handler when done, either when the command has been handled succesfully or when the receiver has indicated its inability to handle the command by beginning a suspension with an appropriate reason. If the command's shouldBufferInAnticipationOfPlayback is YES, the completion handler should also only be called once the playback object is ready to receive a subsequent play command.
        ///
        /// # Safety
        ///
        /// `completion_handler` block must be sendable.
        #[unsafe(method(playbackCoordinator:didIssuePauseCommand:completionHandler:))]
        #[unsafe(method_family = none)]
        unsafe fn playbackCoordinator_didIssuePauseCommand_completionHandler(
            &self,
            coordinator: &AVDelegatingPlaybackCoordinator,
            pause_command: &AVDelegatingPlaybackCoordinatorPauseCommand,
            completion_handler: &block2::DynBlock<dyn Fn()>,
        );

        #[cfg(feature = "block2")]
        /// Called by the coordinator to seek to a new time.
        ///
        /// The coordinator issues this command when the playback object current time changes, potentially also pausing playback.
        ///
        /// - Parameter coordinator: The coordinator requesting the seek.
        /// - Parameter seekCommand: A seek command object. See AVDelegatingPlaybackCoordinatorSeekCommand. The receiver should verify that the command is still valid by inspecting the expectedCurrentItemIdentifier property before applying the command.
        /// - Parameter completionHandler: The receiver must call the completion handler when done, either when the command has been handled succesfully or when the receiver has indicated its inability to handle the command by beginning a suspension with an appropriate reason. If the command's shouldBufferInAnticipationOfPlayback is YES, the completion handler should also only be called once the playback object is ready to receive a subsequent play command.
        ///
        /// # Safety
        ///
        /// `completion_handler` block must be sendable.
        #[unsafe(method(playbackCoordinator:didIssueSeekCommand:completionHandler:))]
        #[unsafe(method_family = none)]
        unsafe fn playbackCoordinator_didIssueSeekCommand_completionHandler(
            &self,
            coordinator: &AVDelegatingPlaybackCoordinator,
            seek_command: &AVDelegatingPlaybackCoordinatorSeekCommand,
            completion_handler: &block2::DynBlock<dyn Fn()>,
        );

        #[cfg(feature = "block2")]
        /// Called by the coordinator to indicate that playback is expected to begin soon and the playback object should begin buffering.
        ///
        /// The coordinator issues this command when playback is currently paused and the coordinator is expecting playback to start soon.
        /// In response to this command, it is appropriate to update playback UI to indicate playback in a waiting state.
        /// The expected start can be cancelled by calling -[AVDelegatingPlaybackCoordinator coordinateRateChangeTo:0].
        ///
        /// - Parameter coordinator: The coordinator requesting buffering to begin.
        /// - Parameter bufferingCommand: A buffering command object. See AVDelegatingPlaybackCoordinatorBufferingCommand. The receiver should verify that the command is still valid by inspecting the expectedCurrentItemIdentifier property before applying the command.
        /// - Parameter completionHandler: The receiver must call the completion handler when done, either when the command has been handled succesfully or when the receiver has indicated its inability to handle the command by beginning a suspension with an appropriate reason. For buffering commands, the command should only be considered complete once the playback object is ready to receive a subsequent play command.
        ///
        /// # Safety
        ///
        /// `completion_handler` block must be sendable.
        #[unsafe(method(playbackCoordinator:didIssueBufferingCommand:completionHandler:))]
        #[unsafe(method_family = none)]
        unsafe fn playbackCoordinator_didIssueBufferingCommand_completionHandler(
            &self,
            coordinator: &AVDelegatingPlaybackCoordinator,
            buffering_command: &AVDelegatingPlaybackCoordinatorBufferingCommand,
            completion_handler: &block2::DynBlock<dyn Fn()>,
        );
    }
);

extern_class!(
    /// Abstract superclass for playback commands
    ///
    /// Subclasses of this type that are used from Swift must fulfill the requirements of a Sendable type.
    ///
    /// See also [Apple's documentation](https://developer.apple.com/documentation/avfoundation/avdelegatingplaybackcoordinatorplaybackcontrolcommand?language=objc)
    #[unsafe(super(NSObject))]
    #[derive(Debug, PartialEq, Eq, Hash)]
    pub struct AVDelegatingPlaybackCoordinatorPlaybackControlCommand;
);

unsafe impl Send for AVDelegatingPlaybackCoordinatorPlaybackControlCommand {}

unsafe impl Sync for AVDelegatingPlaybackCoordinatorPlaybackControlCommand {}

extern_conformance!(
    unsafe impl NSObjectProtocol for AVDelegatingPlaybackCoordinatorPlaybackControlCommand {}
);

impl AVDelegatingPlaybackCoordinatorPlaybackControlCommand {
    extern_methods!(
        #[unsafe(method(init))]
        #[unsafe(method_family = init)]
        pub unsafe fn init(this: Allocated<Self>) -> Retained<Self>;

        #[unsafe(method(new))]
        #[unsafe(method_family = new)]
        pub unsafe fn new() -> Retained<Self>;

        /// The participant causing this command to be issued.
        ///
        /// Only commands issued on behalf of another participant will contain an originator.
        /// Commands caused by local requests, e.g., requests to coordinate a rate change, will not contain an originator.
        /// Similarly, re-application of older commands, e.g., in response to a call to [AVDelegatingPlaybackCoordinator reapplyCurrentItemStateToPlaybackControlDelegate], will not contain an originator.
        /// If the originator is non-nil, it may be appropriate to show UI indicating someone else's action.
        ///
        /// This property is not atomic.
        ///
        /// # Safety
        ///
        /// This might not be thread-safe.
        #[unsafe(method(originator))]
        #[unsafe(method_family = none)]
        pub unsafe fn originator(&self) -> Option<Retained<AVCoordinatedPlaybackParticipant>>;

        /// Indicates the item this command was issued for.
        ///
        /// Commands are always meant for the current item. A command handler should verify that the identifier of its current item matches this identifier.
        /// If it doesn't this command is obsolete and should be ignored. Note that any completion handler of the delegate method issuing the command must still be invoked.
        ///
        /// This property is not atomic.
        ///
        /// # Safety
        ///
        /// This might not be thread-safe.
        #[unsafe(method(expectedCurrentItemIdentifier))]
        #[unsafe(method_family = none)]
        pub unsafe fn expectedCurrentItemIdentifier(&self) -> Retained<NSString>;
    );
}

extern_class!(
    /// A playback command requesting playback with specific timing.
    ///
    /// Subclasses of this type that are used from Swift must fulfill the requirements of a Sendable type.
    ///
    /// See also [Apple's documentation](https://developer.apple.com/documentation/avfoundation/avdelegatingplaybackcoordinatorplaycommand?language=objc)
    #[unsafe(super(AVDelegatingPlaybackCoordinatorPlaybackControlCommand, NSObject))]
    #[derive(Debug, PartialEq, Eq, Hash)]
    pub struct AVDelegatingPlaybackCoordinatorPlayCommand;
);

unsafe impl Send for AVDelegatingPlaybackCoordinatorPlayCommand {}

unsafe impl Sync for AVDelegatingPlaybackCoordinatorPlayCommand {}

extern_conformance!(
    unsafe impl NSObjectProtocol for AVDelegatingPlaybackCoordinatorPlayCommand {}
);

impl AVDelegatingPlaybackCoordinatorPlayCommand {
    extern_methods!(
        #[unsafe(method(init))]
        #[unsafe(method_family = init)]
        pub unsafe fn init(this: Allocated<Self>) -> Retained<Self>;

        #[unsafe(method(new))]
        #[unsafe(method_family = new)]
        pub unsafe fn new() -> Retained<Self>;

        /// Playback rate. Will always be non-zero.
        ///
        /// This property is not atomic.
        ///
        /// # Safety
        ///
        /// This might not be thread-safe.
        #[unsafe(method(rate))]
        #[unsafe(method_family = none)]
        pub unsafe fn rate(&self) -> c_float;

        #[cfg(feature = "objc2-core-media")]
        /// The itemTime that playback should begin at.
        ///
        /// The receiver of this command should verify that data is loaded for the requested time and potentially begin loading it before beginning playback.
        /// It is not important to load data for time exactly. If data "similar" to time is already loaded, it is acceptable to start playback with the loaded data. Playback should still start with the requested timing.
        /// Should the receiver be unable to start with the exact requested timing, playback will be out of sync with the group.
        /// If data for the requested time cannot be loaded, or playback stalls later, the command handler may want to indicate this to the coordinator by beginning a suspension with AVCoordinatedPlaybackSuspensionReasonStallRecovery.
        ///
        /// This property is not atomic.
        ///
        /// # Safety
        ///
        /// This might not be thread-safe.
        #[unsafe(method(itemTime))]
        #[unsafe(method_family = none)]
        pub unsafe fn itemTime(&self) -> CMTime;

        #[cfg(feature = "objc2-core-media")]
        /// This is the host clock time (see CMClockGetHostTimeClock()) defining when playback should start (or should have started) at the given itemTime.
        ///
        /// This property is not atomic.
        ///
        /// # Safety
        ///
        /// This might not be thread-safe.
        #[unsafe(method(hostClockTime))]
        #[unsafe(method_family = none)]
        pub unsafe fn hostClockTime(&self) -> CMTime;
    );
}

extern_class!(
    /// A playback command requesting buffering in anticipation of playback.
    ///
    /// Receiving this command should be reflected to the user as playback in a buffering state.
    /// To cancel the group intent to begin playback and move back into a paused state, call [AVDelegatingPlaybackCoordinator coordinateRateChangeToRate:0 options: 0]
    ///
    /// Subclasses of this type that are used from Swift must fulfill the requirements of a Sendable type.
    ///
    /// See also [Apple's documentation](https://developer.apple.com/documentation/avfoundation/avdelegatingplaybackcoordinatorbufferingcommand?language=objc)
    #[unsafe(super(AVDelegatingPlaybackCoordinatorPlaybackControlCommand, NSObject))]
    #[derive(Debug, PartialEq, Eq, Hash)]
    pub struct AVDelegatingPlaybackCoordinatorBufferingCommand;
);

unsafe impl Send for AVDelegatingPlaybackCoordinatorBufferingCommand {}

unsafe impl Sync for AVDelegatingPlaybackCoordinatorBufferingCommand {}

extern_conformance!(
    unsafe impl NSObjectProtocol for AVDelegatingPlaybackCoordinatorBufferingCommand {}
);

impl AVDelegatingPlaybackCoordinatorBufferingCommand {
    extern_methods!(
        #[unsafe(method(init))]
        #[unsafe(method_family = init)]
        pub unsafe fn init(this: Allocated<Self>) -> Retained<Self>;

        #[unsafe(method(new))]
        #[unsafe(method_family = new)]
        pub unsafe fn new() -> Retained<Self>;

        /// The rate to prepare playback for.
        ///
        /// The command should only be considered complete once the player is ready to receive an AVDelegatingPlaybackCoordinatorPlayCommand with the indicated rate.
        ///
        /// This property is not atomic.
        ///
        /// # Safety
        ///
        /// This might not be thread-safe.
        #[unsafe(method(anticipatedPlaybackRate))]
        #[unsafe(method_family = none)]
        pub unsafe fn anticipatedPlaybackRate(&self) -> c_float;

        /// Communicates when the coordinator expects the command's completion handler at the latest.
        ///
        /// A receiver of a buffering command should fire the completion handler by this date at the latest. This is useful in buffering situations where the receiver
        /// has not yet buffered enough data to be considered ready to play by the due date. The receiver should then decide to either complete the command as is
        /// to try and keep up with the group, or alternatively begin a stall recovery suspension to communicate the situation to the other participants.
        /// Completing the command after this date means that the coordinator will likely send a play command for a later time than the receiver buffered for.
        ///
        /// This property is not atomic.
        ///
        /// # Safety
        ///
        /// This might not be thread-safe.
        #[unsafe(method(completionDueDate))]
        #[unsafe(method_family = none)]
        pub unsafe fn completionDueDate(&self) -> Option<Retained<NSDate>>;
    );
}

extern_class!(
    /// A playback command requesting a pause
    ///
    /// Subclasses of this type that are used from Swift must fulfill the requirements of a Sendable type.
    ///
    /// See also [Apple's documentation](https://developer.apple.com/documentation/avfoundation/avdelegatingplaybackcoordinatorpausecommand?language=objc)
    #[unsafe(super(AVDelegatingPlaybackCoordinatorPlaybackControlCommand, NSObject))]
    #[derive(Debug, PartialEq, Eq, Hash)]
    pub struct AVDelegatingPlaybackCoordinatorPauseCommand;
);

unsafe impl Send for AVDelegatingPlaybackCoordinatorPauseCommand {}

unsafe impl Sync for AVDelegatingPlaybackCoordinatorPauseCommand {}

extern_conformance!(
    unsafe impl NSObjectProtocol for AVDelegatingPlaybackCoordinatorPauseCommand {}
);

impl AVDelegatingPlaybackCoordinatorPauseCommand {
    extern_methods!(
        #[unsafe(method(init))]
        #[unsafe(method_family = init)]
        pub unsafe fn init(this: Allocated<Self>) -> Retained<Self>;

        #[unsafe(method(new))]
        #[unsafe(method_family = new)]
        pub unsafe fn new() -> Retained<Self>;

        /// Indicates that playback is anticipated and the player should begin buffering if necessary.
        ///
        /// When shouldBufferInAnticipationOfPlayback is YES, some participant wants to resume playback at the rate indicated by the anticipatedPlaybackRate property.
        /// This should be treated similar to receiving a separate AVDelegatingPlaybackCoordinatorBufferingCommand.
        /// If YES, the command should only be considered complete once the player is ready to receive an AVDelegatingPlaybackCoordinatorPlayCommand with the indicated rate.
        ///
        /// This property is not atomic.
        ///
        /// # Safety
        ///
        /// This might not be thread-safe.
        #[unsafe(method(shouldBufferInAnticipationOfPlayback))]
        #[unsafe(method_family = none)]
        pub unsafe fn shouldBufferInAnticipationOfPlayback(&self) -> bool;

        /// The rate to prepare for if shouldBufferInAnticipationOfPlayback is YES.
        ///
        /// This property is not atomic.
        ///
        /// # Safety
        ///
        /// This might not be thread-safe.
        #[unsafe(method(anticipatedPlaybackRate))]
        #[unsafe(method_family = none)]
        pub unsafe fn anticipatedPlaybackRate(&self) -> c_float;
    );
}

extern_class!(
    /// A playback command requesting a seek.
    ///
    /// If the current playback rate is non-zero, playback should not automatically resume after the seek. Instead the delegate should pause and wait for the coordinator to issue another PlayCommand. Subclasses of this type that are used from Swift must fulfill the requirements of a Sendable type.
    ///
    /// See also [Apple's documentation](https://developer.apple.com/documentation/avfoundation/avdelegatingplaybackcoordinatorseekcommand?language=objc)
    #[unsafe(super(AVDelegatingPlaybackCoordinatorPlaybackControlCommand, NSObject))]
    #[derive(Debug, PartialEq, Eq, Hash)]
    pub struct AVDelegatingPlaybackCoordinatorSeekCommand;
);

unsafe impl Send for AVDelegatingPlaybackCoordinatorSeekCommand {}

unsafe impl Sync for AVDelegatingPlaybackCoordinatorSeekCommand {}

extern_conformance!(
    unsafe impl NSObjectProtocol for AVDelegatingPlaybackCoordinatorSeekCommand {}
);

impl AVDelegatingPlaybackCoordinatorSeekCommand {
    extern_methods!(
        #[unsafe(method(init))]
        #[unsafe(method_family = init)]
        pub unsafe fn init(this: Allocated<Self>) -> Retained<Self>;

        #[unsafe(method(new))]
        #[unsafe(method_family = new)]
        pub unsafe fn new() -> Retained<Self>;

        #[cfg(feature = "objc2-core-media")]
        /// The time to seek the currentItem to.
        ///
        /// Playback should never automatically resume after seeking to this time. The coordinator will issue a new PlayCommand when everyone else is ready to resume.
        ///
        /// This property is not atomic.
        ///
        /// # Safety
        ///
        /// This might not be thread-safe.
        #[unsafe(method(itemTime))]
        #[unsafe(method_family = none)]
        pub unsafe fn itemTime(&self) -> CMTime;

        /// Indicates that playback is anticipated and the player should begin buffering if necessary.
        ///
        /// When shouldBufferInAnticipationOfPlayback, playback is expected to eventually resume at the rate indicated by the anticipatedPlaybackRate property.
        /// This should be treated similar to receiving a separate AVDelegatingPlaybackCoordinatorBufferingCommand.
        /// If YES, the command should only be considered complete once the player is ready to receive an AVDelegatingPlaybackCoordinatorPlayCommand with the indicated rate.
        ///
        /// This property is not atomic.
        ///
        /// # Safety
        ///
        /// This might not be thread-safe.
        #[unsafe(method(shouldBufferInAnticipationOfPlayback))]
        #[unsafe(method_family = none)]
        pub unsafe fn shouldBufferInAnticipationOfPlayback(&self) -> bool;

        /// The rate to prepare for if shouldBufferInAnticipationOfPlayback is YES.
        ///
        /// This property is not atomic.
        ///
        /// # Safety
        ///
        /// This might not be thread-safe.
        #[unsafe(method(anticipatedPlaybackRate))]
        #[unsafe(method_family = none)]
        pub unsafe fn anticipatedPlaybackRate(&self) -> c_float;

        /// Communicates when the coordinator expects the command's completion handler at the latest.
        ///
        /// A seek command expecting buffering in anticipation of playback does expect the receiver to fire the completion handler by this date at the latest.
        /// This is useful in buffering situations where the receiver has not yet buffered enough data to be considered ready to play by the due date.
        /// The receiver should then decide to either complete the command as is to try and keep up with the group, or alternatively begin a stall recovery
        /// suspension to communicate the situation to the other participants.
        /// Completing the command after this date means that the coordinator will likely send a play command for a later time than the receiver buffered for.
        ///
        /// This property is not atomic.
        ///
        /// # Safety
        ///
        /// This might not be thread-safe.
        #[unsafe(method(completionDueDate))]
        #[unsafe(method_family = none)]
        pub unsafe fn completionDueDate(&self) -> Option<Retained<NSDate>>;
    );
}