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
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
//! This file has been automatically generated by `objc2`'s `header-translator`.
//! DO NOT EDIT
use core::ffi::*;
use core::ptr::NonNull;
#[cfg(feature = "dispatch2")]
use dispatch2::*;
use objc2::__framework_prelude::*;
#[cfg(feature = "objc2-core-media")]
use objc2_core_media::*;
use objc2_foundation::*;

use crate::*;

/// These constants are returned by the AVPlayer status property to indicate whether it can successfully play items.
///
/// See also [Apple's documentation](https://developer.apple.com/documentation/avfoundation/avplayerstatus?language=objc)
// NS_ENUM
#[repr(transparent)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct AVPlayerStatus(pub NSInteger);
impl AVPlayerStatus {
    /// Indicates that the status of the player is not yet known because it has not tried to load new media resources for playback.
    #[doc(alias = "AVPlayerStatusUnknown")]
    pub const Unknown: Self = Self(0);
    /// Indicates that the player is ready to play AVPlayerItem instances.
    #[doc(alias = "AVPlayerStatusReadyToPlay")]
    pub const ReadyToPlay: Self = Self(1);
    /// Indicates that the player can no longer play AVPlayerItem instances because of an error. The error is described by the value of the player's error property.
    #[doc(alias = "AVPlayerStatusFailed")]
    pub const Failed: Self = Self(2);
}

unsafe impl Encode for AVPlayerStatus {
    const ENCODING: Encoding = NSInteger::ENCODING;
}

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

extern_class!(
    /// AVPlayer offers a playback interface for single-item playback that's sufficient for the implementation of playback controllers and playback user interfaces.
    ///
    /// AVPlayer works equally well with local and remote media files, providing clients with appropriate
    /// information about readiness to play or about the need to await additional data before continuing.
    ///
    /// Visual content of items played by an instance of AVPlayer can be displayed in a CoreAnimation layer
    /// of class AVPlayerLayer.
    ///
    /// To allow clients to add and remove their objects as key-value observers safely, AVPlayer serializes notifications of
    /// changes that occur dynamically during playback on a dispatch queue. By default, this queue is the main queue. See dispatch_get_main_queue().
    ///
    /// See also [Apple's documentation](https://developer.apple.com/documentation/avfoundation/avplayer?language=objc)
    #[unsafe(super(NSObject))]
    #[thread_kind = MainThreadOnly]
    #[derive(Debug, PartialEq, Eq, Hash)]
    pub struct AVPlayer;
);

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

impl AVPlayer {
    extern_methods!(
        /// Initializes an AVPlayer with no player items.
        #[unsafe(method(init))]
        #[unsafe(method_family = init)]
        pub unsafe fn init(this: Allocated<Self>) -> Retained<Self>;

        /// Returns an instance of AVPlayer that plays a single audiovisual resource referenced by URL.
        ///
        /// Implicitly creates an AVPlayerItem. Clients can obtain the AVPlayerItem as it becomes the player's currentItem.
        ///
        /// - Parameter URL:
        ///
        /// - Returns: An instance of AVPlayer
        #[unsafe(method(playerWithURL:))]
        #[unsafe(method_family = none)]
        pub unsafe fn playerWithURL(url: &NSURL, mtm: MainThreadMarker) -> Retained<Self>;

        #[cfg(feature = "AVPlayerItem")]
        /// Create an AVPlayer that plays a single audiovisual item.
        ///
        /// Useful in order to play items for which an AVAsset has previously been created. See -[AVPlayerItem initWithAsset:].
        ///
        /// - Parameter item:
        ///
        /// - Returns: An instance of AVPlayer
        #[unsafe(method(playerWithPlayerItem:))]
        #[unsafe(method_family = none)]
        pub unsafe fn playerWithPlayerItem(
            item: Option<&AVPlayerItem>,
            mtm: MainThreadMarker,
        ) -> Retained<Self>;

        /// Initializes an AVPlayer that plays a single audiovisual resource referenced by URL.
        ///
        /// Implicitly creates an AVPlayerItem. Clients can obtain the AVPlayerItem as it becomes the player's currentItem.
        ///
        /// - Parameter URL:
        ///
        /// - Returns: An instance of AVPlayer
        #[unsafe(method(initWithURL:))]
        #[unsafe(method_family = init)]
        pub unsafe fn initWithURL(this: Allocated<Self>, url: &NSURL) -> Retained<Self>;

        #[cfg(feature = "AVPlayerItem")]
        /// Create an AVPlayer that plays a single audiovisual item.
        ///
        /// Useful in order to play items for which an AVAsset has previously been created. See -[AVPlayerItem initWithAsset:].
        /// This method throws an exception if the item is not an AVPlayerItem, or if the item is
        /// associated with another AVPlayer.
        ///
        /// - Parameter item:
        ///
        /// - Returns: An instance of AVPlayer
        #[unsafe(method(initWithPlayerItem:))]
        #[unsafe(method_family = init)]
        pub unsafe fn initWithPlayerItem(
            this: Allocated<Self>,
            item: Option<&AVPlayerItem>,
        ) -> Retained<Self>;

        /// The ability of the receiver to be used for playback.
        ///
        /// The value of this property is an AVPlayerStatus that indicates whether the receiver can be used for playback. When
        /// the value of this property is AVPlayerStatusFailed, the receiver can no longer be used for playback and a new
        /// instance needs to be created in its place. When this happens, clients can check the value of the error property to
        /// determine the nature of the failure. This property is key value observable.
        #[unsafe(method(status))]
        #[unsafe(method_family = none)]
        pub unsafe fn status(&self) -> AVPlayerStatus;

        /// If the receiver's status is AVPlayerStatusFailed, this describes the error that caused the failure.
        ///
        /// The value of this property is an NSError that describes what caused the receiver to no longer be able to play items.
        /// If the receiver's status is not AVPlayerStatusFailed, the value of this property is nil.
        #[unsafe(method(error))]
        #[unsafe(method_family = none)]
        pub unsafe fn error(&self) -> Option<Retained<NSError>>;
    );
}

/// Methods declared on superclass `NSObject`.
impl AVPlayer {
    extern_methods!(
        #[unsafe(method(new))]
        #[unsafe(method_family = new)]
        pub unsafe fn new(mtm: MainThreadMarker) -> Retained<Self>;
    );
}

extern "C" {
    /// Indicates a player rate change.
    ///
    /// Posted by the player when its rate changes. Similar to KVO of AVPlayer.rate, but providing additional information about the rate change in the userInfo. See keys below.
    ///
    /// See also [Apple's documentation](https://developer.apple.com/documentation/avfoundation/avplayerratedidchangenotification?language=objc)
    pub static AVPlayerRateDidChangeNotification: &'static NSNotificationName;
}

extern "C" {
    /// Indicates a reason for the rate change notification.
    ///
    /// The value corresponding to this key is of type AVPlayerRateDidChangeReason.
    ///
    /// See also [Apple's documentation](https://developer.apple.com/documentation/avfoundation/avplayerratedidchangereasonkey?language=objc)
    pub static AVPlayerRateDidChangeReasonKey: &'static NSString;
}

extern "C" {
    /// Indicates a rate change was caused by another participant connected through AVPlayerPlaybackCoordinator.
    ///
    /// Informs the receiver of an AVPlayerRateDidChangeNotification about a rate change originated from another AVCoordinatedPlaybackParticipant connected through AVPlayerPlaybackCoordinator. This can be used to inform UI showing why the playback rate changed. The type of the value for this key is an AVCoordinatedPlaybackParticipant, which is part of the AVPlayerPlaybackCoordinator.otherParticipants array.
    ///
    /// See also [Apple's documentation](https://developer.apple.com/documentation/avfoundation/avplayerratedidchangeoriginatingparticipantkey?language=objc)
    pub static AVPlayerRateDidChangeOriginatingParticipantKey: &'static NSString;
}

/// [Apple's documentation](https://developer.apple.com/documentation/avfoundation/avplayerratedidchangereason?language=objc)
// NS_TYPED_ENUM
pub type AVPlayerRateDidChangeReason = NSString;

extern "C" {
    /// [Apple's documentation](https://developer.apple.com/documentation/avfoundation/avplayerratedidchangereasonsetratecalled?language=objc)
    pub static AVPlayerRateDidChangeReasonSetRateCalled: &'static AVPlayerRateDidChangeReason;
}

extern "C" {
    /// [Apple's documentation](https://developer.apple.com/documentation/avfoundation/avplayerratedidchangereasonsetratefailed?language=objc)
    pub static AVPlayerRateDidChangeReasonSetRateFailed: &'static AVPlayerRateDidChangeReason;
}

extern "C" {
    /// [Apple's documentation](https://developer.apple.com/documentation/avfoundation/avplayerratedidchangereasonaudiosessioninterrupted?language=objc)
    pub static AVPlayerRateDidChangeReasonAudioSessionInterrupted:
        &'static AVPlayerRateDidChangeReason;
}

extern "C" {
    /// [Apple's documentation](https://developer.apple.com/documentation/avfoundation/avplayerratedidchangereasonappbackgrounded?language=objc)
    pub static AVPlayerRateDidChangeReasonAppBackgrounded: &'static AVPlayerRateDidChangeReason;
}

