Prechádzať zdrojové kódy

Merge branch 'master' of 60.205.190.38:iOS/MKRRadioManager

尹永奇 5 rokov pred
rodič
commit
7fdacd3542
28 zmenil súbory, kde vykonal 1001 pridanie a 200 odobranie
  1. 4 0
      Example/MKRRadioManager/MKRPlayControlViewController.m
  2. 4 4
      Example/MKRRadioManager/MKRViewController.m
  3. 2 2
      Example/Podfile.lock
  4. 2 2
      Example/Pods/Local Podspecs/MKRRadioManager.podspec.json
  5. 2 2
      Example/Pods/Manifest.lock
  6. 1 1
      MKRRadioManager.podspec
  7. 9 1
      MKRRadioManager/Classes/MKRRadioManager/Category/NSString+MKRRadioManagerAdd.h
  8. 17 1
      MKRRadioManager/Classes/MKRRadioManager/Category/NSString+MKRRadioManagerAdd.m
  9. 3 1
      MKRRadioManager/Classes/MKRRadioManager/Category/UIDevice+MKRRadioManagerAdd.h
  10. 14 0
      MKRRadioManager/Classes/MKRRadioManager/Category/UIDevice+MKRRadioManagerAdd.m
  11. 12 5
      MKRRadioManager/Classes/MKRRadioManager/Headers/MKRPlayControlProtocol.h
  12. 7 0
      MKRRadioManager/Classes/MKRRadioManager/Headers/MKRPlayResourceUpdateProtocol.h
  13. 3 1
      MKRRadioManager/Classes/MKRRadioManager/Headers/MKRResoureEnumHeader.h
  14. 31 1
      MKRRadioManager/Classes/MKRRadioManager/MKRAVPlayer/MKRAVPlayer.h
  15. 134 16
      MKRRadioManager/Classes/MKRRadioManager/MKRAVPlayer/MKRAVPlayer.m
  16. 7 0
      MKRRadioManager/Classes/MKRRadioManager/MKRAVPlayer/MKRPlayResourceStatus.h
  17. 15 0
      MKRRadioManager/Classes/MKRRadioManager/MKRAVPlayer/MKRPlayResourceStatus.m
  18. 2 0
      MKRRadioManager/Classes/MKRRadioManager/MKRRadioResorce.h
  19. 4 0
      MKRRadioManager/Classes/MKRRadioManager/MKRRadioResorce.m
  20. 11 0
      MKRRadioManager/Classes/MKRRadioManager/MKRWIFIDeviceManager/MKRM3UListModel.h
  21. 62 13
      MKRRadioManager/Classes/MKRRadioManager/MKRWIFIDeviceManager/MKRM3UListModel.m
  22. 126 15
      MKRRadioManager/Classes/MKRRadioManager/MKRWIFIDeviceManager/MKRWIFIDeviceManager.h
  23. 449 134
      MKRRadioManager/Classes/MKRRadioManager/MKRWIFIDeviceManager/MKRWIFIDeviceManager.m
  24. 59 0
      libs/libAS-Control.framework/Headers/ASControlTools.h
  25. 20 0
      libs/libAS-Control.framework/Headers/NSDictionary+MKRXml.h
  26. BIN
      libs/libAS-Control.framework/Info.plist
  27. BIN
      libs/libAS-Control.framework/libAS-Control
  28. 1 1
      upgrade.sh

+ 4 - 0
Example/MKRRadioManager/MKRPlayControlViewController.m

@@ -23,6 +23,10 @@
 - (instancetype)initWithDevice:(MKRUPnPDevice *)device{
     if (self = [super init]) {
 //        [[MKRRadioControlMaster shareMaster] changeCurrentDevice:device];
+        
+        
+        
+        
     }
     return self;
 }

+ 4 - 4
Example/MKRRadioManager/MKRViewController.m

