Playlists, looping, shuffling for iOS

This commit is contained in:
Ryan Heise 2020-07-28 03:54:00 +10:00
parent c0c5d0c2bf
commit a63ef2ba39
44 changed files with 1629 additions and 362 deletions

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,37 @@
#import "AudioSource.h"
#import <AVFoundation/AVFoundation.h>
@implementation AudioSource {
NSString *_sourceId;
}
- (instancetype)initWithId:(NSString *)sid {
self = [super init];
NSAssert(self, @"super init cannot be nil");
_sourceId = sid;
return self;
}
- (NSString *)sourceId {
return _sourceId;
}
- (int)buildSequence:(NSMutableArray *)sequence treeIndex:(int)treeIndex {
return 0;
}
- (void)findById:(NSString *)sourceId matches:(NSMutableArray<AudioSource *> *)matches {
if ([_sourceId isEqualToString:sourceId]) {
[matches addObject:self];
}
}
- (NSArray *)getShuffleOrder {
return @[];
}
- (int)shuffle:(int)treeIndex currentIndex:(int)currentIndex {
return 0;
}
@end

View File

@ -0,0 +1,67 @@
#import "AudioSource.h"
#import "ClippingAudioSource.h"
#import "IndexedPlayerItem.h"
#import "UriAudioSource.h"
#import <AVFoundation/AVFoundation.h>
@implementation ClippingAudioSource {
UriAudioSource *_audioSource;
CMTime _start;
CMTime _end;
}
- (instancetype)initWithId:(NSString *)sid audioSource:(UriAudioSource *)audioSource start:(NSNumber *)start end:(NSNumber *)end {
self = [super initWithId:sid];
NSAssert(self, @"super init cannot be nil");
_audioSource = audioSource;
_start = start == [NSNull null] ? kCMTimeZero : CMTimeMake([start intValue], 1000);
_end = end == [NSNull null] ? kCMTimeInvalid : CMTimeMake([end intValue], 1000);
return self;
}
- (void)findById:(NSString *)sourceId matches:(NSMutableArray<AudioSource *> *)matches {
[super findById:sourceId matches:matches];
[_audioSource findById:sourceId matches:matches];
}
- (void)attach:(AVQueuePlayer *)player {
[super attach:player];
_audioSource.playerItem.forwardPlaybackEndTime = _end;
// XXX: Not needed since currentItem observer handles it?
[self seek:kCMTimeZero];
}
- (IndexedPlayerItem *)playerItem {
return _audioSource.playerItem;
}
- (NSArray *)getShuffleOrder {
return @[@(0)];
}
- (void)play:(AVQueuePlayer *)player {
}
- (void)pause:(AVQueuePlayer *)player {
}
- (void)stop:(AVQueuePlayer *)player {
}
- (void)seek:(CMTime)position completionHandler:(void (^)(BOOL))completionHandler {
CMTime absPosition = CMTimeAdd(_start, position);
[_audioSource.playerItem seekToTime:absPosition toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero completionHandler:completionHandler];
}
- (CMTime)duration {
return CMTimeSubtract(CMTIME_IS_INVALID(_end) ? self.playerItem.duration : _end, _start);
}
- (void)setDuration:(CMTime)duration {
}
- (CMTime)position {
return CMTimeSubtract(self.playerItem.currentTime, _start);
}
@end

View File