/// These constants are the allowable values of AVPlayer's timeControlStatus property. This discussion pertains when automaticallyWaitsToMinimizeStalling is YES, the default setting, and exceptions are discussed in connection with automaticallyWaitsToMinimizeStalling.
///
/// See also [Apple's documentation](https://developer.apple.com/documentation/avfoundation/avplayertimecontrolstatus?language=objc)
// NS_ENUM
#[repr(transparent)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct AVPlayerTimeControlStatus(pub NSInteger);
impl AVPlayerTimeControlStatus {
    /// This state is entered upon receipt of a -pause message, an invocation of -setRate: with a value of 0.0, when a change in overall state requires playback to be halted, such as when an interruption occurs on iOS, as announced by AVAudioSession. In this state, playback is paused indefinitely and will not resume until 1) a subsequent -play message is received or 2) a -setRate: or -playImmediatelyAtRate: message with a non-zero value for rate is received and sufficient media data has been buffered for playback to proceed.
    #[doc(alias = "AVPlayerTimeControlStatusPaused")]
    pub const Paused: Self = Self(0);
    /// This state is entered when 1) the playback buffer becomes empty and playback stalls in AVPlayerTimeControlStatusPlaying, 2) when rate is set from zero to non-zero in AVPlayerTimeControlStatusPaused and insufficient media data has been buffered for playback to occur, or 3) when the player has no item to play, i.e. when the receiver's currentItem is nil. In this state, the value of the rate property is not currently effective but instead indicates the rate at which playback will start or resume. Refer to the value of reasonForWaitingToPlay for details about why the receiver is waiting and the conditions that allow waitStatus to change to AVPlayerWaitStatusPlaying. While waiting for buffering, you can attempt to start playback of any available media data via -playImmediatelyAtRate:.
    #[doc(alias = "AVPlayerTimeControlStatusWaitingToPlayAtSpecifiedRate")]
    pub const WaitingToPlayAtSpecifiedRate: Self = Self(1);
    /// In this state, playback is currently progressing and rate changes will take effect immediately. Should playback stall because of insufficient media data, timeControlStatus will change to AVPlayerTimeControlStatusWaitingToPlayAtSpecifiedRate.
    #[doc(alias = "AVPlayerTimeControlStatusPlaying")]
    pub const Playing: Self = Self(2);
}

unsafe impl Encode for AVPlayerTimeControlStatus {
    const ENCODING: Encoding = NSInteger::ENCODING;
}

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

/// The type of reason that a player is waiting for playback.
///
/// See also [Apple's documentation](https://developer.apple.com/documentation/avfoundation/avplayerwaitingreason?language=objc)
// NS_TYPED_ENUM
pub type AVPlayerWaitingReason = NSString;

extern "C" {
    /// Indicates that the player is waiting for appropriate playback buffer conditions before starting playback
    ///
    /// The player is waiting for playback because automaticallyWaitToMinimizeStalling is YES and playback at the specified rate would likely cause the playback buffer to become empty before playback completes. Playback will resume when 1) playback at the specified rate will likely complete without a stall or 2) the playback buffer becomes full, meaning no forther buffering of media data is possible.
    /// When the value of automaticallyWaitsToMinimizeStalling is NO, timeControlStatus cannot become AVPlayerTimeControlStatusWaitingToPlayAtSpecifiedRate for this reason.
    ///
    /// See also [Apple's documentation](https://developer.apple.com/documentation/avfoundation/avplayerwaitingtominimizestallsreason?language=objc)
    pub static AVPlayerWaitingToMinimizeStallsReason: &'static AVPlayerWaitingReason;
}

extern "C" {
    /// Indicates that the player is monitoring the playback buffer fill rate to determine if playback is likely to complete without interruptions.
    ///
    /// The player is waiting for playback because automaticallyWaitToMinimizeStalling is YES and it has not yet determined if starting playback at the specified rate would likely cause the buffer to become empty. When the brief initial monitoring period is over, either playback will begin or the value of reasonForWaitingToPlayAtSpecifiedRate will switch to AVPlayerWaitingToMinimizeStallsReason.
    /// Recommended practice is not to show UI indicating the waiting state to the user while the value of reasonForWaitingToPlayAtSpecifiedRate is AVPlayerWaitingWhileEvaluatingBufferingRateReason.
    ///
    /// See also [Apple's documentation](https://developer.apple.com/documentation/avfoundation/avplayerwaitingwhileevaluatingbufferingratereason?language=objc)
    pub static AVPlayerWaitingWhileEvaluatingBufferingRateReason: &'static AVPlayerWaitingReason;
}

extern "C" {
    /// Indicates that the AVPlayer is waiting because its currentItem is nil
    ///
    /// The player is waiting for playback because automaticallyWaitToMinimizeStalling is YES and the value of currentItem is nil. When an item becomes available, either because of a call to -replaceCurrentItemWithPlayerItem: or -insertItem: afterItem:, playback will begin or the value of reasonForWaitingToPlay will change.
    ///
    /// See also [Apple's documentation](https://developer.apple.com/documentation/avfoundation/avplayerwaitingwithnoitemtoplayreason?language=objc)
    pub static AVPlayerWaitingWithNoItemToPlayReason: &'static AVPlayerWaitingReason;
}

extern "C" {
    /// Indicates that the player is waiting for another participant connected through its AVPlayerPlaybackCoordinator.
    ///
    /// The player is waiting for playback because its connected AVPlayerPlaybackCoordinator requires information from one of the other participants before playback can start.
    ///
    /// See also [Apple's documentation](https://developer.apple.com/documentation/avfoundation/avplayerwaitingforcoordinatedplaybackreason?language=objc)
    pub static AVPlayerWaitingForCoordinatedPlaybackReason: &'static AVPlayerWaitingReason;
}

/// AVPlayerPlaybackControl.
impl AVPlayer {
    extern_methods!(
        /// Indicates the desired rate of playback; 0.0 means "paused", 1.0 indicates a desire to play at the natural rate of the current item.
        ///
        /// Setting the value of rate to 0.0 pauses playback, causing the value of timeControlStatus to change to AVPlayerTimeControlStatusPaused.
        /// Setting the rate to a non-zero value causes the value of timeControlStatus to become either AVPlayerTimeControlStatusWaitingToPlayAtSpecifiedRate or AVPlayerTimeControlStatusPlaying, depending on whether sufficient media data has been buffered for playback to occur and whether the player's default behavior of waiting in order to minimize stalling is permitted. See discussion of AVPlayerTimeControlStatus for more details.
        ///
        /// AVPlayer can reset the desired rate to 0.0 when a change in overall state requires playback to be halted, such as when an interruption occurs on iOS, as announced by AVAudioSession, or when the playback buffer becomes empty and playback stalls while automaticallyWaitsToMinimizeStalling is NO.
        ///
        /// The effective rate of playback may differ from the desired rate even while timeControlStatus is AVPlayerTimeControlStatusPlaying, if the processing algorithm in use for managing audio pitch requires quantization of playback rate. For information about quantization of rates for audio processing, see AVAudioProcessingSettings.h. You can always obtain the effective rate of playback from the currentItem's timebase; see the timebase property of AVPlayerItem.
        ///
        /// Before macOS 13, iOS 16, tvOS 16, and watchOS 9, this property must be accessed on the main thread/queue.
        #[unsafe(method(rate))]
        #[unsafe(method_family = none)]
        pub unsafe fn rate(&self) -> c_float;

        /// Setter for [`rate`][Self::rate].
        #[unsafe(method(setRate:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setRate(&self, rate: c_float);

        /// Indicates the rate at which to start playback when play is called; defaults to 1.0.
        ///
        /// Setting this property does not imply playback starts automatically at this rate. Clients still have to kick off playback using `play`. Note that using setRate to start playback will skip using the value in this property nor would it update this property. Therefore, `setRate:1.0` is no longer recommended as a means to start playback. Use `play` instead. Use `setRate` for operations like scanning where the rate is to be updated instantaneously. Invoking `play` again would restore playback at the rate set in this property.
        ///
        /// The effective rate of playback may still differ from the default rate subject to restrictions imposed by the system. See documentation for the rate property for a discussion on when the desired rate does not translate to effective rate.
        #[unsafe(method(defaultRate))]
        #[unsafe(method_family = none)]
        pub unsafe fn defaultRate(&self) -> c_float;

        /// Setter for [`defaultRate`][Self::defaultRate].
        #[unsafe(method(setDefaultRate:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setDefaultRate(&self, default_rate: c_float);

        /// Signals the desire to begin playback at the rate set in the defaultRate.
        ///
        /// For releases up to iOS version 16.0, macOS versions 13.0, tvOS 16.0 and watchOS 9.0, this is equivalent to setting the value of rate to `1.0`. Starting from iOS version 16.0, macOS versions 13.0, tvOS 16.0 and watchOS 9.0, this will attempt to use the rate set in the `defaultRate` property. The effective rate of playback may differ from the `defaultRate` due to the reasons mentioned in the documentation of the `rate` property. Clients interested in knowing the effective rate can listen for `AVPlayerRateDidChangeNotification` notification.
        ///
        /// Before macOS 13, iOS 16, tvOS 16, and watchOS 9, this method must be invoked on the main thread/queue.
        #[unsafe(method(play))]
        #[unsafe(method_family = none)]
        pub unsafe fn play(&self);

        /// Pauses playback.
        ///
        /// Equivalent to setting the value of rate to 0.0.
        ///
        /// Before macOS 13, iOS 16, tvOS 16, and watchOS 9, this method must be invoked on the main thread/queue.
        #[unsafe(method(pause))]
        #[unsafe(method_family = none)]
        pub unsafe fn pause(&self);

        /// Indicates whether playback is currently paused indefinitely, suspended while waiting for appropriate conditions, or in progress.
        ///
        /// For possible values and discussion, see AVPlayerTimeControlStatus.
        ///
        /// When automaticallyWaitsToMinimizeStalling is YES, absent intervention in the form of invocations of -setRate: or -pause or, on iOS, an interruption that requires user intervention before playback can resume, the value of the property timeControlStatus automatically changes between AVPlayerTimeControlStatusPlaying and AVPlayerTimeControlStatusWaitingToPlayAtSpecifiedRate depending on whether sufficient media data is available to continue playback. This property is key value observable.
        #[unsafe(method(timeControlStatus))]
        #[unsafe(method_family = none)]
        pub unsafe fn timeControlStatus(&self) -> AVPlayerTimeControlStatus;

        /// Indicates the reason for waiting when the value of timeControlStatus is AVPlayerTimeControlStatusWaitingToPlayAtSpecifiedRate
        ///
        /// When the value of timeControlStatus is AVPlayerTimeControlStatusWaitingToPlayAtSpecifiedRate, this property describes why the player is currently waiting. It is nil otherwise.
        /// You can use the value of reasonForWaitingToPlay to show UI indicating the player's waiting state conditionally.
        /// This property is key value observable.
        /// Possible values are AVPlayerWaitingWithNoItemToPlayReason, AVPlayerWaitingWhileEvaluatingBufferingRateReason, and AVPlayerWaitingToMinimizeStallsReason.
        #[unsafe(method(reasonForWaitingToPlay))]
        #[unsafe(method_family = none)]
        pub unsafe fn reasonForWaitingToPlay(&self) -> Option<Retained<AVPlayerWaitingReason>>;

        /// Immediately plays the available media data at the specified rate.
        ///
        /// When the player's currentItem has a value of NO for playbackBufferEmpty, this method causes the value of rate to change to the specified rate, the value of timeControlStatus to change to AVPlayerTimeControlStatusPlaying, and the receiver to play the available media immediately, whether or not prior buffering of media data is sufficient to ensure smooth playback.
        /// If insufficient media data is buffered for playback to start (e.g. if the current item has a value of YES for playbackBufferEmpty), the receiver will act as if the buffer became empty during playback, except that no AVPlayerItemPlaybackStalledNotification will be posted.
        ///
        /// Before macOS 13, iOS 16, tvOS 16, and watchOS 9, this method must be invoked on the main thread/queue.
        #[unsafe(method(playImmediatelyAtRate:))]
        #[unsafe(method_family = none)]
        pub unsafe fn playImmediatelyAtRate(&self, rate: c_float);
    );
}