@@ -38,14 +38,14 @@
 {
     [super viewDidLoad];
 //    http://openod.sign.qingting.fm/mp3/3235228_128.mp3?sign=47d740e207069a86c539d2c78528f9c2&t=5d8d2d55&clientID=OTRmNmQyZDgtNWZiMi0xMWU3LTkyM2YtMDAxNjNlMDAyMGFk
-    NSString *urlString = [@"http://radio1964-zhibo.oss-cn-shenzhen.aliyuncs.com/audio_data/180112/榜单bandcamp第一期20181月12.mp3" stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
+//    NSString *urlString = [@"http://radio1964-zhibo.oss-cn-shenzhen.aliyuncs.com/audio_data/180112/榜单bandcamp第一期20181月12.mp3" stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
     NSString *string1 = [@"http://openod.sign.qingting.fm/mp3/3235228_128.mp3?sign=47d740e207069a86c539d2c78528f9c2&t=5d8d2d55&clientID=OTRmNmQyZDgtNWZiMi0xMWU3LTkyM2YtMDAxNjNlMDAyMGFk" stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
 //    NSString *realString = [[urlString urlEncodeString] stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
     NSURL *url = [NSURL URLWithString:string1];
     
-    self.player = [[MKRAVPlayer alloc]initWithContentURL:url];
-    self.player.shouldAutoPlay = YES;
-    [self.player play];
+//    self.player = [[MKRAVPlayer alloc]initWithContentURL:url];
+//    self.player.shouldAutoPlay = YES;
+//    [self.player play];
 //    self.tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain];
 //    self.tableView.delegate = self;
 //    self.tableView.dataSource = self;

+ 2 - 2
Example/Podfile.lock

@@ -1,5 +1,5 @@
 PODS:
-  - MKRRadioManager (0.0.1)
+  - MKRRadioManager (0.0.2)
   - YYCategory (0.0.1)
 
 DEPENDENCIES:
@@ -15,7 +15,7 @@ EXTERNAL SOURCES:
     :path: "../"
 
 SPEC CHECKSUMS:
-  MKRRadioManager: dc051d4b5361a49c481dc08d28eaf07fa1c1084c
+  MKRRadioManager: 11a29ba22ec11c476bfadcc85770af93d0937792
   YYCategory: d85135b05d2806c90930a5bbadfc1501396a3db9
 
 PODFILE CHECKSUM: f65396e8a7f07654404054ab9d38dc4b7b6f8818

+ 2 - 2
Example/Pods/Local Podspecs/MKRRadioManager.podspec.json

@@ -1,6 +1,6 @@
 {
   "name": "MKRRadioManager",
-  "version": "0.0.1",
+  "version": "0.0.2",
   "summary": "A short description of MKRRadioManager.",
   "description": "TODO: Add long description of the pod here.",
   "homepage": "http://60.205.190.38:9000/iOS/MKRRadioManager.git",
@@ -13,7 +13,7 @@
   },
   "source": {
     "git": "http://60.205.190.38:9000/iOS/MKRRadioManager.git",
-    "tag": "0.0.1"
+    "tag": "0.0.2"
   },
   "platforms": {
     "ios": "8.0"

+ 2 - 2
Example/Pods/Manifest.lock

@@ -1,5 +1,5 @@
 PODS:
-  - MKRRadioManager (0.0.1)
+  - MKRRadioManager (0.0.2)
   - YYCategory (0.0.1)
 
 DEPENDENCIES:
@@ -15,7 +15,7 @@ EXTERNAL SOURCES:
     :path: "../"
 
 SPEC CHECKSUMS:
-  MKRRadioManager: dc051d4b5361a49c481dc08d28eaf07fa1c1084c
+  MKRRadioManager: 11a29ba22ec11c476bfadcc85770af93d0937792
   YYCategory: d85135b05d2806c90930a5bbadfc1501396a3db9
 
 PODFILE CHECKSUM: f65396e8a7f07654404054ab9d38dc4b7b6f8818

+ 1 - 1
MKRRadioManager.podspec

@@ -8,7 +8,7 @@
 
 Pod::Spec.new do |s|
   s.name             = 'MKRRadioManager'
-  s.version          = '0.0.1'
+  s.version          = '0.0.2'
   s.summary          = 'A short description of MKRRadioManager.'
 
 # This description is used to generate tags and improve search results.

+ 9 - 1
MKRRadioManager/Classes/MKRRadioManager/Category/NSString+MKRRadioManagerAdd.h

@@ -13,4 +13,12 @@
  */
 + (NSString *)HHmmssFormatStrig:(NSInteger)timeInterval;
 
-@end
+/**
+ hh:mm:ss 时分秒格式字符串转换成秒数
+
+ @param timeString hh:mm:ss 字符串
+ @return 秒数
+ */
++ (NSInteger)secondsFromHHmmssFormatStrig:(NSString *)timeString;
+
+@end

+ 17 - 1
MKRRadioManager/Classes/MKRRadioManager/Category/NSString+MKRRadioManagerAdd.m

@@ -17,4 +17,20 @@
     return [NSString stringWithFormat:@"%02d:%02d:%02d",hours,minutes,seconds];
 }
 
-@end
++ (NSInteger)secondsFromHHmmssFormatStrig:(NSString *)timeString{
+    if (!timeString.length) {
+        return 0;
+    }
+    NSInteger seconds = 0;
+    NSArray *arr = [timeString componentsSeparatedByString:@":"];
+    NSArray *reverArr = [[arr reverseObjectEnumerator] allObjects];
+    for (NSInteger i = 0; i<reverArr.count; i++) {
+        NSInteger count = [reverArr[i] integerValue];
+        NSInteger type = (int)pow(60, i);
+        seconds += count * type;
+    }
+    
+    return seconds;
+}
+
+@end

+ 3 - 1
MKRRadioManager/Classes/MKRRadioManager/Category/UIDevice+MKRRadioManagerAdd.h

@@ -10,4 +10,6 @@
 
 + (NSString *)currentDeviceInfo;
 
-@end
++ (NSString *)currentSSID;
+
+@end

+ 14 - 0
MKRRadioManager/Classes/MKRRadioManager/Category/UIDevice+MKRRadioManagerAdd.m

@@ -7,6 +7,7 @@
 #include <net/if.h>
 #include <net/if_dl.h>
 #include <mach/machine.h>
+#import <SystemConfiguration/CaptiveNetwork.h>
 
 #define IOS6_7 [[[UIDevice currentDevice]systemVersion] floatValue] >= 6.0
 
@@ -127,4 +128,17 @@
     return macAddressString;
 }
 
++ (NSString *)currentSSID{
+    NSString *ssid = @"Not Found";
+    CFArrayRef myArray = CNCopySupportedInterfaces();
+    if (myArray != nil) {
+        CFDictionaryRef myDict = CNCopyCurrentNetworkInfo(CFArrayGetValueAtIndex(myArray, 0));
+        if (myDict != nil) {
+            NSDictionary *dict = (NSDictionary*)CFBridgingRelease(myDict);
+            ssid = [dict valueForKey:@"SSID"];
+        }
+    }
+    return ssid;
+}
+
 @end

+ 12 - 5
MKRRadioManager/Classes/MKRRadioManager/Headers/MKRPlayControlProtocol.h

@@ -99,12 +99,19 @@
 - (void)setPlayMode:(MKRRadioPlayMode)playMode channelNO:(NSInteger)channelNO;
 
 /**
+设置设备低电量提醒
+
+@param enable 是否允许低电量提醒
+*/
+- (void)setLowBatteryNoticeEnable:(BOOL)enable;
+
+/**
  播放某个频道某一首歌
 
  @param channelNO 频道号
  @param index 歌曲下标
  */
-- (void)playSongWithChannelNO:(NSInteger)channelNO index:(NSInteger)index userID:(NSString *)userID;
+- (void)playSongWithChannelNO:(NSInteger)channelNO index:(NSInteger)index;
 
 
 /**
@@ -112,7 +119,7 @@
  
  @param channelNO 频道号 从第一首开始播放
  */
-- (void)playSongWithChannelNO:(NSInteger)channelNO userID:(NSString *)userID;
+- (void)playSongWithChannelNO:(NSInteger)channelNO;
 
 
 /**
@@ -120,7 +127,7 @@
 
  @param songs 歌曲数组
  */
-- (void)playTempSongs:(NSArray <id <MKRRadioResorce>> *)songs userID:(NSString *)userID;
+- (void)playTempSongs:(NSArray <id <MKRRadioResorce>> *)songs;
 
 /**
  播放歌曲列表到临时列表
@@ -128,13 +135,13 @@
  @param songs 歌曲数组
  @param index 开始播放的下标
  */
-- (void)playTempSongs:(NSArray <id <MKRRadioResorce>> *)songs index:(NSInteger)index userID:(NSString *)userID;
+- (void)playTempSongs:(NSArray <id <MKRRadioResorce>> *)songs index:(NSInteger)index;
 
 /**
  更新播放列表
 
  @param newPlayList 目标播放列表
  */
-- (void)updatePlayList:(NSArray <id <MKRRadioResorce>> *)newPlayList userID:(NSString *)userID;
+- (void)updatePlayList:(NSArray <id <MKRRadioResorce>> *)newPlayList;
 
 @end

+ 7 - 0
MKRRadioManager/Classes/MKRRadioManager/Headers/MKRPlayResourceUpdateProtocol.h

@@ -57,6 +57,13 @@
 - (void)playStateDidChange:(MKRResourcePlayState)state;
 
 /**
+搜索到新设备
+
+@param device 设备对象
+*/
+- (void)didSearchDevice:(id<MKRUPnPDevice>)newDevice;
+
+/**
  选择了设备
 
  @param device 设备对象

+ 3 - 1
MKRRadioManager/Classes/MKRRadioManager/Headers/MKRResoureEnumHeader.h

@@ -16,7 +16,8 @@ typedef NS_ENUM(NSUInteger, MKRSourceType) {
     MKRSourceTypePodcast,//主播电台
     MKRSourceTypeBroadcast,//广播电台
     MKRSourceTypeHandPick,//精选电台
-    MKRSourceTypeParentChild//亲子
+    MKRSourceTypeParentChild,//亲子
+    MKRSourceTypeMusicRadio//音乐电台
 };
 
 //资源来源
@@ -26,6 +27,7 @@ typedef NS_ENUM(NSUInteger, MKRSourcePlatform) {
     MKRSourcePlatformDMH,     //百度
     MKRSourcePlatformOverSea, //海外
     MKRSourcePlatformQQ,     //QQ音乐
+    MKRSourcePlatformWL,     //蔚来定制
 };
 
 typedef NS_ENUM(NSUInteger, MKRRadioPlayMode) {

+ 31 - 1
MKRRadioManager/Classes/MKRRadioManager/MKRAVPlayer/MKRAVPlayer.h

@@ -54,6 +54,18 @@ typedef enum : NSUInteger {
 - (void)didReadyToPlay;
 
 /**
+ 播放完成 即将按照播放模式开始播放下一首
+ 返回值为YES 将自动按照播放模式开始播放下一首
+ @param nextIndex 下一首的下标
+ */
+- (BOOL)didFinishPlayWillAutoNext:(NSInteger)nextIndex;
+
+/// 即将开始准备播放
+/// 返回值为NO 则不处理播放逻辑,忽略此次播放操作 不实现此方法 默认可以播放
+/// @param index 准备播放的资源在播放列表的下标
+- (BOOL)willPreparePlayAtIndex:(NSInteger)index;
+
+/**
  播放完成
  
  @param currentIndex 播放完成的资源在播放列表中的下表
@@ -68,11 +80,19 @@ typedef enum : NSUInteger {
  */
 - (void)didFailedToPlayToEndTime;
 
+/// 加载资源失败
+/// @param url 加载失败的url
+/// @param error 错误信息
+- (void)didFailedToLoadURL:(NSString *)url error:(NSError *)error;
+
 /**
  播放中断
  */
 - (void)playbackStalled;
 
+/// 可用缓存为空导致
+- (void)stalledByCacheEmtpy;
+
 @end
 
 @interface MKRAVPlayer : NSObject
@@ -89,7 +109,15 @@ typedef enum : NSUInteger {
 
 - (id)initWithObjectsPlayList:(NSArray<id<MKRRadioResorce>> *)playList playMode:(MKRAVPlayerPlayMode)playMode;
 
-- (void)updatePlayList:(NSArray<NSString *> *)playList;
+/**
+更新播放列表
+*/
+- (void)updateResourcePlayList:(NSArray<id<MKRRadioResorce>> *)playList;
+
+/**
+重新播放当前资源
+*/
+- (void)replayCurrentResource;
 
 @property(nonatomic, weak) id<MKRAVPlayerDelegate> delegate;
 
@@ -104,6 +132,8 @@ typedef enum : NSUInteger {
  */
 @property (nonatomic, assign) NSInteger currentIndex;
 
+@property (nonatomic, assign) id <MKRRadioResorce> currentResource;
+
 /**
  是否正在播放中
  */

+ 134 - 16
MKRRadioManager/Classes/MKRRadioManager/MKRAVPlayer/MKRAVPlayer.m

@@ -19,6 +19,7 @@ static void * PlayerStatusObservationContext = &PlayerStatusObservationContext;
 @interface MKRAVPlayer (){
     BOOL _interruptWhenPlaying;
 }
+@property (nonatomic, strong) id                timeObserver;
 @property (nonatomic, assign) UIBackgroundTaskIdentifier bgTaskId;//后台播放id
 @property (nonatomic, strong) AVPlayer *player;//播放器player
 @property (nonatomic, strong) AVPlayerItem *playerItem;//当前播放的item
@@ -33,6 +34,8 @@ static void * PlayerStatusObservationContext = &PlayerStatusObservationContext;
 @property (nonatomic, copy)   MKRAVPlayerURLRequsetBlcok block;
 @property (nonatomic, assign) BOOL isSeeking;//是否快进或快退
 @property (nonatomic, assign) NSTimeInterval seekTime;//快进或者快退的目标时间
+@property (nonatomic, strong) NSMutableArray *resourcePlayList;//MKRRadioResorce播放列表
+@property (nonatomic, assign) BOOL initByUrlPlayList;//是字符串播放列表
 @end
 
 @implementation MKRAVPlayer
@@ -68,6 +71,7 @@ NSURL * MKRUrlWithString(NSString *string){
 - (id)initWithPlayList:(NSArray<NSString *> *)playList{
     self = [self init];
     if (self) {
+        self.initByUrlPlayList = YES;
         self.playList = playList;
     }
     return self;
@@ -84,6 +88,7 @@ NSURL * MKRUrlWithString(NSString *string){
 - (id)initWithContentURL:(NSURL *)aUrl{
     self = [self init];
     if (self) {
+        self.initByUrlPlayList = YES;
         self.playUrl  = aUrl;
         self.playList = [NSArray arrayWithObject:aUrl];
     }
@@ -96,21 +101,44 @@ NSURL * MKRUrlWithString(NSString *string){
 }
 
 - (id)initWithObjectsPlayList:(NSArray<id<MKRRadioResorce>> *)playList{
-    NSArray *urls = [playList valueForKey:@"songUrl"];
+    NSMutableArray *urls = [NSMutableArray arrayWithArray:[playList valueForKey:@"songUrl"]];
+    for (NSInteger i = 0; i<urls.count; i++) {
+        if ([urls[i] isEqual:[NSNull null]]) {
+            [urls replaceObjectAtIndex:i withObject:@""];
+        }
+    }
+    self.resourcePlayList = [NSMutableArray arrayWithArray:playList];
     return [self initWithPlayList:urls];
 }
 
 - (id)initWithObjectsPlayList:(NSArray<id<MKRRadioResorce>> *)playList playMode:(MKRAVPlayerPlayMode)playMode{
-    NSArray *urls = [playList valueForKey:@"songUrl"];
+    NSMutableArray *urls = [NSMutableArray arrayWithArray:[playList valueForKey:@"songUrl"]];
+    for (NSInteger i = 0; i<urls.count; i++) {
+        if ([urls[i] isEqual:[NSNull null]]) {
+            [urls replaceObjectAtIndex:i withObject:@""];
+        }
+    }
+    self.resourcePlayList = [NSMutableArray arrayWithArray:playList];
     return [self initWithPlayList:urls playMode:playMode];
 }
 
-- (void)updatePlayList:(NSArray<NSString *> *)playList{
-    self.playList = playList;
-    NSUInteger index = [playList indexOfObject:self.playUrl.absoluteString];
-    if (index != NSNotFound) {
-        self.currentIndex = index;
+- (void)updateResourcePlayList:(NSArray<id<MKRRadioResorce>> *)playList{
+    __block NSInteger index = 0;
+    [playList enumerateObjectsUsingBlock:^(id<MKRRadioResorce> obj, NSUInteger idx, BOOL * _Nonnull stop) {
+        if (obj.songID == self.currentResource.songID) {
+            index = idx;
+            *stop = YES;
+        }
+    }];
+    NSMutableArray *urls = [NSMutableArray arrayWithArray:[playList valueForKey:@"songUrl"]];
+    for (NSInteger i = 0; i<urls.count; i++) {
+        if ([urls[i] isEqual:[NSNull null]]) {
+            [urls replaceObjectAtIndex:i withObject:@""];
+        }
     }
+    self.currentIndex = index;
+    self.playList = urls;
+    self.resourcePlayList = playList;
 }
 
 #pragma mark - 播放相关
@@ -123,10 +151,8 @@ NSURL * MKRUrlWithString(NSString *string){
             [self.player play];
             self.state = MKRAVPlayerStatePlaying;
         }else if (self.state == MKRAVPlayerStateBuffering){
-            if (!self.shouldAutoPlay) {
-                [self.player play];
-                self.state = MKRAVPlayerStatePlaying;
-            }
+            [self.player play];
+            self.state = MKRAVPlayerStatePlaying;
         }else if (self.state == MKRAVPlayerStatePlaying){
             if (self.player && !self.player.rate) {
                 [self.player play];
@@ -144,6 +170,7 @@ NSURL * MKRUrlWithString(NSString *string){
         self.currentIndex = index;
         NSString *url = [self.playList objectAtIndex:index];
         self.playUrl = MKRUrlWithString(url);
+        self.currentResource = self.resourcePlayList[index];
         [self play];
     }
 }
@@ -168,6 +195,28 @@ NSURL * MKRUrlWithString(NSString *string){
     }
 }
 
+- (NSInteger)_caculateNextIndex:(NSInteger)currentIndex{
+    switch (_playMode) {
+        case MKRAVPlayerPlayModeRandom:{
+            return [self ramdomIndex];
+        }
+            break;
+        case MKRAVPlayerPlayModeSingle:{
+            return currentIndex;
+        }
+            break;
+        case MKRAVPlayerPlayModeOrder:
+        default:{
+            NSInteger index = currentIndex + 1;
+            if (index > self.playList.count - 1) {
+                index = 0;
+            }
+            return index;
+        }
+            break;
+    }
+}
+
 - (void)next{
     if (_playMode == MKRAVPlayerPlayModeRandom) {
         [self nextWhenPlayDidEnd];
@@ -207,29 +256,49 @@ NSURL * MKRUrlWithString(NSString *string){
     }
 }
 
+- (void)replayCurrentResource{
+    [self resetPlayer];
+    [self playAtIndex:self.currentIndex];
+}
+
 - (void)resetPlayer{
+    self.totalTime = 0;
+//    self.currentTime = 0;
     self.playerItem = nil;
     self.isInitPlayer = NO;
+    self.isSeeking = NO;
     [self.player replaceCurrentItemWithPlayerItem:nil];
     [self.player.currentItem cancelPendingSeeks];
     [self.player.currentItem.asset cancelLoading];
     [self.player pause];
     [self removeNotification];
     [self removePlayerKVO];
+    self.state = MKRAVPlayerStateStopped;
     [[NSNotificationCenter defaultCenter] removeObserver:self
                                                     name:nil
                                                   object:_playerItem];
     
-    [self.player removeObserver:self forKeyPath:@"rate"];
+    @try {
+        [self.player removeObserver:self forKeyPath:@"rate"];
+    } @catch (NSException *exception) {
+    } @finally {
+    }
     self.player = nil;
 }
 
 - (void)preparePlay{
+    BOOL shouldPlay = YES;
+    if (self.delegate && [self.delegate respondsToSelector:@selector(willPreparePlayAtIndex:)]) {
+        shouldPlay = [self.delegate willPreparePlayAtIndex:self.currentIndex];
+    }
+    if (!shouldPlay) return;
+    
     if (self.delegate && [self.delegate respondsToSelector:@selector(songPlayUrlWithIndex:completion:)]) {
         __weak __typeof(self)weakSelf = self;
         [self.delegate songPlayUrlWithIndex:self.currentIndex completion:^(NSString * _Nonnull resourceUrl) {
-            weakSelf.playUrl = MKRUrlWithString(resourceUrl);
-            [weakSelf createPlayerAndReadyToPlay];
+            __strong __typeof(weakSelf)strongSelf = weakSelf;
+            strongSelf.playUrl = MKRUrlWithString(resourceUrl);
+            [strongSelf createPlayerAndReadyToPlay];
         }];
         return;
     }
@@ -237,10 +306,13 @@ NSURL * MKRUrlWithString(NSString *string){
 }
 
 - (void)createPlayerAndReadyToPlay{
-    self.isInitPlayer = YES;
+    if (self.isInitPlayer) {
+        return;
+    }
     //注册通知
     [self registerNotification];
     if (self.playerItem) {
+        [self resetPlayer];
         self.player = [AVPlayer playerWithPlayerItem:self.playerItem];
     }else{
         self.playAsset = [AVURLAsset assetWithURL:self.playUrl];
@@ -251,7 +323,15 @@ NSURL * MKRUrlWithString(NSString *string){
         self.playerItem = [AVPlayerItem playerItemWithAsset:self.playAsset];
         self.player = [AVPlayer playerWithPlayerItem:self.playerItem];
         [self.player addObserver:self forKeyPath:@"rate" options:NSKeyValueObservingOptionNew context:PlayerStatusObservationContext];
+        __weak __typeof(self)weakSelf = self;
+        self.timeObserver = [self.player addPeriodicTimeObserverForInterval:CMTimeMake(0.1*30, 30) queue:dispatch_get_main_queue() usingBlock:^(CMTime time) {
+            CGFloat currentT = (CGFloat)CMTimeGetSeconds(time);
+            if (weakSelf.currentStatus) {
+                weakSelf.currentStatus.currentDuration = currentT;
+            }
+        }];
     }
+    self.isInitPlayer = YES;
     if (@available(iOS 10.0, *)) {
         self.player.automaticallyWaitsToMinimizeStalling = NO;
     }
@@ -321,6 +401,9 @@ NSURL * MKRUrlWithString(NSString *string){
 
 - (void)failedToPlayToEndTimeError:(NSNotification *)note{
     NSLog(@"错误e没结束");
+    if (self.delegate && [self.delegate respondsToSelector:@selector(didFailedToPlayToEndTime)]) {
+        [self.delegate didFailedToPlayToEndTime];
+    }
 }
 
 - (void)moviePlayDidEnd:(NSNotification *)note{
@@ -328,10 +411,29 @@ NSURL * MKRUrlWithString(NSString *string){
     self.rate = 1.0f;
     self.seekTime = 0.0f;
     self.isSeeking = NO;
-    [self nextWhenPlayDidEnd];
+    BOOL shouldAutoNext = YES;
+    NSInteger nextIndex = 0;
+    if (self.delegate && [self.delegate respondsToSelector:@selector(didFinishPlayWillAutoNext:)]) {
+        nextIndex = [self _caculateNextIndex:self.currentIndex];
+        shouldAutoNext = [self.delegate didFinishPlayWillAutoNext:nextIndex];
+    }
     if (self.delegate && [self.delegate respondsToSelector:@selector(didFinishPlay:)]) {
         [self.delegate didFinishPlay:self.currentIndex];
     }
+    if (shouldAutoNext) {
+        [self nextWhenPlayDidEnd];
+    }else{
+        if (self.playList.count <= nextIndex) {
+            return;
+        }
+        [self resetPlayer];
+        self.currentIndex = nextIndex;
+        self.currentResource = self.resourcePlayList[nextIndex];
+        self.currentStatus = nil;
+        NSString *url = [self.playList objectAtIndex:self.currentIndex];
+        self.playUrl = MKRUrlWithString(url);
+        self.state = MKRAVPlayerStateStopped;
+    }
 }
 
 #pragma mark - setter
@@ -351,6 +453,8 @@ NSURL * MKRUrlWithString(NSString *string){
         dispatch_async(dispatch_get_main_queue(), ^{
             self->_isSeeking = NO;
             [self.player play];
+            self.player.rate = self.rate;
+            self.state = MKRAVPlayerStatePlaying;
         });
     }];
 }
@@ -395,6 +499,7 @@ NSURL * MKRUrlWithString(NSString *string){
 - (NSInteger)currentTime{
     if (!_player) return 0.0f;
     if (_isSeeking) return _seekTime;
+    if (!self.totalTime) return 0.0f;
     return CMTimeGetSeconds([_player currentTime]);
 }
 
@@ -404,6 +509,8 @@ NSURL * MKRUrlWithString(NSString *string){
     }
     _currentStatus.totalTime = self.totalTime;
     _currentStatus.currentTime = self.currentTime;
+    _currentStatus.totalDuration = self.totalTime;
+//    _currentStatus.currentDuration = self.currentTime;
     _currentStatus.isPlaying = [self isPlaying];
     _currentStatus.playState = (MKRResourcePlayState)self.state;
     return _currentStatus;
@@ -441,6 +548,9 @@ NSURL * MKRUrlWithString(NSString *string){
                 self.state = MKRAVPlayerStateFaild;
                 NSError *error = [self.player.currentItem error];
                 NSLog(@"视频加载失败===%@",error.description);
+                if (self.delegate && [self.delegate respondsToSelector:@selector(didFailedToLoadURL:error:)]) {
+                    [self.delegate didFailedToLoadURL:self.currentUrlString error:error];
+                }
             }
                 break;
         }
@@ -509,6 +619,9 @@ NSURL * MKRUrlWithString(NSString *string){
             self.state = MKRAVPlayerStateBuffering;
         }
     }
+    if (self.delegate && [self.delegate respondsToSelector:@selector(stalledByCacheEmtpy)]) {
+        [self.delegate stalledByCacheEmtpy];
+    }
 }
 
 //计算缓冲进度
@@ -549,6 +662,11 @@ NSURL * MKRUrlWithString(NSString *string){
     [_playerItem removeObserver:self forKeyPath:@"playbackBufferEmpty"];
     [_playerItem removeObserver:self forKeyPath:@"playbackLikelyToKeepUp"];
     [_playerItem removeObserver:self forKeyPath:@"duration"];
+    if (self.timeObserver) {
+        [self.player removeTimeObserver:self.timeObserver];
+        self.timeObserver = nil;
+    }
+    
 }
 
 @end

+ 7 - 0
MKRRadioManager/Classes/MKRRadioManager/MKRAVPlayer/MKRPlayResourceStatus.h

@@ -18,6 +18,9 @@ typedef NS_ENUM(NSUInteger, MKRResourcePlayState) {
 
 @interface MKRPlayResourceStatus : NSObject
 
+/** WIFI设备的播放状态是字符串 根据字符串判断播放状态 */
+- (MKRResourcePlayState)updatePlayState:(NSString *)playStateString;
+
 /**
  当前播放状态
  */
@@ -38,6 +41,10 @@ typedef NS_ENUM(NSUInteger, MKRResourcePlayState) {
  * */
 @property(nonatomic, assign) NSInteger totalTime;
 
+@property (nonatomic, assign) NSTimeInterval currentDuration;
+
+@property (nonatomic, assign) NSTimeInterval totalDuration;
+
 /*
  * 当前播放时间字符串 格式:xx:xx:xx
  **/

+ 15 - 0
MKRRadioManager/Classes/MKRRadioManager/MKRAVPlayer/MKRPlayResourceStatus.m

@@ -9,6 +9,21 @@
 
 @implementation MKRPlayResourceStatus
 
+- (MKRResourcePlayState)updatePlayState:(NSString *)playStateString{
+    if([playStateString isEqualToString:@"STOPPED"] ||
+       [playStateString isEqualToString:@"NO_MEDIA_PRESENT"] ){
+        return MKRResourcePlayStateStopped;
+    }else if([playStateString isEqualToString:@"PLAYING"] ){
+        return MKRResourcePlayStatePlaying;
+    }else if([playStateString isEqualToString:@"TRANSITIONING"] ){
+        return MKRResourcePlayStateBuffering;
+    }else if([playStateString isEqualToString:@"PAUSED_PLAYBACK"]){
+        return MKRResourcePlayStatePause;
+    }else {
+        return MKRResourcePlayStateBuffering;
+    }
+}
+
 - (NSString *)currentTimeFormatString {
     if (self.currentTime == 0){
         return @"00:00";

+ 2 - 0
MKRRadioManager/Classes/MKRRadioManager/MKRRadioResorce.h

@@ -33,6 +33,8 @@
 @property  (nonatomic, assign) NSInteger vip_canPlay;
 @property(nonatomic, strong) NSString *songChannelUid;
 @property(nonatomic, strong) NSString *songFlag;
+/** 资源的类型: 音乐  主播电台  广播电台 */
+@property (nonatomic, assign) MKRSourceType sourceType;
 /** 播放进度相关信息 */
 @property (nonatomic, strong) MKRPlayResourceStatus *resourceStatus;
 @end

+ 4 - 0
MKRRadioManager/Classes/MKRRadioManager/MKRRadioResorce.m

@@ -18,4 +18,8 @@
 @synthesize songName;
 @synthesize songUrl;
 @synthesize vip_canPlay;
+@synthesize songChannelUid;
+@synthesize songFlag;
+@synthesize resourceStatus;
+@synthesize sourceType;
 @end

+ 11 - 0
MKRRadioManager/Classes/MKRRadioManager/MKRWIFIDeviceManager/MKRM3UListModel.h

@@ -31,6 +31,9 @@
 @property (nonatomic, strong) NSMutableArray *songIDList;
 @property (nonatomic, strong) NSMutableArray *songFromList;
 @property (nonatomic, strong) NSMutableArray *songAlbumIDList;
+//后台给回来的每个频道对应的唯一ID
+@property (nonatomic, strong) NSString *channelID;
+//频道号
 @property (nonatomic, strong) NSString *channelNO;
 @property (nonatomic, strong) NSString *playModeString;
 @property (nonatomic, strong) NSString *userID;
@@ -42,5 +45,13 @@
 @property (nonatomic, assign) int endIndex;
 @property (nonatomic, assign) int m3uSize;
 
+
+/// 映射后台的资源类型到app的资源类型
++ (MKRSourceType)convertSorceTypeWithAudioType:(NSInteger)type;
+
+
+/// 映射app的资源类型到后台的资源类型
++ (NSInteger)convertAudioTypeWithSorceType:(MKRSourceType)sourceType;
+
 @end
 

+ 62 - 13
MKRRadioManager/Classes/MKRRadioManager/MKRWIFIDeviceManager/MKRM3UListModel.m

@@ -16,18 +16,31 @@
     return self;
 }
 
-+ (instancetype)tempChannelM3UModelWithSongs:(NSArray <id <MKRRadioResorce>> *)songs
-                                  startIndex:(NSInteger)startIndex {
+//+ (instancetype)tempChannelM3UModelWithSongs:(NSArray <id <MKRRadioResorce>> *)songs
+//                                  startIndex:(NSInteger)startIndex {
+//    MKRM3UListModel *model = [[MKRM3UListModel alloc] init];
+//    [model selectTempChannelTargetSongsForM3u:songs startIndex:startIndex];
+//    model.startIndex = 0;
+//    model.endIndex = (int)(songs.count > 50 ? 49 : songs.count - 1);
+//    model.channelNO = @"12";
+//    model.m3uSize = (int)(songs.count >= 50 ? 50 : songs.count);
+//    model.channelPure = @"NO";
+//    model.channelAlbumID = @"FREESTYLE";
+//    model.channelInfoString = @"3//NULL//NULL//NULL";
+//    model.timeString = [NSString stringWithFormat:@"%.0f", [[NSDate date] timeIntervalSince1970]];
+//    return model;
+//}
+
++ (instancetype)tempChannelM3UModelWithSongs:(NSArray<id<MKRRadioResorce>> *)songs startIndex:(NSInteger)startIndex{
     MKRM3UListModel *model = [[MKRM3UListModel alloc] init];
     [model selectTempChannelTargetSongsForM3u:songs startIndex:startIndex];
+    model.channelNO = @"13";
+    model.timeString = [NSString stringWithFormat:@"%.0f", [[NSDate date] timeIntervalSince1970]];
     model.startIndex = 0;
     model.endIndex = (int)(songs.count > 50 ? 49 : songs.count - 1);
-    model.channelNO = @"12";
     model.m3uSize = (int)(songs.count >= 50 ? 50 : songs.count);
-    model.channelPure = @"NO";
-    model.channelAlbumID = @"FREESTYLE";
     model.channelInfoString = @"3//NULL//NULL//NULL";
-    model.timeString = [NSString stringWithFormat:@"%.0f", [[NSDate date] timeIntervalSince1970]];
+    model.channelID = @"0";
     return model;
 }
 
@@ -56,11 +69,10 @@
     [songs enumerateObjectsUsingBlock:^(id <MKRRadioResorce> obj, NSUInteger idx, BOOL *stop) {
         [self.durationList addObject:@"00:00:00"];
         [self.secondsList addObject:@"0"];
-        [self.artistList addObject:obj.songArtist];
-        [self.albumList addObject:obj.songAlbum];
-        [self.titleList addObject:obj.songName];
-        [self.albumArtUriList addObject:obj.songAlbumCover];
-        [self.urlList addObject:obj.songUrl];
+        [self.artistList addObject:obj.songArtist?:@""];
+        [self.albumList addObject:obj.songAlbum?:@""];
+        [self.titleList addObject:obj.songName?:@""];
+        [self.albumArtUriList addObject:obj.songAlbumCover?:@""];
         [self.protocolInfoList addObject:@"http-get:*:audio/mpeg:*"];
         [self.upnpclassList addObject:@"object.item.audioItem.musicTrack"];
         [self.channelNumList addObject:@(obj.songChannel).stringValue];
@@ -69,8 +81,11 @@
         [self.startTimeList addObject:@"00:00:00"];
         [self.endTimeList addObject:@"00:00:00"];
         [self.vipCanPlay addObject:[NSString stringWithFormat:@"%zd",obj.vip_canPlay]];
-        [self.songIDList addObject:@(obj.songID).stringValue?:@""];
-        [self.songFromList addObject:[NSString stringWithFormat:@"%zd",obj.songFrom]];
+        [self.songIDList addObject:@(obj.songID).stringValue];
+        NSString *songIDString = [NSString stringWithFormat:@"AIRSMART//ID_%zd//",obj.songID];
+        [self.urlList addObject:songIDString];
+        NSString *songFrom = [NSString stringWithFormat:@"1//%zd//%zd//",[self.class convertAudioTypeWithSorceType:obj.sourceType],obj.songID];
+        [self.songFromList addObject:songFrom];
         [self.songAlbumIDList addObject:obj.songAlbumID?:@""];
     }];
 }
@@ -94,4 +109,38 @@
     [self createM3UWithSongs:targetSongs];
 }
 
+//后台资源类型转成本地资源类型
+//type:1音乐直播 2直播电台 3音乐歌单 4主播电台 5音乐单曲 6电台节目 7电台精选
++ (MKRSourceType)convertSorceTypeWithAudioType:(NSInteger)type{
+    
+#define ConvertSourceTypeCase(_value,_sourceType) case _value: \
+                                                    return _sourceType; \
+                                                break;
+    switch (type) {
+        ConvertSourceTypeCase(1, MKRSourceTypeMusicRadio);
+        ConvertSourceTypeCase(2, MKRSourceTypeBroadcast);
+        ConvertSourceTypeCase(3, MKRSourceTypeMusic);
+        ConvertSourceTypeCase(4, MKRSourceTypePodcast);
+        ConvertSourceTypeCase(5, MKRSourceTypeMusic);
+        ConvertSourceTypeCase(6, MKRSourceTypePodcast);
+        ConvertSourceTypeCase(7, MKRSourceTypeHandPick);
+    }
+    return MKRSourceTypeMusic;
+}
+
++ (NSInteger)convertAudioTypeWithSorceType:(MKRSourceType)sourceType{
+    #define ConvertAudioTypeCase(_sourceType,_value) case _sourceType: \
+                                                    return _value; \
+                                                break;
+    switch (sourceType) {
+        ConvertAudioTypeCase(MKRSourceTypeMusic, 3);
+        ConvertAudioTypeCase(MKRSourceTypePodcast, 4);
+        ConvertAudioTypeCase(MKRSourceTypeBroadcast, 2);
+        ConvertAudioTypeCase(MKRSourceTypeHandPick, 7);
+        ConvertAudioTypeCase(MKRSourceTypeMusicRadio, 1);
+        ConvertAudioTypeCase(MKRSourceTypeParentChild, 4);
+    }
+    return MKRSourceTypeMusic;
+}
+
 @end

+ 126 - 15
MKRRadioManager/Classes/MKRRadioManager/MKRWIFIDeviceManager/MKRWIFIDeviceManager.h

@@ -19,6 +19,26 @@
 /** 搜索到新设备 */
 - (void)didSearchNewDevice:(NSDictionary *)newDecice;
 
+/// 收到设备广播的播放状态改变
+/// @param playState 改变后的播放状态
+/// @param deviceUUID 状态改变的设备的UUID
+- (void)didReceivePlayStateChange:(MKRResourcePlayState)playState;
+
+/// 收到设备广播的播放频道改变
+/// @param channel 频道号
+/// @param deviceUUID 频道号改变的设备的UUID
+- (void)didReceivePlayingChannelChange:(NSInteger)channel;
+
+/// 收到设备广播的音量改变
+/// @param volume 改变后的音量值
+- (void)didReceiveVolumeChange:(float)volume;
+
+/// 收到WIFI设备掉线通知
+/// @param deviceUUID 掉线设备的设备UUID
+- (void)didReceiveDeviceOffline:(NSString *)deviceUUID;
+
+- (void)didGetPlayInfo:(id<MKRRadioResorce>)resource;
+
 @end
 
 @interface MKRWIFIDeviceManager : NSObject
@@ -27,16 +47,29 @@
 
 @property (nonatomic, strong)NSString *userID;
 
+//当前临时频道M3U
+@property (nonatomic, strong) MKRM3UListModel *currentTempM3UListModel;
+
+@property (nonatomic, strong) id<MKRUPnPDevice> device;
+
 - (void)addDeviceManagerListener:(id<MKRWIFIDeviceManagerDelegate>)listener;
 
 - (void)removeDeviceManagerListener:(id<MKRWIFIDeviceManagerDelegate>)listener;
 
+@property (nonatomic, strong) id <MKRRadioResorce> currentResource;
+
 /**
  * 初始化UPNP
  * @return UPNP初始化错误码 0为无错误 即初始化成功
  */
 - (NSInteger)startUpnp;
 
+/// 刷新upnp服务
+- (void)reloadUpnp;
+
+/// 停止upnp
+- (void)stopUpnp;
+
 /**
  * 搜索设备
  * @param searchTime 搜索时长
@@ -55,11 +88,9 @@
  * 设置设备单首播放的资源
  * @param song 需要播放的资源
  * @param device 需要设置的设备
- * @param userID 用户ID
  */
 - (void)setAVTransportURIWithSong:(id <MKRRadioResorce>)song
-                           device:(id <MKRUPnPDevice>)device
-                           userID:(NSString *)userID;
+                           device:(id <MKRUPnPDevice>)device;
 
 /**
  * 播放
@@ -69,26 +100,76 @@
 
 /**
  * 播放channelNO频道从第index开始
- * 在播放之前 如果是临时频道(频道号>= 12) 需要先生成M3U列表
- * 如是正式频道(频道号 0~11) 可选生成M3U
- * @param channelNO      频道号
- * @param index          需要播放的下标
- * @param device         播放的设备
- * @param userID         用户ID
+ * 在播放之前 如果是临时频道(频道号>= 13) 需要先生成M3U列表
+ * 如是正式频道(频道号 1~12) 可选生成M3U
+ * @param channelNO         频道号
+ * @param firstPlayingSong  给当前播放下标需要播放资源给设备 设备会更快出声
+ * @param index             需要播放的下标
+ * @param device            播放的设备
+ * @param timeStamp         频道时间戳
  */
 - (void)playSongWithChannelNO:(NSInteger)channelNO
+             firstPlayingSong:(id<MKRRadioResorce>)firstPlayingSong
                         index:(NSInteger)index
                        device:(id <MKRUPnPDevice>)device
-                       userID:(NSString *)userID;
+                    timeStamp:(NSTimeInterval)timeStamp;
 /**
- * 播放channelNO频道 从第0首开始
- * @param channelNO 频道号
- * @param device    需要播放的设备
- * @param userID    用户ID
+ * 播放channelNO频道          从第0首开始
+ * @param channelNO         频道号
+ * @param firstPlayingSong  给当前播放下标需要播放资源给设备 设备会更快出声
+ * @param device            需要播放的设备
  */
 - (void)playSongWithChannelNO:(NSInteger)channelNO
+             firstPlayingSong:(id<MKRRadioResorce>)firstPlayingSong
                        device:(id <MKRUPnPDevice>)device
-                       userID:(NSString *)userID;
+                    timeStamp:(NSTimeInterval)timeStamp;
+
+/**
+* 播放临时频道频道(频道13)  从第index首开始
+* @param index          需要播放的下标
+* @param device         需要播放的设备
+* @param timeStamp      频道时间戳
+*/
+- (void)playTempChannelSongs:(NSArray <id <MKRRadioResorce>> *)songs
+                       index:(NSInteger)index
+                      device:(id <MKRUPnPDevice>)device
+                   timeStamp:(NSTimeInterval)timeStamp;
+
+/**
+* 播放临时频道频道(频道13)  从第index首开始
+* @param index          需要播放的下标
+* @param device         需要播放的设备
+* @param timeStamp      频道时间戳
+* @param playMode       播放模式
+*/
+- (void)playTempChannelSongs:(NSArray<id<MKRRadioResorce>> *)songs
+                       index:(NSInteger)index
+                      device:(id<MKRUPnPDevice>)device
+                   timeStamp:(NSTimeInterval)timeStamp
+                    playMode:(MKRRadioPlayMode)playMode;
+
+/**
+* 播放临时频道频道(频道13)    从第index首开始
+* @param device           需要播放的设备
+* @param userID           用户ID
+* @param timeStamp        频道时间戳
+*/
+- (void)playTempChannelSongs:(NSArray <id <MKRRadioResorce>> *)songs
+                      device:(id <MKRUPnPDevice>)device
+                   timeStamp:(NSTimeInterval)timeStamp;
+
+
+/**
+* 播放临时频道频道(频道13)    从第index首开始
+* @param device           需要播放的设备
+* @param userID           用户ID
+* @param timeStamp        频道时间戳
+* @param playMode         播放模式
+*/
+- (void)playTempChannelSongs:(NSArray <id <MKRRadioResorce>> *)songs
+                      device:(id <MKRUPnPDevice>)device
+                   timeStamp:(NSTimeInterval)timeStamp
+                    playMode:(MKRRadioPlayMode)playMode;
 
 /**
  * 暂停
@@ -137,5 +218,35 @@
 
 - (id <MKRRadioResorce>)getPlayingStatusWithDevice:(id <MKRUPnPDevice>)device;
 
+/// 通知设备刷新频道列表
+/// 当channelFlag 为 @"ALL" 时 为更新12个频道
+/// 当channelFlag 为 @"x(频道号)" 时 为更新x频道 eg:@"3"
+/// 当channelFlag 为 @"audition_x(频道号)"时  为通知设备更新x频道 并且在更新后的频道中找到当前播放的歌曲续播 eg: @"audition_3"
+/// @param channelFlag 频道标识
+- (void)updateChannel:(NSString *)channelFlag device:(id<MKRUPnPDevice>)device;
+
+/// 设置播放模式
+/// @param playMode 播放模式
+/// @param device 需要设置播放模式的设备
+/// @param channelNO 设置播放模式的频道
+- (void)setPlayMode:(MKRRadioPlayMode)playMode device:(id<MKRUPnPDevice>)device channelNO:(NSInteger)channelNO;
+
+
+/// 更新临时频道播放模式
+/// @param playMode 先刷新临时频道的M3U 更改M3U的播放模式 并向设备发送更新频道命令
+/// @param songs 临时频道播放列表
+/// @param index 下标
+/// @param device 需要设置的设备
+- (void)updateTempChannelPlayMode:(MKRRadioPlayMode)playMode songs:(NSArray <id <MKRRadioResorce>> *)songs index:(NSInteger)index device:(id<MKRUPnPDevice>)device;
+
+/// 设置低电量提醒
+/// @param enable 是否开启低电量提醒
+/// @param device 控制的设备
+- (void)setLowPowerNoticeEnable:(BOOL)enable device:(id<MKRUPnPDevice>)device;
+
+/// 获取WIFI设备播放模式字符串
+/// @param playmode 播放模式
+- (NSString *)playModeStringWithPlayMode:(MKRRadioPlayMode)playmode;
+
 @end
 

+ 449 - 134
MKRRadioManager/Classes/MKRRadioManager/MKRWIFIDeviceManager/MKRWIFIDeviceManager.m

@@ -10,6 +10,8 @@
 #import "UIDevice+MKRRadioManagerAdd.h"
 #import <pthread.h>
 #import <libAS-Control/ASControlTools.h>
+#import <libAS-Control/NSDictionary+MKRXml.h>
+#import <NSHashTable+MKRRadioManagerAdd.h>
 
 static inline void wd_main_queue(void (^block)(void)){
     if (pthread_main_np()) {
@@ -19,10 +21,18 @@ static inline void wd_main_queue(void (^block)(void)){
     }
 }
 
+static inline void wd_playControl_queue(void (^block)(void)){
+    dispatch_queue_t queue = dispatch_queue_create("com.maoking.playControlQueue", DISPATCH_QUEUE_SERIAL);
+    dispatch_async(queue, block);
+}
+
 @interface MKRWIFIDeviceManager () <ASControlDelegate> {
     int _upnpErrorCode;
     NSMutableArray *_baseUrlArray;
     dispatch_source_t _searchTimer;
+    NSString *_ssid;
+    BOOL _shutDownUpnping;
+    BOOL _updateLocalResourceLock;
 }
 
 @property (nonatomic, strong) NSHashTable *listeners;
@@ -34,7 +44,9 @@ static inline void wd_main_queue(void (^block)(void)){
 - (instancetype)init {
     if (self = [super init]) {
         _upnpErrorCode = -1;
-        [self startUpnp];
+        wd_playControl_queue(^{
+            [self startUpnp];
+        });
         [ASControlTools sharedInstanceUPNP].delegate = self;
     }
     return self;
@@ -81,15 +93,53 @@ static inline void wd_main_queue(void (^block)(void)){
     return _upnpErrorCode;
 }
 
+- (void)stopUpnp{
+    wd_playControl_queue(^{
+        libupnp_StopBuildFilesList();
+        [NSThread sleepForTimeInterval:5];
+        if(_upnpErrorCode == 0){
+            libupnp_UpnpQuickExit();
+        }
+    });
+}
+
+- (void)reloadUpnp{
+    NSString *ssid = [UIDevice currentSSID];
+    if ([ssid isEqualToString:_ssid]) {
+        return;
+    }
+    if (_shutDownUpnping) {
+        return;
+    }
+    _ssid = ssid;
+    wd_playControl_queue(^{
+        _shutDownUpnping = YES;
+        libupnp_StopBuildFilesList();
+        int exitCount = 0;
+        while (_updateLocalResourceLock) {
+            exitCount++;
+            [NSThread sleepForTimeInterval:1.0];
+            if (exitCount > 10)
+                break;
+        }
+        _updateLocalResourceLock = NO;
+        [self searchDeviceWithSearchTime:20 timeBlock:nil];
+    });
+}
+
 - (void)searchDeviceWithSearchTime:(int)searchTime
                          timeBlock:(void(^)(NSInteger time))timeBlock {
-    if (_upnpErrorCode == 0) {//开始搜索设备
-        [self checkBaseURL];
-        libupnp_BuildFilesList();
+    wd_playControl_queue(^{
+        _updateLocalResourceLock = YES;
+        if (_upnpErrorCode != 0) {
+            if ([self startUpnp] == 0) {
+                [self checkBaseURL];
+                libupnp_BuildFilesList();
+            }
+        }
         libupnp_SearchDevice(20);
-    } else {
-        [self startUpnp];
-    }
+    });
+    _ssid = [UIDevice currentSSID];
     __block int count = searchTime +1;
     _searchTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(0, 0));
     dispatch_source_set_timer(_searchTimer, DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC, 0 * NSEC_PER_SEC);
@@ -128,19 +178,42 @@ static inline void wd_main_queue(void (^block)(void)){
 #pragma mark - ASControlDelegate
 
 -(void)ReceivedPlayCallBack:(NSString *)nUDN{
-    NSLog(@"%s",__func__);
+    NSLog(@"收到播放回调%@",nUDN);
+    wd_main_queue(^{
+        if ([nUDN containsString:self.device.deviceUUID]) {
+            self.currentResource.resourceStatus.playState = MKRResourcePlayStatePlaying;
+            [self.listeners makeObjectsPerformSelectorWithObjects:@selector(didReceivePlayStateChange:),MKRResourcePlayStatePlaying];
+        }
+    });
 }
 
 -(void)ReceivedPauseCallBack:(NSString *)nUDN{
-    NSLog(@"%s",__func__);
+    NSLog(@"收到暂停回调%@",nUDN);
+    wd_main_queue(^{
+        if ([nUDN containsString:self.device.deviceUUID]) {
+            self.currentResource.resourceStatus.playState = MKRResourcePlayStatePause;
+            [self.listeners makeObjectsPerformSelectorWithObjects:@selector(didReceivePlayStateChange:),MKRResourcePlayStatePause];
+        }
+    });
 }
 
 -(void)ReceivedStopCallBack:(NSString *)nUDN{
-    NSLog(@"%s",__func__);
+    NSLog(@"收到停止回调%@",nUDN);
+    wd_main_queue(^{
+        if ([nUDN containsString:self.device.deviceUUID]) {
+            self.currentResource.resourceStatus.playState = MKRResourcePlayStateStopped;
+            [self.listeners makeObjectsPerformSelectorWithObjects:@selector(didReceivePlayStateChange:),MKRResourcePlayStateStopped];
+        }
+    });
 }
 
 -(void)ReceivedSetVolumeCallBack:(NSString *)nUDN Volume:(NSInteger)Volume{
-    NSLog(@"%s",__func__);
+     wd_main_queue(^{
+               if ([nUDN containsString:self.device.deviceUUID]) {
+                   NSLog(@"收到设备音量回调SetZoneVolumeCallBack:%zd",Volume);
+                   [self.listeners makeObjectsPerformSelectorWithObjects:@selector(didReceiveVolumeChange:),(float)Volume];
+               }
+           });
 }
 
 -(void)ReceivedSetMuteCallBack:(NSString *)nUDN Mute:(NSInteger)Mute{
@@ -173,7 +246,9 @@ static inline void wd_main_queue(void (^block)(void)){
 
 -(void)CallBackRemoveZoneMedia:(NSString *)nByeUDN BaseURL:(NSString *)BaseURL{
     NSLog(@"%s",__func__);
-    
+    wd_main_queue(^{
+        [self.listeners makeObjectsPerformSelectorWithObjects:@selector(didReceiveDeviceOffline:),nByeUDN];
+    });
 }
 
 -(void)CallBackRemoveRenderer:(NSString *)nByeUDN BaseURL:(NSString *)BaseURL
@@ -189,7 +264,9 @@ static inline void wd_main_queue(void (^block)(void)){
 -(void)CallBackAddZoneMedia:(NSArray *)nStr Size:(NSInteger)size{
     NSLog(@"搜索到设备:%@",nStr);
     NSLog(@"%s",__func__);
-    [self addDevice:nStr];
+    wd_playControl_queue(^{
+        [self addDevice:nStr];
+    });
 }
 
 - (void)updateClockID:(NSString *)clockID clockDic:(NSDictionary *)clockDic clockTime:(NSString *)clockTime operationType:(BOOL)isOn deleteClock:(BOOL)isDelete{
@@ -208,6 +285,12 @@ static inline void wd_main_queue(void (^block)(void)){
 
 -(void)ReceivedChangeChannelCallBack:(NSString *)nUDN Channel:(NSString *)channel{
     NSLog(@"%s",__func__);
+    NSLog(@"收到频道改变回调%@",nUDN);
+    wd_main_queue(^{
+        if ([nUDN containsString:self.device.deviceUUID]) {
+            [self.listeners makeObjectsPerformSelectorWithObjects:@selector(didReceivePlayingChannelChange:),[channel integerValue]];
+        }
+    });
 }
 
 -(void)getLocalIp:(NSString *)Ip{
@@ -242,6 +325,7 @@ static inline void wd_main_queue(void (^block)(void)){
     [deviceDict setObject:[deviceInfo[28] length]?deviceInfo[28]:@"WIFI" forKey:@"devSourceList"];
     [deviceDict setObject:deviceInfo[12] forKey:@"channelLR"];
     [deviceDict setObject:[deviceInfo[29] length] ? deviceInfo[29]: @"0.0.0.0" forKey:@"devType"];
+    [deviceDict setObject:[deviceInfo[32] length] ? deviceInfo[32]: @"" forKey:@"deviceClockInfo"];
     [deviceDict setObject:[deviceInfo[33] length]? deviceInfo[33]:@"NULL" forKey:@"devPower"];
     [deviceDict setObject:[deviceInfo[36] length] ? deviceInfo[36]:@"NULL" forKey:@"devUserID"];
     NSString *devFlag = [NSString stringWithFormat:@"%@-%@",deviceInfo[9],deviceInfo[10]];
@@ -256,7 +340,7 @@ static inline void wd_main_queue(void (^block)(void)){
     [deviceDict setObject:[deviceInfo[40] length] ?deviceInfo[40] :@"-1" forKey:@"devPauseShutDownTime"];
     NSString *devNowStatus = [deviceInfo[2] length] ? deviceInfo[2] : @"STOPPED";
     [deviceDict setObject:devNowStatus forKey:@"devNowStatus"];
-    [deviceDict setObject:@"REPEAT_ALL" forKey:@"devNowPlayMode"];
+    [deviceDict setObject:[deviceInfo[30] length] ?deviceInfo[30] :@"REPEAT_ALL" forKey:@"devNowPlayMode"];
     NSURL *url = [NSURL URLWithString:array[2]];
     [deviceDict setObject:url.URLByDeletingLastPathComponent.absoluteString?:@"" forKey:@"devIP"];
     if([devNowStatus isEqualToString:@"PAUSED_PLAYBACK"]){
@@ -277,175 +361,406 @@ static inline void wd_main_queue(void (^block)(void)){
         [deviceDict setObject:@"Unknown" forKey:@"devNowArtist"];
     }
     [deviceDict setObject:@"1" forKey:@"isOnLine"];
-    id<MKRWIFIDeviceManagerDelegate> obj;
-    NSEnumerator *enumerator = [self.listeners objectEnumerator];
-    while ((obj = [enumerator nextObject]) != nil) {
-        wd_main_queue(^{
+    wd_main_queue(^{
+        id<MKRWIFIDeviceManagerDelegate> obj;
+        NSEnumerator *enumerator = [self.listeners objectEnumerator];
+        while ((obj = [enumerator nextObject]) != nil) {
             if ([obj respondsToSelector:@selector(didSearchNewDevice:)]) {
                 [obj didSearchNewDevice:deviceDict];
             }
-        });
-    }
+        }
+    });
 }
 
-- (void)setM3UList:(MKRM3UListModel *)m3uListModel {
-    libupnp_SetNewM3UList(
-                          m3uListModel.secondsList,
-                          m3uListModel.artistList,
-                          m3uListModel.titleList,
-                          m3uListModel.urlList,
-                          m3uListModel.cueList,
-                          m3uListModel.startTimeList,
-                          m3uListModel.endTimeList,
-                          m3uListModel.vipCanPlay,
-                          m3uListModel.albumList,
-                          m3uListModel.albumArtUriList,
-                          m3uListModel.durationList,
-                          m3uListModel.protocolInfoList,
-                          m3uListModel.upnpclassList,
-                          m3uListModel.channelNumList,
-                          m3uListModel.songOrderList,
-                          m3uListModel.userID,
-                          m3uListModel.songIDList,
-                          m3uListModel.songFromList,
-                          m3uListModel.songAlbumIDList,
-                          m3uListModel.channelNO,
-                          m3uListModel.playModeString,
-                          m3uListModel.timeString,
-                          m3uListModel.channelPure,
-                          m3uListModel.channelAlbumID,
-                          m3uListModel.channelInfoString,
-                          m3uListModel.userID,
-                          m3uListModel.startIndex,
-                          m3uListModel.endIndex,
-                          m3uListModel.m3uSize,
-                          @""
-                          );
+- (void)setM3UList:(MKRM3UListModel *)m3uListModel{
+    self.currentTempM3UListModel = m3uListModel;
+    libupnp_SetNewM3UListV2(m3uListModel.secondsList,
+                            m3uListModel.artistList,
+                            m3uListModel.titleList,
+                            m3uListModel.urlList,
+                            m3uListModel.songFromList,
+                            m3uListModel.vipCanPlay,
+                            m3uListModel.channelNO,
+                            m3uListModel.playModeString,
+                            m3uListModel.timeString,
+                            m3uListModel.startIndex,
+                            m3uListModel.endIndex,
+                            m3uListModel.m3uSize,
+                            m3uListModel.channelID,
+                            m3uListModel.channelInfoString);
 }
 
 - (void)setAVTransportURIWithSong:(id <MKRRadioResorce>)song
-                           device:(id <MKRUPnPDevice>)device
-                           userID:(NSString *)userID {
+                           device:(id <MKRUPnPDevice>)device{
     NSString *timestamp = [NSString stringWithFormat:@"%.0f", [[NSDate date] timeIntervalSince1970]];
-    NSString *channelNumString = [NSString stringWithFormat:@"CHANNEL_UPDATE_%zd",song.songChannel];
-    libupnp_SetAVTransportURI(
-                              device.avTransportUrl,
-                              song.songUrl,
-                              song.songName,
-                              song.songArtist,
-                              song.songAlbum,
-                              song.songAlbumCover,
-                              @"0",
-                              @"null",
-                              @"null",
-                              timestamp,
-                              channelNumString,
-                              @"0",
-                              userID,
-                              @(song.songID).stringValue,
-                              @(song.songFrom).stringValue,
-                              song.songAlbumID?:@""
-                              );
+    NSString *channelNumString = @(song.songChannel).stringValue;
+    NSString *userID = self.userID;
+    NSString *songUrlString = [NSString stringWithFormat:@"AIRSMART//ID_%zd//",song.songID];
+    NSString *songFrom = [NSString stringWithFormat:@"1//%zd//%zd//",[MKRM3UListModel convertAudioTypeWithSorceType:song.sourceType],song.songID];
+    libupnp_SetAVTransportURIV2(
+    device.avTransportUrl,
+    songUrlString,
+    song.songName?:@"",
+    song.songArtist?:@"",
+    song.songAlbum?:@"",
+    song.songAlbumCover?:@"",
+    @"0",
+    @"null",
+    @"null",
+    timestamp,
+    channelNumString,
+    @"0",
+    userID?:@"",
+    @(song.songID).stringValue,
+    songFrom,
+    song.songAlbumID?:@""
+    );
+    
 }
 
 - (void)playWithDevice:(id <MKRUPnPDevice>)device {
-    libupnp_Play(device.avTransportUrl);
+    wd_playControl_queue(^{
+        libupnp_Play(device.avTransportUrl);
+    });
 }
 
-- (void)playSongWithChannelNO:(NSInteger)channelNO
-                        index:(NSInteger)index
-                       device:(id <MKRUPnPDevice>)device
-                       userID:(NSString *)userID {
-    NSString *playFlag = [NSString stringWithFormat:@"%zd-%zd",channelNO,index];
+- (void)_playPlayFlag:(NSString *)playFlag
+              device:(id <MKRUPnPDevice>)device
+           timeStamp:(NSTimeInterval)timeStamp{
     NSString *playListUrl = [NSString stringWithFormat:@"%@/web/playlist",[ASControlTools sharedInstanceUPNP].myIp];
-    NSString *timestamp = [NSString stringWithFormat:@"%.0f", [[NSDate date] timeIntervalSince1970]];
-    libupnp_PlayNumFlag(
-                        device.avTransportUrl,
-                        playFlag,
-                        timestamp,
-                        userID,
-                        playListUrl,
-                        @"1"
-                        );
+    NSString *timestamp = [NSString stringWithFormat:@"%.0f", timeStamp];
+    NSString *userID = self.userID;
+    libupnp_PlayNumFlagV2(
+    device.avTransportUrl,
+    playFlag,
+    timestamp,
+    userID,
+    playListUrl,
+    @"0"
+    );
+}
+
+- (void)playSongWithChannelNO:(NSInteger)channelNO
+             firstPlayingSong:(id<MKRRadioResorce>)firstPlayingSong
+                       device:(id<MKRUPnPDevice>)device
+                    timeStamp:(NSTimeInterval)timeStamp{
+    self.currentTempM3UListModel = nil;
+    wd_playControl_queue(^{
+        NSString *playFlag = [NSString stringWithFormat:@"%zd",channelNO];
+        [self _playPlayFlag:playFlag device:device timeStamp:timeStamp];
+    });
 }
 
 - (void)playSongWithChannelNO:(NSInteger)channelNO
-                       device:(id <MKRUPnPDevice>)device
-                       userID:(NSString *)userID {
-    [self playSongWithChannelNO:channelNO index:0 device:device userID:userID];
+             firstPlayingSong:(id<MKRRadioResorce>)firstPlayingSong
+                        index:(NSInteger)index
+                       device:(id<MKRUPnPDevice>)device
+                    timeStamp:(NSTimeInterval)timeStamp{
+    self.currentTempM3UListModel = nil;
+    wd_playControl_queue(^{
+        if (firstPlayingSong && firstPlayingSong.songID) {
+            [self setAVTransportURIWithSong:firstPlayingSong device:device];
+        }
+        NSString *playFlag = [NSString stringWithFormat:@"%zd-%zd",channelNO,index];
+        [self _playPlayFlag:playFlag device:device timeStamp:timeStamp];
+    });
+}
+
+- (void)playTempChannelSongs:(NSArray<id<MKRRadioResorce>> *)songs
+                       index:(NSInteger)index
+                      device:(id<MKRUPnPDevice>)device
+                   timeStamp:(NSTimeInterval)timeStamp{
+    [self playTempChannelSongs:songs index:index device:device timeStamp:timeStamp playMode:MKRRadioPlayModeOrder];
+}
+
+- (void)playTempChannelSongs:(NSArray<id<MKRRadioResorce>> *)songs
+                       index:(NSInteger)index
+                      device:(id<MKRUPnPDevice>)device
+                   timeStamp:(NSTimeInterval)timeStamp
+                    playMode:(MKRRadioPlayMode)playMode{
+    MKRM3UListModel *m3uModel = [MKRM3UListModel tempChannelM3UModelWithSongs:songs startIndex:index];
+    m3uModel.userID = self.userID;
+    m3uModel.playModeString = [self playModeStringWithPlayMode:playMode];
+    wd_playControl_queue(^{
+        [[MKRWIFIDeviceManager shareManager] setM3UList:m3uModel];
+        id <MKRRadioResorce> song = songs[index];
+        song.songChannel = 13;
+        [self setAVTransportURIWithSong:song device:device];
+        NSString *playFlag = [NSString stringWithFormat:@"13-%zd",index];
+        [self _playPlayFlag:playFlag device:device timeStamp:timeStamp];
+    });
+}
+
+- (void)playTempChannelSongs:(NSArray<id<MKRRadioResorce>> *)songs
+                      device:(id<MKRUPnPDevice>)device
+                   timeStamp:(NSTimeInterval)timeStamp{
+    [self playTempChannelSongs:songs device:device timeStamp:timeStamp playMode:MKRRadioPlayModeOrder];
+}
+
+- (void)playTempChannelSongs:(NSArray<id<MKRRadioResorce>> *)songs
+                      device:(id<MKRUPnPDevice>)device
+                   timeStamp:(NSTimeInterval)timeStamp
+                    playMode:(MKRRadioPlayMode)playMode{
+    MKRM3UListModel *m3uModel = [MKRM3UListModel tempChannelM3UModelWithSongs:songs startIndex:index];
+    m3uModel.userID = self.userID;
+    m3uModel.playModeString = [self playModeStringWithPlayMode:playMode];
+    wd_playControl_queue(^{
+        [[MKRWIFIDeviceManager shareManager] setM3UList:m3uModel];
+        id <MKRRadioResorce> song = songs[0];
+        song.songChannel = 13;
+        [self setAVTransportURIWithSong:song device:device];
+        [self _playPlayFlag:@"13" device:device timeStamp:timeStamp];
+    });
 }
 
 - (void)pauseWithDevice:(id <MKRUPnPDevice>)device {
-    libupnp_Pause(device.avTransportUrl);
+    wd_playControl_queue(^{
+        libupnp_Pause(device.avTransportUrl);
+    });
 }
 
 - (void)nextWithDevice:(id <MKRUPnPDevice>)device{
-    libupnp_Previous(device.avTransportUrl);
+    wd_playControl_queue(^{
+        libupnp_Next(device.avTransportUrl);
+    });
 }
 
 - (void)previousWithDevice:(id <MKRUPnPDevice>)device{
-    libupnp_Previous(device.avTransportUrl);
+    wd_playControl_queue(^{
+        libupnp_Previous(device.avTransportUrl);
+    });
+    
 }
 
 - (void)stopWithDevice:(id <MKRUPnPDevice>)device{
-    libupnp_Stop(device.avTransportUrl);
+    wd_playControl_queue(^{
+        libupnp_Stop(device.avTransportUrl);
+    });
 }
 
 - (void)setVolume:(int)volume device:(id <MKRUPnPDevice>)device{
-    libupnp_SetZoneVolume(
-                          device.groupManagementUrl,
-                          @"urn:schemas-upnp-org:service:GroupManagement:1",
-                          @"Master",
-                          volume
-                          );
+    wd_playControl_queue(^{
+        libupnp_SetZoneVolume(
+        device.groupManagementUrl,
+        @"urn:schemas-upnp-org:service:GroupManagement:1",
+        @"Master",
+        volume
+        );
+    });
+    
 }
 
 - (void)seekToTimeInterval:(NSInteger)timeInterval device:(id <MKRUPnPDevice>)device {
     NSString *timeString = [NSString HHmmssFormatStrig:timeInterval];
-    libupnp_SetMediaSeek(device.avTransportUrl, timeString);
+    wd_playControl_queue(^{
+        libupnp_SetMediaSeek(device.avTransportUrl, timeString);
+    });
 }
 
 - (void)clearChannelWithChannelNO:(NSString *)channelNO device:(id <MKRUPnPDevice>)device {
     NSString *channelID = [NSString stringWithFormat:@"CHANNEL_UPDATE_%@",channelNO];
     NSString *timestamp = [NSString stringWithFormat:@"%.0f", [[NSDate date] timeIntervalSince1970]];
-    libupnp_SetChannelClear(device.groupManagementUrl, channelID, timestamp);
+    wd_playControl_queue(^{
+        libupnp_SetChannelClear(device.groupManagementUrl, channelID, timestamp);
+    });
 }
 
-- (id <MKRRadioResorce>)getPlayingStatusWithDevice:(id <MKRUPnPDevice>)device {
-    NSArray *dmrPositionInfo = [[ASControlTools sharedInstanceUPNP] libupnp_GetPositionInfo:device.avTransportUrl];
-    if (dmrPositionInfo.count < 16) {
-        //执行检查设备是否掉线操作
+- (void)updateChannel:(NSString *)channelFlag device:(id<MKRUPnPDevice>)device{
+    wd_playControl_queue(^{
+        NSString *timestamp = [NSString stringWithFormat:@"%.0f", [[NSDate date] timeIntervalSince1970]];
+        NSInteger channelNo = [channelFlag integerValue];
+        NSString *playListUrl = @"null";
+        if (channelNo >= 13) {
+            playListUrl = [NSString stringWithFormat:@"%@/web/playlist",[ASControlTools sharedInstanceUPNP].myIp];
+        }
+        int result = libupnp_SetChannelUpdateV2(device.groupManagementUrl, self.userID, timestamp, channelFlag, playListUrl);
+    });
+}
+
+- (void)setPlayMode:(MKRRadioPlayMode)playMode device:(id<MKRUPnPDevice>)device channelNO:(NSInteger)channelNO{
+    NSString *playModeString = @"";
+    switch (playMode) {
+        case MKRRadioPlayModeOrder:{
+             playModeString = @"REPEAT_ALL";
+        }
+            break;
+        case MKRRadioPlayModeSingle:{
+             playModeString = @"REPEAT_ONE";
+        }
+            break;
+        case MKRRadioPlayModeRandom:{
+             playModeString = @"SHUFFLE";
+        }
+            break;
+        default:{
+             playModeString = @"REPEAT_ALL";
+        }
+            break;
+    }
+    NSString *channelFlag = [NSString stringWithFormat:@"CHANNEL_UPDATE_%zd",channelNO];
+    wd_playControl_queue(^{
+        int result = libupnp_SetChannelPlayModeV2(device.groupManagementUrl, channelFlag, playModeString, self.userID);
+    });
+}
+
+- (void)updateTempChannelPlayMode:(MKRRadioPlayMode)playMode songs:(NSArray <id <MKRRadioResorce>> *)songs index:(NSInteger)index device:(id<MKRUPnPDevice>)device{
+    if (!self.currentTempM3UListModel) {
+        MKRM3UListModel *m3uModel = [MKRM3UListModel tempChannelM3UModelWithSongs:songs startIndex:index];
+        m3uModel.userID = self.userID;
+        m3uModel.playModeString = [self playModeStringWithPlayMode:playMode];
+        self.currentTempM3UListModel = m3uModel;
     }
-    MKRRadioResorce *resource = [[MKRRadioResorce alloc] init];
-    resource.songName = dmrPositionInfo[2];
-    resource.songArtist = dmrPositionInfo[3];
-    resource.songAlbumCover = dmrPositionInfo[5];
-    resource.songUrl = dmrPositionInfo[7];
-    resource.songID = [dmrPositionInfo[16] integerValue];
-    NSString *songFrom = dmrPositionInfo[17];
-    if ([songFrom containsString:@"//"]) {
-        NSArray *arr = [songFrom componentsSeparatedByString:@"//"];
-        if (arr.count > 1) {
-            songFrom = arr[1];
+    self.currentTempM3UListModel.playModeString = [self playModeStringWithPlayMode:playMode];
+    wd_playControl_queue(^{
+        [self setM3UList:self.currentTempM3UListModel];
+        [self updateChannel:@(13).stringValue device:device];
+    });
+}
+
+- (void)setLowPowerNoticeEnable:(BOOL)enable device:(id<MKRUPnPDevice>)device{
+    wd_playControl_queue(^{
+        libupnp_SetLowBatteryNotification(device.groupManagementUrl,enable);
+    });
+}
+
+- (NSDictionary *)parsePlayInfoString:(NSString *)playInfoXmlString{
+    NSMutableDictionary *resultDic = [NSMutableDictionary dictionaryWithDictionary:[NSDictionary mkr_dictionaryWithXML:playInfoXmlString]];
+    NSString *metaDataString = [resultDic objectForKey:@"TrackMetaData"];
+    if ([metaDataString isKindOfClass:NSString.class]) {
+        metaDataString = [metaDataString stringByReplacingOccurrencesOfString:@"&" withString:@"mkr_***"];
+        NSDictionary *metaDic = [NSDictionary mkr_dictionaryWithXML:metaDataString];
+        NSDictionary *metaItemDic = metaDic[@"item"];
+        if (![metaItemDic isKindOfClass:NSDictionary.class]) {
+            metaItemDic = @{};
+        }
+        [resultDic setObject:metaDic[@"item"]?:@{} forKey:@"TrackMetaData"];
+        return resultDic;
+    }else{
+        return nil;
+    }
+}
+
+- (id <MKRRadioResorce>)getPlayingStatusWithDevice:(id <MKRUPnPDevice>)device {
+    wd_playControl_queue(^{
+        NSString *resultString = [[ASControlTools sharedInstanceUPNP] libupnp_getPlayInfoString:device.avTransportUrl];
+        NSMutableDictionary *resultDic = [self parsePlayInfoString:resultString];
+        if (!resultDic || !resultDic.allKeys.count) {
+            return ;
+        }
+        if ([resultDic[@"TrackMetaData"][@"upnp:songInfoID"] isKindOfClass:NSString.class]) {
+            NSInteger songID = [resultDic[@"TrackMetaData"][@"upnp:songInfoID"] integerValue];
+            if (songID != self.currentResource.songID) {
+                self.currentResource = [self defaultSong];
+            }
+        }
+        @synchronized (self.currentResource) {
+            if ([resultDic[@"TrackMetaData"][@"upnp:songType"] isKindOfClass:NSString.class]) {
+                NSInteger sourceType = [MKRM3UListModel convertSorceTypeWithAudioType:[resultDic[@"TrackMetaData"][@"upnp:songType"] integerValue]];
+                self.currentResource.sourceType = sourceType;
+            }
+            if ([resultDic[@"TrackMetaData"][@"upnp:songName"] isKindOfClass:NSString.class]) {
+                self.currentResource.songName = resultDic[@"TrackMetaData"][@"upnp:songName"];
+            }
+            if ([resultDic[@"TrackMetaData"][@"upnp:songPlayer"] isKindOfClass:NSString.class]) {
+                if (self.currentResource.sourceType == MKRSourceTypeHandPick || self.currentResource.sourceType == MKRSourceTypeBroadcast) {
+                    self.currentResource.songName = resultDic[@"TrackMetaData"][@"upnp:songPlayer"];
+                }else{
+                    self.currentResource.songArtist = resultDic[@"TrackMetaData"][@"upnp:songPlayer"];
+                }
+            }
+            if ([resultDic[@"TrackMetaData"][@"upnp:songThumb"] isKindOfClass:NSString.class]) {
+                self.currentResource.songAlbumCover = resultDic[@"TrackMetaData"][@"upnp:songThumb"];
+            }
+            if ([resultDic[@"TrackMetaData"][@"upnp:songInfoID"] isKindOfClass:NSString.class]) {
+                self.currentResource.songID = [resultDic[@"TrackMetaData"][@"upnp:songInfoID"] integerValue];
+            }
+            if ([resultDic[@"TrackMetaData"][@"upnp:songPlatform"] isKindOfClass:NSString.class]) {
+                self.currentResource.songFrom = [resultDic[@"TrackMetaData"][@"upnp:songPlatform"] integerValue];
+            }
+            if ([resultDic[@"TrackDuration"] isKindOfClass:NSString.class]) {
+                self.currentResource.resourceStatus.totalTime = [NSString secondsFromHHmmssFormatStrig:resultDic[@"TrackDuration"]];
+            }
+            if ([resultDic[@"RelTime"] isKindOfClass:NSString.class]) {
+                self.currentResource.resourceStatus.currentTime = [NSString secondsFromHHmmssFormatStrig:resultDic[@"RelTime"]];
+            }
+            if ([resultDic[@"CurrentTransportState"] isKindOfClass:NSString.class]) {
+                self.currentResource.resourceStatus.playState = [self.currentResource.resourceStatus updatePlayState:resultDic[@"CurrentTransportState"]];
+            }
+            if ([resultDic[@"TrackMetaData"][@"upnp:songAlbumID"] isKindOfClass:NSString.class]) {
+                id songAlbumID = resultDic[@"TrackMetaData"][@"upnp:songAlbumID"];
+                if ([songAlbumID isKindOfClass:NSString.class]) {
+                    self.currentResource.songAlbumID = resultDic[@"TrackMetaData"][@"upnp:songAlbumID"];
+                }
+            }
+            if ([resultDic[@"TrackMetaData"][@"upnp:songAlbumID"] isKindOfClass:NSString.class]) {
+                id songAlbumID = resultDic[@"TrackMetaData"][@"upnp:songAlbumID"];
+                if ([songAlbumID isKindOfClass:NSString.class]) {
+                    self.currentResource.songAlbumID = resultDic[@"TrackMetaData"][@"upnp:songAlbumID"];
+                }
+            }
+            NSString *channelString = resultDic[@"TrackMetaData"][@"upnp:songFlag"];
+            NSInteger songChannel = 0;
+            if ([channelString containsString:@"-"]) {
+                NSArray *channelStringArr = [channelString componentsSeparatedByString:@"-"];
+                songChannel = [[channelStringArr firstObject] integerValue];
+            }else{
+                songChannel = [channelString integerValue];
+            }
+            self.currentResource.songChannel = songChannel;
+            NSString *songChannelUid = [NSString stringWithFormat:@"%@-%@-%zd",self.userID,device.deviceUUID,songChannel];
+            self.currentResource.songChannelUid = songChannelUid;
+            self.currentResource.songFlag = [NSString stringWithFormat:@"%@_%zd",songChannelUid,self.currentResource.songID];
+            wd_main_queue(^{
+                [self.listeners makeObjectsPerformSelectorWithObjects:@selector(didGetPlayInfo:),self.currentResource];
+            });
+        }
+    });
+    return self.currentResource;
+}
+
+- (void)mkr_setObject:(id)obj forKey:(NSString *)key{
+    
+}
+
+- (NSString *)playModeStringWithPlayMode:(MKRRadioPlayMode)playmode{
+    switch (playmode) {
+        case MKRRadioPlayModeOrder:{
+            return @"REPEAT_ALL";
         }
+            break;
+        case MKRRadioPlayModeSingle:{
+            return @"REPEAT_ONE";
+        }
+            break;
+        case MKRRadioPlayModeRandom:{
+            return @"SHUFFLE";
+        }
+            break;
+        default:{
+             return @"REPEAT_ALL";
+        }
+            break;
     }
-    resource.songFrom = (MKRSourcePlatform)[songFrom integerValue];
-    NSString *channelString = dmrPositionInfo[8];
-    if (![channelString containsString:@"Unknown:TrackMetaData Incomplete"]) {
-        if ([channelString containsString:@"CHANNEL_UPDATE_"]) {
-            resource.songChannel = [[channelString componentsSeparatedByString:@"CHANNEL_UPDATE_"].lastObject integerValue];
-        } else {
-            resource.songChannel = [channelString integerValue];
+}
+
+- (id<MKRRadioResorce>)currentResource{
+    if (!_currentResource) {
+        _currentResource = [[MKRRadioResorce alloc] init];
+        _currentResource.songName = @"猫王妙播";
+        _currentResource.songArtist = @"Keep radio on!";
+        if (!_currentResource.resourceStatus) {
+            _currentResource.resourceStatus = [[MKRPlayResourceStatus alloc] init];
         }
     }
-    //    resource.songLength = [self secondsFromTimeString:dmrPositionInfo[1]];
-    //    MKRPlayResourceStatus *status = [MKRPlayResourceStatus new];
-    //    status.currentTime = [[self secondsFromTimeString:dmrPositionInfo[10]] integerValue];
-    //    status.totalTime = [oneSong.songLength integerValue];
-    NSString *songChannelUid = [NSString stringWithFormat:@"%@-%@-%zd",self.userID,device.deviceUUID,resource.songChannel];
-    resource.songChannelUid = songChannelUid;
-    resource.songFlag = [NSString stringWithFormat:@"%@_%@_%@",songChannelUid,resource.songID,songFrom];
-    return resource;
+    return _currentResource;
+}
+
+- (id<MKRRadioResorce>)defaultSong{
+    MKRRadioResorce *song = [[MKRRadioResorce alloc] init];
+    song.songName = @"猫王妙播";
+    song.songArtist = @"Keep radio on!";
+    song.resourceStatus = [[MKRPlayResourceStatus alloc] init];
+    return song;
 }
 
 - (NSHashTable *)listeners{

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 59 - 0
libs/libAS-Control.framework/Headers/ASControlTools.h


+ 20 - 0
libs/libAS-Control.framework/Headers/NSDictionary+MKRXml.h

@@ -0,0 +1,20 @@
+//
+//  NSDictionary+MKRXml.h
+//  libAS-Control
+//
+//  Created by yyqxiaoyin on 2019/10/23.
+//  Copyright © 2019 AirSmart. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+#import <Foundation/Foundation.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface NSDictionary (MKRXml)
+
++ (nullable NSDictionary *)mkr_dictionaryWithXML:(id)xmlDataOrString;
+
+@end
+
+NS_ASSUME_NONNULL_END

BIN
libs/libAS-Control.framework/Info.plist


BIN
libs/libAS-Control.framework/libAS-Control


+ 1 - 1
upgrade.sh

@@ -1 +1 @@
-fastlane ManagerLib tag:0.0.1 target:MKRRadioManager
+fastlane ManagerLib tag:0.0.2 target:MKRRadioManager