Commit 698b0359 cgx

引入DOUAudioStreamer

1 个父辈 bc6a86ac
正在显示 71 个修改的文件 包含 3116 行增加14 行删除
......@@ -58,6 +58,7 @@
D0CFD3D027FB3B920002982B /* launcher@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = D0CFD3CD27FB3B910002982B /* launcher@3x.png */; };
D0CFD3D127FB3B920002982B /* launcher.png in Resources */ = {isa = PBXBuildFile; fileRef = D0CFD3CE27FB3B920002982B /* launcher.png */; };
D0E9408927FE96A900D57495 /* libWeChatSDK.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D0E9408727FE96A900D57495 /* libWeChatSDK.a */; settings = {ATTRIBUTES = (Required, ); }; };
D0F808F52803D4E70097899F /* Track.m in Sources */ = {isa = PBXBuildFile; fileRef = D0F808F32803D4E70097899F /* Track.m */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
......@@ -161,6 +162,8 @@
D0E9408627FE96A900D57495 /* WechatAuthSDK.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WechatAuthSDK.h; sourceTree = "<group>"; };
D0E9408727FE96A900D57495 /* libWeChatSDK.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libWeChatSDK.a; sourceTree = "<group>"; };
D0F808ED2803C83A0097899F /* DreamSleepDebug.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DreamSleepDebug.entitlements; sourceTree = "<group>"; };
D0F808F32803D4E70097899F /* Track.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Track.m; sourceTree = "<group>"; };
D0F808F42803D4E70097899F /* Track.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Track.h; sourceTree = "<group>"; };
F02C34A5649294F60932630C /* Pods-DreamSleep.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-DreamSleep.release.xcconfig"; path = "Target Support Files/Pods-DreamSleep/Pods-DreamSleep.release.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */
......@@ -297,6 +300,8 @@
D01814DE27FFDB6A00583D4E /* HomeTableViewCell.m */,
D0C09EDE28007E5F00709D4C /* BreatheController.h */,
D0C09EDF28007E5F00709D4C /* BreatheController.m */,
D0F808F42803D4E70097899F /* Track.h */,
D0F808F32803D4E70097899F /* Track.m */,
);
path = Home;
sourceTree = "<group>";
......@@ -598,6 +603,7 @@
D01814DC27FFD92200583D4E /* DSDataSource.m in Sources */,
D0B5ECC827F2E97A003EDFE3 /* MacroFuncUtil.m in Sources */,
D01814E227FFDBB800583D4E /* HomeHeaderView.m in Sources */,
D0F808F52803D4E70097899F /* Track.m in Sources */,
D0C50B3C27FD2EFD00DC68F0 /* PrivacyViewController.m in Sources */,
D0930F122801124E006B497A /* BaseNaviController.m in Sources */,
D0930F1A2801874B006B497A /* UIViewController+Swizzling.m in Sources */,
......@@ -760,7 +766,7 @@
GENERATE_INFOPLIST_FILE = YES;
HEADER_SEARCH_PATHS = "$(inherited)/**";
INFOPLIST_FILE = DreamSleep/DSConfig/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = "${Bundle_Display_Name}";
INFOPLIST_KEY_CFBundleDisplayName = "小梦睡眠-Dev";
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
......@@ -808,7 +814,7 @@
GENERATE_INFOPLIST_FILE = YES;
HEADER_SEARCH_PATHS = "$(inherited)/**";
INFOPLIST_FILE = DreamSleep/DSConfig/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = "${Bundle_Display_Name}";
INFOPLIST_KEY_CFBundleDisplayName = "小梦睡眠-Dev";
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
......@@ -914,7 +920,7 @@
GENERATE_INFOPLIST_FILE = YES;
HEADER_SEARCH_PATHS = "$(inherited)/**";
INFOPLIST_FILE = DreamSleep/DSConfig/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = "${Bundle_Display_Name}";
INFOPLIST_KEY_CFBundleDisplayName = "小梦睡眠-Dev";
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
......
......@@ -27,5 +27,9 @@
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
<key>UIBackgroundModes</key>
<array>
<string>audio</string>
</array>
</dict>
</plist>
......@@ -18,7 +18,10 @@ typedef NS_ENUM(NSInteger, LottieStyle) {
///  均衡呼吸法和舒睡4-7-8呼吸法
@interface BreatheController : UIViewController
// 动画样式
@property (nonatomic, assign) LottieStyle style;
// 音频URL
@property (nonatomic, strong) NSURL *audioFileURL;
@end
NS_ASSUME_NONNULL_END
/* vim: set ft=objc fenc=utf-8 sw=2 ts=2 et: */
/*
* DOUAudioStreamer - A Core Audio based streaming audio player for iOS/Mac:
*
* https://github.com/douban/DOUAudioStreamer
*
* Copyright 2013-2016 Douban Inc. All rights reserved.
*
* Use and distribution licensed under the BSD license. See
* the LICENSE file for full text.
*
* Authors:
* Chongyu Zhu <i@lembacon.com>
*
*/
#import <Foundation/Foundation.h>
#import <DOUAudioFile.h>
@interface Track : NSObject <DOUAudioFile>
@property (nonatomic, strong) NSString *artist;
@property (nonatomic, strong) NSString *title;
@property (nonatomic, strong) NSURL *audioFileURL;
@property (nonatomic, assign) int playId;
@end
/* vim: set ft=objc fenc=utf-8 sw=2 ts=2 et: */
/*
* DOUAudioStreamer - A Core Audio based streaming audio player for iOS/Mac:
*
* https://github.com/douban/DOUAudioStreamer
*
* Copyright 2013-2016 Douban Inc. All rights reserved.
*
* Use and distribution licensed under the BSD license. See
* the LICENSE file for full text.
*
* Authors:
* Chongyu Zhu <i@lembacon.com>
*
*/
#import "Track.h"
@implementation Track
@end
......@@ -7,6 +7,7 @@ target 'DreamSleep' do
pod 'MJRefresh', '~> 3.7.5'
pod 'Masonry', '~> 1.1.0'
pod 'lottie-ios', '~> 2.5.3'
pod 'DOUAudioStreamer', '~> 0.2.16'
end
# AFNetworking (4.0.1)
......@@ -15,3 +16,4 @@ end
# MJRefresh (3.7.5)
# Masonry (1.1.0)
# lottie-ios (2.5.3)
# DOUAudioStreamer (0.2.16)
......@@ -19,6 +19,7 @@ PODS:
- DKNightVersion/Core
- DKNightVersion/UIKit (2.4.3):
- DKNightVersion/Core
- DOUAudioStreamer (0.2.16)
- lottie-ios (2.5.3)
- Masonry (1.1.0)
- MJRefresh (3.7.5)
......@@ -27,6 +28,7 @@ PODS:
DEPENDENCIES:
- DKNightVersion (~> 2.4.3)
- DOUAudioStreamer (~> 0.2.16)
- lottie-ios (~> 2.5.3)
- Masonry (~> 1.1.0)
- MJRefresh (~> 3.7.5)
......@@ -36,6 +38,7 @@ SPEC REPOS:
trunk:
- AFNetworking
- DKNightVersion
- DOUAudioStreamer
- lottie-ios
- Masonry
- MJRefresh
......@@ -44,11 +47,12 @@ SPEC REPOS:
SPEC CHECKSUMS:
AFNetworking: 7864c38297c79aaca1500c33288e429c3451fdce
DKNightVersion: eaa80cc4014b4bae7d4b535fd87ecc6a3c2767b3
DOUAudioStreamer: c503ba2ecb9a54ff7bda0eff66963ad224f3c7dc
lottie-ios: a50d5c0160425cd4b01b852bb9578963e6d92d31
Masonry: 678fab65091a9290e40e2832a55e7ab731aad201
MJRefresh: fdf5e979eb406a0341468932d1dfc8b7f9fce961
YTKNetwork: c16be90b06be003de9e9cd0d3b187cc8eaf35c04
PODFILE CHECKSUM: da4f3494cbd800091ea38764f7f43754ca9369ea
PODFILE CHECKSUM: e7bb0ee0a6fff85de99e8ba732a1592a8a5ab9c4
COCOAPODS: 1.11.3
Copyright (c) 2013-2016, Douban Inc. <http://www.douban.com/>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of the Douban Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# DOUAudioStreamer
[![CocoaPods](https://img.shields.io/cocoapods/v/DOUAudioStreamer.svg)](https://cocoapods.org/pods/DOUAudioStreamer)
[![Platform](https://img.shields.io/cocoapods/p/DOUAudioStreamer.svg)](https://cocoapods.org/pods/DOUAudioStreamer)
[![License](https://img.shields.io/cocoapods/l/DOUAudioStreamer.svg)](https://github.com/douban/DOUAudioStreamer/blob/master/LICENSE)
DOUAudioStreamer is a Core Audio based streaming audio player for iOS/Mac.
## How to Use
[Download](https://github.com/douban/DOUAudioStreamer/archive/master.zip) DOUAudioStreamer, drag everything inside src into your Xcode project and you are ready to go.
## Examples
A working demonstration is included inside [example](https://github.com/douban/DOUAudioStreamer/tree/master/example) folder.
The documentation for DOUAudioStreamer is coming.
## License
Use and distribution of licensed under the BSD license. See the [LICENSE](https://github.com/douban/DOUAudioStreamer/blob/master/LICENSE) file for full text.
/* vim: set ft=objc fenc=utf-8 sw=2 ts=2 et: */
/*
* DOUAudioStreamer - A Core Audio based streaming audio player for iOS/Mac:
*
* https://github.com/douban/DOUAudioStreamer
*
* Copyright 2013-2016 Douban Inc. All rights reserved.
*
* Use and distribution licensed under the BSD license. See
* the LICENSE file for full text.
*
* Authors:
* Chongyu Zhu <i@lembacon.com>
*
*/
#import "DOUAudioAnalyzer.h"
@interface DOUAudioAnalyzer (Default)
+ (instancetype)spatialAnalyzer;
+ (instancetype)frequencyAnalyzer;
@end
/* vim: set ft=objc fenc=utf-8 sw=2 ts=2 et: */
/*
* DOUAudioStreamer - A Core Audio based streaming audio player for iOS/Mac:
*
* https://github.com/douban/DOUAudioStreamer
*
* Copyright 2013-2016 Douban Inc. All rights reserved.
*
* Use and distribution licensed under the BSD license. See
* the LICENSE file for full text.
*
* Authors:
* Chongyu Zhu <i@lembacon.com>
*
*/
#import "DOUAudioAnalyzer+Default.h"
#import "DOUAudioSpatialAnalyzer.h"
#import "DOUAudioFrequencyAnalyzer.h"
@implementation DOUAudioAnalyzer (Default)
+ (instancetype)spatialAnalyzer
{
return [DOUAudioSpatialAnalyzer analyzer];
}
+ (instancetype)frequencyAnalyzer
{
return [DOUAudioFrequencyAnalyzer analyzer];
}
@end
/* vim: set ft=objc fenc=utf-8 sw=2 ts=2 et: */
/*
* DOUAudioStreamer - A Core Audio based streaming audio player for iOS/Mac:
*
* https://github.com/douban/DOUAudioStreamer
*
* Copyright 2013-2016 Douban Inc. All rights reserved.
*
* Use and distribution licensed under the BSD license. See
* the LICENSE file for full text.
*
* Authors:
* Chongyu Zhu <i@lembacon.com>
*
*/
#import <Foundation/Foundation.h>
#define kDOUAudioAnalyzerLevelCount 20
@interface DOUAudioAnalyzer : NSObject
+ (instancetype)analyzer;
- (void)handleLPCMSamples:(int16_t *)samples count:(NSUInteger)count;
- (void)flush;
- (void)copyLevels:(float *)levels;
@property (nonatomic, assign) NSTimeInterval interval;
@property (nonatomic, assign, getter=isEnabled) BOOL enabled;
@end
/* vim: set ft=objc fenc=utf-8 sw=2 ts=2 et: */
/*
* DOUAudioStreamer - A Core Audio based streaming audio player for iOS/Mac:
*
* https://github.com/douban/DOUAudioStreamer
*
* Copyright 2013-2016 Douban Inc. All rights reserved.
*
* Use and distribution licensed under the BSD license. See
* the LICENSE file for full text.
*
* Authors:
* Chongyu Zhu <i@lembacon.com>
*
*/
#import "DOUAudioAnalyzer.h"
#import "DOUAudioAnalyzer_Private.h"
#include <Accelerate/Accelerate.h>
#include <pthread.h>
#include <mach/mach_time.h>
@interface DOUAudioAnalyzer () {
@private
int16_t _sampleBuffer[kDOUAudioAnalyzerSampleCount];
struct {
float sample[kDOUAudioAnalyzerSampleCount];
float left[kDOUAudioAnalyzerCount];
float right[kDOUAudioAnalyzerCount];
} _vectors;
struct {
float left[kDOUAudioAnalyzerLevelCount];
float right[kDOUAudioAnalyzerLevelCount];
float overall[kDOUAudioAnalyzerLevelCount];
} _levels;
uint64_t _interval;
uint64_t _lastTime;
BOOL _enabled;
pthread_mutex_t _mutex;
}
@end
@implementation DOUAudioAnalyzer
@synthesize enabled = _enabled;
+ (instancetype)analyzer
{
return [[self alloc] init];
}
- (id)init
{
self = [super init];
if (self) {
_enabled = NO;
pthread_mutex_init(&_mutex, NULL);
_lastTime = 0;
[self setInterval:0.1];
[self flush];
}
return self;
}
- (void)dealloc
{
pthread_mutex_destroy(&_mutex);
}
- (void)handleLPCMSamples:(int16_t *)samples count:(NSUInteger)count
{
pthread_mutex_lock(&_mutex);
if (samples == NULL ||
count == 0) {
pthread_mutex_unlock(&_mutex);
return;
}
if (!_enabled) {
pthread_mutex_unlock(&_mutex);
return;
}
uint64_t currentTime = mach_absolute_time();
if (currentTime - _lastTime < _interval) {
pthread_mutex_unlock(&_mutex);
return;
}
else {
_lastTime = currentTime;
}
if (count >= kDOUAudioAnalyzerSampleCount) {
[self _analyzeLinearPCMSamples:samples];
}
else {
memcpy(_sampleBuffer, samples, sizeof(int16_t) * count);
memset(_sampleBuffer + count, 0, sizeof(int16_t) * (kDOUAudioAnalyzerSampleCount - count));
[self _analyzeLinearPCMSamples:_sampleBuffer];
}
pthread_mutex_unlock(&_mutex);
}
- (void)flush
{
pthread_mutex_lock(&_mutex);
vDSP_vclr(_levels.overall, 1, kDOUAudioAnalyzerLevelCount);
pthread_mutex_unlock(&_mutex);
}
+ (double)_absoluteTimeConversion
{
static double conversion;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
mach_timebase_info_data_t info;
mach_timebase_info(&info);
conversion = 1.0e-9 * info.numer / info.denom;
});
return conversion;
}
- (NSTimeInterval)interval
{
return [[self class] _absoluteTimeConversion] * _interval;
}
- (void)setInterval:(NSTimeInterval)interval
{
pthread_mutex_lock(&_mutex);
_interval = (uint64_t)llrint(round(interval / [[self class] _absoluteTimeConversion]));
pthread_mutex_unlock(&_mutex);
}
- (void)setEnabled:(BOOL)enabled
{
if (_enabled != enabled) {
pthread_mutex_lock(&_mutex);
_enabled = enabled;
pthread_mutex_unlock(&_mutex);
}
}
- (void)copyLevels:(float *)levels
{
pthread_mutex_lock(&_mutex);
if (levels != NULL) {
memcpy(levels, _levels.overall, sizeof(float) * kDOUAudioAnalyzerLevelCount);
}
pthread_mutex_unlock(&_mutex);
}
- (void)_analyzeLinearPCMSamples:(const int16_t *)samples
{
[self _splitStereoSamples:samples];
[self processChannelVectors:_vectors.left toLevels:_levels.left];
[self processChannelVectors:_vectors.right toLevels:_levels.right];
[self _updateLevels];
}
- (void)_splitStereoSamples:(const int16_t *)samples
{
static const float scale = INT16_MAX;
vDSP_vflt16((int16_t *)samples, 1, _vectors.sample, 1, kDOUAudioAnalyzerSampleCount);
vDSP_vsdiv(_vectors.sample, 1, (float *)&scale, _vectors.sample, 1, kDOUAudioAnalyzerSampleCount);
DSPSplitComplex complexSplit;
complexSplit.realp = _vectors.left;
complexSplit.imagp = _vectors.right;
vDSP_ctoz((const DSPComplex *)_vectors.sample, 2, &complexSplit, 1, kDOUAudioAnalyzerCount);
}
- (void)_updateLevels
{
static const float scale = 2.0f;
vDSP_vadd(_levels.left, 1, _levels.right, 1, _levels.overall, 1, kDOUAudioAnalyzerLevelCount);
vDSP_vsdiv(_levels.overall, 1, (float *)&scale, _levels.overall, 1, kDOUAudioAnalyzerLevelCount);
static const float min = 0.0f;
static const float max = 1.0f;
vDSP_vclip(_levels.overall, 1, (float *)&min, (float *)&max, _levels.overall, 1, kDOUAudioAnalyzerLevelCount);
}
- (void)processChannelVectors:(const float *)vectors toLevels:(float *)levels
{
[self doesNotRecognizeSelector:_cmd];
}
@end
/* vim: set ft=objc fenc=utf-8 sw=2 ts=2 et: */
/*
* DOUAudioStreamer - A Core Audio based streaming audio player for iOS/Mac:
*
* https://github.com/douban/DOUAudioStreamer
*
* Copyright 2013-2016 Douban Inc. All rights reserved.
*
* Use and distribution licensed under the BSD license. See
* the LICENSE file for full text.
*
* Authors:
* Chongyu Zhu <i@lembacon.com>
*
*/
#import "DOUAudioAnalyzer.h"
#define kDOUAudioAnalyzerSampleCount 1024
#define kDOUAudioAnalyzerCount (kDOUAudioAnalyzerSampleCount / 2)
@interface DOUAudioAnalyzer ()
- (void)processChannelVectors:(const float *)vectors toLevels:(float *)levels;
@end
/* vim: set ft=objc fenc=utf-8 sw=2 ts=2 et: */
/*
* DOUAudioStreamer - A Core Audio based streaming audio player for iOS/Mac:
*
* https://github.com/douban/DOUAudioStreamer
*
* Copyright 2013-2016 Douban Inc. All rights reserved.
*
* Use and distribution licensed under the BSD license. See
* the LICENSE file for full text.
*
* Authors:
* Chongyu Zhu <i@lembacon.com>
*
*/
#ifdef __cplusplus
#define DOUAS_EXTERN extern "C"
#else /* __cplusplus */
#define DOUAS_EXTERN extern
#endif /* __cplusplus */
/* vim: set ft=objc fenc=utf-8 sw=2 ts=2 et: */
/*
* DOUAudioStreamer - A Core Audio based streaming audio player for iOS/Mac:
*
* https://github.com/douban/DOUAudioStreamer
*
* Copyright 2013-2016 Douban Inc. All rights reserved.
*
* Use and distribution licensed under the BSD license. See
* the LICENSE file for full text.
*
* Authors:
* Chongyu Zhu <i@lembacon.com>
*
*/
#import <Foundation/Foundation.h>
#include <CoreAudio/CoreAudioTypes.h>
typedef NS_ENUM(NSUInteger, DOUAudioDecoderStatus) {
DOUAudioDecoderSucceeded,
DOUAudioDecoderFailed,
DOUAudioDecoderEndEncountered,
DOUAudioDecoderWaiting
};
@class DOUAudioPlaybackItem;
@class DOUAudioLPCM;
@interface DOUAudioDecoder : NSObject
+ (AudioStreamBasicDescription)defaultOutputFormat;
+ (instancetype)decoderWithPlaybackItem:(DOUAudioPlaybackItem *)playbackItem
bufferSize:(NSUInteger)bufferSize;
- (instancetype)initWithPlaybackItem:(DOUAudioPlaybackItem *)playbackItem
bufferSize:(NSUInteger)bufferSize;
- (BOOL)setUp;
- (void)tearDown;
- (DOUAudioDecoderStatus)decodeOnce;
- (void)seekToTime:(NSUInteger)milliseconds;
@property (nonatomic, readonly) DOUAudioPlaybackItem *playbackItem;
@property (nonatomic, readonly) DOUAudioLPCM *lpcm;
@end
/* vim: set ft=objc fenc=utf-8 sw=2 ts=2 et: */
/*
* DOUAudioStreamer - A Core Audio based streaming audio player for iOS/Mac:
*
* https://github.com/douban/DOUAudioStreamer
*
* Copyright 2013-2016 Douban Inc. All rights reserved.
*
* Use and distribution licensed under the BSD license. See
* the LICENSE file for full text.
*
* Authors:
* Chongyu Zhu <i@lembacon.com>
*
*/
#import <Foundation/Foundation.h>
@class DOUAudioStreamer;
@interface DOUAudioEventLoop : NSObject
+ (instancetype)sharedEventLoop;
@property (nonatomic, strong) DOUAudioStreamer *currentStreamer;
@property (nonatomic, assign) NSTimeInterval currentTime;
@property (nonatomic, assign) double volume;
@property (nonatomic, copy) NSArray *analyzers;
- (void)play;
- (void)pause;
- (void)stop;
@end
/* vim: set ft=objc fenc=utf-8 sw=2 ts=2 et: */
/*
* DOUAudioStreamer - A Core Audio based streaming audio player for iOS/Mac:
*
* https://github.com/douban/DOUAudioStreamer
*
* Copyright 2013-2016 Douban Inc. All rights reserved.
*
* Use and distribution licensed under the BSD license. See
* the LICENSE file for full text.
*
* Authors:
* Chongyu Zhu <i@lembacon.com>
*
*/
#import <Foundation/Foundation.h>
@class DOUAudioFilePreprocessor;
@protocol DOUAudioFile <NSObject>
@required
- (NSURL *)audioFileURL;
@optional
- (NSString *)audioFileHost;
- (DOUAudioFilePreprocessor *)audioFilePreprocessor;
@end
/* vim: set ft=objc fenc=utf-8 sw=2 ts=2 et: */
/*
* DOUAudioStreamer - A Core Audio based streaming audio player for iOS/Mac:
*
* https://github.com/douban/DOUAudioStreamer
*
* Copyright 2013-2016 Douban Inc. All rights reserved.
*
* Use and distribution licensed under the BSD license. See
* the LICENSE file for full text.
*
* Authors:
* Chongyu Zhu <i@lembacon.com>
*
*/
#import <Foundation/Foundation.h>
@interface DOUAudioFilePreprocessor : NSObject
- (NSData *)handleData:(NSData *)data offset:(NSUInteger)offset;
@end
/* vim: set ft=objc fenc=utf-8 sw=2 ts=2 et: */
/*
* DOUAudioStreamer - A Core Audio based streaming audio player for iOS/Mac:
*
* https://github.com/douban/DOUAudioStreamer
*
* Copyright 2013-2016 Douban Inc. All rights reserved.
*
* Use and distribution licensed under the BSD license. See
* the LICENSE file for full text.
*
* Authors:
* Chongyu Zhu <i@lembacon.com>
*
*/
#import "DOUAudioFilePreprocessor.h"
@implementation DOUAudioFilePreprocessor
- (NSData *)handleData:(NSData *)data offset:(NSUInteger)offset
{
[self doesNotRecognizeSelector:_cmd];
return nil;
}
@end
/* vim: set ft=objc fenc=utf-8 sw=2 ts=2 et: */
/*
* DOUAudioStreamer - A Core Audio based streaming audio player for iOS/Mac:
*
* https://github.com/douban/DOUAudioStreamer
*
* Copyright 2013-2016 Douban Inc. All rights reserved.
*
* Use and distribution licensed under the BSD license. See
* the LICENSE file for full text.
*
* Authors:
* Chongyu Zhu <i@lembacon.com>
*
*/
#import <Foundation/Foundation.h>
#import "DOUAudioFile.h"
typedef void (^DOUAudioFileProviderEventBlock)(void);
@interface DOUAudioFileProvider : NSObject
+ (instancetype)fileProviderWithAudioFile:(id <DOUAudioFile>)audioFile;
+ (void)setHintWithAudioFile:(id <DOUAudioFile>)audioFile;
@property (nonatomic, readonly) id <DOUAudioFile> audioFile;
@property (nonatomic, copy) DOUAudioFileProviderEventBlock eventBlock;
@property (nonatomic, readonly) NSString *cachedPath;
@property (nonatomic, readonly) NSURL *cachedURL;
@property (nonatomic, readonly) NSString *mimeType;
@property (nonatomic, readonly) NSString *fileExtension;
@property (nonatomic, readonly) NSString *sha256;
@property (nonatomic, readonly) NSData *mappedData;
@property (nonatomic, readonly) NSUInteger expectedLength;
@property (nonatomic, readonly) NSUInteger receivedLength;
@property (nonatomic, readonly) NSUInteger downloadSpeed;
@property (nonatomic, readonly, getter=isFailed) BOOL failed;
@property (nonatomic, readonly, getter=isReady) BOOL ready;
@property (nonatomic, readonly, getter=isFinished) BOOL finished;
@end
/* vim: set ft=objc fenc=utf-8 sw=2 ts=2 et: */
/*
* DOUAudioStreamer - A Core Audio based streaming audio player for iOS/Mac:
*
* https://github.com/douban/DOUAudioStreamer
*
* Copyright 2013-2016 Douban Inc. All rights reserved.
*
* Use and distribution licensed under the BSD license. See
* the LICENSE file for full text.
*
* Authors:
* Chongyu Zhu <i@lembacon.com>
*
*/
#import "DOUAudioAnalyzer.h"
@interface DOUAudioFrequencyAnalyzer : DOUAudioAnalyzer
@end
/* vim: set ft=objc fenc=utf-8 sw=2 ts=2 et: */
/*
* DOUAudioStreamer - A Core Audio based streaming audio player for iOS/Mac:
*
* https://github.com/douban/DOUAudioStreamer
*
* Copyright 2013-2016 Douban Inc. All rights reserved.
*
* Use and distribution licensed under the BSD license. See
* the LICENSE file for full text.
*
* Authors:
* Chongyu Zhu <i@lembacon.com>
*
*/
#import "DOUAudioFrequencyAnalyzer.h"
#import "DOUAudioAnalyzer_Private.h"
#include <Accelerate/Accelerate.h>
@interface DOUAudioFrequencyAnalyzer () {
@private
size_t _log2Count;
float _hammingWindow[kDOUAudioAnalyzerCount];
struct {
float real[kDOUAudioAnalyzerCount / 2];
float imag[kDOUAudioAnalyzerCount / 2];
} _complexSplitBuffer;
DSPSplitComplex _complexSplit;
FFTSetup _fft;
}
@end
@implementation DOUAudioFrequencyAnalyzer
- (id)init
{
self = [super init];
if (self) {
_log2Count = (size_t)lrintf(log2f(kDOUAudioAnalyzerCount));
vDSP_hamm_window(_hammingWindow, kDOUAudioAnalyzerCount, 0);
_complexSplit.realp = _complexSplitBuffer.real;
_complexSplit.imagp = _complexSplitBuffer.imag;
_fft = vDSP_create_fftsetup(_log2Count, kFFTRadix2);
}
return self;
}
- (void)dealloc
{
vDSP_destroy_fftsetup(_fft);
}
- (void)_splitInterleavedComplexVectors:(const float *)vectors
{
vDSP_vmul(vectors, 1, _hammingWindow, 1, (float *)vectors, 1, kDOUAudioAnalyzerCount);
vDSP_ctoz((const DSPComplex *)vectors, 2, &_complexSplit, 1, kDOUAudioAnalyzerCount / 2);
}
- (void)_performForwardDFTWithVectors:(const float *)vectors
{
vDSP_fft_zrip(_fft, &_complexSplit, 1, _log2Count, kFFTDirection_Forward);
vDSP_zvabs(&_complexSplit, 1, (float *)vectors, 1, kDOUAudioAnalyzerCount / 2);
static const float scale = 0.5f;
vDSP_vsmul(vectors, 1, &scale, (float *)vectors, 1, kDOUAudioAnalyzerCount / 2);
}
- (void)_normalizeVectors:(const float *)vectors toLevels:(float *)levels
{
static const int size = kDOUAudioAnalyzerCount / 4;
vDSP_vsq(vectors, 1, (float *)vectors, 1, size);
vvlog10f((float *)vectors, vectors, &size);
static const float multiplier = 1.0f / 16.0f;
const float increment = sqrtf(multiplier);
vDSP_vsmsa((float *)vectors, 1, (float *)&multiplier, (float *)&increment, (float *)vectors, 1, kDOUAudioAnalyzerCount / 2);
for (size_t i = 0; i < kDOUAudioAnalyzerLevelCount; ++i) {
levels[i] = vectors[1 + ((size - 1) / kDOUAudioAnalyzerLevelCount) * i];
}
}
- (void)processChannelVectors:(const float *)vectors toLevels:(float *)levels
{
[self _splitInterleavedComplexVectors:vectors];
[self _performForwardDFTWithVectors:vectors];
[self _normalizeVectors:vectors toLevels:levels];
}
@end
/* vim: set ft=objc fenc=utf-8 sw=2 ts=2 et: */
/*
* DOUAudioStreamer - A Core Audio based streaming audio player for iOS/Mac:
*
* https://github.com/douban/DOUAudioStreamer
*
* Copyright 2013-2016 Douban Inc. All rights reserved.
*
* Use and distribution licensed under the BSD license. See
* the LICENSE file for full text.
*
* Authors:
* Chongyu Zhu <i@lembacon.com>
*
*/
#import <Foundation/Foundation.h>
@interface DOUAudioLPCM : NSObject
@property (nonatomic, assign, getter=isEnd) BOOL end;
- (BOOL)readBytes:(void **)bytes length:(NSUInteger *)length;
- (void)writeBytes:(const void *)bytes length:(NSUInteger)length;
@end
/* vim: set ft=objc fenc=utf-8 sw=2 ts=2 et: */
/*
* DOUAudioStreamer - A Core Audio based streaming audio player for iOS/Mac:
*
* https://github.com/douban/DOUAudioStreamer
*
* Copyright 2013-2016 Douban Inc. All rights reserved.
*
* Use and distribution licensed under the BSD license. See
* the LICENSE file for full text.
*
* Authors:
* Chongyu Zhu <i@lembacon.com>
*
*/
#import "DOUAudioLPCM.h"
#include <libkern/OSAtomic.h>
typedef struct data_segment {
void *bytes;
NSUInteger length;
struct data_segment *next;
} data_segment;
@interface DOUAudioLPCM () {
@private
data_segment *_segments;
BOOL _end;
OSSpinLock _lock;
}
@end
@implementation DOUAudioLPCM
@synthesize end = _end;
- (id)init
{
self = [super init];
if (self) {
_lock = OS_SPINLOCK_INIT;
}
return self;
}
- (void)dealloc
{
while (_segments != NULL) {
data_segment *next = _segments->next;
free(_segments);
_segments = next;
}
}
- (void)setEnd:(BOOL)end
{
OSSpinLockLock(&_lock);
if (end && !_end) {
_end = YES;
}
OSSpinLockUnlock(&_lock);
}
- (BOOL)readBytes:(void **)bytes length:(NSUInteger *)length
{
*bytes = NULL;
*length = 0;
OSSpinLockLock(&_lock);
if (_end && _segments == NULL) {
OSSpinLockUnlock(&_lock);
return NO;
}
if (_segments != NULL) {
*length = _segments->length;
*bytes = malloc(*length);
memcpy(*bytes, _segments->bytes, *length);
data_segment *next = _segments->next;
free(_segments);
_segments = next;
}
OSSpinLockUnlock(&_lock);
return YES;
}
- (void)writeBytes:(const void *)bytes length:(NSUInteger)length
{
OSSpinLockLock(&_lock);
if (_end) {
OSSpinLockUnlock(&_lock);
return;
}
if (bytes == NULL || length == 0) {
OSSpinLockUnlock(&_lock);
return;
}
data_segment *segment = (data_segment *)malloc(sizeof(data_segment) + length);
segment->bytes = segment + 1;
segment->length = length;
segment->next = NULL;
memcpy(segment->bytes, bytes, length);
data_segment **link = &_segments;
while (*link != NULL) {
data_segment *current = *link;
link = &current->next;
}
*link = segment;
OSSpinLockUnlock(&_lock);
}
@end
/* vim: set ft=objc fenc=utf-8 sw=2 ts=2 et: */
/*
* DOUAudioStreamer - A Core Audio based streaming audio player for iOS/Mac:
*
* https://github.com/douban/DOUAudioStreamer
*
* Copyright 2013-2016 Douban Inc. All rights reserved.
*
* Use and distribution licensed under the BSD license. See
* the LICENSE file for full text.
*
* Authors:
* Chongyu Zhu <i@lembacon.com>
*
*/
#import <Foundation/Foundation.h>
#include <CoreAudio/CoreAudioTypes.h>
#include <AudioToolbox/AudioToolbox.h>
@class DOUAudioFileProvider;
@class DOUAudioFilePreprocessor;
@protocol DOUAudioFile;
@interface DOUAudioPlaybackItem : NSObject
+ (instancetype)playbackItemWithFileProvider:(DOUAudioFileProvider *)fileProvider;
- (instancetype)initWithFileProvider:(DOUAudioFileProvider *)fileProvider;
@property (nonatomic, readonly) DOUAudioFileProvider *fileProvider;
@property (nonatomic, readonly) DOUAudioFilePreprocessor *filePreprocessor;
@property (nonatomic, readonly) id <DOUAudioFile> audioFile;
@property (nonatomic, readonly) NSURL *cachedURL;
@property (nonatomic, readonly) NSData *mappedData;
@property (nonatomic, readonly) AudioFileID fileID;
@property (nonatomic, readonly) AudioStreamBasicDescription fileFormat;
@property (nonatomic, readonly) NSUInteger bitRate;
@property (nonatomic, readonly) NSUInteger dataOffset;
@property (nonatomic, readonly) NSUInteger estimatedDuration;
@property (nonatomic, readonly, getter=isOpened) BOOL opened;
- (BOOL)open;
- (void)close;
@end
/* vim: set ft=objc fenc=utf-8 sw=2 ts=2 et: */
/*
* DOUAudioStreamer - A Core Audio based streaming audio player for iOS/Mac:
*
* https://github.com/douban/DOUAudioStreamer
*
* Copyright 2013-2016 Douban Inc. All rights reserved.
*
* Use and distribution licensed under the BSD license. See
* the LICENSE file for full text.
*
* Authors:
* Chongyu Zhu <i@lembacon.com>
*
*/
#import "DOUAudioPlaybackItem.h"
#import "DOUAudioFileProvider.h"
#import "DOUAudioFilePreprocessor.h"
@interface DOUAudioPlaybackItem () {
@private
DOUAudioFileProvider *_fileProvider;
DOUAudioFilePreprocessor *_filePreprocessor;
AudioFileID _fileID;
AudioStreamBasicDescription _fileFormat;
NSUInteger _bitRate;
NSUInteger _dataOffset;
NSUInteger _estimatedDuration;
}
@end
@implementation DOUAudioPlaybackItem
@synthesize fileProvider = _fileProvider;
@synthesize filePreprocessor = _filePreprocessor;
@synthesize fileID = _fileID;
@synthesize fileFormat = _fileFormat;
@synthesize bitRate = _bitRate;
@synthesize dataOffset = _dataOffset;
@synthesize estimatedDuration = _estimatedDuration;
- (id <DOUAudioFile>)audioFile
{
return [_fileProvider audioFile];
}
- (NSURL *)cachedURL
{
return [_fileProvider cachedURL];
}
- (NSData *)mappedData
{
return [_fileProvider mappedData];
}
- (BOOL)isOpened
{
return _fileID != NULL;
}
static OSStatus audio_file_read(void *inClientData,
SInt64 inPosition,
UInt32 requestCount,
void *buffer,
UInt32 *actualCount)
{
__unsafe_unretained DOUAudioPlaybackItem *item = (__bridge DOUAudioPlaybackItem *)inClientData;
if (inPosition + requestCount > [[item mappedData] length]) {
if (inPosition >= [[item mappedData] length]) {
*actualCount = 0;
}
else {
*actualCount = (UInt32)((SInt64)[[item mappedData] length] - inPosition);
}
}
else {
*actualCount = requestCount;
}
if (*actualCount == 0) {
return noErr;
}
if ([item filePreprocessor] == nil) {
memcpy(buffer, (uint8_t *)[[item mappedData] bytes] + inPosition, *actualCount);
}
else {
NSData *input = [NSData dataWithBytesNoCopy:(uint8_t *)[[item mappedData] bytes] + inPosition
length:*actualCount
freeWhenDone:NO];
NSData *output = [[item filePreprocessor] handleData:input offset:(NSUInteger)inPosition];
memcpy(buffer, [output bytes], [output length]);
}
return noErr;
}
static SInt64 audio_file_get_size(void *inClientData)
{
__unsafe_unretained DOUAudioPlaybackItem *item = (__bridge DOUAudioPlaybackItem *)inClientData;
return (SInt64)[[item mappedData] length];
}
- (BOOL)_openWithFileTypeHint:(AudioFileTypeID)fileTypeHint
{
OSStatus status;
status = AudioFileOpenWithCallbacks((__bridge void *)self,
audio_file_read,
NULL,
audio_file_get_size,
NULL,
fileTypeHint,
&_fileID);
return status == noErr;
}
- (BOOL)_openWithFallbacks
{
NSArray *fallbackTypeIDs = [self _fallbackTypeIDs];
for (NSNumber *typeIDNumber in fallbackTypeIDs) {
AudioFileTypeID typeID = (AudioFileTypeID)[typeIDNumber unsignedLongValue];
if ([self _openWithFileTypeHint:typeID]) {
return YES;
}
}
return NO;
}
- (NSArray *)_fallbackTypeIDs
{
NSMutableArray *fallbackTypeIDs = [NSMutableArray array];
NSMutableSet *fallbackTypeIDSet = [NSMutableSet set];
struct {
CFStringRef specifier;
AudioFilePropertyID propertyID;
} properties[] = {
{ (__bridge CFStringRef)[_fileProvider mimeType], kAudioFileGlobalInfo_TypesForMIMEType },
{ (__bridge CFStringRef)[_fileProvider fileExtension], kAudioFileGlobalInfo_TypesForExtension }
};
const size_t numberOfProperties = sizeof(properties) / sizeof(properties[0]);
for (size_t i = 0; i < numberOfProperties; ++i) {
if (properties[i].specifier == NULL) {
continue;
}
UInt32 outSize = 0;
OSStatus status;
status = AudioFileGetGlobalInfoSize(properties[i].propertyID,
sizeof(properties[i].specifier),
&properties[i].specifier,
&outSize);
if (status != noErr) {
continue;
}
size_t count = outSize / sizeof(AudioFileTypeID);
AudioFileTypeID *buffer = (AudioFileTypeID *)malloc(outSize);
if (buffer == NULL) {
continue;
}
status = AudioFileGetGlobalInfo(properties[i].propertyID,
sizeof(properties[i].specifier),
&properties[i].specifier,
&outSize,
buffer);
if (status != noErr) {
free(buffer);
continue;
}
for (size_t j = 0; j < count; ++j) {
NSNumber *tid = [NSNumber numberWithUnsignedLong:buffer[j]];
if ([fallbackTypeIDSet containsObject:tid]) {
continue;
}
[fallbackTypeIDs addObject:tid];
[fallbackTypeIDSet addObject:tid];
}
free(buffer);
}
return fallbackTypeIDs;
}
- (BOOL)open
{
if ([self isOpened]) {
return YES;
}
if (![self _openWithFileTypeHint:0] &&
![self _openWithFallbacks]) {
_fileID = NULL;
return NO;
}
if (![self _fillFileFormat] ||
![self _fillMiscProperties]) {
AudioFileClose(_fileID);
_fileID = NULL;
return NO;
}
return YES;
}
- (BOOL)_fillFileFormat
{
UInt32 size;
OSStatus status;
status = AudioFileGetPropertyInfo(_fileID, kAudioFilePropertyFormatList, &size, NULL);
if (status != noErr) {
return NO;
}
UInt32 numFormats = size / sizeof(AudioFormatListItem);
AudioFormatListItem *formatList = (AudioFormatListItem *)malloc(size);
status = AudioFileGetProperty(_fileID, kAudioFilePropertyFormatList, &size, formatList);
if (status != noErr) {
free(formatList);
return NO;
}
if (numFormats == 1) {
_fileFormat = formatList[0].mASBD;
}
else {
status = AudioFormatGetPropertyInfo(kAudioFormatProperty_DecodeFormatIDs, 0, NULL, &size);
if (status != noErr) {
free(formatList);
return NO;
}
UInt32 numDecoders = size / sizeof(OSType);
OSType *decoderIDS = (OSType *)malloc(size);
status = AudioFormatGetProperty(kAudioFormatProperty_DecodeFormatIDs, 0, NULL, &size, decoderIDS);
if (status != noErr) {
free(formatList);
free(decoderIDS);
return NO;
}
UInt32 i;
for (i = 0; i < numFormats; ++i) {
OSType decoderID = formatList[i].mASBD.mFormatID;
BOOL found = NO;
for (UInt32 j = 0; j < numDecoders; ++j) {
if (decoderID == decoderIDS[j]) {
found = YES;
break;
}
}
if (found) {
break;
}
}
free(decoderIDS);
if (i >= numFormats) {
free(formatList);
return NO;
}
_fileFormat = formatList[i].mASBD;
}
free(formatList);
return YES;
}
- (BOOL)_fillMiscProperties
{
UInt32 size;
OSStatus status;
UInt32 bitRate = 0;
size = sizeof(bitRate);
status = AudioFileGetProperty(_fileID, kAudioFilePropertyBitRate, &size, &bitRate);
if (status != noErr) {
return NO;
}
_bitRate = bitRate;
SInt64 dataOffset = 0;
size = sizeof(dataOffset);
status = AudioFileGetProperty(_fileID, kAudioFilePropertyDataOffset, &size, &dataOffset);
if (status != noErr) {
return NO;
}
_dataOffset = (NSUInteger)dataOffset;
Float64 estimatedDuration = 0.0;
size = sizeof(estimatedDuration);
status = AudioFileGetProperty(_fileID, kAudioFilePropertyEstimatedDuration, &size, &estimatedDuration);
if (status != noErr) {
return NO;
}
_estimatedDuration = estimatedDuration * 1000.0;
return YES;
}
- (void)close
{
if (![self isOpened]) {
return;
}
AudioFileClose(_fileID);
_fileID = NULL;
}
+ (instancetype)playbackItemWithFileProvider:(DOUAudioFileProvider *)fileProvider
{
return [[[self class] alloc] initWithFileProvider:fileProvider];
}
- (instancetype)initWithFileProvider:(DOUAudioFileProvider *)fileProvider
{
self = [super init];
if (self) {
_fileProvider = fileProvider;
if ([[self audioFile] respondsToSelector:@selector(audioFilePreprocessor)]) {
_filePreprocessor = [[self audioFile] audioFilePreprocessor];
}
}
return self;
}
- (void)dealloc
{
if ([self isOpened]) {
[self close];
}
}
@end
/* vim: set ft=objc fenc=utf-8 sw=2 ts=2 et: */
/*
* DOUAudioStreamer - A Core Audio based streaming audio player for iOS/Mac:
*
* https://github.com/douban/DOUAudioStreamer
*
* Copyright 2013-2016 Douban Inc. All rights reserved.
*
* Use and distribution licensed under the BSD license. See
* the LICENSE file for full text.
*
* Authors:
* Chongyu Zhu <i@lembacon.com>
*
*/
#import <Foundation/Foundation.h>
@interface DOUAudioRenderer : NSObject
+ (instancetype)rendererWithBufferTime:(NSUInteger)bufferTime;
- (instancetype)initWithBufferTime:(NSUInteger)bufferTime;
- (BOOL)setUp;
- (void)tearDown;
- (void)renderBytes:(const void *)bytes length:(NSUInteger)length;
- (void)stop;
- (void)flush;
- (void)flushShouldResetTiming:(BOOL)shouldResetTiming;
@property (nonatomic, readonly) NSUInteger currentTime;
@property (nonatomic, readonly, getter=isStarted) BOOL started;
@property (nonatomic, assign, getter=isInterrupted) BOOL interrupted;
@property (nonatomic, assign) double volume;
@property (nonatomic, copy) NSArray *analyzers;
@end
/* vim: set ft=objc fenc=utf-8 sw=2 ts=2 et: */
/*
* DOUAudioStreamer - A Core Audio based streaming audio player for iOS/Mac:
*
* https://github.com/douban/DOUAudioStreamer
*
* Copyright 2013-2016 Douban Inc. All rights reserved.
*
* Use and distribution licensed under the BSD license. See
* the LICENSE file for full text.
*
* Authors:
* Chongyu Zhu <i@lembacon.com>
*
*/
#import "DOUAudioAnalyzer.h"
@interface DOUAudioSpatialAnalyzer : DOUAudioAnalyzer
@end
/* vim: set ft=objc fenc=utf-8 sw=2 ts=2 et: */
/*
* DOUAudioStreamer - A Core Audio based streaming audio player for iOS/Mac:
*
* https://github.com/douban/DOUAudioStreamer
*
* Copyright 2013-2016 Douban Inc. All rights reserved.
*
* Use and distribution licensed under the BSD license. See
* the LICENSE file for full text.
*
* Authors:
* Chongyu Zhu <i@lembacon.com>
*
*/
#import "DOUAudioSpatialAnalyzer.h"
#import "DOUAudioAnalyzer_Private.h"
@implementation DOUAudioSpatialAnalyzer
- (void)processChannelVectors:(const float *)vectors toLevels:(float *)levels
{
for (size_t i = 0; i < kDOUAudioAnalyzerLevelCount; ++i) {
levels[i] = vectors[kDOUAudioAnalyzerCount * i / kDOUAudioAnalyzerLevelCount];
}
}
@end
/* vim: set ft=objc fenc=utf-8 sw=2 ts=2 et: */
/*
* DOUAudioStreamer - A Core Audio based streaming audio player for iOS/Mac:
*
* https://github.com/douban/DOUAudioStreamer
*
* Copyright 2013-2016 Douban Inc. All rights reserved.
*
* Use and distribution licensed under the BSD license. See
* the LICENSE file for full text.
*
* Authors:
* Chongyu Zhu <i@lembacon.com>
*
*/
#import "DOUAudioStreamer.h"
DOUAS_EXTERN NSString *const kDOUAudioStreamerVolumeKey;
DOUAS_EXTERN const NSUInteger kDOUAudioStreamerBufferTime;
typedef NS_OPTIONS(NSUInteger, DOUAudioStreamerOptions) {
DOUAudioStreamerKeepPersistentVolume = 1 << 0,
DOUAudioStreamerRemoveCacheOnDeallocation = 1 << 1,
DOUAudioStreamerRequireSHA256 = 1 << 2,
DOUAudioStreamerDefaultOptions = DOUAudioStreamerKeepPersistentVolume |
DOUAudioStreamerRemoveCacheOnDeallocation
};
@interface DOUAudioStreamer (Options)
+ (DOUAudioStreamerOptions)options;
+ (void)setOptions:(DOUAudioStreamerOptions)options;
@end
/* vim: set ft=objc fenc=utf-8 sw=2 ts=2 et: */
/*
* DOUAudioStreamer - A Core Audio based streaming audio player for iOS/Mac:
*
* https://github.com/douban/DOUAudioStreamer
*
* Copyright 2013-2016 Douban Inc. All rights reserved.
*
* Use and distribution licensed under the BSD license. See
* the LICENSE file for full text.
*
* Authors:
* Chongyu Zhu <i@lembacon.com>
*
*/
#import "DOUAudioStreamer+Options.h"
NSString *const kDOUAudioStreamerVolumeKey = @"DOUAudioStreamerVolume";
const NSUInteger kDOUAudioStreamerBufferTime = 200;
static DOUAudioStreamerOptions gOptions = DOUAudioStreamerDefaultOptions;
@implementation DOUAudioStreamer (Options)
+ (DOUAudioStreamerOptions)options
{
return gOptions;
}
+ (void)setOptions:(DOUAudioStreamerOptions)options
{
if (!!((gOptions ^ options) & DOUAudioStreamerKeepPersistentVolume) &&
!(options & DOUAudioStreamerKeepPersistentVolume)) {
[[NSUserDefaults standardUserDefaults] removeObjectForKey:kDOUAudioStreamerVolumeKey];
}
gOptions = options;
}
@end
/* vim: set ft=objc fenc=utf-8 sw=2 ts=2 et: */
/*
* DOUAudioStreamer - A Core Audio based streaming audio player for iOS/Mac:
*
* https://github.com/douban/DOUAudioStreamer
*
* Copyright 2013-2016 Douban Inc. All rights reserved.
*
* Use and distribution licensed under the BSD license. See
* the LICENSE file for full text.
*
* Authors:
* Chongyu Zhu <i@lembacon.com>
*
*/
#import <Foundation/Foundation.h>
#import "DOUAudioBase.h"
#import "DOUAudioFile.h"
#import "DOUAudioFilePreprocessor.h"
#import "DOUAudioAnalyzer+Default.h"
DOUAS_EXTERN NSString *const kDOUAudioStreamerErrorDomain;
typedef NS_ENUM(NSUInteger, DOUAudioStreamerStatus) {
DOUAudioStreamerPlaying,
DOUAudioStreamerPaused,
DOUAudioStreamerIdle,
DOUAudioStreamerFinished,
DOUAudioStreamerBuffering,
DOUAudioStreamerError
};
typedef NS_ENUM(NSInteger, DOUAudioStreamerErrorCode) {
DOUAudioStreamerNetworkError,
DOUAudioStreamerDecodingError
};
@interface DOUAudioStreamer : NSObject
+ (instancetype)streamerWithAudioFile:(id <DOUAudioFile>)audioFile;
- (instancetype)initWithAudioFile:(id <DOUAudioFile>)audioFile;
+ (double)volume;
+ (void)setVolume:(double)volume;
+ (NSArray *)analyzers;
+ (void)setAnalyzers:(NSArray *)analyzers;
+ (void)setHintWithAudioFile:(id <DOUAudioFile>)audioFile;
@property (assign, readonly) DOUAudioStreamerStatus status;
@property (strong, readonly) NSError *error;
@property (nonatomic, readonly) id <DOUAudioFile> audioFile;
@property (nonatomic, readonly) NSURL *url;
@property (nonatomic, assign, readonly) NSTimeInterval duration;
@property (nonatomic, assign) NSTimeInterval currentTime;
@property (nonatomic, assign) double volume;
@property (nonatomic, copy) NSArray *analyzers;
@property (nonatomic, readonly) NSString *cachedPath;
@property (nonatomic, readonly) NSURL *cachedURL;
@property (nonatomic, readonly) NSString *sha256;
@property (nonatomic, readonly) NSUInteger expectedLength;
@property (nonatomic, readonly) NSUInteger receivedLength;
@property (nonatomic, readonly) NSUInteger downloadSpeed;
@property (nonatomic, assign, readonly) double bufferingRatio;
- (void)play;
- (void)pause;
- (void)stop;
@end
/* vim: set ft=objc fenc=utf-8 sw=2 ts=2 et: */
/*
* DOUAudioStreamer - A Core Audio based streaming audio player for iOS/Mac:
*
* https://github.com/douban/DOUAudioStreamer
*
* Copyright 2013-2016 Douban Inc. All rights reserved.
*
* Use and distribution licensed under the BSD license. See
* the LICENSE file for full text.
*
* Authors:
* Chongyu Zhu <i@lembacon.com>
*
*/
#import "DOUAudioStreamer.h"
#import "DOUAudioStreamer_Private.h"
#import "DOUAudioFileProvider.h"
#import "DOUAudioEventLoop.h"
NSString *const kDOUAudioStreamerErrorDomain = @"com.douban.audio-streamer.error-domain";
@interface DOUAudioStreamer () {
@private
id <DOUAudioFile> _audioFile;
DOUAudioStreamerStatus _status;
NSError *_error;
NSTimeInterval _duration;
NSInteger _timingOffset;
DOUAudioFileProvider *_fileProvider;
DOUAudioPlaybackItem *_playbackItem;
DOUAudioDecoder *_decoder;
double _bufferingRatio;
#if TARGET_OS_IPHONE
BOOL _pausedByInterruption;
#endif /* TARGET_OS_IPHONE */
}
@end
@implementation DOUAudioStreamer
@synthesize status = _status;
@synthesize error = _error;
@synthesize duration = _duration;
@synthesize timingOffset = _timingOffset;
@synthesize fileProvider = _fileProvider;
@synthesize playbackItem = _playbackItem;
@synthesize decoder = _decoder;
@synthesize bufferingRatio = _bufferingRatio;
#if TARGET_OS_IPHONE
@synthesize pausedByInterruption = _pausedByInterruption;
#endif /* TARGET_OS_IPHONE */
+ (instancetype)streamerWithAudioFile:(id <DOUAudioFile>)audioFile
{
return [[[self class] alloc] initWithAudioFile:audioFile];
}
- (instancetype)initWithAudioFile:(id <DOUAudioFile>)audioFile
{
self = [super init];
if (self) {
_audioFile = audioFile;
_status = DOUAudioStreamerIdle;
_fileProvider = [DOUAudioFileProvider fileProviderWithAudioFile:_audioFile];
if (_fileProvider == nil) {
return nil;
}
_bufferingRatio = (double)[_fileProvider receivedLength] / [_fileProvider expectedLength];
}
return self;
}
+ (double)volume
{
return [[DOUAudioEventLoop sharedEventLoop] volume];
}
+ (void)setVolume:(double)volume
{
[[DOUAudioEventLoop sharedEventLoop] setVolume:volume];
}
+ (NSArray *)analyzers
{
return [[DOUAudioEventLoop sharedEventLoop] analyzers];
}
+ (void)setAnalyzers:(NSArray *)analyzers
{
[[DOUAudioEventLoop sharedEventLoop] setAnalyzers:analyzers];
}
+ (void)setHintWithAudioFile:(id <DOUAudioFile>)audioFile
{
[DOUAudioFileProvider setHintWithAudioFile:audioFile];
}
- (id <DOUAudioFile>)audioFile
{
return _audioFile;
}
- (NSURL *)url
{
return [_audioFile audioFileURL];
}
- (NSTimeInterval)currentTime
{
if ([[DOUAudioEventLoop sharedEventLoop] currentStreamer] != self) {
return 0.0;
}
return [[DOUAudioEventLoop sharedEventLoop] currentTime];
}
- (void)setCurrentTime:(NSTimeInterval)currentTime
{
if ([[DOUAudioEventLoop sharedEventLoop] currentStreamer] != self) {
return;
}
[[DOUAudioEventLoop sharedEventLoop] setCurrentTime:currentTime];
}
- (double)volume
{
return [[self class] volume];
}
- (void)setVolume:(double)volume
{
[[self class] setVolume:volume];
}
- (NSArray *)analyzers
{
return [[self class] analyzers];
}
- (void)setAnalyzers:(NSArray *)analyzers
{
[[self class] setAnalyzers:analyzers];
}
- (NSString *)cachedPath
{
return [_fileProvider cachedPath];
}
- (NSURL *)cachedURL
{
return [_fileProvider cachedURL];
}
- (NSString *)sha256
{
return [_fileProvider sha256];
}
- (NSUInteger)expectedLength
{
return [_fileProvider expectedLength];
}
- (NSUInteger)receivedLength
{
return [_fileProvider receivedLength];
}
- (NSUInteger)downloadSpeed
{
return [_fileProvider downloadSpeed];
}
- (void)play
{
@synchronized(self) {
if (_status != DOUAudioStreamerPaused &&
_status != DOUAudioStreamerIdle &&
_status != DOUAudioStreamerFinished) {
return;
}
if ([[DOUAudioEventLoop sharedEventLoop] currentStreamer] != self) {
[[DOUAudioEventLoop sharedEventLoop] pause];
[[DOUAudioEventLoop sharedEventLoop] setCurrentStreamer:self];
}
[[DOUAudioEventLoop sharedEventLoop] play];
}
}
- (void)pause
{
@synchronized(self) {
if (_status == DOUAudioStreamerPaused ||
_status == DOUAudioStreamerIdle ||
_status == DOUAudioStreamerFinished) {
return;
}
if ([[DOUAudioEventLoop sharedEventLoop] currentStreamer] != self) {
return;
}
[[DOUAudioEventLoop sharedEventLoop] pause];
}
}
- (void)stop
{
@synchronized(self) {
if (_status == DOUAudioStreamerIdle) {
return;
}
if ([[DOUAudioEventLoop sharedEventLoop] currentStreamer] != self) {
return;
}
[[DOUAudioEventLoop sharedEventLoop] stop];
[[DOUAudioEventLoop sharedEventLoop] setCurrentStreamer:nil];
}
}
@end
/* vim: set ft=objc fenc=utf-8 sw=2 ts=2 et: */
/*
* DOUAudioStreamer - A Core Audio based streaming audio player for iOS/Mac:
*
* https://github.com/douban/DOUAudioStreamer
*
* Copyright 2013-2016 Douban Inc. All rights reserved.
*
* Use and distribution licensed under the BSD license. See
* the LICENSE file for full text.
*
* Authors:
* Chongyu Zhu <i@lembacon.com>
*
*/
#import "DOUAudioStreamer.h"
@class DOUAudioFileProvider;
@class DOUAudioPlaybackItem;
@class DOUAudioDecoder;
@interface DOUAudioStreamer ()
@property (assign) DOUAudioStreamerStatus status;
@property (strong) NSError *error;
@property (nonatomic, assign) NSTimeInterval duration;
@property (nonatomic, assign) NSInteger timingOffset;
@property (nonatomic, readonly) DOUAudioFileProvider *fileProvider;
@property (nonatomic, strong) DOUAudioPlaybackItem *playbackItem;
@property (nonatomic, strong) DOUAudioDecoder *decoder;
@property (nonatomic, assign) double bufferingRatio;
#if TARGET_OS_IPHONE
@property (nonatomic, assign, getter=isPausedByInterruption) BOOL pausedByInterruption;
#endif /* TARGET_OS_IPHONE */
@end
/* vim: set ft=objc fenc=utf-8 sw=2 ts=2 et: */
/*
* DOUAudioStreamer - A Core Audio based streaming audio player for iOS/Mac:
*
* https://github.com/douban/DOUAudioStreamer
*
* Copyright 2013-2016 Douban Inc. All rights reserved.
*
* Use and distribution licensed under the BSD license. See
* the LICENSE file for full text.
*
* Authors:
* Chongyu Zhu <i@lembacon.com>
*
*/
#if TARGET_OS_IPHONE
#import "DOUEAGLView.h"
typedef NS_ENUM(NSUInteger, DOUAudioVisualizerInterpolationType) {
DOUAudioVisualizerLinearInterpolation,
DOUAudioVisualizerSmoothInterpolation
};
@interface DOUAudioVisualizer : DOUEAGLView
@property (nonatomic, assign) NSUInteger stepCount;
@property (nonatomic, assign) DOUAudioVisualizerInterpolationType interpolationType;
@end
#endif /* TARGET_OS_IPHONE */
/* vim: set ft=objc fenc=utf-8 sw=2 ts=2 et: */
/*
* DOUAudioStreamer - A Core Audio based streaming audio player for iOS/Mac:
*
* https://github.com/douban/DOUAudioStreamer
*
* Copyright 2013-2016 Douban Inc. All rights reserved.
*
* Use and distribution licensed under the BSD license. See
* the LICENSE file for full text.
*
* Authors:
* Chongyu Zhu <i@lembacon.com>
*
*/
#if TARGET_OS_IPHONE
#import "DOUAudioVisualizer.h"
#import "DOUAudioStreamer.h"
#include <Accelerate/Accelerate.h>
#define kBarHeight 6.0
#define kBarHorizontalPadding 2.0
#define kBarVerticalPadding 1.0
@interface DOUAudioVisualizer () {
@private
struct {
float current[kDOUAudioAnalyzerLevelCount];
float last[kDOUAudioAnalyzerLevelCount];
float pacing[kDOUAudioAnalyzerLevelCount];
} _levels;
float _coefficient;
NSUInteger _step;
NSUInteger _stepCount;
DOUAudioVisualizerInterpolationType _interpolationType;
struct {
CGFloat width;
CGFloat height;
CGFloat horizontalPadding;
CGFloat verticalPadding;
NSUInteger horizontalCount;
NSUInteger verticalCount;
} _bar;
GLuint _vbo;
GLuint _ibo;
}
@end
@implementation DOUAudioVisualizer
@synthesize stepCount = _stepCount;
@synthesize interpolationType = _interpolationType;
#pragma mark - Shared Analyzer
+ (void)_applicationDidEnterBackgroundNotification:(NSNotification *)notification
{
[[self _sharedAnalyzer] setEnabled:NO];
}
+ (void)_applicationWillEnterForegroundNotification:(NSNotification *)notification
{
[[self _sharedAnalyzer] setEnabled:YES];
}
+ (void)_setupNotifications
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(_applicationDidEnterBackgroundNotification:)
name:UIApplicationDidEnterBackgroundNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(_applicationWillEnterForegroundNotification:)
name:UIApplicationWillEnterForegroundNotification
object:nil];
}
+ (DOUAudioAnalyzer *)_sharedAnalyzer
{
static DOUAudioAnalyzer *sharedAnalyzer = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedAnalyzer = [DOUAudioAnalyzer frequencyAnalyzer];
[sharedAnalyzer setEnabled:YES];
[DOUAudioStreamer setAnalyzers:@[sharedAnalyzer]];
[self performSelector:@selector(_setupNotifications)
withObject:nil
afterDelay:0.0];
});
return sharedAnalyzer;
}
#pragma mark - Miscellaneous
- (void)_applicationDidEnterBackgroundNotification:(NSNotification *)notification
{
[self setPaused:YES];
}
- (void)_applicationWillEnterForegroundNotification:(NSNotification *)notification
{
[self setPaused:NO];
}
- (void)_setupNotifications
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(_applicationDidEnterBackgroundNotification:)
name:UIApplicationDidEnterBackgroundNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(_applicationWillEnterForegroundNotification:)
name:UIApplicationWillEnterForegroundNotification
object:nil];
}
- (void)_setupVisualizer
{
_coefficient = 0.0f;
_step = 0;
_stepCount = 6;
_interpolationType = DOUAudioVisualizerLinearInterpolation;
}
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self _setupNotifications];
[self _setupVisualizer];
}
return self;
}
- (id)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self) {
[self _setupNotifications];
[self _setupVisualizer];
}
return self;
}
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
#pragma mark - Animation
- (void)_updateStepAndLevels
{
#define COEFFICIENT ((float)_step / _stepCount)
#define INTERPOLATED_COEFFICIENT_LINEAR (COEFFICIENT)
#define INTERPOLATED_COEFFICIENT_SMOOTH (sinf(COEFFICIENT * M_PI - M_PI_2) * 0.5f + 0.5f)
switch (_interpolationType) {
default:
case DOUAudioVisualizerLinearInterpolation:
_coefficient = INTERPOLATED_COEFFICIENT_LINEAR;
break;
case DOUAudioVisualizerSmoothInterpolation:
_coefficient = INTERPOLATED_COEFFICIENT_SMOOTH;
break;
}
if (_coefficient >= 1.0f) {
_coefficient = 0.0f;
}
#undef COEFFICIENT
#undef INTERPOLATED_COEFFICIENT_LINEAR
#undef INTERPOLATED_COEFFICIENT_SMOOTH
if (++_step > _stepCount) {
_step = 0;
memcpy(_levels.last, _levels.current, sizeof(float) * kDOUAudioAnalyzerLevelCount);
[[[self class] _sharedAnalyzer] copyLevels:_levels.current];
}
}
- (void)_updatePacingLevels
{
vDSP_vintb(_levels.last, 1,
_levels.current, 1,
&_coefficient,
_levels.pacing, 1,
kDOUAudioAnalyzerLevelCount);
}
#pragma mark - Pre-calculation
- (void)_updateBarGeometries
{
CGFloat width = CGRectGetWidth([self bounds]);
CGFloat height = CGRectGetHeight([self bounds]);
_bar.width = width / kDOUAudioAnalyzerLevelCount;
_bar.height = kBarHeight;
_bar.horizontalPadding = kBarHorizontalPadding;
_bar.verticalPadding = kBarVerticalPadding;
_bar.horizontalCount = kDOUAudioAnalyzerLevelCount;
_bar.verticalCount = (NSUInteger)lrint(floor(height / kBarHeight));
}
- (void)_updateVBO
{
[self _updateBarGeometries];
NSUInteger verticesCount = _bar.verticalCount * 4 * 2;
GLfloat *vertices = (GLfloat *)malloc(sizeof(GLfloat) * verticesCount);
NSUInteger indicesCount = _bar.verticalCount * 4;
GLuint *indices = (GLuint *)malloc(sizeof(GLuint) * indicesCount);
for (NSUInteger i = 0; i < _bar.verticalCount; ++i) {
CGRect rect;
rect.origin.x = _bar.horizontalPadding;
rect.origin.y = _bar.verticalPadding + _bar.height * i;
rect.size.width = _bar.width - 2.0 * _bar.horizontalPadding;
rect.size.height = _bar.height - 2.0 * _bar.verticalPadding;
if (i & 1) {
vertices[i * 4 * 2 + 0 * 2 + 0] = CGRectGetMaxX(rect);
vertices[i * 4 * 2 + 0 * 2 + 1] = CGRectGetMinY(rect);
vertices[i * 4 * 2 + 1 * 2 + 0] = CGRectGetMaxX(rect);
vertices[i * 4 * 2 + 1 * 2 + 1] = CGRectGetMaxY(rect);
vertices[i * 4 * 2 + 2 * 2 + 0] = CGRectGetMinX(rect);
vertices[i * 4 * 2 + 2 * 2 + 1] = CGRectGetMinY(rect);
vertices[i * 4 * 2 + 3 * 2 + 0] = CGRectGetMinX(rect);
vertices[i * 4 * 2 + 3 * 2 + 1] = CGRectGetMaxY(rect);
}
else {
vertices[i * 4 * 2 + 0 * 2 + 0] = CGRectGetMinX(rect);
vertices[i * 4 * 2 + 0 * 2 + 1] = CGRectGetMinY(rect);
vertices[i * 4 * 2 + 1 * 2 + 0] = CGRectGetMinX(rect);
vertices[i * 4 * 2 + 1 * 2 + 1] = CGRectGetMaxY(rect);
vertices[i * 4 * 2 + 2 * 2 + 0] = CGRectGetMaxX(rect);
vertices[i * 4 * 2 + 2 * 2 + 1] = CGRectGetMinY(rect);
vertices[i * 4 * 2 + 3 * 2 + 0] = CGRectGetMaxX(rect);
vertices[i * 4 * 2 + 3 * 2 + 1] = CGRectGetMaxY(rect);
}
indices[i * 4 + 0] = (GLuint)i * 4 + 0;
indices[i * 4 + 1] = (GLuint)i * 4 + 1;
indices[i * 4 + 2] = (GLuint)i * 4 + 2;
indices[i * 4 + 3] = (GLuint)i * 4 + 3;
}
glBindBuffer(GL_ARRAY_BUFFER, _vbo);
glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)(sizeof(GLfloat) * verticesCount), vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, (GLsizeiptr)(sizeof(GLuint) * indicesCount), indices, GL_STATIC_DRAW);
free(vertices);
free(indices);
}
#pragma mark - Renderer
- (void)prepare
{
glGenBuffers(1, &_vbo);
glGenBuffers(1, &_ibo);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glColor4f(0.784f, 0.867f, 0.839f, 1.0f);
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
}
- (void)cleanup
{
glDeleteBuffers(1, &_vbo);
glDeleteBuffers(1, &_ibo);
}
- (void)reshape
{
CGFloat width = CGRectGetWidth([self bounds]);
CGFloat height = CGRectGetHeight([self bounds]);
CGFloat scale = [[UIScreen mainScreen] scale];
glViewport(0, 0, (GLsizei)lrint(width * scale), (GLsizei)lrint(height * scale));
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrthof(0.0f, width, 0.0f, height, -100.0f, 100.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
[self _updateVBO];
}
- (void)render
{
glClear(GL_COLOR_BUFFER_BIT);
[self _updateStepAndLevels];
[self _updatePacingLevels];
glEnableClientState(GL_VERTEX_ARRAY);
for (NSUInteger i = 0; i < _bar.horizontalCount; ++i) {
NSUInteger verticalCount = (NSUInteger)lroundf(_levels.pacing[i] * _bar.verticalCount);
glPushMatrix();
glTranslatef(_bar.width * i, 0.0f, 0.0f);
glBindBuffer(GL_ARRAY_BUFFER, _vbo);
glVertexPointer(2, GL_FLOAT, 0, NULL);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _ibo);
glDrawElements(GL_TRIANGLE_STRIP, (GLsizei)verticalCount * 4, GL_UNSIGNED_INT_OES, NULL);
glPopMatrix();
}
glDisableClientState(GL_VERTEX_ARRAY);
}
@end
#endif /* TARGET_OS_IPHONE */
/* vim: set ft=objc fenc=utf-8 sw=2 ts=2 et: */
/*
* DOUAudioStreamer - A Core Audio based streaming audio player for iOS/Mac:
*
* https://github.com/douban/DOUAudioStreamer
*
* Copyright 2013-2016 Douban Inc. All rights reserved.
*
* Use and distribution licensed under the BSD license. See
* the LICENSE file for full text.
*
* Authors:
* Chongyu Zhu <i@lembacon.com>
*
*/
#if TARGET_OS_IPHONE
#import <UIKit/UIKit.h>
#import <OpenGLES/EAGL.h>
#import <OpenGLES/ES1/gl.h>
#import <OpenGLES/ES1/glext.h>
@interface DOUEAGLView : UIView
@property (nonatomic, getter=isPaused) BOOL paused;
@property (nonatomic, assign) NSInteger frameInterval;
- (void)prepare;
- (void)cleanup;
- (void)reshape;
- (void)render;
@end
#endif /* TARGET_OS_IPHONE */
/* vim: set ft=objc fenc=utf-8 sw=2 ts=2 et: */
/*
* DOUAudioStreamer - A Core Audio based streaming audio player for iOS/Mac:
*
* https://github.com/douban/DOUAudioStreamer
*
* Copyright 2013-2016 Douban Inc. All rights reserved.
*
* Use and distribution licensed under the BSD license. See
* the LICENSE file for full text.
*
* Authors:
* Chongyu Zhu <i@lembacon.com>
*
*/
#if TARGET_OS_IPHONE
#import "DOUEAGLView.h"
#import <QuartzCore/QuartzCore.h>
#import <OpenGLES/EAGLDrawable.h>
@interface DOUEAGLView () {
@private
EAGLContext *_context;
CAEAGLLayer *_eaglLayer;
CADisplayLink *_displayLink;
NSThread *_displayLinkThread;
GLuint _framebuffer;
GLuint _renderbufferColor;
}
@end
@implementation DOUEAGLView
@dynamic paused;
@dynamic frameInterval;
+ (Class)layerClass
{
return [CAEAGLLayer class];
}
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self _initialize];
}
return self;
}
- (id)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self) {
[self _initialize];
}
return self;
}
- (void)dealloc
{
[self _finalize];
}
- (void)_initialize
{
[self setOpaque:NO];
[self setBackgroundColor:[UIColor clearColor]];
[self _setupEAGLContextAndLayer];
[self _setupFBO];
[self _setupDisplayLink];
}
- (void)_finalize
{
[_displayLink invalidate];
[EAGLContext setCurrentContext:_context];
[self cleanup];
glDeleteFramebuffersOES(1, &_framebuffer);
glDeleteRenderbuffersOES(1, &_renderbufferColor);
[EAGLContext setCurrentContext:nil];
}
- (void)_setupEAGLContextAndLayer
{
_context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];
[EAGLContext setCurrentContext:_context];
[self prepare];
_eaglLayer = (CAEAGLLayer *)[self layer];
[_eaglLayer setOpaque:NO];
[_eaglLayer setContentsScale:[[UIScreen mainScreen] scale]];
[_eaglLayer setDrawableProperties:@{
kEAGLDrawablePropertyRetainedBacking: @NO,
kEAGLDrawablePropertyColorFormat: kEAGLColorFormatRGBA8
}];
}
- (void)_setupFBO
{
glGenFramebuffersOES(1, &_framebuffer);
glBindFramebufferOES(GL_FRAMEBUFFER_OES, _framebuffer);
glGenRenderbuffersOES(1, &_renderbufferColor);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, _renderbufferColor);
[_context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:_eaglLayer];
glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, _renderbufferColor);
if (glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES) {
abort();
}
}
- (void)layoutSubviews
{
[EAGLContext setCurrentContext:_context];
glBindRenderbufferOES(GL_RENDERBUFFER_OES, _renderbufferColor);
[_context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:_eaglLayer];
glBindFramebufferOES(GL_FRAMEBUFFER_OES, _framebuffer);
if (glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES) {
abort();
}
[self reshape];
}
- (void)_setupDisplayLink
{
_displayLink = [CADisplayLink displayLinkWithTarget:self
selector:@selector(_displayLinkCallback:)];
[_displayLink setPaused:NO];
[_displayLink setFrameInterval:1];
[_displayLink addToRunLoop:[NSRunLoop mainRunLoop]
forMode:NSDefaultRunLoopMode];
}
- (void)_displayLinkCallback:(CADisplayLink *)displayLink
{
@autoreleasepool {
[EAGLContext setCurrentContext:_context];
glBindFramebufferOES(GL_FRAMEBUFFER_OES, _framebuffer);
[self render];
glBindRenderbufferOES(GL_RENDERBUFFER_OES, _renderbufferColor);
[_context presentRenderbuffer:GL_RENDERBUFFER_OES];
}
}
- (void)prepare
{
}
- (void)cleanup
{
}
- (void)reshape
{
}
- (void)render
{
}
- (id)forwardingTargetForSelector:(SEL)aSelector
{
if (aSelector == @selector(isPaused) ||
aSelector == @selector(setPaused:) ||
aSelector == @selector(frameInterval) ||
aSelector == @selector(setFrameInterval:)) {
return _displayLink;
}
return [super forwardingTargetForSelector:aSelector];
}
@end
#endif /* TARGET_OS_IPHONE */
/* vim: set ft=objc fenc=utf-8 sw=2 ts=2 et: */
/*
* DOUAudioStreamer - A Core Audio based streaming audio player for iOS/Mac:
*
* https://github.com/douban/DOUAudioStreamer
*
* Copyright 2013-2016 Douban Inc. All rights reserved.
*
* Use and distribution licensed under the BSD license. See
* the LICENSE file for full text.
*
* Authors:
* Chongyu Zhu <i@lembacon.com>
*
*/
#if TARGET_OS_IPHONE
#import <Foundation/Foundation.h>
typedef void (^DOUMPMediaLibraryAssetLoaderCompletedBlock)(void);
@interface DOUMPMediaLibraryAssetLoader : NSObject
+ (instancetype)loaderWithURL:(NSURL *)url;
- (instancetype)initWithURL:(NSURL *)url;
@property (nonatomic, strong, readonly) NSURL *assetURL;
@property (nonatomic, strong, readonly) NSString *cachedPath;
@property (nonatomic, strong, readonly) NSString *mimeType;
@property (nonatomic, strong, readonly) NSString *fileExtension;
@property (nonatomic, assign, readonly, getter=isFailed) BOOL failed;
@property (copy) DOUMPMediaLibraryAssetLoaderCompletedBlock completedBlock;
- (void)start;
- (void)cancel;
@end
#endif /* TARGET_OS_IPHONE */
/* vim: set ft=objc fenc=utf-8 sw=2 ts=2 et: */
/*
* DOUAudioStreamer - A Core Audio based streaming audio player for iOS/Mac:
*
* https://github.com/douban/DOUAudioStreamer
*
* Copyright 2013-2016 Douban Inc. All rights reserved.
*
* Use and distribution licensed under the BSD license. See
* the LICENSE file for full text.
*
* Authors:
* Chongyu Zhu <i@lembacon.com>
*
*/
#if TARGET_OS_IPHONE
#import "DOUMPMediaLibraryAssetLoader.h"
#import <AVFoundation/AVFoundation.h>
#include <CommonCrypto/CommonDigest.h>
@interface DOUMPMediaLibraryAssetLoader () {
@private
NSString *_cachedPath;
AVAssetExportSession *_exportSession;
}
@end
@implementation DOUMPMediaLibraryAssetLoader
+ (instancetype)loaderWithURL:(NSURL *)url
{
return [[[self class] alloc] initWithURL:url];
}
- (instancetype)initWithURL:(NSURL *)url
{
self = [super init];
if (self) {
_assetURL = url;
}
return self;
}
- (void)start
{
if (_exportSession != nil) {
return;
}
AVURLAsset *asset = [AVURLAsset assetWithURL:_assetURL];
if (asset == nil) {
[self _reportFailure];
return;
}
_exportSession = [AVAssetExportSession exportSessionWithAsset:asset
presetName:AVAssetExportPresetPassthrough];
if (_exportSession == nil) {
[self _reportFailure];
return;
}
[_exportSession setOutputFileType:AVFileTypeCoreAudioFormat];
[_exportSession setOutputURL:[NSURL fileURLWithPath:[self cachedPath]]];
__weak typeof(self) weakSelf = self;
[_exportSession exportAsynchronouslyWithCompletionHandler:^{
__strong typeof(weakSelf) strongSelf = weakSelf;
[strongSelf _exportSessionDidComplete];
}];
}
- (void)cancel
{
if (_exportSession == nil) {
return;
}
[_exportSession cancelExport];
_exportSession = nil;
}
- (void)_exportSessionDidComplete
{
if ([_exportSession status] != AVAssetExportSessionStatusCompleted ||
[_exportSession error] != nil) {
[self _reportFailure];
return;
}
[self _invokeCompletedBlock];
}
- (void)_invokeCompletedBlock
{
@synchronized(self) {
if (_completedBlock != NULL) {
_completedBlock();
}
}
}
- (void)_reportFailure
{
_failed = YES;
[self _invokeCompletedBlock];
}
- (NSString *)cachedPath
{
if (_cachedPath == nil) {
NSString *filename = [NSString stringWithFormat:@"douas-mla-%@.%@", [[self class] _sha256ForURL:_assetURL], [self fileExtension]];
_cachedPath = [NSTemporaryDirectory() stringByAppendingPathComponent:filename];
if ([[NSFileManager defaultManager] fileExistsAtPath:_cachedPath]) {
[[NSFileManager defaultManager] removeItemAtPath:_cachedPath error:NULL];
}
}
return _cachedPath;
}
- (NSString *)mimeType
{
return AVFileTypeCoreAudioFormat;
}
- (NSString *)fileExtension
{
return @"caf";
}
+ (NSString *)_sha256ForURL:(NSURL *)url
{
NSString *string = [url absoluteString];
unsigned char hash[CC_SHA256_DIGEST_LENGTH];
CC_SHA256([string UTF8String], (CC_LONG)[string lengthOfBytesUsingEncoding:NSUTF8StringEncoding], hash);
NSMutableString *result = [NSMutableString stringWithCapacity:CC_SHA256_DIGEST_LENGTH * 2];
for (size_t i = 0; i < CC_SHA256_DIGEST_LENGTH; ++i) {
[result appendFormat:@"%02x", hash[i]];
}
return result;
}
@end
#endif /* TARGET_OS_IPHONE */
/* vim: set ft=objc fenc=utf-8 sw=2 ts=2 et: */
/*
* DOUAudioStreamer - A Core Audio based streaming audio player for iOS/Mac:
*
* https://github.com/douban/DOUAudioStreamer
*
* Copyright 2013-2016 Douban Inc. All rights reserved.
*
* Use and distribution licensed under the BSD license. See
* the LICENSE file for full text.
*
* Authors:
* Chongyu Zhu <i@lembacon.com>
*
*/
#import <Foundation/Foundation.h>
typedef void (^DOUSimpleHTTPRequestCompletedBlock)(void);
typedef void (^DOUSimpleHTTPRequestProgressBlock)(double downloadProgress);
typedef void (^DOUSimpleHTTPRequestDidReceiveResponseBlock)(void);
typedef void (^DOUSimpleHTTPRequestDidReceiveDataBlock)(NSData *data);
@interface DOUSimpleHTTPRequest : NSObject
+ (instancetype)requestWithURL:(NSURL *)url;
- (instancetype)initWithURL:(NSURL *)url;
+ (NSTimeInterval)defaultTimeoutInterval;
+ (NSString *)defaultUserAgent;
@property (nonatomic, assign) NSTimeInterval timeoutInterval;
@property (nonatomic, strong) NSString *userAgent;
@property (nonatomic, strong) NSString *host;
@property (nonatomic, readonly) NSData *responseData;
@property (nonatomic, readonly) NSString *responseString;
@property (nonatomic, readonly) NSDictionary *responseHeaders;
@property (nonatomic, readonly) NSUInteger responseContentLength;
@property (nonatomic, readonly) NSInteger statusCode;
@property (nonatomic, readonly) NSString *statusMessage;
@property (nonatomic, readonly) NSUInteger downloadSpeed;
@property (nonatomic, readonly, getter=isFailed) BOOL failed;
@property (copy) DOUSimpleHTTPRequestCompletedBlock completedBlock;
@property (copy) DOUSimpleHTTPRequestProgressBlock progressBlock;
@property (copy) DOUSimpleHTTPRequestDidReceiveResponseBlock didReceiveResponseBlock;
@property (copy) DOUSimpleHTTPRequestDidReceiveDataBlock didReceiveDataBlock;
- (void)start;
- (void)cancel;
@end
/* vim: set ft=objc fenc=utf-8 sw=2 ts=2 et: */
/*
* DOUAudioStreamer - A Core Audio based streaming audio player for iOS/Mac:
*
* https://github.com/douban/DOUAudioStreamer
*
* Copyright 2013-2016 Douban Inc. All rights reserved.
*
* Use and distribution licensed under the BSD license. See
* the LICENSE file for full text.
*
* Authors:
* Chongyu Zhu <i@lembacon.com>
*
*/
#import <Foundation/Foundation.h>
@interface NSData (DOUAudioMappedFile)
+ (instancetype)dou_dataWithMappedContentsOfFile:(NSString *)path;
+ (instancetype)dou_dataWithMappedContentsOfURL:(NSURL *)url;
+ (instancetype)dou_modifiableDataWithMappedContentsOfFile:(NSString *)path;
+ (instancetype)dou_modifiableDataWithMappedContentsOfURL:(NSURL *)url;
- (void)dou_synchronizeMappedFile;
@end
/* vim: set ft=objc fenc=utf-8 sw=2 ts=2 et: */
/*
* DOUAudioStreamer - A Core Audio based streaming audio player for iOS/Mac:
*
* https://github.com/douban/DOUAudioStreamer
*
* Copyright 2013-2016 Douban Inc. All rights reserved.
*
* Use and distribution licensed under the BSD license. See
* the LICENSE file for full text.
*
* Authors:
* Chongyu Zhu <i@lembacon.com>
*
*/
#import "NSData+DOUAudioMappedFile.h"
#include <sys/types.h>
#include <sys/mman.h>
static NSMutableDictionary *get_size_map()
{
static NSMutableDictionary *map = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
map = [[NSMutableDictionary alloc] init];
});
return map;
}
static void mmap_deallocate(void *ptr, void *info)
{
NSNumber *key = [NSNumber numberWithUnsignedLongLong:(uintptr_t)ptr];
NSNumber *fileSize = nil;
NSMutableDictionary *sizeMap = get_size_map();
@synchronized(sizeMap) {
fileSize = [sizeMap objectForKey:key];
[sizeMap removeObjectForKey:key];
}
size_t size = (size_t)[fileSize unsignedLongLongValue];
munmap(ptr, size);
}
static CFAllocatorRef get_mmap_deallocator()
{
static CFAllocatorRef deallocator = NULL;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
CFAllocatorContext context;
bzero(&context, sizeof(context));
context.deallocate = mmap_deallocate;
deallocator = CFAllocatorCreate(kCFAllocatorDefault, &context);
});
return deallocator;
}
@implementation NSData (DOUAudioMappedFile)
+ (instancetype)dou_dataWithMappedContentsOfFile:(NSString *)path
{
return [[self class] _dou_dataWithMappedContentsOfFile:path modifiable:NO];
}
+ (instancetype)dou_dataWithMappedContentsOfURL:(NSURL *)url
{
return [[self class] dou_dataWithMappedContentsOfFile:[url path]];
}
+ (instancetype)dou_modifiableDataWithMappedContentsOfFile:(NSString *)path
{
return [[self class] _dou_dataWithMappedContentsOfFile:path modifiable:YES];
}
+ (instancetype)dou_modifiableDataWithMappedContentsOfURL:(NSURL *)url
{
return [[self class] dou_modifiableDataWithMappedContentsOfFile:[url path]];
}
+ (instancetype)_dou_dataWithMappedContentsOfFile:(NSString *)path modifiable:(BOOL)modifiable
{
NSFileHandle *fileHandle = nil;
if (modifiable) {
fileHandle = [NSFileHandle fileHandleForUpdatingAtPath:path];
}
else {
fileHandle = [NSFileHandle fileHandleForReadingAtPath:path];
}
if (fileHandle == nil) {
return nil;
}
int fd = [fileHandle fileDescriptor];
if (fd < 0) {
return nil;
}
off_t size = lseek(fd, 0, SEEK_END);
if (size < 0) {
return nil;
}
int protection = PROT_READ;
if (modifiable) {
protection |= PROT_WRITE;
}
void *address = mmap(NULL, (size_t)size, protection, MAP_FILE | MAP_SHARED, fd, 0);
if (address == MAP_FAILED) {
return nil;
}
NSMutableDictionary *sizeMap = get_size_map();
@synchronized(sizeMap) {
[sizeMap setObject:[NSNumber numberWithUnsignedLongLong:(unsigned long long)size]
forKey:[NSNumber numberWithUnsignedLongLong:(uintptr_t)address]];
}
return CFBridgingRelease(CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, (const UInt8 *)address, (CFIndex)size, get_mmap_deallocator()));
}
- (void)dou_synchronizeMappedFile
{
NSNumber *key = [NSNumber numberWithUnsignedLongLong:(uintptr_t)[self bytes]];
NSNumber *fileSize = nil;
NSMutableDictionary *sizeMap = get_size_map();
@synchronized(sizeMap) {
fileSize = [sizeMap objectForKey:key];
}
if (fileSize == nil) {
return;
}
size_t size = (size_t)[fileSize unsignedLongLongValue];
msync((void *)[self bytes], size, MS_SYNC | MS_INVALIDATE);
}
@end
......@@ -19,6 +19,7 @@ PODS:
- DKNightVersion/Core
- DKNightVersion/UIKit (2.4.3):
- DKNightVersion/Core
- DOUAudioStreamer (0.2.16)
- lottie-ios (2.5.3)
- Masonry (1.1.0)
- MJRefresh (3.7.5)
......@@ -27,6 +28,7 @@ PODS:
DEPENDENCIES:
- DKNightVersion (~> 2.4.3)
- DOUAudioStreamer (~> 0.2.16)
- lottie-ios (~> 2.5.3)
- Masonry (~> 1.1.0)
- MJRefresh (~> 3.7.5)
......@@ -36,6 +38,7 @@ SPEC REPOS:
trunk:
- AFNetworking
- DKNightVersion
- DOUAudioStreamer
- lottie-ios
- Masonry
- MJRefresh
......@@ -44,11 +47,12 @@ SPEC REPOS:
SPEC CHECKSUMS:
AFNetworking: 7864c38297c79aaca1500c33288e429c3451fdce
DKNightVersion: eaa80cc4014b4bae7d4b535fd87ecc6a3c2767b3
DOUAudioStreamer: c503ba2ecb9a54ff7bda0eff66963ad224f3c7dc
lottie-ios: a50d5c0160425cd4b01b852bb9578963e6d92d31
Masonry: 678fab65091a9290e40e2832a55e7ab731aad201
MJRefresh: fdf5e979eb406a0341468932d1dfc8b7f9fce961
YTKNetwork: c16be90b06be003de9e9cd0d3b187cc8eaf35c04
PODFILE CHECKSUM: da4f3494cbd800091ea38764f7f43754ca9369ea
PODFILE CHECKSUM: e7bb0ee0a6fff85de99e8ba732a1592a8a5ab9c4
COCOAPODS: 1.11.3
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIdentifier</key>
<string>${PRODUCT_BUNDLE_IDENTIFIER}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>${PRODUCT_NAME}</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>0.2.16</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>${CURRENT_PROJECT_VERSION}</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>
#import <Foundation/Foundation.h>
@interface PodsDummy_DOUAudioStreamer : NSObject
@end
@implementation PodsDummy_DOUAudioStreamer
@end
#ifdef __OBJC__
#import <UIKit/UIKit.h>
#else
#ifndef FOUNDATION_EXPORT
#if defined(__cplusplus)
#define FOUNDATION_EXPORT extern "C"
#else
#define FOUNDATION_EXPORT extern
#endif
#endif
#endif
#ifdef __OBJC__
#import <UIKit/UIKit.h>
#else
#ifndef FOUNDATION_EXPORT
#if defined(__cplusplus)
#define FOUNDATION_EXPORT extern "C"
#else
#define FOUNDATION_EXPORT extern
#endif
#endif
#endif
#import "DOUAudioAnalyzer+Default.h"
#import "DOUAudioAnalyzer.h"
#import "DOUAudioAnalyzer_Private.h"
#import "DOUAudioBase.h"
#import "DOUAudioDecoder.h"
#import "DOUAudioEventLoop.h"
#import "DOUAudioFile.h"
#import "DOUAudioFilePreprocessor.h"
#import "DOUAudioFileProvider.h"
#import "DOUAudioFrequencyAnalyzer.h"
#import "DOUAudioLPCM.h"
#import "DOUAudioPlaybackItem.h"
#import "DOUAudioRenderer.h"
#import "DOUAudioSpatialAnalyzer.h"
#import "DOUAudioStreamer+Options.h"
#import "DOUAudioStreamer.h"
#import "DOUAudioStreamer_Private.h"
#import "DOUAudioVisualizer.h"
#import "DOUEAGLView.h"
#import "DOUMPMediaLibraryAssetLoader.h"
#import "DOUSimpleHTTPRequest.h"
#import "NSData+DOUAudioMappedFile.h"
FOUNDATION_EXPORT double DOUAudioStreamerVersionNumber;
FOUNDATION_EXPORT const unsigned char DOUAudioStreamerVersionString[];
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/DOUAudioStreamer
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
OTHER_LDFLAGS = $(inherited) -framework "AVFoundation" -framework "Accelerate" -framework "AudioToolbox" -framework "CFNetwork" -framework "CoreAudio" -framework "MediaPlayer" -framework "MobileCoreServices" -framework "OpenGLES" -framework "QuartzCore"
PODS_BUILD_DIR = ${BUILD_DIR}
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
PODS_ROOT = ${SRCROOT}
PODS_TARGET_SRCROOT = ${PODS_ROOT}/DOUAudioStreamer
PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
SKIP_INSTALL = YES
USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
framework module DOUAudioStreamer {
umbrella header "DOUAudioStreamer-umbrella.h"
export *
module * { export * }
}
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/DOUAudioStreamer
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
OTHER_LDFLAGS = $(inherited) -framework "AVFoundation" -framework "Accelerate" -framework "AudioToolbox" -framework "CFNetwork" -framework "CoreAudio" -framework "MediaPlayer" -framework "MobileCoreServices" -framework "OpenGLES" -framework "QuartzCore"
PODS_BUILD_DIR = ${BUILD_DIR}
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
PODS_ROOT = ${SRCROOT}
PODS_TARGET_SRCROOT = ${PODS_ROOT}/DOUAudioStreamer
PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
SKIP_INSTALL = YES
USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
......@@ -50,6 +50,40 @@ SOFTWARE.
## DOUAudioStreamer
Copyright (c) 2013-2016, Douban Inc. <http://www.douban.com/>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of the Douban Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
## MJRefresh
Copyright (c) 2013-2015 MJRefresh (https://github.com/CoderMJLee/MJRefresh)
......
......@@ -75,6 +75,46 @@ SOFTWARE.
</dict>
<dict>
<key>FooterText</key>
<string>Copyright (c) 2013-2016, Douban Inc. &lt;http://www.douban.com/&gt;
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of the Douban Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
</string>
<key>License</key>
<string>BSD</string>
<key>Title</key>
<string>DOUAudioStreamer</string>
<key>Type</key>
<string>PSGroupSpecifier</string>
</dict>
<dict>
<key>FooterText</key>
<string>Copyright (c) 2013-2015 MJRefresh (https://github.com/CoderMJLee/MJRefresh)
Permission is hereby granted, free of charge, to any person obtaining a copy
......
${PODS_ROOT}/Target Support Files/Pods-DreamSleep/Pods-DreamSleep-frameworks.sh
${BUILT_PRODUCTS_DIR}/AFNetworking/AFNetworking.framework
${BUILT_PRODUCTS_DIR}/DKNightVersion/DKNightVersion.framework
${BUILT_PRODUCTS_DIR}/DOUAudioStreamer/DOUAudioStreamer.framework
${BUILT_PRODUCTS_DIR}/MJRefresh/MJRefresh.framework
${BUILT_PRODUCTS_DIR}/Masonry/Masonry.framework
${BUILT_PRODUCTS_DIR}/YTKNetwork/YTKNetwork.framework
......
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/AFNetworking.framework
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/DKNightVersion.framework
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/DOUAudioStreamer.framework
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MJRefresh.framework
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Masonry.framework
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/YTKNetwork.framework
......
${PODS_ROOT}/Target Support Files/Pods-DreamSleep/Pods-DreamSleep-frameworks.sh
${BUILT_PRODUCTS_DIR}/AFNetworking/AFNetworking.framework
${BUILT_PRODUCTS_DIR}/DKNightVersion/DKNightVersion.framework
${BUILT_PRODUCTS_DIR}/DOUAudioStreamer/DOUAudioStreamer.framework
${BUILT_PRODUCTS_DIR}/MJRefresh/MJRefresh.framework
${BUILT_PRODUCTS_DIR}/Masonry/Masonry.framework
${BUILT_PRODUCTS_DIR}/YTKNetwork/YTKNetwork.framework
......
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/AFNetworking.framework
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/DKNightVersion.framework
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/DOUAudioStreamer.framework
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MJRefresh.framework
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Masonry.framework
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/YTKNetwork.framework
......
${PODS_ROOT}/Target Support Files/Pods-DreamSleep/Pods-DreamSleep-frameworks.sh
${BUILT_PRODUCTS_DIR}/AFNetworking/AFNetworking.framework
${BUILT_PRODUCTS_DIR}/DKNightVersion/DKNightVersion.framework
${BUILT_PRODUCTS_DIR}/DOUAudioStreamer/DOUAudioStreamer.framework
${BUILT_PRODUCTS_DIR}/MJRefresh/MJRefresh.framework
${BUILT_PRODUCTS_DIR}/Masonry/Masonry.framework
${BUILT_PRODUCTS_DIR}/YTKNetwork/YTKNetwork.framework
......
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/AFNetworking.framework
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/DKNightVersion.framework
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/DOUAudioStreamer.framework
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MJRefresh.framework
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Masonry.framework
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/YTKNetwork.framework
......
......@@ -178,6 +178,7 @@ code_sign_if_enabled() {
if [[ "$CONFIGURATION" == "Beta" ]]; then
install_framework "${BUILT_PRODUCTS_DIR}/AFNetworking/AFNetworking.framework"
install_framework "${BUILT_PRODUCTS_DIR}/DKNightVersion/DKNightVersion.framework"
install_framework "${BUILT_PRODUCTS_DIR}/DOUAudioStreamer/DOUAudioStreamer.framework"
install_framework "${BUILT_PRODUCTS_DIR}/MJRefresh/MJRefresh.framework"
install_framework "${BUILT_PRODUCTS_DIR}/Masonry/Masonry.framework"
install_framework "${BUILT_PRODUCTS_DIR}/YTKNetwork/YTKNetwork.framework"
......@@ -186,6 +187,7 @@ fi
if [[ "$CONFIGURATION" == "Debug" ]]; then
install_framework "${BUILT_PRODUCTS_DIR}/AFNetworking/AFNetworking.framework"
install_framework "${BUILT_PRODUCTS_DIR}/DKNightVersion/DKNightVersion.framework"
install_framework "${BUILT_PRODUCTS_DIR}/DOUAudioStreamer/DOUAudioStreamer.framework"
install_framework "${BUILT_PRODUCTS_DIR}/MJRefresh/MJRefresh.framework"
install_framework "${BUILT_PRODUCTS_DIR}/Masonry/Masonry.framework"
install_framework "${BUILT_PRODUCTS_DIR}/YTKNetwork/YTKNetwork.framework"
......@@ -194,6 +196,7 @@ fi
if [[ "$CONFIGURATION" == "Release" ]]; then
install_framework "${BUILT_PRODUCTS_DIR}/AFNetworking/AFNetworking.framework"
install_framework "${BUILT_PRODUCTS_DIR}/DKNightVersion/DKNightVersion.framework"
install_framework "${BUILT_PRODUCTS_DIR}/DOUAudioStreamer/DOUAudioStreamer.framework"
install_framework "${BUILT_PRODUCTS_DIR}/MJRefresh/MJRefresh.framework"
install_framework "${BUILT_PRODUCTS_DIR}/Masonry/Masonry.framework"
install_framework "${BUILT_PRODUCTS_DIR}/YTKNetwork/YTKNetwork.framework"
......
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/AFNetworking" "${PODS_CONFIGURATION_BUILD_DIR}/DKNightVersion" "${PODS_CONFIGURATION_BUILD_DIR}/MJRefresh" "${PODS_CONFIGURATION_BUILD_DIR}/Masonry" "${PODS_CONFIGURATION_BUILD_DIR}/YTKNetwork" "${PODS_CONFIGURATION_BUILD_DIR}/lottie-ios"
FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/AFNetworking" "${PODS_CONFIGURATION_BUILD_DIR}/DKNightVersion" "${PODS_CONFIGURATION_BUILD_DIR}/DOUAudioStreamer" "${PODS_CONFIGURATION_BUILD_DIR}/MJRefresh" "${PODS_CONFIGURATION_BUILD_DIR}/Masonry" "${PODS_CONFIGURATION_BUILD_DIR}/YTKNetwork" "${PODS_CONFIGURATION_BUILD_DIR}/lottie-ios"
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/AFNetworking/AFNetworking.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/DKNightVersion/DKNightVersion.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/MJRefresh/MJRefresh.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Masonry/Masonry.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/YTKNetwork/YTKNetwork.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/lottie-ios/Lottie.framework/Headers"
HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/AFNetworking/AFNetworking.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/DKNightVersion/DKNightVersion.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/DOUAudioStreamer/DOUAudioStreamer.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/MJRefresh/MJRefresh.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Masonry/Masonry.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/YTKNetwork/YTKNetwork.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/lottie-ios/Lottie.framework/Headers"
LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
OTHER_LDFLAGS = $(inherited) -framework "AFNetworking" -framework "CFNetwork" -framework "DKNightVersion" -framework "Foundation" -framework "Lottie" -framework "MJRefresh" -framework "Masonry" -framework "UIKit" -framework "YTKNetwork"
OTHER_LDFLAGS = $(inherited) -framework "AFNetworking" -framework "AVFoundation" -framework "Accelerate" -framework "AudioToolbox" -framework "CFNetwork" -framework "CoreAudio" -framework "DKNightVersion" -framework "DOUAudioStreamer" -framework "Foundation" -framework "Lottie" -framework "MJRefresh" -framework "Masonry" -framework "MediaPlayer" -framework "MobileCoreServices" -framework "OpenGLES" -framework "QuartzCore" -framework "UIKit" -framework "YTKNetwork"
PODS_BUILD_DIR = ${BUILD_DIR}
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
......
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/AFNetworking" "${PODS_CONFIGURATION_BUILD_DIR}/DKNightVersion" "${PODS_CONFIGURATION_BUILD_DIR}/MJRefresh" "${PODS_CONFIGURATION_BUILD_DIR}/Masonry" "${PODS_CONFIGURATION_BUILD_DIR}/YTKNetwork" "${PODS_CONFIGURATION_BUILD_DIR}/lottie-ios"
FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/AFNetworking" "${PODS_CONFIGURATION_BUILD_DIR}/DKNightVersion" "${PODS_CONFIGURATION_BUILD_DIR}/DOUAudioStreamer" "${PODS_CONFIGURATION_BUILD_DIR}/MJRefresh" "${PODS_CONFIGURATION_BUILD_DIR}/Masonry" "${PODS_CONFIGURATION_BUILD_DIR}/YTKNetwork" "${PODS_CONFIGURATION_BUILD_DIR}/lottie-ios"
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/AFNetworking/AFNetworking.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/DKNightVersion/DKNightVersion.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/MJRefresh/MJRefresh.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Masonry/Masonry.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/YTKNetwork/YTKNetwork.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/lottie-ios/Lottie.framework/Headers"
HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/AFNetworking/AFNetworking.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/DKNightVersion/DKNightVersion.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/DOUAudioStreamer/DOUAudioStreamer.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/MJRefresh/MJRefresh.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Masonry/Masonry.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/YTKNetwork/YTKNetwork.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/lottie-ios/Lottie.framework/Headers"
LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
OTHER_LDFLAGS = $(inherited) -framework "AFNetworking" -framework "CFNetwork" -framework "DKNightVersion" -framework "Foundation" -framework "Lottie" -framework "MJRefresh" -framework "Masonry" -framework "UIKit" -framework "YTKNetwork"
OTHER_LDFLAGS = $(inherited) -framework "AFNetworking" -framework "AVFoundation" -framework "Accelerate" -framework "AudioToolbox" -framework "CFNetwork" -framework "CoreAudio" -framework "DKNightVersion" -framework "DOUAudioStreamer" -framework "Foundation" -framework "Lottie" -framework "MJRefresh" -framework "Masonry" -framework "MediaPlayer" -framework "MobileCoreServices" -framework "OpenGLES" -framework "QuartzCore" -framework "UIKit" -framework "YTKNetwork"
PODS_BUILD_DIR = ${BUILD_DIR}
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
......
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/AFNetworking" "${PODS_CONFIGURATION_BUILD_DIR}/DKNightVersion" "${PODS_CONFIGURATION_BUILD_DIR}/MJRefresh" "${PODS_CONFIGURATION_BUILD_DIR}/Masonry" "${PODS_CONFIGURATION_BUILD_DIR}/YTKNetwork" "${PODS_CONFIGURATION_BUILD_DIR}/lottie-ios"
FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/AFNetworking" "${PODS_CONFIGURATION_BUILD_DIR}/DKNightVersion" "${PODS_CONFIGURATION_BUILD_DIR}/DOUAudioStreamer" "${PODS_CONFIGURATION_BUILD_DIR}/MJRefresh" "${PODS_CONFIGURATION_BUILD_DIR}/Masonry" "${PODS_CONFIGURATION_BUILD_DIR}/YTKNetwork" "${PODS_CONFIGURATION_BUILD_DIR}/lottie-ios"
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/AFNetworking/AFNetworking.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/DKNightVersion/DKNightVersion.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/MJRefresh/MJRefresh.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Masonry/Masonry.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/YTKNetwork/YTKNetwork.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/lottie-ios/Lottie.framework/Headers"
HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/AFNetworking/AFNetworking.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/DKNightVersion/DKNightVersion.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/DOUAudioStreamer/DOUAudioStreamer.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/MJRefresh/MJRefresh.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Masonry/Masonry.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/YTKNetwork/YTKNetwork.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/lottie-ios/Lottie.framework/Headers"
LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
OTHER_LDFLAGS = $(inherited) -framework "AFNetworking" -framework "CFNetwork" -framework "DKNightVersion" -framework "Foundation" -framework "Lottie" -framework "MJRefresh" -framework "Masonry" -framework "UIKit" -framework "YTKNetwork"
OTHER_LDFLAGS = $(inherited) -framework "AFNetworking" -framework "AVFoundation" -framework "Accelerate" -framework "AudioToolbox" -framework "CFNetwork" -framework "CoreAudio" -framework "DKNightVersion" -framework "DOUAudioStreamer" -framework "Foundation" -framework "Lottie" -framework "MJRefresh" -framework "Masonry" -framework "MediaPlayer" -framework "MobileCoreServices" -framework "OpenGLES" -framework "QuartzCore" -framework "UIKit" -framework "YTKNetwork"
PODS_BUILD_DIR = ${BUILD_DIR}
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
......
支持 Markdown 格式
你添加了 0 到此讨论。请谨慎行事。
Finish editing this message first!