/// These constants are the allowable values of AVPlayer's actionAtItemEnd property.
///
/// See also [Apple's documentation](https://developer.apple.com/documentation/avfoundation/avplayeractionatitemend?language=objc)
// NS_ENUM
#[repr(transparent)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct AVPlayerActionAtItemEnd(pub NSInteger);
impl AVPlayerActionAtItemEnd {
    /// Indicates that when an AVPlayerItem reaches its end time the player will automatically advance to the next item in its queue. This value is supported only for players of class AVQueuePlayer. An AVPlayer that's not an AVQueuePlayer will raise an NSInvalidArgumentException if an attempt is made to set its actionAtItemEnd to AVPlayerActionAtItemEndAdvance.
    #[doc(alias = "AVPlayerActionAtItemEndAdvance")]
    pub const Advance: Self = Self(0);
    /// Indicates that when an AVPlayerItem reaches its end time the player will automatically pause (which is to say, the player's rate will automatically be set to 0).
    #[doc(alias = "AVPlayerActionAtItemEndPause")]
    pub const Pause: Self = Self(1);
    /// Indicates that when an AVPlayerItem reaches its end time the player will take no action (which is to say, the player's rate will not change, its currentItem will not change, and its currentTime will continue to be incremented or decremented as time elapses, according to its rate). After this, if the player's actionAtItemEnd is set to a value other than AVPlayerActionAtItemEndNone, the player will immediately take the action appropriate to that value.
    #[doc(alias = "AVPlayerActionAtItemEndNone")]
    pub const None: Self = Self(2);
}

unsafe impl Encode for AVPlayerActionAtItemEnd {
    const ENCODING: Encoding = NSInteger::ENCODING;
}

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

/// AVPlayerItemControl.
impl AVPlayer {
    extern_methods!(
        #[cfg(feature = "AVPlayerItem")]
        /// Indicates the current item of the player
        #[unsafe(method(currentItem))]
        #[unsafe(method_family = none)]
        pub unsafe fn currentItem(&self) -> Option<Retained<AVPlayerItem>>;

        #[cfg(feature = "AVPlayerItem")]
        /// Replaces the player's current item with the specified player item.
        ///
        /// In all releases of iOS 4, invoking replaceCurrentItemWithPlayerItem: with an AVPlayerItem that's already the receiver's currentItem results in an exception being raised. Starting with iOS 5, it's a no-op.
        /// This method throws an exception if the item already exists in the play queue.
        ///
        /// - Parameter item: The AVPlayerItem that will become the player's current item.
        #[unsafe(method(replaceCurrentItemWithPlayerItem:))]
        #[unsafe(method_family = none)]
        pub unsafe fn replaceCurrentItemWithPlayerItem(&self, item: Option<&AVPlayerItem>);

        /// Indicates the action that the player should perform when playback of an item reaches its end time.
        ///
        /// This property throws an exception if set to AVPlayerActionAtItemEndAdvance on an AVPlayer which is not an AVQueuePlayer.
        #[unsafe(method(actionAtItemEnd))]
        #[unsafe(method_family = none)]
        pub unsafe fn actionAtItemEnd(&self) -> AVPlayerActionAtItemEnd;

        /// Setter for [`actionAtItemEnd`][Self::actionAtItemEnd].
        #[unsafe(method(setActionAtItemEnd:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setActionAtItemEnd(&self, action_at_item_end: AVPlayerActionAtItemEnd);
    );
}

/// AVPlayerTimeControl.
impl AVPlayer {
    extern_methods!(
        #[cfg(feature = "objc2-core-media")]
        /// Returns the current time of the current item.
        ///
        /// Returns the current time of the current item. Not key-value observable; use -addPeriodicTimeObserverForInterval:queue:usingBlock: instead.
        ///
        /// - Returns: A CMTime
        #[unsafe(method(currentTime))]
        #[unsafe(method_family = none)]
        pub unsafe fn currentTime(&self) -> CMTime;

        /// Moves the playback cursor.
        ///
        /// Use this method to seek to a specified time for the current player item.
        /// The time seeked to may differ from the specified time for efficiency. For sample accurate seeking see seekToTime:toleranceBefore:toleranceAfter:.
        ///
        /// - Parameter date:
        #[unsafe(method(seekToDate:))]
        #[unsafe(method_family = none)]
        pub unsafe fn seekToDate(&self, date: &NSDate);

        #[cfg(feature = "block2")]
        /// Moves the playback cursor and invokes the specified block when the seek operation has either been completed or been interrupted.
        ///
        /// Use this method to seek to a specified time for the current player item and to be notified when the seek operation is complete.
        /// The completion handler for any prior seek request that is still in process will be invoked immediately with the finished parameter
        /// set to NO. If the new request completes without being interrupted by another seek request or by any other operation the specified
        /// completion handler will be invoked with the finished parameter set to YES. If no item is attached, the completion handler will be
        /// invoked immediately with the finished parameter set to NO.
        ///
        /// - Parameter date:
        /// - Parameter completionHandler:
        ///
        /// # Safety
        ///
        /// `completion_handler` block must be sendable.
        #[unsafe(method(seekToDate:completionHandler:))]
        #[unsafe(method_family = none)]
        pub unsafe fn seekToDate_completionHandler(
            &self,
            date: &NSDate,
            completion_handler: &block2::DynBlock<dyn Fn(Bool)>,
        );

        #[cfg(feature = "objc2-core-media")]
        /// Moves the playback cursor.
        ///
        /// Use this method to seek to a specified time for the current player item.
        /// The time seeked to may differ from the specified time for efficiency. For sample accurate seeking see seekToTime:toleranceBefore:toleranceAfter:.
        ///
        /// - Parameter time:
        #[unsafe(method(seekToTime:))]
        #[unsafe(method_family = none)]
        pub unsafe fn seekToTime(&self, time: CMTime);

        #[cfg(feature = "objc2-core-media")]
        /// Moves the playback cursor within a specified time bound.
        ///
        /// Use this method to seek to a specified time for the current player item.
        /// The time seeked to will be within the range [time-toleranceBefore, time+toleranceAfter] and may differ from the specified time for efficiency.
        /// Pass kCMTimeZero for both toleranceBefore and toleranceAfter to request sample accurate seeking which may incur additional decoding delay.
        /// Messaging this method with beforeTolerance:kCMTimePositiveInfinity and afterTolerance:kCMTimePositiveInfinity is the same as messaging seekToTime: directly.
        ///
        /// - Parameter time:
        /// - Parameter toleranceBefore:
        /// - Parameter toleranceAfter:
        #[unsafe(method(seekToTime:toleranceBefore:toleranceAfter:))]
        #[unsafe(method_family = none)]
        pub unsafe fn seekToTime_toleranceBefore_toleranceAfter(
            &self,
            time: CMTime,
            tolerance_before: CMTime,
            tolerance_after: CMTime,
        );

        #[cfg(all(feature = "block2", feature = "objc2-core-media"))]
        /// Moves the playback cursor and invokes the specified block when the seek operation has either been completed or been interrupted.
        ///
        /// Use this method to seek to a specified time for the current player item and to be notified when the seek operation is complete.
        /// The completion handler for any prior seek request that is still in process will be invoked immediately with the finished parameter
        /// set to NO. If the new request completes without being interrupted by another seek request or by any other operation the specified
        /// completion handler will be invoked with the finished parameter set to YES. If no item is attached, the completion handler will be
        /// invoked immediately with the finished parameter set to NO.
        ///
        /// - Parameter time:
        /// - Parameter completionHandler:
        ///
        /// # Safety
        ///
        /// `completion_handler` block must be sendable.
        #[unsafe(method(seekToTime:completionHandler:))]
        #[unsafe(method_family = none)]
        pub unsafe fn seekToTime_completionHandler(
            &self,
            time: CMTime,
            completion_handler: &block2::DynBlock<dyn Fn(Bool)>,
        );

        #[cfg(all(feature = "block2", feature = "objc2-core-media"))]
        /// Moves the playback cursor within a specified time bound and invokes the specified block when the seek operation has either been completed or been interrupted.
        ///
        /// Use this method to seek to a specified time for the current player item and to be notified when the seek operation is complete.
        /// The time seeked to will be within the range [time-toleranceBefore, time+toleranceAfter] and may differ from the specified time for efficiency.
        /// Pass kCMTimeZero for both toleranceBefore and toleranceAfter to request sample accurate seeking which may incur additional decoding delay.
        /// Messaging this method with beforeTolerance:kCMTimePositiveInfinity and afterTolerance:kCMTimePositiveInfinity is the same as messaging seekToTime: directly.
        /// The completion handler for any prior seek request that is still in process will be invoked immediately with the finished parameter set to NO. If the new
        /// request completes without being interrupted by another seek request or by any other operation the specified completion handler will be invoked with the
        /// finished parameter set to YES. If no item is attached, the completion handler will be invoked immediately with the finished parameter set to NO.
        ///
        /// - Parameter time:
        /// - Parameter toleranceBefore:
        /// - Parameter toleranceAfter:
        ///
        /// # Safety
        ///
        /// `completion_handler` block must be sendable.
        #[unsafe(method(seekToTime:toleranceBefore:toleranceAfter:completionHandler:))]
        #[unsafe(method_family = none)]
        pub unsafe fn seekToTime_toleranceBefore_toleranceAfter_completionHandler(
            &self,
            time: CMTime,
            tolerance_before: CMTime,
            tolerance_after: CMTime,
            completion_handler: &block2::DynBlock<dyn Fn(Bool)>,
        );
    );
}