@ -0,0 +1,109 @@
#import "AudioSource.h"
#import "ConcatenatingAudioSource.h"
#import <AVFoundation/AVFoundation.h>
#import <stdlib.h>
@implementation ConcatenatingAudioSource {
NSMutableArray<AudioSource *> *_audioSources;
NSMutableArray<NSNumber *> *_shuffleOrder;
}
- (instancetype)initWithId:(NSString *)sid audioSources:(NSMutableArray<AudioSource *> *)audioSources {
self = [super initWithId:sid];
NSAssert(self, @"super init cannot be nil");
_audioSources = audioSources;
return self;
}
- (int)count {
return _audioSources.count;
}
- (void)insertSource:(AudioSource *)audioSource atIndex:(int)index {
[_audioSources insertObject:audioSource atIndex:index];
}
- (void)removeSourcesFromIndex:(int)start toIndex:(int)end {
if (end == -1) end = _audioSources.count;
for (int i = start; i < end; i++) {
[_audioSources removeObjectAtIndex:start];
}
}
- (void)moveSourceFromIndex:(int)currentIndex toIndex:(int)newIndex {
AudioSource *source = _audioSources[currentIndex];
[_audioSources removeObjectAtIndex:currentIndex];
[_audioSources insertObject:source atIndex:newIndex];
}
- (int)buildSequence:(NSMutableArray *)sequence treeIndex:(int)treeIndex {
for (int i = 0; i < [_audioSources count]; i++) {
treeIndex = [_audioSources[i] buildSequence:sequence treeIndex:treeIndex];
}
return treeIndex;
}
- (void)findById:(NSString *)sourceId matches:(NSMutableArray<AudioSource *> *)matches {
[super findById:sourceId matches:matches];
for (int i = 0; i < [_audioSources count]; i++) {
[_audioSources[i] findById:sourceId matches:matches];
}
}
- (NSArray *)getShuffleOrder {
NSMutableArray *order = [NSMutableArray new];
int offset = [order count];
NSMutableArray *childOrders = [NSMutableArray new]; // array of array of ints
for (int i = 0; i < [_audioSources count]; i++) {
AudioSource *audioSource = _audioSources[i];
NSArray *childShuffleOrder = [audioSource getShuffleOrder];
NSMutableArray *offsetChildShuffleOrder = [NSMutableArray new];
for (int j = 0; j < [childShuffleOrder count]; j++) {
[offsetChildShuffleOrder addObject:@([childShuffleOrder[j] integerValue] + offset)];
}
[childOrders addObject:offsetChildShuffleOrder];
offset += [childShuffleOrder count];
}
for (int i = 0; i < [_audioSources count]; i++) {
[order addObjectsFromArray:childOrders[[_shuffleOrder[i] integerValue]]];
}
return order;
}
- (int)shuffle:(int)treeIndex currentIndex:(int)currentIndex {
int currentChildIndex = -1;
for (int i = 0; i < [_audioSources count]; i++) {
int indexBefore = treeIndex;
AudioSource *child = _audioSources[i];
treeIndex = [child shuffle:treeIndex currentIndex:currentIndex];
if (currentIndex >= indexBefore && currentIndex < treeIndex) {
currentChildIndex = i;
} else {}
}
// Shuffle so that the current child is first in the shuffle order
_shuffleOrder = [NSMutableArray arrayWithCapacity:[_audioSources count]];
for (int i = 0; i < [_audioSources count]; i++) {
[_shuffleOrder addObject:@(0)];
}
NSLog(@"shuffle: audioSources.count=%d and shuffleOrder.count=%d", [_audioSources count], [_shuffleOrder count]);
// First generate a random shuffle
for (int i = 0; i < [_audioSources count]; i++) {
int j = arc4random_uniform(i + 1);
_shuffleOrder[i] = _shuffleOrder[j];
_shuffleOrder[j] = @(i);
}
// Then bring currentIndex to the front
if (currentChildIndex != -1) {
for (int i = 1; i < [_audioSources count]; i++) {
if ([_shuffleOrder[i] integerValue] == currentChildIndex) {
NSNumber *v = _shuffleOrder[0];
_shuffleOrder[0] = _shuffleOrder[i];
_shuffleOrder[i] = v;
break;
}
}
}
return treeIndex;
}
@end

View File

