Merge branch 'master' of https://github.com/tumtumtum/StreamingKit
# Conflicts: # StreamingKit/StreamingKit/STKAudioPlayer.h # StreamingKit/StreamingKit/STKAudioPlayer.m # StreamingKit/StreamingKit/STKQueueEntry.m
This commit is contained in:
commit
7def768397
|
|
@ -230,7 +230,7 @@
|
|||
A1115929188D686000641365 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastUpgradeCheck = 0510;
|
||||
LastUpgradeCheck = 0710;
|
||||
ORGANIZATIONNAME = "Thong Nguyen";
|
||||
TargetAttributes = {
|
||||
A111594B188D686000641365 = {
|
||||
|
|
@ -346,6 +346,7 @@
|
|||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
|
|
@ -422,6 +423,7 @@
|
|||
IPHONEOS_DEPLOYMENT_TARGET = 6.0;
|
||||
LLVM_LTO = YES;
|
||||
OTHER_LDFLAGS = "-ObjC";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "abstractpath.com.${PRODUCT_NAME:rfc1034identifier}";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
WRAPPER_EXTENSION = app;
|
||||
};
|
||||
|
|
@ -438,6 +440,7 @@
|
|||
IPHONEOS_DEPLOYMENT_TARGET = 6.0;
|
||||
LLVM_LTO = YES;
|
||||
OTHER_LDFLAGS = "-ObjC";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "abstractpath.com.${PRODUCT_NAME:rfc1034identifier}";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
WRAPPER_EXTENSION = app;
|
||||
};
|
||||
|
|
@ -459,6 +462,7 @@
|
|||
"$(inherited)",
|
||||
);
|
||||
INFOPLIST_FILE = "ExampleAppTests/ExampleAppTests-Info.plist";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "abstractpath.com.${PRODUCT_NAME:rfc1034identifier}";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
TEST_HOST = "$(BUNDLE_LOADER)";
|
||||
WRAPPER_EXTENSION = xctest;
|
||||
|
|
@ -477,6 +481,7 @@
|
|||
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||
GCC_PREFIX_HEADER = "ExampleApp/ExampleApp-Prefix.pch";
|
||||
INFOPLIST_FILE = "ExampleAppTests/ExampleAppTests-Info.plist";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "abstractpath.com.${PRODUCT_NAME:rfc1034identifier}";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
TEST_HOST = "$(BUNDLE_LOADER)";
|
||||
WRAPPER_EXTENSION = xctest;
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@
|
|||
AudioSessionSetProperty(kAudioSessionProperty_PreferredHardwareIOBufferDuration, sizeof(bufferLength), &bufferLength);
|
||||
|
||||
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
|
||||
self.window.rootViewController = [[UIViewController alloc] init];
|
||||
|
||||
self.window.backgroundColor = [UIColor whiteColor];
|
||||
|
||||
|
|
@ -39,7 +40,6 @@
|
|||
audioPlayer.meteringEnabled = YES;
|
||||
audioPlayer.volume = 1;
|
||||
|
||||
|
||||
AudioPlayerView* audioPlayerView = [[AudioPlayerView alloc] initWithFrame:self.window.bounds andAudioPlayer:audioPlayer];
|
||||
|
||||
audioPlayerView.delegate = self;
|
||||
|
|
@ -47,9 +47,9 @@
|
|||
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
|
||||
[self becomeFirstResponder];
|
||||
|
||||
[self.window addSubview:audioPlayerView];
|
||||
|
||||
[self.window makeKeyAndVisible];
|
||||
|
||||
[self.window.rootViewController.view addSubview:audioPlayerView];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,27 +58,27 @@
|
|||
CGSize size = CGSizeMake(220, 50);
|
||||
|
||||
playFromHTTPButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
|
||||
playFromHTTPButton.frame = CGRectMake((320 - size.width) / 2, frame.size.height * 0.10, size.width, size.height);
|
||||
playFromHTTPButton.frame = CGRectMake((frame.size.width - size.width) / 2, frame.size.height * 0.10, size.width, size.height);
|
||||
[playFromHTTPButton addTarget:self action:@selector(playFromHTTPButtonTouched) forControlEvents:UIControlEventTouchUpInside];
|
||||
[playFromHTTPButton setTitle:@"Play from HTTP" forState:UIControlStateNormal];
|
||||
|
||||
playFromIcecastButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
|
||||
playFromIcecastButton.frame = CGRectMake((320 - size.width) / 2, frame.size.height * 0.10 + 35, size.width, size.height);
|
||||
playFromIcecastButton.frame = CGRectMake((frame.size.width - size.width) / 2, frame.size.height * 0.10 + 35, size.width, size.height);
|
||||
[playFromIcecastButton addTarget:self action:@selector(playFromIcecasButtonTouched) forControlEvents:UIControlEventTouchUpInside];
|
||||
[playFromIcecastButton setTitle:@"Play from Icecast" forState:UIControlStateNormal];
|
||||
|
||||
playFromLocalFileButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
|
||||
playFromLocalFileButton.frame = CGRectMake((320 - size.width) / 2, frame.size.height * 0.10 + 70, size.width, size.height);
|
||||
playFromLocalFileButton.frame = CGRectMake((frame.size.width - size.width) / 2, frame.size.height * 0.10 + 70, size.width, size.height);
|
||||
[playFromLocalFileButton addTarget:self action:@selector(playFromLocalFileButtonTouched) forControlEvents:UIControlEventTouchUpInside];
|
||||
[playFromLocalFileButton setTitle:@"Play from Local File" forState:UIControlStateNormal];
|
||||
|
||||
queueShortFileButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
|
||||
queueShortFileButton.frame = CGRectMake((320 - size.width) / 2, frame.size.height * 0.10 + 105, size.width, size.height);
|
||||
queueShortFileButton.frame = CGRectMake((frame.size.width - size.width) / 2, frame.size.height * 0.10 + 105, size.width, size.height);
|
||||
[queueShortFileButton addTarget:self action:@selector(queueShortFileButtonTouched) forControlEvents:UIControlEventTouchUpInside];
|
||||
[queueShortFileButton setTitle:@"Queue short file" forState:UIControlStateNormal];
|
||||
|
||||
queuePcmWaveFileFromHTTPButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
|
||||
queuePcmWaveFileFromHTTPButton.frame = CGRectMake((320 - size.width) / 2, frame.size.height * 0.10 + 140, size.width, size.height);
|
||||
queuePcmWaveFileFromHTTPButton.frame = CGRectMake((frame.size.width - size.width) / 2, frame.size.height * 0.10 + 140, size.width, size.height);
|
||||
[queuePcmWaveFileFromHTTPButton addTarget:self action:@selector(queuePcmWaveFileButtonTouched) forControlEvents:UIControlEventTouchUpInside];
|
||||
[queuePcmWaveFileFromHTTPButton setTitle:@"Queue PCM/WAVE from HTTP" forState:UIControlStateNormal];
|
||||
|
||||
|
|
@ -89,12 +89,12 @@
|
|||
[playButton addTarget:self action:@selector(playButtonPressed) forControlEvents:UIControlEventTouchUpInside];
|
||||
|
||||
stopButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
|
||||
stopButton.frame = CGRectMake((320 - size.width) - 30, 400, size.width, size.height);
|
||||
stopButton.frame = CGRectMake((frame.size.width - size.width) - 30, 400, size.width, size.height);
|
||||
[stopButton addTarget:self action:@selector(stopButtonPressed) forControlEvents:UIControlEventTouchUpInside];
|
||||
[stopButton setTitle:@"Stop" forState:UIControlStateNormal];
|
||||
|
||||
muteButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
|
||||
muteButton.frame = CGRectMake((320 - size.width) - 30, 430, size.width, size.height);
|
||||
muteButton.frame = CGRectMake((frame.size.width - size.width) - 30, 430, size.width, size.height);
|
||||
[muteButton addTarget:self action:@selector(muteButtonPressed) forControlEvents:UIControlEventTouchUpInside];
|
||||
[muteButton setTitle:@"Mute" forState:UIControlStateNormal];
|
||||
|
||||
|
|
@ -106,7 +106,7 @@
|
|||
|
||||
repeatSwitch = [[UISwitch alloc] initWithFrame:CGRectMake(30, frame.size.height * 0.15 + 180, size.width, size.height)];
|
||||
|
||||
enableEqSwitch = [[UISwitch alloc] initWithFrame:CGRectMake(320 - size.width - 30, frame.size.height * 0.15 + 180, size.width, size.height)];
|
||||
enableEqSwitch = [[UISwitch alloc] initWithFrame:CGRectMake(frame.size.width - size.width - 30, frame.size.height * 0.15 + 180, size.width, size.height)];
|
||||
enableEqSwitch.on = audioPlayer.equalizerEnabled;
|
||||
|
||||
[enableEqSwitch addTarget:self action:@selector(onEnableEqSwitch) forControlEvents:UIControlEventAllTouchEvents];
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
<key>CFBundleExecutable</key>
|
||||
<string>${EXECUTABLE_NAME}</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>abstractpath.com.${PRODUCT_NAME:rfc1034identifier}</string>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
|
|
|
|||
|
|
@ -5,16 +5,31 @@
|
|||
"size" : "29x29",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "29x29",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "40x40",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "40x40",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "60x60",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "iphone",
|
||||
"size" : "60x60",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"idiom" : "ipad",
|
||||
"size" : "29x29",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,31 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"extent" : "full-screen",
|
||||
"idiom" : "iphone",
|
||||
"subtype" : "736h",
|
||||
"filename" : "TX6sV.png",
|
||||
"minimum-system-version" : "8.0",
|
||||
"orientation" : "portrait",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"orientation" : "landscape",
|
||||
"idiom" : "iphone",
|
||||
"extent" : "full-screen",
|
||||
"minimum-system-version" : "8.0",
|
||||
"subtype" : "736h",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"extent" : "full-screen",
|
||||
"idiom" : "iphone",
|
||||
"subtype" : "667h",
|
||||
"filename" : "dBEHd.png",
|
||||
"minimum-system-version" : "8.0",
|
||||
"orientation" : "portrait",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"orientation" : "portrait",
|
||||
"idiom" : "iphone",
|
||||
|
|
@ -8,11 +34,12 @@
|
|||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"orientation" : "portrait",
|
||||
"extent" : "full-screen",
|
||||
"idiom" : "iphone",
|
||||
"subtype" : "retina4",
|
||||
"extent" : "full-screen",
|
||||
"filename" : "TX6sV-2.png",
|
||||
"minimum-system-version" : "7.0",
|
||||
"orientation" : "portrait",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
|
|
@ -42,6 +69,26 @@
|
|||
"extent" : "full-screen",
|
||||
"minimum-system-version" : "7.0",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"orientation" : "portrait",
|
||||
"idiom" : "iphone",
|
||||
"extent" : "full-screen",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"orientation" : "portrait",
|
||||
"idiom" : "iphone",
|
||||
"extent" : "full-screen",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"orientation" : "portrait",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "TX6sV-1.png",
|
||||
"extent" : "full-screen",
|
||||
"subtype" : "retina4",
|
||||
"scale" : "2x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
|
|
|
|||
Binary file not shown.
|
After Width: | Height: | Size: 17 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 17 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 8.3 KiB |
|
|
@ -7,7 +7,7 @@
|
|||
<key>CFBundleExecutable</key>
|
||||
<string>${EXECUTABLE_NAME}</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>abstractpath.com.${PRODUCT_NAME:rfc1034identifier}</string>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
|
|
|
|||
6
LICENSE
6
LICENSE
|
|
@ -4,7 +4,7 @@
|
|||
Inspired by Matt Gallagher's AudioStreamer:
|
||||
https://github.com/mattgallagher/AudioStreamer
|
||||
|
||||
Copyright (c) 2012 Thong Nguyen (tumtumtum@gmail.com). All rights reserved.
|
||||
Copyright (c) 2015 Thong Nguyen (tumtumtum@gmail.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:
|
||||
|
|
@ -15,12 +15,12 @@
|
|||
documentation and/or other materials provided with the distribution.
|
||||
3. All advertising materials mentioning features or use of this software
|
||||
must display the following acknowledgement:
|
||||
This product includes software developed by the <organization>.
|
||||
This product includes software developed by Thong Nguyen.
|
||||
4. Neither the name of the <organization> 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 <COPYRIGHT HOLDER> ''AS IS'' AND ANY
|
||||
THIS SOFTWARE IS PROVIDED BY THONG NGUYEN ''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 <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ The primary motivation of this project was to decouple the input data sources fr
|
|||
* Easy to read source.
|
||||
* Carefully multi-threaded to provide a responsive API that won't block your UI thread nor starve the audio buffers.
|
||||
* Buffered and gapless playback between all format types.
|
||||
* Easy to implement audio data sources (Local, HTTP, AutoRecoveryingHTTP DataSources are provided).
|
||||
* Easy to implement audio data sources (Local, HTTP, AutoRecoveringHTTP DataSources are provided).
|
||||
* Easy to extend DataSource to support adaptive buffering, encryption, etc.
|
||||
* Optimised for low CPU/battery usage (0% - 1% CPU usage when streaming).
|
||||
* Optimised for linear data sources. Random access sources are required only for seeking.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
Pod::Spec.new do |s|
|
||||
s.name = "StreamingKit"
|
||||
s.version = "0.1.25"
|
||||
s.version = "0.1.29"
|
||||
s.summary = "A fast and extensible audio streamer for iOS and OSX with support for gapless playback and custom (non-HTTP) sources."
|
||||
s.homepage = "https://github.com/tumtumtum/StreamingKit/"
|
||||
s.license = 'MIT'
|
||||
|
|
|
|||
|
|
@ -432,7 +432,7 @@
|
|||
isa = PBXProject;
|
||||
attributes = {
|
||||
CLASSPREFIX = STK;
|
||||
LastUpgradeCheck = 0610;
|
||||
LastUpgradeCheck = 0710;
|
||||
ORGANIZATIONNAME = "Thong Nguyen";
|
||||
};
|
||||
buildConfigurationList = A1E7C4C3188D57F50010896F /* Build configuration list for PBXProject "StreamingKit" */;
|
||||
|
|
@ -641,6 +641,7 @@
|
|||
);
|
||||
INFOPLIST_FILE = "StreamingKitMacTests/StreamingKitMacTests-Info.plist";
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.8;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.abstractpath.${PRODUCT_NAME:rfc1034identifier}";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = macosx;
|
||||
WRAPPER_EXTENSION = xctest;
|
||||
|
|
@ -661,6 +662,7 @@
|
|||
GCC_PREFIX_HEADER = "StreamingKitMac/StreamingKitMac-Prefix.pch";
|
||||
INFOPLIST_FILE = "StreamingKitMacTests/StreamingKitMacTests-Info.plist";
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.8;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "com.abstractpath.${PRODUCT_NAME:rfc1034identifier}";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = macosx;
|
||||
WRAPPER_EXTENSION = xctest;
|
||||
|
|
@ -684,6 +686,7 @@
|
|||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
|
|
@ -784,6 +787,7 @@
|
|||
"$(inherited)",
|
||||
);
|
||||
INFOPLIST_FILE = "StreamingKitTests/StreamingKitTests-Info.plist";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "abstractpath.com.${PRODUCT_NAME:rfc1034identifier}";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
WRAPPER_EXTENSION = xctest;
|
||||
};
|
||||
|
|
@ -800,6 +804,7 @@
|
|||
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||
GCC_PREFIX_HEADER = "StreamingKit/StreamingKit-Prefix.pch";
|
||||
INFOPLIST_FILE = "StreamingKitTests/StreamingKitTests-Info.plist";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "abstractpath.com.${PRODUCT_NAME:rfc1034identifier}";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
WRAPPER_EXTENSION = xctest;
|
||||
};
|
||||
|
|
|
|||
7
StreamingKit/StreamingKit.xcodeproj/project.xcworkspace/contents.xcworkspacedata
generated
Normal file
7
StreamingKit/StreamingKit.xcodeproj/project.xcworkspace/contents.xcworkspacedata
generated
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "self:">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
|
|
@ -8,10 +8,14 @@
|
|||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface NSMutableArray (STKAudioPlayer)
|
||||
-(void) enqueue:(id)obj;
|
||||
-(void) skipQueue:(id)obj;
|
||||
-(void) skipQueueWithQueue:(NSMutableArray*)queue;
|
||||
-(id) dequeue;
|
||||
-(id) peek;
|
||||
-(nullable id) dequeue;
|
||||
-(nullable id) peek;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
|
|
|||
|
|
@ -44,7 +44,9 @@
|
|||
#include "UIKit/UIApplication.h"
|
||||
#endif
|
||||
|
||||
typedef enum
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
typedef NS_OPTIONS(NSInteger, STKAudioPlayerState)
|
||||
{
|
||||
STKAudioPlayerStateReady,
|
||||
STKAudioPlayerStateRunning = 1,
|
||||
|
|
@ -54,10 +56,9 @@ typedef enum
|
|||
STKAudioPlayerStateStopped = (1 << 4),
|
||||
STKAudioPlayerStateError = (1 << 5),
|
||||
STKAudioPlayerStateDisposed = (1 << 6)
|
||||
}
|
||||
STKAudioPlayerState;
|
||||
};
|
||||
|
||||
typedef enum
|
||||
typedef NS_ENUM(NSInteger, STKAudioPlayerStopReason)
|
||||
{
|
||||
STKAudioPlayerStopReasonNone = 0,
|
||||
STKAudioPlayerStopReasonEof,
|
||||
|
|
@ -65,10 +66,9 @@ typedef enum
|
|||
STKAudioPlayerStopReasonPendingNext,
|
||||
STKAudioPlayerStopReasonDisposed,
|
||||
STKAudioPlayerStopReasonError = 0xffff
|
||||
}
|
||||
STKAudioPlayerStopReason;
|
||||
};
|
||||
|
||||
typedef enum
|
||||
typedef NS_ENUM(NSInteger, STKAudioPlayerErrorCode)
|
||||
{
|
||||
STKAudioPlayerErrorNone = 0,
|
||||
STKAudioPlayerErrorDataSource,
|
||||
|
|
@ -77,9 +77,13 @@ typedef enum
|
|||
STKAudioPlayerErrorCodecError,
|
||||
STKAudioPlayerErrorDataNotFound,
|
||||
STKAudioPlayerErrorOther = 0xffff
|
||||
}
|
||||
STKAudioPlayerErrorCode;
|
||||
};
|
||||
|
||||
///
|
||||
/// Options to initiailise the Audioplayer with.
|
||||
/// By default if you set buffer size or seconds to 0, the non-zero default will be used
|
||||
/// If you would like to disable the buffer option completely set to STK_DISABLE_BUFFER
|
||||
///
|
||||
typedef struct
|
||||
{
|
||||
/// If YES then seeking a track will cause all pending items to be flushed from the queue
|
||||
|
|
@ -101,6 +105,8 @@ typedef struct
|
|||
}
|
||||
STKAudioPlayerOptions;
|
||||
|
||||
#define STK_DISABLE_BUFFER (0xffffffff)
|
||||
|
||||
typedef void(^STKFrameFilter)(UInt32 channelsPerFrame, UInt32 bytesPerFrame, UInt32 frameCount, float* frames);
|
||||
|
||||
@interface STKFrameFilterEntry : NSObject
|
||||
|
|
@ -149,13 +155,13 @@ typedef void(^STKFrameFilter)(UInt32 channelsPerFrame, UInt32 bytesPerFrame, UIn
|
|||
/// Enables or disables the EQ
|
||||
@property (readwrite) BOOL equalizerEnabled;
|
||||
/// Returns an array of STKFrameFilterEntry objects representing the filters currently in use
|
||||
@property (readonly) NSArray* frameFilters;
|
||||
@property (readonly, nullable) NSArray* frameFilters;
|
||||
/// Returns the items pending to be played (includes buffering and upcoming items but does not include the current item)
|
||||
@property (readonly) NSArray* pendingQueue;
|
||||
/// The number of items pending to be played (includes buffering and upcoming items but does not include the current item)
|
||||
@property (readonly) NSUInteger pendingQueueCount;
|
||||
/// Gets the most recently queued item that is still pending to play
|
||||
@property (readonly) NSObject* mostRecentlyQueuedStillPendingItem;
|
||||
@property (readonly, nullable) NSObject* mostRecentlyQueuedStillPendingItem;
|
||||
/// Gets the current state of the player
|
||||
@property (readwrite) STKAudioPlayerState state;
|
||||
/// Gets the options provided to the player on startup
|
||||
|
|
@ -172,10 +178,10 @@ typedef void(^STKFrameFilter)(UInt32 channelsPerFrame, UInt32 bytesPerFrame, UIn
|
|||
+(STKDataSource*) dataSourceFromURL:(NSURL*)url;
|
||||
|
||||
/// Initializes a new STKAudioPlayer with the default options
|
||||
-(id) init;
|
||||
-(instancetype) init;
|
||||
|
||||
/// Initializes a new STKAudioPlayer with the given options
|
||||
-(id) initWithOptions:(STKAudioPlayerOptions)optionsIn;
|
||||
-(instancetype) initWithOptions:(STKAudioPlayerOptions)optionsIn;
|
||||
|
||||
/// Plays an item from the given URL string (all pending queued items are removed).
|
||||
/// The NSString is used as the queue item ID
|
||||
|
|
@ -252,7 +258,7 @@ typedef void(^STKFrameFilter)(UInt32 channelsPerFrame, UInt32 bytesPerFrame, UIn
|
|||
|
||||
/// Appends a frame filter with the given name and filter block just after the filter with the given name.
|
||||
/// If the given name is nil, the filter will be inserted at the beginning of the filter change
|
||||
-(void) addFrameFilterWithName:(NSString*)name afterFilterWithName:(NSString*)afterFilterWithName block:(STKFrameFilter)block;
|
||||
-(void) addFrameFilterWithName:(NSString*)name afterFilterWithName:(nullable NSString*)afterFilterWithName block:(STKFrameFilter)block;
|
||||
|
||||
/// Reads the peak power in decibals for the given channel (0 or 1).
|
||||
/// Return values are between -60 (low) and 0 (high).
|
||||
|
|
@ -266,3 +272,5 @@ typedef void(^STKFrameFilter)(UInt32 channelsPerFrame, UInt32 bytesPerFrame, UIn
|
|||
-(void) setGain:(float)gain forEqualizerBand:(int)bandIndex;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@
|
|||
#define STK_DEFAULT_GRACE_PERIOD_AFTER_SEEK_SECONDS (0.5)
|
||||
|
||||
#define OSSTATUS_PRINTF_PLACEHOLDER @"%c%c%c%c"
|
||||
#define OSSTATUS_PRINTF_VALUE(status) ((status) >> 24) & 0xFF, ((status) >> 16) & 0xFF, ((status) >> 8) & 0xFF, (status) & 0xFF
|
||||
#define OSSTATUS_PRINTF_VALUE(status) (char)(((status) >> 24) & 0xFF), (char)(((status) >> 16) & 0xFF), (char)(((status) >> 8) & 0xFF), (char)((status) & 0xFF)
|
||||
|
||||
#define LOGINFO(x) [self logInfo:[NSString stringWithFormat:@"%s %@", sel_getName(_cmd), x]];
|
||||
|
||||
|
|
@ -97,6 +97,34 @@ static void PopulateOptionsWithDefault(STKAudioPlayerOptions* options)
|
|||
}
|
||||
}
|
||||
|
||||
static void NormalizeDisabledBuffers(STKAudioPlayerOptions* options)
|
||||
{
|
||||
if (options->bufferSizeInSeconds == STK_DISABLE_BUFFER)
|
||||
{
|
||||
options->bufferSizeInSeconds = 0;
|
||||
}
|
||||
|
||||
if (options->readBufferSize == STK_DISABLE_BUFFER)
|
||||
{
|
||||
options->readBufferSize = 0;
|
||||
}
|
||||
|
||||
if (options->secondsRequiredToStartPlaying == STK_DISABLE_BUFFER)
|
||||
{
|
||||
options->secondsRequiredToStartPlaying = 0;
|
||||
}
|
||||
|
||||
if (options->secondsRequiredToStartPlayingAfterBufferUnderun == STK_DISABLE_BUFFER)
|
||||
{
|
||||
options->secondsRequiredToStartPlayingAfterBufferUnderun = 0;
|
||||
}
|
||||
|
||||
if (options->gracePeriodAfterSeekInSeconds == STK_DISABLE_BUFFER)
|
||||
{
|
||||
options->gracePeriodAfterSeekInSeconds = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#define CHECK_STATUS_AND_REPORT(call) \
|
||||
if ((status = (call))) \
|
||||
{ \
|
||||
|
|
@ -146,7 +174,7 @@ STKAudioPlayerInternalState;
|
|||
@end
|
||||
|
||||
@implementation STKFrameFilterEntry
|
||||
-(id) initWithFilter:(STKFrameFilter)filterIn andName:(NSString*)nameIn
|
||||
-(instancetype) initWithFilter:(STKFrameFilter)filterIn andName:(NSString*)nameIn
|
||||
{
|
||||
if (self = [super init])
|
||||
{
|
||||
|
|
@ -480,12 +508,12 @@ static void AudioFileStreamPacketsProc(void* clientData, UInt32 numberBytes, UIn
|
|||
}
|
||||
}
|
||||
|
||||
-(id) init
|
||||
-(instancetype) init
|
||||
{
|
||||
return [self initWithOptions:(STKAudioPlayerOptions){}];
|
||||
}
|
||||
|
||||
-(id) initWithOptions:(STKAudioPlayerOptions)optionsIn
|
||||
-(instancetype) initWithOptions:(STKAudioPlayerOptions)optionsIn
|
||||
{
|
||||
if (self = [super init])
|
||||
{
|
||||
|
|
@ -495,6 +523,7 @@ static void AudioFileStreamPacketsProc(void* clientData, UInt32 numberBytes, UIn
|
|||
self->equalizerEnabled = optionsIn.equalizerBandFrequencies[0] != 0;
|
||||
|
||||
PopulateOptionsWithDefault(&options);
|
||||
NormalizeDisabledBuffers(&options);
|
||||
|
||||
framesRequiredToStartPlaying = canonicalAudioStreamBasicDescription.mSampleRate * options.secondsRequiredToStartPlaying;
|
||||
framesRequiredToPlayAfterRebuffering = canonicalAudioStreamBasicDescription.mSampleRate * options.secondsRequiredToStartPlayingAfterBufferUnderun;
|
||||
|
|
@ -896,7 +925,7 @@ static void AudioFileStreamPacketsProc(void* clientData, UInt32 numberBytes, UIn
|
|||
}
|
||||
case kAudioFileStreamProperty_ReadyToProducePackets:
|
||||
{
|
||||
if (!audioConverterAudioStreamBasicDescription.mFormatID == kAudioFormatLinearPCM)
|
||||
if (audioConverterAudioStreamBasicDescription.mFormatID != kAudioFormatLinearPCM)
|
||||
{
|
||||
discontinuous = YES;
|
||||
}
|
||||
|
|
@ -1966,10 +1995,8 @@ static BOOL GetHardwareCodecClassDesc(UInt32 formatId, AudioClassDescription* cl
|
|||
|
||||
[self destroyAudioConverter];
|
||||
|
||||
//This breaks mono files
|
||||
//canonicalAudioStreamBasicDescription.mChannelsPerFrame = asbd->mChannelsPerFrame;
|
||||
|
||||
BOOL isRecording = currentlyReadingEntry.dataSource.recordToFileUrl != nil;
|
||||
|
||||
if (isRecording)
|
||||
{
|
||||
recordAudioStreamBasicDescription = (AudioStreamBasicDescription)
|
||||
|
|
@ -2432,6 +2459,9 @@ static BOOL GetHardwareCodecClassDesc(UInt32 formatId, AudioClassDescription* cl
|
|||
}
|
||||
else if (!isRunning)
|
||||
{
|
||||
stopReason = stopReasonIn;
|
||||
self.internalState = STKAudioPlayerInternalStateStopped;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -36,6 +36,8 @@
|
|||
#import "STKHTTPDataSource.h"
|
||||
#import "STKDataSourceWrapper.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int watchdogPeriodSeconds;
|
||||
|
|
@ -45,8 +47,10 @@ STKAutoRecoveringHTTPDataSourceOptions;
|
|||
|
||||
@interface STKAutoRecoveringHTTPDataSource : STKDataSourceWrapper
|
||||
|
||||
-(id) initWithHTTPDataSource:(STKHTTPDataSource*)innerDataSource;
|
||||
-(instancetype) initWithHTTPDataSource:(STKHTTPDataSource*)innerDataSource;
|
||||
|
||||
@property (readonly) STKHTTPDataSource* innerDataSource;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
|
|
|||
|
|
@ -101,22 +101,24 @@ static void PopulateOptionsWithDefault(STKAutoRecoveringHTTPDataSourceOptions* o
|
|||
|
||||
@implementation STKAutoRecoveringHTTPDataSource
|
||||
|
||||
@dynamic innerDataSource;
|
||||
|
||||
-(STKHTTPDataSource*) innerHTTPDataSource
|
||||
{
|
||||
return (STKHTTPDataSource*)self.innerDataSource;
|
||||
}
|
||||
|
||||
-(id) initWithDataSource:(STKDataSource *)innerDataSource
|
||||
-(instancetype) initWithDataSource:(STKDataSource *)innerDataSource
|
||||
{
|
||||
return [self initWithHTTPDataSource:(STKHTTPDataSource*)innerDataSource];
|
||||
}
|
||||
|
||||
-(id) initWithHTTPDataSource:(STKHTTPDataSource*)innerDataSourceIn
|
||||
-(instancetype) initWithHTTPDataSource:(STKHTTPDataSource*)innerDataSourceIn
|
||||
{
|
||||
return [self initWithHTTPDataSource:innerDataSourceIn andOptions:(STKAutoRecoveringHTTPDataSourceOptions){}];
|
||||
}
|
||||
|
||||
-(id) initWithHTTPDataSource:(STKHTTPDataSource*)innerDataSourceIn andOptions:(STKAutoRecoveringHTTPDataSourceOptions)optionsIn
|
||||
-(instancetype) initWithHTTPDataSource:(STKHTTPDataSource*)innerDataSourceIn andOptions:(STKAutoRecoveringHTTPDataSourceOptions)optionsIn
|
||||
{
|
||||
if (self = [super initWithDataSource:innerDataSourceIn])
|
||||
{
|
||||
|
|
|
|||
|
|
@ -34,6 +34,8 @@
|
|||
|
||||
#import "STKDataSource.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class STKCoreFoundationDataSource;
|
||||
|
||||
@interface CoreFoundationDataSourceClientInfo : NSObject
|
||||
|
|
@ -62,3 +64,5 @@
|
|||
-(CFStreamStatus) status;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
|
|
|||
|
|
@ -35,6 +35,8 @@
|
|||
#import <Foundation/Foundation.h>
|
||||
#include <AudioToolbox/AudioToolbox.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class STKDataSource;
|
||||
|
||||
@protocol STKDataSourceDelegate<NSObject>
|
||||
|
|
@ -50,8 +52,8 @@
|
|||
@property (readonly) SInt64 length;
|
||||
@property (readonly) BOOL hasBytesAvailable;
|
||||
@property (nonatomic, readwrite, assign) double durationHint;
|
||||
@property (readwrite, unsafe_unretained) id<STKDataSourceDelegate> delegate;
|
||||
@property (nonatomic, strong) NSURL *recordToFileUrl;
|
||||
@property (readwrite, unsafe_unretained, nullable) id<STKDataSourceDelegate> delegate;
|
||||
@property (nonatomic, strong, nullable) NSURL *recordToFileUrl;
|
||||
|
||||
-(BOOL) registerForEvents:(NSRunLoop*)runLoop;
|
||||
-(void) unregisterForEvents;
|
||||
|
|
@ -62,3 +64,5 @@
|
|||
-(AudioFileTypeID) audioFileTypeHint;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
|
|
|||
|
|
@ -34,10 +34,14 @@
|
|||
|
||||
#import "STKDataSource.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface STKDataSourceWrapper : STKDataSource<STKDataSourceDelegate>
|
||||
|
||||
-(id) initWithDataSource:(STKDataSource*)innerDataSource;
|
||||
-(instancetype) initWithDataSource:(STKDataSource*)innerDataSource;
|
||||
|
||||
@property (readonly) STKDataSource* innerDataSource;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@
|
|||
|
||||
@implementation STKDataSourceWrapper
|
||||
|
||||
-(id) initWithDataSource:(STKDataSource*)innerDataSourceIn
|
||||
-(instancetype) initWithDataSource:(STKDataSource*)innerDataSourceIn
|
||||
{
|
||||
if (self = [super init])
|
||||
{
|
||||
|
|
|
|||
|
|
@ -34,10 +34,12 @@
|
|||
|
||||
#import "STKCoreFoundationDataSource.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class STKHTTPDataSource;
|
||||
|
||||
typedef void(^STKURLBlock)(NSURL* url);
|
||||
typedef NSURL*(^STKURLProvider)();
|
||||
typedef NSURL* _Nonnull (^STKURLProvider)();
|
||||
typedef void(^STKAsyncURLProvider)(STKHTTPDataSource* dataSource, BOOL forSeek, STKURLBlock callback);
|
||||
|
||||
@interface STKHTTPDataSource : STKCoreFoundationDataSource
|
||||
|
|
@ -46,11 +48,13 @@ typedef void(^STKAsyncURLProvider)(STKHTTPDataSource* dataSource, BOOL forSeek,
|
|||
@property (readonly) UInt32 httpStatusCode;
|
||||
|
||||
+(AudioFileTypeID) audioFileTypeHintFromMimeType:(NSString*)fileExtension;
|
||||
-(id) initWithURL:(NSURL*)url;
|
||||
-(id) initWithURL:(NSURL *)url httpRequestHeaders:(NSDictionary *)httpRequestHeaders;
|
||||
-(id) initWithURLProvider:(STKURLProvider)urlProvider;
|
||||
-(id) initWithAsyncURLProvider:(STKAsyncURLProvider)asyncUrlProvider;
|
||||
-(NSRunLoop*) eventsRunLoop;
|
||||
-(instancetype) initWithURL:(NSURL*)url;
|
||||
-(instancetype) initWithURL:(NSURL*)url httpRequestHeaders:(NSDictionary*)httpRequestHeaders;
|
||||
-(instancetype) initWithURLProvider:(STKURLProvider)urlProvider;
|
||||
-(instancetype) initWithAsyncURLProvider:(STKAsyncURLProvider)asyncUrlProvider;
|
||||
-(nullable NSRunLoop*) eventsRunLoop;
|
||||
-(void) reconnect;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
|
|
|||
|
|
@ -64,19 +64,19 @@
|
|||
|
||||
@implementation STKHTTPDataSource
|
||||
|
||||
-(id) initWithURL:(NSURL*)urlIn
|
||||
-(instancetype) initWithURL:(NSURL*)urlIn
|
||||
{
|
||||
return [self initWithURLProvider:^NSURL* { return urlIn; }];
|
||||
}
|
||||
|
||||
-(id) initWithURL:(NSURL *)urlIn httpRequestHeaders:(NSDictionary *)httpRequestHeaders
|
||||
-(instancetype) initWithURL:(NSURL *)urlIn httpRequestHeaders:(NSDictionary *)httpRequestHeaders
|
||||
{
|
||||
self = [self initWithURLProvider:^NSURL* { return urlIn; }];
|
||||
self->requestHeaders = httpRequestHeaders;
|
||||
return self;
|
||||
}
|
||||
|
||||
-(id) initWithURLProvider:(STKURLProvider)urlProviderIn
|
||||
-(instancetype) initWithURLProvider:(STKURLProvider)urlProviderIn
|
||||
{
|
||||
urlProviderIn = [urlProviderIn copy];
|
||||
|
||||
|
|
@ -86,7 +86,7 @@
|
|||
}];
|
||||
}
|
||||
|
||||
-(id) initWithAsyncURLProvider:(STKAsyncURLProvider)asyncUrlProviderIn
|
||||
-(instancetype) initWithAsyncURLProvider:(STKAsyncURLProvider)asyncUrlProviderIn
|
||||
{
|
||||
if (self = [super init])
|
||||
{
|
||||
|
|
@ -411,7 +411,7 @@
|
|||
|
||||
eventsRunLoop = savedEventsRunLoop;
|
||||
|
||||
[self seekToOffset:self.position];
|
||||
[self seekToOffset:self->supportsSeek ? self.position : 0];
|
||||
}
|
||||
|
||||
-(void) seekToOffset:(SInt64)offset
|
||||
|
|
|
|||
|
|
@ -34,10 +34,14 @@
|
|||
|
||||
#import "STKCoreFoundationDataSource.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface STKLocalFileDataSource : STKCoreFoundationDataSource
|
||||
|
||||
+(AudioFileTypeID) audioFileTypeHintFromFileExtension:(NSString*)fileExtension;
|
||||
@property (readonly, copy) NSString* filePath;
|
||||
-(id) initWithFilePath:(NSString*)filePath;
|
||||
-(instancetype) initWithFilePath:(NSString*)filePath;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@
|
|||
@implementation STKLocalFileDataSource
|
||||
@synthesize filePath;
|
||||
|
||||
-(id) initWithFilePath:(NSString*)filePathIn
|
||||
-(instancetype) initWithFilePath:(NSString*)filePathIn
|
||||
{
|
||||
if (self = [super init])
|
||||
{
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@
|
|||
#import "libkern/OSAtomic.h"
|
||||
#import "AudioToolbox/AudioToolbox.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface STKQueueEntry : NSObject
|
||||
{
|
||||
@public
|
||||
|
|
@ -35,7 +37,7 @@
|
|||
@property (readwrite, retain) NSObject* queueItemId;
|
||||
@property (readwrite, retain) STKDataSource* dataSource;
|
||||
|
||||
-(id) initWithDataSource:(STKDataSource*)dataSource andQueueItemId:(NSObject*)queueItemId;
|
||||
-(instancetype) initWithDataSource:(STKDataSource*)dataSource andQueueItemId:(NSObject*)queueItemId;
|
||||
|
||||
-(void) reset;
|
||||
-(double) duration;
|
||||
|
|
@ -43,4 +45,6 @@
|
|||
-(double) calculatedBitRate;
|
||||
-(BOOL) isDefinitelyCompatible:(AudioStreamBasicDescription*)basicDescription;
|
||||
|
||||
@end
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
@implementation STKQueueEntry
|
||||
|
||||
-(id) initWithDataSource:(STKDataSource*)dataSourceIn andQueueItemId:(NSObject*)queueItemIdIn
|
||||
-(instancetype) initWithDataSource:(STKDataSource*)dataSourceIn andQueueItemId:(NSObject*)queueItemIdIn
|
||||
{
|
||||
if (self = [super init])
|
||||
{
|
||||
|
|
@ -121,4 +121,4 @@
|
|||
return [[self queueItemId] description];
|
||||
}
|
||||
|
||||
@end
|
||||
@end
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
<key>CFBundleExecutable</key>
|
||||
<string>${EXECUTABLE_NAME}</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.abstractpath.${PRODUCT_NAME:rfc1034identifier}</string>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
<key>CFBundleExecutable</key>
|
||||
<string>${EXECUTABLE_NAME}</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>abstractpath.com.${PRODUCT_NAME:rfc1034identifier}</string>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
|
|
|
|||
Loading…
Reference in New Issue