/// AVPlayerAdvancedRateControl.
impl AVPlayer {
    extern_methods!(
        /// Indicates that the player is allowed to delay playback at the specified rate in order to minimize stalling
        ///
        /// When this property is YES, whenever 1) the rate is set from zero to non-zero or 2) the playback buffer becomes empty and playback stalls, the player will attempt to determine if, at the specified rate, its currentItem will play to the end without interruptions. Should it determine that such interruptions would occur and these interruptions can be avoided by delaying the start or resumption of playback, the value of timeControlStatus will become AVPlayerTimeControlStatusWaitingToPlayAtSpecifiedRate and playback will start automatically when the likelihood of stalling has been minimized.
        ///
        /// You may want to set this property to NO when you need precise control over playback start times, e.g., when synchronizing multiple instances of AVPlayer, and you should set it to NO if you use an AVAssetResourceLoader delegate to load media data (more on this below). If the value of this property is NO, reasonForWaitingToPlay cannot assume a value of AVPlayerWaitingToMinimizeStallsReason.
        /// This implies that setting rate to a non-zero value in AVPlayerTimeControlStatusPaused will cause playback to start immediately as long as the playback buffer is not empty. When the playback buffer becomes empty during AVPlayerTimeControlStatusPlaying and playback stalls, playback state will switch to AVPlayerTimeControlStatusPaused and the rate will become 0.0.
        ///
        /// Changing the value of this property to NO while the value of timeControlStatus is AVPlayerTimeControlStatusWaitingToPlayAtSpecifiedRate with a reasonForWaitingToPlay of AVPlayerWaitingToMinimizeStallsReason will cause the player to attempt playback at the specified rate immediately.
        ///
        /// For clients linked against iOS 10.0 and running on that version or later or linked against macOS 10.12 and running on that version or later, the default value of this property is YES.
        /// In versions of iOS prior to iOS 10.0 and versions of macOS prior to 10.12, this property is unavailable, and the behavior of the AVPlayer corresponds to the type of content being played. For streaming content, including HTTP Live Streaming, the AVPlayer acts as if automaticallyWaitsToMinimizeStalling is YES. For file-based content, including file-based content accessed via progressive http download, the AVPlayer acts as if automaticallyWaitsToMinimizeStalling is NO.
        ///
        /// If you employ an AVAssetResourceLoader delegate that loads media data for playback, you should set the value of your AVPlayer’s automaticallyWaitsToMinimizeStalling property to NO. Allowing the value of automaticallyWaitsToMinimizeStalling to remain YES when an AVAssetResourceLoader delegate is used for the loading of media data can result in poor start-up times for playback and poor recovery from stalls, because the behaviors provided by AVPlayer when automaticallyWaitsToMinimizeStalling has a value of YES depend on predictions of the future availability of media data that that do not function as expected when data is loaded via a client-controlled means, using the AVAssetResourceLoader delegate interface.
        ///
        /// You can allow the value of automaticallyWaitsToMinimizeStalling to remain YES if you use an AVAssetResourceLoader delegate to manage content keys for FairPlay Streaming, to provide dynamically-generated master playlists for HTTP Live Streaming, or to respond to authentication challenges, but not to load media data for playback.
        ///
        /// Before macOS 13, iOS 16, tvOS 16, and watchOS 9, this property must be accessed on the main thread/queue.
        #[unsafe(method(automaticallyWaitsToMinimizeStalling))]
        #[unsafe(method_family = none)]
        pub unsafe fn automaticallyWaitsToMinimizeStalling(&self) -> bool;

        /// Setter for [`automaticallyWaitsToMinimizeStalling`][Self::automaticallyWaitsToMinimizeStalling].
        #[unsafe(method(setAutomaticallyWaitsToMinimizeStalling:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setAutomaticallyWaitsToMinimizeStalling(
            &self,
            automatically_waits_to_minimize_stalling: bool,
        );

        #[cfg(feature = "objc2-core-media")]
        /// Simultaneously sets the playback rate and the relationship between the current item's current time and host time.
        ///
        /// You can use this function to synchronize playback with an external activity.
        ///
        /// The current item's timebase is adjusted so that its time will be (or was) itemTime when host time is (or was) hostClockTime.
        /// In other words: if hostClockTime is in the past, the timebase's time will be interpolated as though the timebase has been running at the requested rate since that time. If hostClockTime is in the future, the timebase will immediately start running at the requested rate from an earlier time so that it will reach the requested itemTime at the requested hostClockTime. (Note that the item's time will not jump backwards, but instead will sit at itemTime until the timebase reaches that time.)
        ///
        /// Note that setRate:time:atHostTime: is not supported when automaticallyWaitsToMinimizeStalling is YES. For clients linked against iOS 10.0 and later or macOS 12.0 and later, invoking setRate:time:atHostTime: when automaticallyWaitsToMinimizeStalling is YES will raise an NSInvalidArgument exception. Support for HTTP Live Streaming content requires iOS 11, tvOS 11, macOS 10.13 or later.
        ///
        /// Before macOS 13, iOS 16, tvOS 16, and watchOS 9, this method must be invoked on the main thread/queue.
        ///
        /// - Parameter itemTime: The time to start playback from, specified precisely (i.e., with zero tolerance). Pass kCMTimeInvalid to use the current item's current time.
        /// - Parameter hostClockTime: The host time at which to start playback. If hostClockTime is specified, the player will not ensure that media data is loaded before the timebase starts moving. If hostClockTime is kCMTimeInvalid, the rate and time will be set together, but without external synchronization; a host time in the near future will be used, allowing some time for media data loading.
        #[unsafe(method(setRate:time:atHostTime:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setRate_time_atHostTime(
            &self,
            rate: c_float,
            item_time: CMTime,
            host_clock_time: CMTime,
        );

        #[cfg(feature = "block2")]
        /// Begins loading media data to prime the render pipelines for playback from the current time with the given rate.
        ///
        /// Once the completion handler is called with YES, the player's rate can be set with minimal latency.
        /// The completion handler will be called with NO if the preroll is interrupted by a time change or incompatible rate change, or if preroll is not possible for some other reason.
        /// Call this method only when the rate is currently zero and only after the AVPlayer's status has become AVPlayerStatusReadyToPlay.
        /// This method throws an exception if the status is not AVPlayerStatusReadyToPlay.
        ///
        /// - Parameter rate: The intended rate for subsequent playback.
        /// - Parameter completionHandler: The block that will be called when the preroll is either completed or is interrupted.
        ///
        /// # Safety
        ///
        /// `completion_handler` block must be sendable.
        #[unsafe(method(prerollAtRate:completionHandler:))]
        #[unsafe(method_family = none)]
        pub unsafe fn prerollAtRate_completionHandler(
            &self,
            rate: c_float,
            completion_handler: Option<&block2::DynBlock<dyn Fn(Bool)>>,
        );

        /// Cancel any pending preroll requests and invoke the corresponding completion handlers if present.
        ///
        /// Use this method to cancel and release the completion handlers for pending prerolls. The finished parameter of the completion handlers will be set to NO.
        #[unsafe(method(cancelPendingPrerolls))]
        #[unsafe(method_family = none)]
        pub unsafe fn cancelPendingPrerolls(&self);

        #[cfg(feature = "objc2-core-media")]
        /// Set to override the automatic choice of source clock for item timebases.
        ///
        /// NULL by default. This is most useful for synchronizing video-only movies with audio played via other means. IMPORTANT NOTE: If you specify a source clock other than the appropriate audio device clock, audio may drift out of sync.
        #[unsafe(method(sourceClock))]
        #[unsafe(method_family = none)]
        pub unsafe fn sourceClock(&self) -> Option<Retained<CMClock>>;

        #[cfg(feature = "objc2-core-media")]
        /// Setter for [`sourceClock`][Self::sourceClock].
        #[unsafe(method(setSourceClock:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setSourceClock(&self, source_clock: Option<&CMClock>);
    );
}