@ -0,0 +1,64 @@
#import "IndexedAudioSource.h"
#import "IndexedPlayerItem.h"
#import <AVFoundation/AVFoundation.h>
@implementation IndexedAudioSource {
BOOL _isAttached;
}
- (instancetype)initWithId:(NSString *)sid {
self = [super init];
NSAssert(self, @"super init cannot be nil");
_isAttached = NO;
return self;
}
- (IndexedPlayerItem *)playerItem {
return nil;
}
- (BOOL)isAttached {
return _isAttached;
}
- (int)buildSequence:(NSMutableArray *)sequence treeIndex:(int)treeIndex {
[sequence addObject:self];
return treeIndex + 1;
}
- (int)shuffle:(int)treeIndex currentIndex:(int)currentIndex {
return treeIndex + 1;
}
- (void)attach:(AVQueuePlayer *)player {
_isAttached = YES;
}
- (void)play:(AVQueuePlayer *)player {
}
- (void)pause:(AVQueuePlayer *)player {
}
- (void)stop:(AVQueuePlayer *)player {
}
- (void)seek:(CMTime)position {
[self seek:position completionHandler:nil];
}
- (void)seek:(CMTime)position completionHandler:(void (^)(BOOL))completionHandler {
}
- (CMTime)duration {
return kCMTimeInvalid;
}
- (void)setDuration:(CMTime)duration {
}
- (CMTime)position {
return kCMTimeInvalid;
}
@end

View File

@ -0,0 +1,16 @@
#import "IndexedPlayerItem.h"
#import "IndexedAudioSource.h"
@implementation IndexedPlayerItem {
IndexedAudioSource *_audioSource;
}
-(void)setAudioSource:(IndexedAudioSource *)audioSource {
_audioSource = audioSource;
}
-(IndexedAudioSource *)audioSource {
return _audioSource;
}
@end

View File