/// AVPlayerTimeObservation.
impl AVPlayer {
    extern_methods!(
        #[cfg(all(
            feature = "block2",
            feature = "dispatch2",
            feature = "objc2-core-media"
        ))]
        /// Requests invocation of a block during playback to report changing time.
        ///
        /// The block is invoked periodically at the interval specified, interpreted according to the timeline of the current item.
        /// The block is also invoked whenever time jumps and whenever playback starts or stops.
        /// If the interval corresponds to a very short interval in real time, the player may invoke the block less frequently
        /// than requested. Even so, the player will invoke the block sufficiently often for the client to update indications
        /// of the current time appropriately in its end-user interface.
        /// Each call to -addPeriodicTimeObserverForInterval:queue:usingBlock: should be paired with a corresponding call to -removeTimeObserver:.
        /// Releasing the observer object without a call to -removeTimeObserver: will result in undefined behavior.
        ///
        /// - Parameter interval: The interval of invocation of the block during normal playback, according to progress of the current time of the player.
        /// - Parameter queue: The serial queue onto which block should be enqueued. If you pass NULL, the main queue (obtained using dispatch_get_main_queue()) will be used. Passing a concurrent queue to this method will result in undefined behavior.
        /// - Parameter block: The block to be invoked periodically.
        ///
        /// - Returns: An object conforming to the NSObject protocol.  You must retain this returned value as long as you want the time observer to be invoked by the player.
        /// Pass this object to -removeTimeObserver: to cancel time observation.
        ///
        /// # Safety
        ///
        /// - `queue` possibly has additional threading requirements.
        /// - `block` block must be sendable.
        #[unsafe(method(addPeriodicTimeObserverForInterval:queue:usingBlock:))]
        #[unsafe(method_family = none)]
        pub unsafe fn addPeriodicTimeObserverForInterval_queue_usingBlock(
            &self,
            interval: CMTime,
            queue: Option<&DispatchQueue>,
            block: &block2::DynBlock<dyn Fn(CMTime)>,
        ) -> Retained<AnyObject>;

        #[cfg(all(feature = "block2", feature = "dispatch2"))]
        /// Requests invocation of a block when specified times are traversed during normal playback.
        ///
        /// Each call to -addPeriodicTimeObserverForInterval:queue:usingBlock: should be paired with a corresponding call to -removeTimeObserver:.
        /// Releasing the observer object without a call to -removeTimeObserver: will result in undefined behavior.
        ///
        /// - Parameter times: The times for which the observer requests notification, supplied as an array of NSValues carrying CMTimes.
        /// - Parameter queue: The serial queue onto which block should be enqueued. If you pass NULL, the main queue (obtained using dispatch_get_main_queue()) will be used. Passing a concurrent queue to this method will result in undefined behavior.
        /// - Parameter block: The block to be invoked when any of the specified times is crossed during normal playback.
        ///
        /// - Returns: An object conforming to the NSObject protocol.  You must retain this returned value as long as you want the time observer to be invoked by the player.
        /// Pass this object to -removeTimeObserver: to cancel time observation.
        ///
        /// # Safety
        ///
        /// - `queue` possibly has additional threading requirements.
        /// - `block` block must be sendable.
        #[unsafe(method(addBoundaryTimeObserverForTimes:queue:usingBlock:))]
        #[unsafe(method_family = none)]
        pub unsafe fn addBoundaryTimeObserverForTimes_queue_usingBlock(
            &self,
            times: &NSArray<NSValue>,
            queue: Option<&DispatchQueue>,
            block: &block2::DynBlock<dyn Fn()>,
        ) -> Retained<AnyObject>;

        /// Cancels a previously registered time observer.
        ///
        /// Upon return, the caller is guaranteed that no new time observer blocks will begin executing. Depending on the calling thread and the queue
        /// used to add the time observer, an in-flight block may continue to execute after this method returns. You can guarantee synchronous time
        /// observer removal by enqueuing the call to -removeTimeObserver: on that queue. Alternatively, call dispatch_sync(queue, ^{}) after
        /// -removeTimeObserver: to wait for any in-flight blocks to finish executing.
        /// -removeTimeObserver: should be used to explicitly cancel each time observer added using -addPeriodicTimeObserverForInterval:queue:usingBlock:
        /// and -addBoundaryTimeObserverForTimes:queue:usingBlock:.
        ///
        /// This method throws an exception for any of the following reasons:
        /// - observer was added by a different instance of AVPlayer
        /// - observer was not returned by -addPeriodicTimeObserverForInterval:queue:usingBlock:
        /// - observer was not returned by -addBoundaryTimeObserverForTimes:queue:usingBlock:
        ///
        /// - Parameter observer: An object returned by a previous call to -addPeriodicTimeObserverForInterval:queue:usingBlock: or -addBoundaryTimeObserverForTimes:queue:usingBlock:.
        ///
        /// # Safety
        ///
        /// `observer` should be of the correct type.
        #[unsafe(method(removeTimeObserver:))]
        #[unsafe(method_family = none)]
        pub unsafe fn removeTimeObserver(&self, observer: &AnyObject);
    );
}

/// AVPlayerMediaControl.
impl AVPlayer {
    extern_methods!(
        /// Indicates the current audio volume of the player; 0.0 means "silence all audio", 1.0 means "play at the full volume of the current item".
        ///
        /// iOS note: Do not use this property to implement a volume slider for media playback. For that purpose, use MPVolumeView, which is customizable in appearance and provides standard media playback behaviors that users expect.
        /// This property is most useful on iOS to control the volume of the AVPlayer relative to other audio output, not for volume control by end users.
        #[unsafe(method(volume))]
        #[unsafe(method_family = none)]
        pub unsafe fn volume(&self) -> c_float;

        /// Setter for [`volume`][Self::volume].
        #[unsafe(method(setVolume:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setVolume(&self, volume: c_float);

        /// Indicates whether or not audio output of the player is muted. Only affects audio muting for the player instance and not for the device.
        #[unsafe(method(isMuted))]
        #[unsafe(method_family = none)]
        pub unsafe fn isMuted(&self) -> bool;

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

/// AVPlayerAutomaticMediaSelection.
impl AVPlayer {
    extern_methods!(
        /// Indicates whether the receiver should apply the current selection criteria automatically to AVPlayerItems.
        ///
        /// For clients linked against the iOS 7 SDK or later or against the macOS 10.9 SDK or later, the default is YES. For all others, the default is NO.
        ///
        /// By default, AVPlayer applies selection criteria based on system preferences. To override the default criteria for any media selection group, use -[AVPlayer setMediaSelectionCriteria:forMediaCharacteristic:].
        #[unsafe(method(appliesMediaSelectionCriteriaAutomatically))]
        #[unsafe(method_family = none)]
        pub unsafe fn appliesMediaSelectionCriteriaAutomatically(&self) -> bool;

        /// Setter for [`appliesMediaSelectionCriteriaAutomatically`][Self::appliesMediaSelectionCriteriaAutomatically].
        #[unsafe(method(setAppliesMediaSelectionCriteriaAutomatically:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setAppliesMediaSelectionCriteriaAutomatically(
            &self,
            applies_media_selection_criteria_automatically: bool,
        );

        #[cfg(all(feature = "AVMediaFormat", feature = "AVPlayerMediaSelectionCriteria"))]
        /// Applies automatic selection criteria for media that has the specified media characteristic.
        ///
        /// Criteria will be applied to an AVPlayerItem when:
        /// a) It is made ready to play
        /// b) Specific media selections are made by -[AVPlayerItem selectMediaOption:inMediaSelectionGroup:] in a different group. The automatic choice in one group may be influenced by a specific selection in another group.
        /// c) Underlying system preferences change, e.g. system language, accessibility captions.
        ///
        /// Specific selections made by -[AVPlayerItem selectMediaOption:inMediaSelectionGroup:] within any group will override automatic selection in that group until -[AVPlayerItem selectMediaOptionAutomaticallyInMediaSelectionGroup:] is received.
        ///
        /// Before macOS 13, iOS 16, tvOS 16, and watchOS 9, this method must be invoked on the main thread/queue.
        ///
        /// - Parameter criteria: An instance of AVPlayerMediaSelectionCriteria.
        /// - Parameter mediaCharacteristic: The media characteristic for which the selection criteria are to be applied. Supported values include AVMediaCharacteristicAudible, AVMediaCharacteristicLegible, and AVMediaCharacteristicVisual.
        #[unsafe(method(setMediaSelectionCriteria:forMediaCharacteristic:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setMediaSelectionCriteria_forMediaCharacteristic(
            &self,
            criteria: Option<&AVPlayerMediaSelectionCriteria>,
            media_characteristic: &AVMediaCharacteristic,
        );

        #[cfg(all(feature = "AVMediaFormat", feature = "AVPlayerMediaSelectionCriteria"))]
        /// Returns the automatic selection criteria for media that has the specified media characteristic.
        ///
        /// - Parameter mediaCharacteristic: The media characteristic for which the selection criteria is to be returned. Supported values include AVMediaCharacteristicAudible, AVMediaCharacteristicLegible, and AVMediaCharacteristicVisual. Before macOS 13, iOS 16, tvOS 16, and watchOS 9, this method must be invoked on the main thread/queue.
        #[unsafe(method(mediaSelectionCriteriaForMediaCharacteristic:))]
        #[unsafe(method_family = none)]
        pub unsafe fn mediaSelectionCriteriaForMediaCharacteristic(
            &self,
            media_characteristic: &AVMediaCharacteristic,
        ) -> Option<Retained<AVPlayerMediaSelectionCriteria>>;
    );
}

/// AVPlayerAudioDeviceSupport.
impl AVPlayer {
    extern_methods!(
        /// Specifies the unique ID of the Core Audio output device used to play audio.
        ///
        /// By default, the value of this property is nil, indicating that the default audio output device is used. Otherwise the value of this property is an NSString containing the unique ID of the Core Audio output device to be used for audio output.
        ///
        /// Core Audio's kAudioDevicePropertyDeviceUID is a suitable source of audio output device unique IDs.
        #[unsafe(method(audioOutputDeviceUniqueID))]
        #[unsafe(method_family = none)]
        pub unsafe fn audioOutputDeviceUniqueID(&self) -> Option<Retained<NSString>>;

        /// Setter for [`audioOutputDeviceUniqueID`][Self::audioOutputDeviceUniqueID].
        ///
        /// This is [copied][objc2_foundation::NSCopying::copy] when set.
        #[unsafe(method(setAudioOutputDeviceUniqueID:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setAudioOutputDeviceUniqueID(
            &self,
            audio_output_device_unique_id: Option<&NSString>,
        );
    );
}

/// AVPlayerExternalPlaybackSupport.
///
/// Methods for supporting "external playback" of video
///
/// "External playback" is a mode where video data is sent to an external device for full screen playback at its original fidelity.
/// AirPlay Video playback is considered as an "external playback" mode.
///
/// In "external screen" mode (also known as mirroring and second display), video data is rendered on the host
/// device (e.g. Mac and iPhone), rendered video is recompressed and transferred to the external device, and the
/// external device decompresses and displays the video.
///
/// AVPlayerExternalPlaybackSupport properties affect AirPlay Video playback and are the replacement for the
/// deprecated AVPlayerAirPlaySupport properties.
///
/// Additional note for iOS: AVPlayerExternalPlaybackSupport properties apply to the Lightning-based
/// video adapters but do not apply to 30-pin-connector-based video output cables and adapters.
impl AVPlayer {
    extern_methods!(
        /// Indicates whether the player allows switching to "external playback" mode. The default value is YES.
        #[unsafe(method(allowsExternalPlayback))]
        #[unsafe(method_family = none)]
        pub unsafe fn allowsExternalPlayback(&self) -> bool;

        /// Setter for [`allowsExternalPlayback`][Self::allowsExternalPlayback].
        #[unsafe(method(setAllowsExternalPlayback:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setAllowsExternalPlayback(&self, allows_external_playback: bool);

        /// Indicates whether the player is currently playing video in "external playback" mode.
        #[unsafe(method(isExternalPlaybackActive))]
        #[unsafe(method_family = none)]
        pub unsafe fn isExternalPlaybackActive(&self) -> bool;

        /// Indicates whether the player should automatically switch to "external playback" mode while the "external screen" mode is active in order to play video content and switching back to "external screen" mode as soon as playback is done. Brief transition may be visible on the external display when automatically switching between the two modes. The default value is NO. Has no effect if allowsExternalPlayback is NO.
        #[unsafe(method(usesExternalPlaybackWhileExternalScreenIsActive))]
        #[unsafe(method_family = none)]
        pub unsafe fn usesExternalPlaybackWhileExternalScreenIsActive(&self) -> bool;

        /// Setter for [`usesExternalPlaybackWhileExternalScreenIsActive`][Self::usesExternalPlaybackWhileExternalScreenIsActive].
        #[unsafe(method(setUsesExternalPlaybackWhileExternalScreenIsActive:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setUsesExternalPlaybackWhileExternalScreenIsActive(
            &self,
            uses_external_playback_while_external_screen_is_active: bool,
        );

        #[cfg(feature = "AVAnimation")]
        /// Video gravity strictly for "external playback" mode, one of AVLayerVideoGravity* defined in AVAnimation.h
        #[unsafe(method(externalPlaybackVideoGravity))]
        #[unsafe(method_family = none)]
        pub unsafe fn externalPlaybackVideoGravity(&self) -> Retained<AVLayerVideoGravity>;

        #[cfg(feature = "AVAnimation")]
        /// Setter for [`externalPlaybackVideoGravity`][Self::externalPlaybackVideoGravity].
        ///
        /// This is [copied][objc2_foundation::NSCopying::copy] when set.
        #[unsafe(method(setExternalPlaybackVideoGravity:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setExternalPlaybackVideoGravity(
            &self,
            external_playback_video_gravity: &AVLayerVideoGravity,
        );
    );
}

/// AVPlayerProtectedContent.
///
/// Methods supporting protected content.
impl AVPlayer {
    extern_methods!(
        /// Whether or not decoded output is being obscured due to insufficient external protection.
        ///
        /// The value of this property indicates whether the player is purposefully obscuring the visual output
        /// of the current item because the requirement for an external protection mechanism is not met by the
        /// current device configuration. It is highly recommended that clients whose content requires external
        /// protection observe this property and set the playback rate to zero and display an appropriate user
        /// interface when the value changes to YES. This property is key value observable.
        ///
        /// Note that the value of this property is dependent on the external protection requirements of the
        /// current item. These requirements are inherent to the content itself and cannot be externally specified.
        /// If the current item does not require external protection, the value of this property will be NO.
        #[unsafe(method(outputObscuredDueToInsufficientExternalProtection))]
        #[unsafe(method_family = none)]
        pub unsafe fn outputObscuredDueToInsufficientExternalProtection(&self) -> bool;
    );
}

/// A bitfield type that specifies an HDR mode.
///
/// See also [Apple's documentation](https://developer.apple.com/documentation/avfoundation/avplayerhdrmode?language=objc)
// NS_OPTIONS
#[deprecated = "The deprecated availableHDRModes uses this enum. Use eligibleForHDRPlayback instead"]
#[repr(transparent)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct AVPlayerHDRMode(pub NSInteger);
bitflags::bitflags! {
    impl AVPlayerHDRMode: NSInteger {
/// Indicates that HLG (Hybrid Log-Gamma) HDR mode is available.
        #[doc(alias = "AVPlayerHDRModeHLG")]
#[deprecated = "The deprecated availableHDRModes uses this enum. Use eligibleForHDRPlayback instead"]
        const HLG = 0x1;
/// Indicates that HDR10 HDR mode is available.
        #[doc(alias = "AVPlayerHDRModeHDR10")]
#[deprecated = "The deprecated availableHDRModes uses this enum. Use eligibleForHDRPlayback instead"]
        const HDR10 = 0x2;
/// Indicates that Dolby Vision HDR mode is available.
        #[doc(alias = "AVPlayerHDRModeDolbyVision")]
#[deprecated = "The deprecated availableHDRModes uses this enum. Use eligibleForHDRPlayback instead"]
        const DolbyVision = 0x4;
    }
}

unsafe impl Encode for AVPlayerHDRMode {
    const ENCODING: Encoding = NSInteger::ENCODING;
}

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

extern "C" {
    /// A notification that fires whenever availableHDRModes changes.
    ///
    /// This notification fires when a value is added or removed from the list of availableHDRModes. This can be caused by display connection/disconnection or resource changes.
    ///
    /// See also [Apple's documentation](https://developer.apple.com/documentation/avfoundation/avplayeravailablehdrmodesdidchangenotification?language=objc)
    #[deprecated]
    pub static AVPlayerAvailableHDRModesDidChangeNotification: &'static NSNotificationName;
}

extern "C" {
    /// A notification that fires whenever eligibleForHDRPlayback changes.
    ///
    /// This notification fires when eligibleForHDRPlayback changes. This can be caused by display connection/disconnection or resource changes.
    ///
    /// See also [Apple's documentation](https://developer.apple.com/documentation/avfoundation/avplayereligibleforhdrplaybackdidchangenotification?language=objc)
    pub static AVPlayerEligibleForHDRPlaybackDidChangeNotification: &'static NSNotificationName;
}

/// AVPlayerPlaybackCapabilities.
impl AVPlayer {
    extern_methods!(
        /// An AVPlayerHDRMode value that indicates the HDR modes the device can play to an appropriate display. A value of 0 indicates that no HDR modes are supported.
        ///
        /// This property indicates all of the HDR modes that the device can play. Each value indicates that an appropriate HDR display is available for the specified HDR mode. Additionally, the device must be capable of playing the specified HDR type. This property does not indicate whether video contains HDR content, whether HDR video is currently playing, or whether video is playing on an HDR display.
        #[deprecated = "Use eligibleForHDRPlayback instead"]
        #[unsafe(method(availableHDRModes))]
        #[unsafe(method_family = none)]
        pub unsafe fn availableHDRModes(mtm: MainThreadMarker) -> AVPlayerHDRMode;

        /// Indicates whether HDR content can be played to an appropriate display.
        ///
        /// This property is YES if an HDR display is available and the device is capable of playing HDR content from an appropriate AVAsset, NO otherwise. This property does not indicate whether video contains HDR content, whether HDR video is currently playing, or whether video is playing on an HDR display. This property is not KVO observable.
        #[unsafe(method(eligibleForHDRPlayback))]
        #[unsafe(method_family = none)]
        pub unsafe fn eligibleForHDRPlayback(mtm: MainThreadMarker) -> bool;
    );
}

/// AVPlayerVideoDecoderGPUSupport.
impl AVPlayer {
    extern_methods!(
        /// Specifies a registryID associated with a GPU that should be used for video decode.
        ///
        /// By default, whenever possible, video decode will be performed on the GPU associated with the display on which the presenting CALayer is located. Decode will be transitioned to a new GPU if appropriate when the CALayer moves to a new display. This property overrides this default behavior, forcing decode to prefer an affinity to the GPU specified regardless of which GPU is being used to display the associated CALayer.
        ///
        /// The GPU registryID can be obtained from the GPU MTLDevice using [MTLDevice registryID] or can be obtained from OpenGL or OpenCL.
        #[unsafe(method(preferredVideoDecoderGPURegistryID))]
        #[unsafe(method_family = none)]
        pub unsafe fn preferredVideoDecoderGPURegistryID(&self) -> u64;

        /// Setter for [`preferredVideoDecoderGPURegistryID`][Self::preferredVideoDecoderGPURegistryID].
        #[unsafe(method(setPreferredVideoDecoderGPURegistryID:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setPreferredVideoDecoderGPURegistryID(
            &self,
            preferred_video_decoder_gpu_registry_id: u64,
        );
    );
}