@ -1,6 +1,5 @@
#import "JustAudioPlugin.h"
#import "AudioPlayer.h"
#import "AudioPlayer.h"
#import <AVFoundation/AVFoundation.h>
@implementation JustAudioPlugin {

View File

@ -0,0 +1,53 @@
#import "AudioSource.h"
#import "LoopingAudioSource.h"
#import <AVFoundation/AVFoundation.h>
@implementation LoopingAudioSource {
// An array of duplicates
NSArray<AudioSource *> *_audioSources; // <AudioSource *>
}
- (instancetype)initWithId:(NSString *)sid audioSources:(NSArray<AudioSource *> *)audioSources {
self = [super initWithId:sid];
NSAssert(self, @"super init cannot be nil");
_audioSources = audioSources;
return self;
}
- (int)buildSequence:(NSMutableArray *)sequence treeIndex:(int)treeIndex {
for (int i = 0; i < [_audioSources count]; i++) {
treeIndex = [_audioSources[i] buildSequence:sequence treeIndex:treeIndex];
}
return treeIndex;
}
- (void)findById:(NSString *)sourceId matches:(NSMutableArray<AudioSource *> *)matches {
[super findById:sourceId matches:matches];
for (int i = 0; i < [_audioSources count]; i++) {
[_audioSources[i] findById:sourceId matches:matches];
}
}
- (NSArray *)getShuffleOrder {
NSMutableArray *order = [NSMutableArray new];
int offset = [order count];
for (int i = 0; i < [_audioSources count]; i++) {
AudioSource *audioSource = _audioSources[i];
NSArray *childShuffleOrder = [audioSource getShuffleOrder];
for (int j = 0; j < [childShuffleOrder count]; j++) {
[order addObject:@([childShuffleOrder[j] integerValue] + offset)];
}
offset += [childShuffleOrder count];
}
return order;
}
- (int)shuffle:(int)treeIndex currentIndex:(int)currentIndex {
// TODO: This should probably shuffle the same way on all duplicates.
for (int i = 0; i < [_audioSources count]; i++) {
treeIndex = [_audioSources[i] shuffle:treeIndex currentIndex:currentIndex];
}
return treeIndex;
}
@end

View File

@ -0,0 +1,66 @@
#import "UriAudioSource.h"
#import "IndexedAudioSource.h"
#import "IndexedPlayerItem.h"
#import <AVFoundation/AVFoundation.h>
@implementation UriAudioSource {
NSString *_uri;
IndexedPlayerItem *_playerItem;
/* CMTime _duration; */
}
- (instancetype)initWithId:(NSString *)sid uri:(NSString *)uri {
self = [super initWithId:sid];
NSAssert(self, @"super init cannot be nil");
_uri = uri;
if ([_uri hasPrefix:@"file://"]) {
_playerItem = [[IndexedPlayerItem alloc] initWithURL:[NSURL fileURLWithPath:[_uri substringFromIndex:7]]];
} else {
_playerItem = [[IndexedPlayerItem alloc] initWithURL:[NSURL URLWithString:_uri]];
}
if (@available(macOS 10.13, iOS 11.0, *)) {
// This does the best at reducing distortion on voice with speeds below 1.0
_playerItem.audioTimePitchAlgorithm = AVAudioTimePitchAlgorithmTimeDomain;
}
/* NSKeyValueObservingOptions options = */
/* NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew; */
/* [_playerItem addObserver:self */
/* forKeyPath:@"duration" */
/* options:options */
/* context:nil]; */
return self;
}
- (IndexedPlayerItem *)playerItem {
return _playerItem;
}
- (NSArray *)getShuffleOrder {
return @[@(0)];
}
- (void)play:(AVQueuePlayer *)player {
}
- (void)pause:(AVQueuePlayer *)player {
}
- (void)stop:(AVQueuePlayer *)player {
}
- (void)seek:(CMTime)position completionHandler:(void (^)(BOOL))completionHandler {
[_playerItem seekToTime:position toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero completionHandler:completionHandler];
}
- (CMTime)duration {
return _playerItem.duration;
}
- (void)setDuration:(CMTime)duration {
}
- (CMTime)position {
return _playerItem.currentTime;
}
@end

View File

@ -4,11 +4,17 @@ PODS:
- Flutter
- path_provider (0.0.1):
- Flutter
- path_provider_linux (0.0.1):
- Flutter
- path_provider_macos (0.0.1):
- Flutter
DEPENDENCIES:
- Flutter (from `Flutter`)
- just_audio (from `.symlinks/plugins/just_audio/ios`)
- path_provider (from `.symlinks/plugins/path_provider/ios`)
- path_provider_linux (from `.symlinks/plugins/path_provider_linux/ios`)
- path_provider_macos (from `.symlinks/plugins/path_provider_macos/ios`)
EXTERNAL SOURCES:
Flutter:
@ -17,12 +23,18 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/just_audio/ios"
path_provider:
:path: ".symlinks/plugins/path_provider/ios"
path_provider_linux:
:path: ".symlinks/plugins/path_provider_linux/ios"
path_provider_macos:
:path: ".symlinks/plugins/path_provider_macos/ios"
SPEC CHECKSUMS:
Flutter: 0e3d915762c693b495b44d77113d4970485de6ec
just_audio: baa7252489dbcf47a4c7cc9ca663e9661c99aafa
path_provider: fb74bd0465e96b594bb3b5088ee4a4e7bb1f2a9d
path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c
path_provider_linux: 4d630dc393e1f20364f3e3b4a2ff41d9674a84e4
path_provider_macos: f760a3c5b04357c380e2fddb6f9db6f3015897e0
PODFILE CHECKSUM: f32fb4e7c14f8b3ca19a369d7be425dd9241af27
COCOAPODS: 1.9.1
COCOAPODS: 1.9.3

View File

@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:just_audio/just_audio.dart';
import 'package:rxdart/rxdart.dart';
@ -28,6 +29,27 @@ class _MyAppState extends State<MyApp> {
),
),
),
//LoopingAudioSource(
// count: 2,
// audioSource: AudioSource.uri(
// Uri.parse(
// "https://s3.amazonaws.com/scifri-episodes/scifri20181123-episode.mp3"),
// tag: AudioMetadata(
// album: "Science Friday",
// title: "A Salute To Head-Scratching Science (full)",
// ),
// ),
//),
//ClippingAudioSource(
// start: Duration(seconds: 60),
// end: Duration(seconds: 65),
// audioSource: AudioSource.uri(Uri.parse(
// "https://s3.amazonaws.com/scifri-episodes/scifri20181123-episode.mp3")),
// tag: AudioMetadata(
// album: "Science Friday",
// title: "A Salute To Head-Scratching Science (5 seconds)",
// ),
//),
AudioSource.uri(
Uri.parse(
"https://s3.amazonaws.com/scifri-episodes/scifri20181123-episode.mp3"),
@ -296,7 +318,8 @@ class _SeekBarState extends State<SeekBar> {
return Slider(
min: 0.0,
max: widget.duration.inMilliseconds.toDouble(),
value: _dragValue ?? widget.position.inMilliseconds.toDouble(),
value: min(_dragValue ?? widget.position.inMilliseconds.toDouble(),
widget.duration.inMilliseconds.toDouble()),
onChanged: (value) {
setState(() {
_dragValue = value;

View File

@ -1,6 +1,20 @@
# Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile
packages:
archive:
dependency: transitive
description:
name: archive
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.13"
args:
dependency: transitive
description:
name: args
url: "https://pub.dartlang.org"
source: hosted
version: "1.6.0"
async:
dependency: transitive
description:
@ -22,13 +36,6 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.3"
clock:
dependency: transitive
description:
name: clock
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.1"
collection:
dependency: transitive
description:
@ -57,13 +64,6 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.3"
fake_async:
dependency: transitive
description:
name: fake_async
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
file:
dependency: transitive
description:
@ -86,6 +86,13 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
image:
dependency: transitive
description:
name: image
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.12"
intl:
dependency: transitive
description:
@ -120,7 +127,7 @@ packages:
name: path
url: "https://pub.dartlang.org"
source: hosted
version: "1.7.0"
version: "1.6.4"
path_provider:
dependency: transitive
description:
@ -149,6 +156,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.2"
petitparser:
dependency: transitive
description:
name: petitparser
url: "https://pub.dartlang.org"
source: hosted
version: "2.4.0"
platform:
dependency: transitive
description:
@ -170,6 +184,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.13"
quiver:
dependency: transitive
description:
name: quiver
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.3"
rxdart:
dependency: "direct main"
description:
@ -223,7 +244,7 @@ packages:
name: test_api
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.16"
version: "0.2.15"
typed_data:
dependency: transitive
description:
@ -252,6 +273,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.0"
xml:
dependency: transitive
description:
name: xml
url: "https://pub.dartlang.org"
source: hosted
version: "3.6.1"
sdks:
dart: ">=2.7.0 <3.0.0"
dart: ">=2.6.0 <3.0.0"
flutter: ">=1.12.13+hotfix.5 <2.0.0"

View File

@ -14,3 +14,9 @@ enum PlaybackState {
connecting,
completed
};
enum LoopMode {
loopOff,
loopOne,
loopAll
};

13
ios/Classes/AudioSource.h Normal file
View File

@ -0,0 +1,13 @@
#import <Flutter/Flutter.h>
@interface AudioSource : NSObject
@property (readonly, nonatomic) NSString* sourceId;
- (instancetype)initWithId:(NSString *)sid;
- (int)buildSequence:(NSMutableArray *)sequence treeIndex:(int)treeIndex;
- (void)findById:(NSString *)sourceId matches:(NSMutableArray<AudioSource *> *)matches;
- (NSArray *)getShuffleOrder;
- (int)shuffle:(int)treeIndex currentIndex:(int)currentIndex;
@end

1
ios/Classes/AudioSource.m Symbolic link
View File

@ -0,0 +1 @@
../../darwin/Classes/AudioSource.m

View File

@ -0,0 +1,9 @@
#import "AudioSource.h"
#import "UriAudioSource.h"
#import <Flutter/Flutter.h>
@interface ClippingAudioSource : IndexedAudioSource
- (instancetype)initWithId:(NSString *)sid audioSource:(UriAudioSource *)audioSource start:(NSNumber *)start end:(NSNumber *)end;
@end

View File

@ -0,0 +1 @@
../../darwin/Classes/ClippingAudioSource.m

View File

@ -0,0 +1,13 @@
#import "AudioSource.h"
#import <Flutter/Flutter.h>
@interface ConcatenatingAudioSource : AudioSource
@property (readonly, nonatomic) int count;
- (instancetype)initWithId:(NSString *)sid audioSources:(NSMutableArray<AudioSource *> *)audioSources;
- (void)insertSource:(AudioSource *)audioSource atIndex:(int)index;
- (void)removeSourcesFromIndex:(int)start toIndex:(int)end;
- (void)moveSourceFromIndex:(int)currentIndex toIndex:(int)newIndex;
@end

View File

@ -0,0 +1 @@
../../darwin/Classes/ConcatenatingAudioSource.m

View File

@ -0,0 +1,20 @@
#import "AudioSource.h"
#import "IndexedPlayerItem.h"
#import <Flutter/Flutter.h>
#import <AVFoundation/AVFoundation.h>
@interface IndexedAudioSource : AudioSource
@property (readonly, nonatomic) IndexedPlayerItem *playerItem;
@property (readwrite, nonatomic) CMTime duration;
@property (readonly, nonatomic) CMTime position;
@property (readonly, nonatomic) BOOL isAttached;
- (void)attach:(AVQueuePlayer *)player;
- (void)play:(AVQueuePlayer *)player;
- (void)pause:(AVQueuePlayer *)player;
- (void)stop:(AVQueuePlayer *)player;
- (void)seek:(CMTime)position;
- (void)seek:(CMTime)position completionHandler:(void (^)(BOOL))completionHandler;
@end

View File

@ -0,0 +1 @@
../../darwin/Classes/IndexedAudioSource.m

View File

@ -0,0 +1,9 @@
#import <AVFoundation/AVFoundation.h>
@class IndexedAudioSource;
@interface IndexedPlayerItem : AVPlayerItem
@property (readwrite, nonatomic) IndexedAudioSource *audioSource;
@end

View File

@ -0,0 +1 @@
../../darwin/Classes/IndexedPlayerItem.m

View File

@ -0,0 +1,8 @@
#import "AudioSource.h"
#import <Flutter/Flutter.h>
@interface LoopingAudioSource : AudioSource
- (instancetype)initWithId:(NSString *)sid audioSources:(NSArray<AudioSource *> *)audioSources;
@end

View File

@ -0,0 +1 @@
../../darwin/Classes/LoopingAudioSource.m

View File

@ -0,0 +1,8 @@
#import "IndexedAudioSource.h"
#import <Flutter/Flutter.h>
@interface UriAudioSource : IndexedAudioSource
- (instancetype)initWithId:(NSString *)sid uri:(NSString *)uri;
@end

View File

@ -0,0 +1 @@
../../darwin/Classes/UriAudioSource.m

View File

@ -136,6 +136,8 @@ class AudioPlayer {
_eventChannelStream = EventChannel('com.ryanheise.just_audio.events.$_id')
.receiveBroadcastStream()
.map((data) {
try {
//print("received raw event: $data");
final duration = (data['duration'] ?? -1) < 0
? null
: Duration(milliseconds: data['duration']);
@ -154,7 +156,13 @@ class AudioPlayer {
: IcyMetadata.fromJson(data['icyMetadata']),
currentIndex: data['currentIndex'],
);
//print("created event object with state: ${_audioPlaybackEvent.state}");
return _audioPlaybackEvent;
} catch (e, stacktrace) {
print("Error parsing event: $e");
print("$stacktrace");
rethrow;
}
});
_eventChannelStreamSubscription = _eventChannelStream.listen(
_playbackEventSubject.add,

View File

@ -77,6 +77,8 @@ abstract class JustAudioPlayer {
return await setLoopMode(args[0]);
case 'setShuffleModeEnabled':
return await setShuffleModeEnabled(args[0]);
case 'setAutomaticallyWaitsToMinimizeStalling':
return null;
case 'seek':
return await seek(args[0], args[1]);
case 'dispose':

View File

@ -2,7 +2,7 @@
@interface AudioPlayer : NSObject<FlutterStreamHandler>
- (instancetype)initWithRegistrar:(NSObject<FlutterPluginRegistrar> *)registrar playerId:(NSString*)idParam;
- (instancetype)initWithRegistrar:(NSObject<FlutterPluginRegistrar> *)registrar playerId:(NSString*)idParam configuredSession:(BOOL)configuredSession;
@end
@ -14,3 +14,9 @@ enum PlaybackState {
connecting,
completed
};
enum LoopMode {
loopOff,
loopOne,
loopAll
};

View File

@ -0,0 +1,13 @@
#import <FlutterMacOS/FlutterMacOS.h>
@interface AudioSource : NSObject
@property (readonly, nonatomic) NSString* sourceId;
- (instancetype)initWithId:(NSString *)sid;
- (int)buildSequence:(NSMutableArray *)sequence treeIndex:(int)treeIndex;
- (void)findById:(NSString *)sourceId matches:(NSMutableArray<AudioSource *> *)matches;
- (NSArray *)getShuffleOrder;
- (int)shuffle:(int)treeIndex currentIndex:(int)currentIndex;
@end

1
macos/Classes/AudioSource.m Symbolic link
View File

@ -0,0 +1 @@
../../darwin/Classes/AudioSource.m

View File

@ -0,0 +1,9 @@
#import "AudioSource.h"
#import "UriAudioSource.h"
#import <FlutterMacOS/FlutterMacOS.h>
@interface ClippingAudioSource : IndexedAudioSource
- (instancetype)initWithId:(NSString *)sid audioSource:(UriAudioSource *)audioSource start:(NSNumber *)start end:(NSNumber *)end;
@end

View File

@ -0,0 +1 @@
../../darwin/Classes/ClippingAudioSource.m

View File

@ -0,0 +1,13 @@
#import "AudioSource.h"
#import <FlutterMacOS/FlutterMacOS.h>
@interface ConcatenatingAudioSource : AudioSource
@property (readonly, nonatomic) int count;
- (instancetype)initWithId:(NSString *)sid audioSources:(NSMutableArray<AudioSource *> *)audioSources;
- (void)insertSource:(AudioSource *)audioSource atIndex:(int)index;
- (void)removeSourcesFromIndex:(int)start toIndex:(int)end;
- (void)moveSourceFromIndex:(int)currentIndex toIndex:(int)newIndex;
@end

View File

@ -0,0 +1 @@
../../darwin/Classes/ConcatenatingAudioSource.m

View File

@ -0,0 +1,20 @@
#import "AudioSource.h"
#import "IndexedPlayerItem.h"
#import <FlutterMacOS/FlutterMacOS.h>
#import <AVFoundation/AVFoundation.h>
@interface IndexedAudioSource : AudioSource
@property (readonly, nonatomic) IndexedPlayerItem *playerItem;
@property (readwrite, nonatomic) CMTime duration;
@property (readonly, nonatomic) CMTime position;
@property (readonly, nonatomic) BOOL isAttached;
- (void)attach:(AVQueuePlayer *)player;
- (void)play:(AVQueuePlayer *)player;
- (void)pause:(AVQueuePlayer *)player;
- (void)stop:(AVQueuePlayer *)player;
- (void)seek:(CMTime)position;
- (void)seek:(CMTime)position completionHandler:(void (^)(BOOL))completionHandler;
@end

View File

@ -0,0 +1 @@
../../darwin/Classes/IndexedAudioSource.m

View File

@ -0,0 +1,9 @@
#import <AVFoundation/AVFoundation.h>
@class IndexedAudioSource;
@interface IndexedPlayerItem : AVPlayerItem
@property (readwrite, nonatomic) IndexedAudioSource *audioSource;
@end

View File

@ -0,0 +1 @@
../../darwin/Classes/IndexedPlayerItem.m

View File

@ -0,0 +1,8 @@
#import "AudioSource.h"
#import <FlutterMacOS/FlutterMacOS.h>
@interface LoopingAudioSource : AudioSource
- (instancetype)initWithId:(NSString *)sid audioSources:(NSArray<AudioSource *> *)audioSources;
@end

View File

@ -0,0 +1 @@
../../darwin/Classes/LoopingAudioSource.m

View File

@ -0,0 +1,8 @@
#import "IndexedAudioSource.h"
#import <FlutterMacOS/FlutterMacOS.h>
@interface UriAudioSource : IndexedAudioSource
- (instancetype)initWithId:(NSString *)sid uri:(NSString *)uri;
@end

View File

@ -0,0 +1 @@
../../darwin/Classes/UriAudioSource.m