/// AVPlayerVideoDisplaySleepPrevention.
impl AVPlayer {
    extern_methods!(
        /// Indicates whether video playback prevents display and device sleep.
        ///
        /// Default is YES on iOS, tvOS and in Mac Catalyst apps. Default is NO on macOS.
        /// Setting this property to NO does not force the display to sleep, it simply stops preventing display sleep. Other apps or frameworks within your app may still be preventing display sleep for various reasons.
        ///
        /// Before macOS 13, iOS 16, tvOS 16, and watchOS 9, this property must be accessed on the main thread/queue.
        #[unsafe(method(preventsDisplaySleepDuringVideoPlayback))]
        #[unsafe(method_family = none)]
        pub unsafe fn preventsDisplaySleepDuringVideoPlayback(&self) -> bool;

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

/// AVPlayerAutomaticBackgroundPrevention.
impl AVPlayer {
    extern_methods!(
        /// Indicates whether video playback prevents the app from automatically getting backgrounded.
        ///
        /// Default value is YES.
        /// Setting this property to YES prevents an application that is playing video from automatically getting backgrounded. This property does not prevent the user from backgrounding the application.
        #[unsafe(method(preventsAutomaticBackgroundingDuringVideoPlayback))]
        #[unsafe(method_family = none)]
        pub unsafe fn preventsAutomaticBackgroundingDuringVideoPlayback(&self) -> bool;

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

/// This policy describes how AVPlayer behaves when the application transitions to UIApplicationStateBackground while playing video.
///
/// See also [Apple's documentation](https://developer.apple.com/documentation/avfoundation/avplayeraudiovisualbackgroundplaybackpolicy?language=objc)
// NS_ENUM
#[repr(transparent)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct AVPlayerAudiovisualBackgroundPlaybackPolicy(pub NSInteger);
impl AVPlayerAudiovisualBackgroundPlaybackPolicy {
    /// Indicates that the system is free to decide. This is the default policy.
    #[doc(alias = "AVPlayerAudiovisualBackgroundPlaybackPolicyAutomatic")]
    pub const Automatic: Self = Self(1);
    /// Indicates that the player must be paused on going to background.
    #[doc(alias = "AVPlayerAudiovisualBackgroundPlaybackPolicyPauses")]
    pub const Pauses: Self = Self(2);
    /// Indicates that the player continues to play if possible in background.
    #[doc(alias = "AVPlayerAudiovisualBackgroundPlaybackPolicyContinuesIfPossible")]
    pub const ContinuesIfPossible: Self = Self(3);
}

unsafe impl Encode for AVPlayerAudiovisualBackgroundPlaybackPolicy {
    const ENCODING: Encoding = NSInteger::ENCODING;
}

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

/// AVPlayerBackgroundSupport.
impl AVPlayer {
    extern_methods!(
        /// Controls the policy to be used in deciding how playback of audiovisual content should continue while the application transitions to background.
        ///
        /// By default, the system is free to decide the background playback policy (AVPlayerAudiovisualBackgroundPlaybackPolicyAutomatic).
        /// If set to AVPlayerAudiovisualBackgroundPlaybackPolicyPauses, player will be paused on entering background.
        /// If set to AVPlayerAudiovisualBackgroundPlaybackPolicyContinuesIfPossible, the system makes the best effort to continue playback but the app also needs appropriate UIBackgroundModes for the system to let it continue running in the background. Note that this policy only applies to items with enabled video.
        #[unsafe(method(audiovisualBackgroundPlaybackPolicy))]
        #[unsafe(method_family = none)]
        pub unsafe fn audiovisualBackgroundPlaybackPolicy(
            &self,
        ) -> AVPlayerAudiovisualBackgroundPlaybackPolicy;

        /// Setter for [`audiovisualBackgroundPlaybackPolicy`][Self::audiovisualBackgroundPlaybackPolicy].
        #[unsafe(method(setAudiovisualBackgroundPlaybackPolicy:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setAudiovisualBackgroundPlaybackPolicy(
            &self,
            audiovisual_background_playback_policy: AVPlayerAudiovisualBackgroundPlaybackPolicy,
        );
    );
}

/// PlaybackCoordination.
impl AVPlayer {
    extern_methods!(
        #[cfg(feature = "AVPlaybackCoordinator")]
        /// The playback coordinator for this player.
        ///
        /// If the playback coordinator is connected to other participants, rate changes and seeks on the current item will be automatically mirrored to all connected participants.
        /// Depending on policies, the coordinator may also intercept rate changes to non-zero to coordinate playback start with the rest of the group.
        /// Use [AVPlayer playImmediatelyAtRate:] to override the coordinated startup behavior and start playback immediately. This is useful to give users an opportunity to override waiting caused by other participants' suspensions.
        /// Player configuration other than rate and seeks are not communicated to other participants and can be configured independently by each participant.
        /// A player with a connected playbackCoordinator will change behavior in situations that require the player to pause for internal reasons, such as a route change or a stall.
        /// When resuming after these events, the player will not resume at the stop time. Instead, it will attempt to rejoin the group, potentially seeking to match the other participant's progress.
        /// It is left to the owner of the AVPlayer to ensure that all participants are playing the same item. See the discussion of AVPlaybackCoordinator for considerations about item transitions.
        #[unsafe(method(playbackCoordinator))]
        #[unsafe(method_family = none)]
        pub unsafe fn playbackCoordinator(&self) -> Retained<AVPlayerPlaybackCoordinator>;
    );
}

/// AVPlayerOutputSupport.
impl AVPlayer {
    extern_methods!(
        #[cfg(feature = "AVPlayerOutput")]
        /// The video output for this player, if one was set.
        ///
        /// When an AVPlayerVideoOutput is associated with an AVPlayer, the AVPlayerVideoOutput can then be used to receive video-related samples during playback.
        ///
        /// - NOTE: If an output is set while AVPlayer has a current item it may cause different data channels to be selected for that item, which can have a performance impact.
        /// As a result, when possible, it is best to set an output before setting items on an AVPlayer.
        #[unsafe(method(videoOutput))]
        #[unsafe(method_family = none)]
        pub unsafe fn videoOutput(&self) -> Option<Retained<AVPlayerVideoOutput>>;

        #[cfg(feature = "AVPlayerOutput")]
        /// Setter for [`videoOutput`][Self::videoOutput].
        #[unsafe(method(setVideoOutput:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setVideoOutput(&self, video_output: Option<&AVPlayerVideoOutput>);
    );
}

/// This defines the network resource priority for a player.
///
/// See also [Apple's documentation](https://developer.apple.com/documentation/avfoundation/avplayernetworkresourcepriority?language=objc)
// NS_ENUM
#[repr(transparent)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct AVPlayerNetworkResourcePriority(pub NSInteger);
impl AVPlayerNetworkResourcePriority {
    /// The default priority level given to a player for loading network resources. Use this when the player requires an optimal level of network resources and streaming in high-quality resolution is ideal. Players with AVPlayerNetworkResourcePriorityHigh will take precedence over this player. This player will take precedence over players with AVPlayerNetworkResourcePriorityLow.
    #[doc(alias = "AVPlayerNetworkResourcePriorityDefault")]
    pub const Default: Self = Self(0);
    /// Indicates a low priority level for loading network resources. Use this when the player requires minimal network bandwidth and streaming in high-quality resolution is not crucial. Other players with higher priority will take precedence over this player.
    #[doc(alias = "AVPlayerNetworkResourcePriorityLow")]
    pub const Low: Self = Self(1);
    /// Indicates a high priority level for loading network resources. Use this when the player requires a high level of network resources and streaming in high-quality resolution is crucial. This player will take precedence over other lower priority players.
    #[doc(alias = "AVPlayerNetworkResourcePriorityHigh")]
    pub const High: Self = Self(2);
}

unsafe impl Encode for AVPlayerNetworkResourcePriority {
    const ENCODING: Encoding = NSInteger::ENCODING;
}

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

/// AVPlayerResourceArbitrationSupport.
impl AVPlayer {
    extern_methods!(
        /// Indicates the priority of this player for network bandwidth resource distribution.
        ///
        /// This value determines the priority of the player during network resource allocation among all other players within the same application process. The default value for this is AVPlayerNetworkResourcePriorityDefault.
        #[unsafe(method(networkResourcePriority))]
        #[unsafe(method_family = none)]
        pub unsafe fn networkResourcePriority(&self) -> AVPlayerNetworkResourcePriority;

        /// Setter for [`networkResourcePriority`][Self::networkResourcePriority].
        #[unsafe(method(setNetworkResourcePriority:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setNetworkResourcePriority(
            &self,
            network_resource_priority: AVPlayerNetworkResourcePriority,
        );
    );
}

/// AVPlayerSpatialAudioExperience.
impl AVPlayer {
    extern_methods!();
}

/// AVPlayerRoutingPlaybackArbitrationSupport.
impl AVPlayer {
    extern_methods!(
        /// Whether the player's audio output is suppressed due to being on a non-mixable audio route.
        ///
        /// If YES, the player's audio output is suppressed. The player is muted while on a non-mixable audio route and cannot play audio. The player's mute property does not reflect the true mute status.
        /// If NO, the player's audio output is not suppressed. The player may be muted or unmuted while on a non-mixable audio route and can play audio. The player's mute property reflects the true mute status.
        /// In a non-mixable audio route, only one player can play audio. To play audio in non-mixable states, the player must be specified as the priority participant in AVRoutingPlaybackArbiter.preferredParticipantForNonMixableAudioRoutes. If this player becomes the preferred player, it will gain audio priority and suppress the audio of all other players. If another participant becomes the preferred participant, this player will lose audio priority and have their audio suppressed. This property is key-value observed.
        #[unsafe(method(audioOutputSuppressedDueToNonMixableAudioRoute))]
        #[unsafe(method_family = none)]
        pub unsafe fn audioOutputSuppressedDueToNonMixableAudioRoute(&self) -> bool;
    );
}

/// AVPlayerObservation.
impl AVPlayer {
    extern_methods!(
        /// AVPlayer and other AVFoundation types can optionally be observed using Swift Observation.
        ///
        /// When set to YES, new instances of AVPlayer, AVQueuePlayer, AVPlayerItem, and AVPlayerItemTrack are observable with Swift Observation. The default value is NO (not observable).  An exception is thrown if this property is set YES after initializing any objects of these types, or if it is set to NO after any observable objects are initialized.  In other words, all objects of these types must either be observable or not observable in an application instance.
        ///
        /// For more information regarding management of class objects in SwiftUI, please refer to https://developer.apple.com/documentation/swiftui/state.
        #[unsafe(method(isObservationEnabled))]
        #[unsafe(method_family = none)]
        pub unsafe fn isObservationEnabled(mtm: MainThreadMarker) -> bool;

        /// Setter for [`isObservationEnabled`][Self::isObservationEnabled].
        #[unsafe(method(setObservationEnabled:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setObservationEnabled(observation_enabled: bool, mtm: MainThreadMarker);
    );
}

/// AVPlayerDeprecated.
impl AVPlayer {
    extern_methods!(
        /// Indicates whether display of closed captions is enabled.
        ///
        /// This property is deprecated.
        ///
        /// When the value of appliesMediaSelectionCriteriaAutomatically is YES, the receiver will enable closed captions automatically either according to user preferences or, if you provide them, according to AVPlayerMediaSelectionCriteria for the media characteristic AVMediaCharacteristicLegible.
        ///
        /// If you want to determine whether closed captions may be available for a given AVPlayerItem, you can examine the AVMediaSelectionOptions in the AVMediaSelectionGroup for the characteristic AVMediaCharacteristicLegible, as vended by -[AVAsset mediaSelectionGroupForMediaCharacteristic:]. See AVMediaCharacteristicTranscribesSpokenDialogForAccessibility and AVMediaCharacteristicDescribesMusicAndSoundForAccessibility as documented in AVMediaFormat.h for information about how to identify legible media selection options that offer the features of closed captions for accessibility purposes.
        ///
        /// You can select or deselect a specific AVMediaSelectionOption via -[AVPlayerItem selectMediaOption:inMediaSelectionGroup:].
        ///
        /// For further information about Media Accessibility preferences, see MediaAccessibility framework documentation.
        #[deprecated = "Allow AVPlayer to enable closed captions automatically according to user preferences by ensuring that the value of appliesMediaSelectionCriteriaAutomatically is YES."]
        #[unsafe(method(isClosedCaptionDisplayEnabled))]
        #[unsafe(method_family = none)]
        pub unsafe fn isClosedCaptionDisplayEnabled(&self) -> bool;

        /// Setter for [`isClosedCaptionDisplayEnabled`][Self::isClosedCaptionDisplayEnabled].
        #[deprecated = "Allow AVPlayer to enable closed captions automatically according to user preferences by ensuring that the value of appliesMediaSelectionCriteriaAutomatically is YES."]
        #[unsafe(method(setClosedCaptionDisplayEnabled:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setClosedCaptionDisplayEnabled(&self, closed_caption_display_enabled: bool);

        #[cfg(feature = "objc2-core-media")]
        /// Use sourceClock instead.
        #[deprecated]
        #[unsafe(method(masterClock))]
        #[unsafe(method_family = none)]
        pub unsafe fn masterClock(&self) -> Option<Retained<CMClock>>;

        #[cfg(feature = "objc2-core-media")]
        /// Setter for [`masterClock`][Self::masterClock].
        #[deprecated]
        #[unsafe(method(setMasterClock:))]
        #[unsafe(method_family = none)]
        pub unsafe fn setMasterClock(&self, master_clock: Option<&CMClock>);
    );
}

extern_class!(
    /// AVQueuePlayer is a subclass of AVPlayer that offers an interface for multiple-item playback.
    ///
    /// AVQueuePlayer extends AVPlayer with methods for managing a queue of items to be played in sequence.
    /// It plays these items as gaplessly as possible in the current runtime environment, depending on
    /// the timely availability of media data for the enqueued items.
    ///
    /// For best performance clients should typically enqueue only as many AVPlayerItems as are necessary
    /// to ensure smooth playback. Note that once an item is enqueued it becomes eligible to be loaded and
    /// made ready for playback, with whatever I/O and processing overhead that entails.
    ///
    /// See also [Apple's documentation](https://developer.apple.com/documentation/avfoundation/avqueueplayer?language=objc)
    #[unsafe(super(AVPlayer, NSObject))]
    #[derive(Debug, PartialEq, Eq, Hash)]
    pub struct AVQueuePlayer;
);

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

impl AVQueuePlayer {
    extern_methods!(
        #[cfg(feature = "AVPlayerItem")]
        /// Creates an instance of AVQueuePlayer and enqueues the AVPlayerItems from the specified array.
        ///
        /// - Parameter items: An NSArray of AVPlayerItems with which to populate the player's queue initially.
        ///
        /// - Returns: An instance of AVQueuePlayer.
        #[unsafe(method(queuePlayerWithItems:))]
        #[unsafe(method_family = none)]
        pub unsafe fn queuePlayerWithItems(
            items: &NSArray<AVPlayerItem>,
            mtm: MainThreadMarker,
        ) -> Retained<Self>;

        #[cfg(feature = "AVPlayerItem")]
        /// Initializes an instance of AVQueuePlayer by enqueueing the AVPlayerItems from the specified array.
        ///
        /// This method throws an exception if items contains duplicated values or values associated with another AVPlayer.
        ///
        /// - Parameter items: An NSArray of AVPlayerItems with which to populate the player's queue initially.
        ///
        /// - Returns: An instance of AVQueuePlayer.
        #[unsafe(method(initWithItems:))]
        #[unsafe(method_family = init)]
        pub unsafe fn initWithItems(
            this: Allocated<Self>,
            items: &NSArray<AVPlayerItem>,
        ) -> Retained<Self>;

        #[cfg(feature = "AVPlayerItem")]
        /// Provides an array of the currently enqueued items.
        ///
        /// - Returns: An NSArray containing the enqueued AVPlayerItems.
        #[unsafe(method(items))]
        #[unsafe(method_family = none)]
        pub unsafe fn items(&self) -> Retained<NSArray<AVPlayerItem>>;

        /// Ends playback of the current item and initiates playback of the next item in the player's queue.
        ///
        /// Removes the current item from the play queue.
        #[unsafe(method(advanceToNextItem))]
        #[unsafe(method_family = none)]
        pub unsafe fn advanceToNextItem(&self);

        #[cfg(feature = "AVPlayerItem")]
        /// Tests whether an AVPlayerItem can be inserted into the player's queue.
        ///
        /// Note that adding the same AVPlayerItem to an AVQueuePlayer at more than one position in the queue is not supported.
        ///
        /// - Parameter item: The AVPlayerItem to be tested.
        /// - Parameter afterItem: The item that the item to be tested is to follow in the queue. Pass nil to test whether the item can be appended to the queue.
        ///
        /// - Returns: An indication of whether the item can be inserted into the queue after the specified item.
        #[unsafe(method(canInsertItem:afterItem:))]
        #[unsafe(method_family = none)]
        pub unsafe fn canInsertItem_afterItem(
            &self,
            item: &AVPlayerItem,
            after_item: Option<&AVPlayerItem>,
        ) -> bool;

        #[cfg(feature = "AVPlayerItem")]
        /// Places an AVPlayerItem after the specified item in the queue.
        ///
        /// This method throws an exception if item already exists in the queue.
        ///
        /// - Parameter item: The item to be inserted.
        /// - Parameter afterItem: The item that the newly inserted item should follow in the queue. Pass nil to append the item to the queue.
        #[unsafe(method(insertItem:afterItem:))]
        #[unsafe(method_family = none)]
        pub unsafe fn insertItem_afterItem(
            &self,
            item: &AVPlayerItem,
            after_item: Option<&AVPlayerItem>,
        );

        #[cfg(feature = "AVPlayerItem")]
        /// Removes an AVPlayerItem from the queue.
        ///
        /// If the item to be removed is currently playing, has the same effect as -advanceToNextItem.
        ///
        /// - Parameter item: The item to be removed.
        #[unsafe(method(removeItem:))]
        #[unsafe(method_family = none)]
        pub unsafe fn removeItem(&self, item: &AVPlayerItem);

        /// Removes all items from the queue.
        ///
        /// Stops playback by the target.
        #[unsafe(method(removeAllItems))]
        #[unsafe(method_family = none)]
        pub unsafe fn removeAllItems(&self);
    );
}

/// Methods declared on superclass `AVPlayer`.
impl AVQueuePlayer {
    extern_methods!(
        /// Initializes an AVPlayer with no player items.
        #[unsafe(method(init))]
        #[unsafe(method_family = init)]
        pub unsafe fn init(this: Allocated<Self>) -> Retained<Self>;

        /// Returns an instance of AVPlayer that plays a single audiovisual resource referenced by URL.
        ///
        /// Implicitly creates an AVPlayerItem. Clients can obtain the AVPlayerItem as it becomes the player's currentItem.
        ///
        /// - Parameter URL:
        ///
        /// - Returns: An instance of AVPlayer
        #[unsafe(method(playerWithURL:))]
        #[unsafe(method_family = none)]
        pub unsafe fn playerWithURL(url: &NSURL, mtm: MainThreadMarker) -> Retained<Self>;

        #[cfg(feature = "AVPlayerItem")]
        /// Create an AVPlayer that plays a single audiovisual item.
        ///
        /// Useful in order to play items for which an AVAsset has previously been created. See -[AVPlayerItem initWithAsset:].
        ///
        /// - Parameter item:
        ///
        /// - Returns: An instance of AVPlayer
        #[unsafe(method(playerWithPlayerItem:))]
        #[unsafe(method_family = none)]
        pub unsafe fn playerWithPlayerItem(
            item: Option<&AVPlayerItem>,
            mtm: MainThreadMarker,
        ) -> Retained<Self>;

        /// Initializes an AVPlayer that plays a single audiovisual resource referenced by URL.
        ///
        /// Implicitly creates an AVPlayerItem. Clients can obtain the AVPlayerItem as it becomes the player's currentItem.
        ///
        /// - Parameter URL:
        ///
        /// - Returns: An instance of AVPlayer
        #[unsafe(method(initWithURL:))]
        #[unsafe(method_family = init)]
        pub unsafe fn initWithURL(this: Allocated<Self>, url: &NSURL) -> Retained<Self>;

        #[cfg(feature = "AVPlayerItem")]
        /// Create an AVPlayer that plays a single audiovisual item.
        ///
        /// Useful in order to play items for which an AVAsset has previously been created. See -[AVPlayerItem initWithAsset:].
        /// This method throws an exception if the item is not an AVPlayerItem, or if the item is
        /// associated with another AVPlayer.
        ///
        /// - Parameter item:
        ///
        /// - Returns: An instance of AVPlayer
        #[unsafe(method(initWithPlayerItem:))]
        #[unsafe(method_family = init)]
        pub unsafe fn initWithPlayerItem(
            this: Allocated<Self>,
            item: Option<&AVPlayerItem>,
        ) -> Retained<Self>;
    );
}

/// Methods declared on superclass `NSObject`.
impl AVQueuePlayer {
    extern_methods!(
        #[unsafe(method(new))]
        #[unsafe(method_family = new)]
        pub unsafe fn new(mtm: MainThreadMarker) -> Retained<Self>;
    );
}