Compare commits

..

34 Commits

Author SHA1 Message Date
Anton 6b6a5ad434 STKAutoRecoveringHTTPDataSource http errors handling fix 2016-09-22 16:07:06 +03:00
Anton 7def768397 Merge branch 'master' of https://github.com/tumtumtum/StreamingKit
# Conflicts:
#	StreamingKit/StreamingKit/STKAudioPlayer.h
#	StreamingKit/StreamingKit/STKAudioPlayer.m
#	StreamingKit/StreamingKit/STKQueueEntry.m
2016-06-15 00:35:31 +03:00
Николай Ашанин 532bac1e07 buffer size in seconds to float
decibel commented
2016-02-09 04:41:35 +03:00
Николай Ашанин 15a9f6d395 aef to stk 2016-02-08 19:09:59 +03:00
Николай Ашанин d13282d84e add float converter 2016-02-08 18:56:16 +03:00
Николай Ашанин dfe6c73621 add vizualizer for player buffers 2016-02-08 00:21:29 +03:00
Thong Nguyen 2d251d5150 Updated podspec 2016-01-04 11:06:47 +00:00
Thong Nguyen 2043330287 Removed commented out bad code 2016-01-04 11:05:20 +00:00
Thong Nguyen 3cb6349c97 Merge pull request #209 from corprew/patch-1
spelling fix
2015-12-19 23:14:54 +00:00
Thong Nguyen b51035a267 Merge branch 'richardgroves-patch-1' 2015-12-19 23:14:13 +00:00
Thong Nguyen 0d0280b631 Fix conflicts with richardgroves-patch-1 2015-12-19 23:14:02 +00:00
Thong Nguyen f9f8199015 Merge branch 'NOUSguide-master' 2015-12-19 23:11:33 +00:00
Thong Nguyen d9a6ba7248 Fixed conflicts 2015-12-19 23:11:25 +00:00
Thong Nguyen 6264442f58 Merge pull request #247 from kwillick/master
Swift compatibilty improvements
2015-12-19 23:09:30 +00:00
Kipp Hickman 830ed0f3db Added nullablity tags for better Swift compatibility. 2015-12-18 14:04:31 -08:00
Kipp Hickman 6ef69bacf0 Changed init methods to return instancetype instead of id.
Using instancetype allows the compiler to perform more error
checking. This article provides an in-depth explanation:
http://nshipster.com/instancetype/.
2015-12-18 14:04:24 -08:00
Thong Nguyen d8b77ae214 Fixed bug in progressInFrames 2015-12-11 01:06:53 +00:00
Thong Nguyen 499e54731d Merge pull request #175 from sergiou87/master
Paused Audio Player doesn't transit to Stopped state on stop
2015-12-11 01:02:14 +00:00
Thong Nguyen da71b04aaf Updated version number in podspec 2015-12-07 13:02:44 +00:00
Thong Nguyen 55a314b966 Fix int->double truncation when doing duration calculation 2015-12-07 13:00:53 +00:00
Thong Nguyen 8fa821a944 Fixed int->double truncation in duration calculation 2015-12-07 12:59:32 +00:00
Thong Nguyen 0f69b7ea76 Merge pull request #239 from reindernijhoff/master
Fixed memory leak
2015-12-06 14:00:49 +00:00
Reinder Nijhoff 4d0fccdd70 Fixed memory leak 2015-12-06 14:06:15 +01:00
Thong Nguyen 5909657368 Changed enums to NS_ENUM to better support Swift. Added launch images to remove warnings 2015-12-04 22:47:14 +00:00
Thong Nguyen 50bec46acc Fixed build issue with OSSTATUS_PRINTF_VALUE on 64bit 2015-12-03 17:25:30 +00:00
Thong Nguyen dec8b87498 Updated podspec version 2015-12-03 16:18:50 +00:00
Thong Nguyen f872de223d Added support for disabling buffers in options using STK_DISABLE_BUFFER. Changed bufferSizeInSeconds from a UInt32 to Float32 2015-12-03 16:18:06 +00:00
kampfgnu f84f1ef0bd use brackets to test for formatID 2015-11-26 11:43:41 +01:00
kampfgnu 3bc3a85df3 fix mono streams
by removing a line that is already removed in v 0.1.25, but not in master...
2015-11-26 11:41:07 +01:00
kampfgnu 520f98a6b3 fix reconnect to live streams
seeking to a non-zero offset works only if seek is supported (accept-ranges header)
2015-11-10 11:02:57 +01:00
Thong Nguyen 4f72249c94 Fixed License 2015-10-29 18:16:01 +00:00
Richard Groves 726ec86d77 Update STKAudioPlayer.m
The original line throws this warning in XCode - 
...../External Libraries/StreamingKit/StreamingKit/StreamingKit/STKAudioPlayer.m:880:61: Comparison of constant 'kAudioFormatLinearPCM' (1819304813) with boolean expression is always false

I'm guessing the precedence of ! vs == causes it to be 'mis-interpreted'.

Not quite sure of the logic where audio format != linear PCM implies a discontinuous stream, but...
2015-06-26 11:45:29 +01:00
Corprew Reed 15b0242305 spelling fix 2015-06-18 14:14:47 -07:00
Sergio Padrino de99ec9d7a Make sure the audio player changes to stopped state when it's stopped from paused state 2015-01-14 16:56:06 +01:00
36 changed files with 664 additions and 138 deletions

View File

@ -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;

View File

@ -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;
}

View File

@ -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];

View File

@ -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>

View File

@ -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",

View File

@ -0,0 +1,6 @@
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}

View File

@ -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

View File

@ -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>

View File

@ -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

View File

@ -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.

View File

@ -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'

View File

@ -15,6 +15,8 @@
5B949CD71A1140E4005675A0 /* STKHTTPDataSource.h in Headers */ = {isa = PBXBuildFile; fileRef = A1E7C4FB188D5E550010896F /* STKHTTPDataSource.h */; settings = {ATTRIBUTES = (Public, ); }; };
5B949CD81A1140E4005675A0 /* STKLocalFileDataSource.h in Headers */ = {isa = PBXBuildFile; fileRef = A1E7C4FD188D5E550010896F /* STKLocalFileDataSource.h */; settings = {ATTRIBUTES = (Public, ); }; };
5B949CD91A1140E4005675A0 /* STKQueueEntry.h in Headers */ = {isa = PBXBuildFile; fileRef = A1BF65D0189A6582004DD08C /* STKQueueEntry.h */; settings = {ATTRIBUTES = (Public, ); }; };
95F80F4E1C68EE2300DB24B3 /* STKFloatConverter.h in Headers */ = {isa = PBXBuildFile; fileRef = 95F80F4C1C68EE2300DB24B3 /* STKFloatConverter.h */; };
95F80F4F1C68EE2300DB24B3 /* STKFloatConverter.m in Sources */ = {isa = PBXBuildFile; fileRef = 95F80F4D1C68EE2300DB24B3 /* STKFloatConverter.m */; };
A1A4996B189E744400E2A2E2 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A1A4996A189E744400E2A2E2 /* Cocoa.framework */; };
A1A49975189E744500E2A2E2 /* StreamingKitMac.m in Sources */ = {isa = PBXBuildFile; fileRef = A1A49974189E744500E2A2E2 /* StreamingKitMac.m */; };
A1A4997B189E744500E2A2E2 /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A1E7C4D9188D57F60010896F /* XCTest.framework */; };
@ -91,6 +93,8 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
95F80F4C1C68EE2300DB24B3 /* STKFloatConverter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = STKFloatConverter.h; sourceTree = "<group>"; };
95F80F4D1C68EE2300DB24B3 /* STKFloatConverter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = STKFloatConverter.m; sourceTree = "<group>"; };
A1A49969189E744400E2A2E2 /* libStreamingKitMac.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libStreamingKitMac.a; sourceTree = BUILT_PRODUCTS_DIR; };
A1A4996A189E744400E2A2E2 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = Library/Frameworks/Cocoa.framework; sourceTree = DEVELOPER_DIR; };
A1A4996D189E744500E2A2E2 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
@ -270,6 +274,8 @@
A1E7C4CD188D57F50010896F /* StreamingKit */ = {
isa = PBXGroup;
children = (
95F80F4C1C68EE2300DB24B3 /* STKFloatConverter.h */,
95F80F4D1C68EE2300DB24B3 /* STKFloatConverter.m */,
A1E7C4F1188D5E550010896F /* STKAudioPlayer.h */,
A1E7C4F2188D5E550010896F /* STKAudioPlayer.m */,
A1E7C4F3188D5E550010896F /* STKAutoRecoveringHTTPDataSource.h */,
@ -331,6 +337,7 @@
5B949CD41A1140E4005675A0 /* STKCoreFoundationDataSource.h in Headers */,
5B949CD51A1140E4005675A0 /* STKDataSource.h in Headers */,
5B949CD61A1140E4005675A0 /* STKDataSourceWrapper.h in Headers */,
95F80F4E1C68EE2300DB24B3 /* STKFloatConverter.h in Headers */,
5B949CD71A1140E4005675A0 /* STKHTTPDataSource.h in Headers */,
5B949CD81A1140E4005675A0 /* STKLocalFileDataSource.h in Headers */,
5B949CD91A1140E4005675A0 /* STKQueueEntry.h in Headers */,
@ -425,7 +432,7 @@
isa = PBXProject;
attributes = {
CLASSPREFIX = STK;
LastUpgradeCheck = 0610;
LastUpgradeCheck = 0710;
ORGANIZATIONNAME = "Thong Nguyen";
};
buildConfigurationList = A1E7C4C3188D57F50010896F /* Build configuration list for PBXProject "StreamingKit" */;
@ -525,6 +532,7 @@
A1E7C505188D5E550010896F /* STKLocalFileDataSource.m in Sources */,
A1BF65D2189A6582004DD08C /* STKQueueEntry.m in Sources */,
A1E7C504188D5E550010896F /* STKHTTPDataSource.m in Sources */,
95F80F4F1C68EE2300DB24B3 /* STKFloatConverter.m in Sources */,
A1E7C503188D5E550010896F /* STKDataSourceWrapper.m in Sources */,
A1E7C502188D5E550010896F /* STKDataSource.m in Sources */,
A1BF65D5189A65C6004DD08C /* NSMutableArray+STKAudioPlayer.m in Sources */,
@ -633,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;
@ -653,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;
@ -676,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;
@ -776,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;
};
@ -792,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;
};

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:">
</FileRef>
</Workspace>

View File

@ -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

View File

@ -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
@ -91,7 +95,7 @@ typedef struct
/// The size of the internal I/O read buffer. This data in this buffer is transient and does not need to be larger.
UInt32 readBufferSize;
/// The size of the decompressed buffer (Default is 10 seconds which uses about 1.7MB of RAM)
UInt32 bufferSizeInSeconds;
float bufferSizeInSeconds;
/// Number of seconds of decompressed audio is required before playback first starts for each item (Default is 0.5 seconds. Must be larger than bufferSizeInSeconds)
Float32 secondsRequiredToStartPlaying;
/// Seconds after a seek is performed before data needs to come in (after which the state will change to playing/buffering)
@ -101,7 +105,9 @@ typedef struct
}
STKAudioPlayerOptions;
typedef void(^STKFrameFilter)(UInt32 channelsPerFrame, UInt32 bytesPerFrame, UInt32 frameCount, void* frames);
#define STK_DISABLE_BUFFER (0xffffffff)
typedef void(^STKFrameFilter)(UInt32 channelsPerFrame, UInt32 bytesPerFrame, UInt32 frameCount, float* frames);
@interface STKFrameFilterEntry : NSObject
@property (readonly) NSString* name;
@ -129,6 +135,8 @@ typedef void(^STKFrameFilter)(UInt32 channelsPerFrame, UInt32 bytesPerFrame, UIn
/// Raised when items queued items are cleared (usually because of a call to play, setDataSource or stop)
-(void) audioPlayer:(STKAudioPlayer*)audioPlayer didCancelQueuedItems:(NSArray*)queuedItems;
-(void) plotGraphWithBuffer:(float*)buffer andLength:(UInt32)count;
@end
@interface STKAudioPlayer : NSObject<STKDataSourceDelegate>
@ -147,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
@ -170,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
@ -250,17 +258,19 @@ 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).
-(float) peakPowerInDecibelsForChannel:(NSUInteger)channelNumber;
//-(float) peakPowerInDecibelsForChannel:(NSUInteger)channelNumber;
/// Reads the average power in decibals for the given channel (0 or 1)
/// Return values are between -60 (low) and 0 (high).
-(float) averagePowerInDecibelsForChannel:(NSUInteger)channelNumber;
//-(float) averagePowerInDecibelsForChannel:(NSUInteger)channelNumber;
/// Sets the gain value (from -96 low to +24 high) for an equalizer band (0 based index)
-(void) setGain:(float)gain forEqualizerBand:(int)bandIndex;
@end
NS_ASSUME_NONNULL_END

View File

@ -41,6 +41,7 @@
#import "NSMutableArray+STKAudioPlayer.h"
#import "libkern/OSAtomic.h"
#import <float.h>
#import "STKFloatConverter.h"
#ifndef DBL_MAX
#define DBL_MAX 1.7976931348623157e+308
@ -51,20 +52,20 @@
#define kOutputBus 0
#define kInputBus 1
#define STK_DBMIN (-60)
#define STK_DBOFFSET (-74.0)
//#define STK_DBMIN (-60)
//#define STK_DBOFFSET (-74.0)
#define STK_LOWPASSFILTERTIMESLICE (0.0005)
#define STK_DEFAULT_PCM_BUFFER_SIZE_IN_SECONDS (2 * 60)
#define STK_DEFAULT_PCM_BUFFER_SIZE_IN_SECONDS (0.1)
#define STK_DEFAULT_SECONDS_REQUIRED_TO_START_PLAYING (1)
#define STK_DEFAULT_SECONDS_REQUIRED_TO_START_PLAYING_AFTER_BUFFER_UNDERRUN (7.5)
#define STK_MAX_COMPRESSED_PACKETS_FOR_BITRATE_CALCULATION (4096)
#define STK_DEFAULT_READ_BUFFER_SIZE (64 * 1024)
#define STK_DEFAULT_READ_BUFFER_SIZE (128 * 1024)
#define STK_DEFAULT_PACKET_BUFFER_SIZE (2048)
#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]];
@ -96,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))) \
{ \
@ -145,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])
{
@ -271,6 +300,9 @@ static AudioStreamBasicDescription recordAudioStreamBasicDescription;
volatile BOOL disposeWasRequested;
volatile BOOL seekToTimeWasRequested;
volatile STKAudioPlayerStopReason stopReason;
float **_floatBuffers;
STKFloatConverter *_floatConverter;
}
@property (readwrite) STKAudioPlayerInternalState internalState;
@ -476,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])
{
@ -491,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;
@ -526,7 +559,21 @@ static void AudioFileStreamPacketsProc(void* clientData, UInt32 numberBytes, UIn
upcomingQueue = [[NSMutableArray alloc] init];
bufferingQueue = [[NSMutableArray alloc] init];
//initialie the float converter
// Allocate the float buffers
_floatConverter = [[STKFloatConverter alloc] initWithSourceFormat:canonicalAudioStreamBasicDescription];
size_t sizeToAllocate = sizeof(float*) * canonicalAudioStreamBasicDescription.mChannelsPerFrame;
sizeToAllocate = MAX(8, sizeToAllocate);
_floatBuffers = (float**)malloc( sizeToAllocate );
UInt32 outputBufferSize = 32 * 1024; // 32 KB
for ( int i=0; i< canonicalAudioStreamBasicDescription.mChannelsPerFrame; i++ ) {
_floatBuffers[i] = (float*)malloc(outputBufferSize);
}
[self resetPcmBuffers];
[self createAudioGraph];
[self createPlaybackThread];
@ -878,7 +925,7 @@ static void AudioFileStreamPacketsProc(void* clientData, UInt32 numberBytes, UIn
}
case kAudioFileStreamProperty_ReadyToProducePackets:
{
if (!audioConverterAudioStreamBasicDescription.mFormatID == kAudioFormatLinearPCM)
if (audioConverterAudioStreamBasicDescription.mFormatID != kAudioFormatLinearPCM)
{
discontinuous = YES;
}
@ -1716,10 +1763,10 @@ static void AudioFileStreamPacketsProc(void* clientData, UInt32 numberBytes, UIn
self->pcmBufferFrameStartIndex = 0;
self->pcmBufferUsedFrameCount = 0;
self->peakPowerDb[0] = STK_DBMIN;
self->peakPowerDb[1] = STK_DBMIN;
self->averagePowerDb[0] = STK_DBMIN;
self->averagePowerDb[1] = STK_DBMIN;
// self->peakPowerDb[0] = STK_DBMIN;
// self->peakPowerDb[1] = STK_DBMIN;
// self->averagePowerDb[0] = STK_DBMIN;
// self->averagePowerDb[1] = STK_DBMIN;
OSSpinLockUnlock(&pcmBufferSpinLock);
}
@ -1948,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)
@ -2414,6 +2459,9 @@ static BOOL GetHardwareCodecClassDesc(UInt32 formatId, AudioClassDescription* cl
}
else if (!isRunning)
{
stopReason = stopReasonIn;
self.internalState = STKAudioPlayerInternalStateStopped;
return;
}
@ -3207,60 +3255,66 @@ static OSStatus OutputRenderCallback(void* inRefCon, AudioUnitRenderActionFlags*
}
else
{
[self appendFrameFilterWithName:@"STKMeteringFilter" block:^(UInt32 channelsPerFrame, UInt32 bytesPerFrame, UInt32 frameCount, void* frames)
[self appendFrameFilterWithName:@"STKMeteringFilter" block:^(UInt32 channelsPerFrame, UInt32 bytesPerFrame, UInt32 frameCount, float* frames)
{
SInt16* samples16 = (SInt16*)frames;
SInt32* samples32 = (SInt32*)frames;
UInt32 countLeft = 0;
UInt32 countRight = 0;
Float32 decibelsLeft = STK_DBMIN;
Float32 peakValueLeft = STK_DBMIN;
Float64 totalValueLeft = 0;
Float32 previousFilteredValueOfSampleAmplitudeLeft = 0;
Float32 decibelsRight = STK_DBMIN;
Float32 peakValueRight = STK_DBMIN;
Float64 totalValueRight = 0;
Float32 previousFilteredValueOfSampleAmplitudeRight = 0;
if (bytesPerFrame / channelsPerFrame == 2)
{
for (int i = 0; i < frameCount * channelsPerFrame; i += channelsPerFrame)
{
Float32 absoluteValueOfSampleAmplitudeLeft = abs(samples16[i]);
Float32 absoluteValueOfSampleAmplitudeRight = abs(samples16[i + 1]);
CALCULATE_METER(Left);
CALCULATE_METER(Right);
}
}
else if (bytesPerFrame / channelsPerFrame == 4)
{
for (int i = 0; i < frameCount * channelsPerFrame; i += channelsPerFrame)
{
Float32 absoluteValueOfSampleAmplitudeLeft = abs(samples32[i]) / 32768.0;
Float32 absoluteValueOfSampleAmplitudeRight = abs(samples32[i + 1]) / 32768.0;
CALCULATE_METER(Left);
CALCULATE_METER(Right);
}
}
else
{
return;
}
peakPowerDb[0] = MIN(MAX(decibelsLeft, -60), 0);
peakPowerDb[1] = MIN(MAX(decibelsRight, -60), 0);
if (countLeft > 0)
{
averagePowerDb[0] = MIN(MAX(totalValueLeft / frameCount, -60), 0);
}
if (countRight != 0)
{
averagePowerDb[1] = MIN(MAX(totalValueRight / frameCount, -60), 0);
}
STKFloatConverterToFloat(_floatConverter,&(pcmAudioBufferList),_floatBuffers,frameCount);
if ([self.delegate respondsToSelector:@selector(plotGraphWithBuffer:andLength:)]) {
[self.delegate plotGraphWithBuffer:*(_floatBuffers) andLength:frameCount];
}
// SInt16* samples16 = (SInt16*)frames;
// SInt32* samples32 = (SInt32*)frames;
// UInt32 countLeft = 0;
// UInt32 countRight = 0;
// Float32 decibelsLeft = STK_DBMIN;
// Float32 peakValueLeft = STK_DBMIN;
// Float64 totalValueLeft = 0;
// Float32 previousFilteredValueOfSampleAmplitudeLeft = 0;
// Float32 decibelsRight = STK_DBMIN;
// Float32 peakValueRight = STK_DBMIN;
// Float64 totalValueRight = 0;
// Float32 previousFilteredValueOfSampleAmplitudeRight = 0;
//
// if (bytesPerFrame / channelsPerFrame == 2)
// {
// for (int i = 0; i < frameCount * channelsPerFrame; i += channelsPerFrame)
// {
// Float32 absoluteValueOfSampleAmplitudeLeft = abs(samples16[i]);
// Float32 absoluteValueOfSampleAmplitudeRight = abs(samples16[i + 1]);
//
// CALCULATE_METER(Left);
// CALCULATE_METER(Right);
// }
// }
// else if (bytesPerFrame / channelsPerFrame == 4)
// {
// for (int i = 0; i < frameCount * channelsPerFrame; i += channelsPerFrame)
// {
// Float32 absoluteValueOfSampleAmplitudeLeft = abs(samples32[i]) / 32768.0;
// Float32 absoluteValueOfSampleAmplitudeRight = abs(samples32[i + 1]) / 32768.0;
//
// CALCULATE_METER(Left);
// CALCULATE_METER(Right);
// }
// }
// else
// {
// return;
// }
//
// peakPowerDb[0] = MIN(MAX(decibelsLeft, -60), 0);
// peakPowerDb[1] = MIN(MAX(decibelsRight, -60), 0);
//
// if (countLeft > 0)
// {
// averagePowerDb[0] = MIN(MAX(totalValueLeft / frameCount, -60), 0);
// }
//
// if (countRight != 0)
// {
// averagePowerDb[1] = MIN(MAX(totalValueRight / frameCount, -60), 0);
// }
}];
}
}

View File

@ -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

View File

@ -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])
{

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -40,7 +40,7 @@
@implementation STKDataSourceWrapper
-(id) initWithDataSource:(STKDataSource*)innerDataSourceIn
-(instancetype) initWithDataSource:(STKDataSource*)innerDataSourceIn
{
if (self = [super init])
{

View File

@ -0,0 +1,124 @@
//
// AEFloatConverter.h
// The Amazing Audio Engine
//
// Created by Michael Tyson on 25/10/2012.
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
#ifdef __cplusplus
extern "C" {
#endif
#import <Foundation/Foundation.h>
#import <AudioToolbox/AudioToolbox.h>
/*!
* Universal converter to float format
*
* Use this class to easily convert arbitrary audio formats to floating point
* for use with utilities like the Accelerate framework.
*/
@interface STKFloatConverter : NSObject
/*!
* Initialize
*
* @param sourceFormat The audio format to use
*/
- (id)initWithSourceFormat:(AudioStreamBasicDescription)sourceFormat;
/*!
* Convert audio to floating-point
*
* This C function, safe to use in a Core Audio realtime thread context, will take
* an audio buffer list of audio in the format you provided at initialisation, and
* convert it into a noninterleaved float array.
*
* @param converter Pointer to the converter object.
* @param sourceBuffer An audio buffer list containing the source audio.
* @param targetBuffers An array of floating-point arrays to store the converted float audio into.
* Note that you must provide the correct number of arrays, to match the number of channels.
* @param frames The number of frames to convert.
* @return YES on success; NO on failure
*/
BOOL STKFloatConverterToFloat(STKFloatConverter* converter, AudioBufferList *sourceBuffer, float * const * targetBuffers, UInt32 frames);
/*!
* Convert audio to floating-point, in a buffer list
*
* This C function, safe to use in a Core Audio realtime thread context, will take
* an audio buffer list of audio in the format you provided at initialisation, and
* convert it into a noninterleaved float format.
*
* @param converter Pointer to the converter object.
* @param sourceBuffer An audio buffer list containing the source audio.
* @param targetBuffer An audio buffer list to store the converted floating-point audio.
* @param frames The number of frames to convert.
* @return YES on success; NO on failure
*/
BOOL STKFloatConverterToFloatBufferList(STKFloatConverter* converter, AudioBufferList *sourceBuffer, AudioBufferList *targetBuffer, UInt32 frames);
/*!
* Convert audio from floating-point
*
* This C function, safe to use in a Core Audio realtime thread context, will take
* an audio buffer list of audio in the format you provided at initialisation, and
* convert it into a float array.
*
* @param converter Pointer to the converter object.
* @param sourceBuffers An array of floating-point arrays containing the floating-point audio to convert.
* Note that you must provide the correct number of arrays, to match the number of channels.
* @param targetBuffer An audio buffer list to store the converted audio into.
* @param frames The number of frames to convert.
* @return YES on success; NO on failure
*/
BOOL STKFloatConverterFromFloat(STKFloatConverter* converter, float * const * sourceBuffers, AudioBufferList *targetBuffer, UInt32 frames);
/*!
* Convert audio from floating-point, in a buffer list
*
* This C function, safe to use in a Core Audio realtime thread context, will take
* an audio buffer list of audio in the format you provided at initialisation, and
* convert it into a float array.
*
* @param converter Pointer to the converter object.
* @param sourceBuffer An audio buffer list containing the source audio.
* @param targetBuffer An audio buffer list to store the converted audio into.
* @param frames The number of frames to convert.
* @return YES on success; NO on failure
*/
BOOL STKFloatConverterFromFloatBufferList(STKFloatConverter* converter, AudioBufferList *sourceBuffer, AudioBufferList *targetBuffer, UInt32 frames);
/*!
* The AudioStreamBasicDescription representing the converted floating-point format
*/
@property (nonatomic, readonly) AudioStreamBasicDescription floatingPointAudioDescription;
/*!
* The source audio format set at initialization
*/
@property (nonatomic, readonly) AudioStreamBasicDescription sourceFormat;
@end
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,211 @@
//
// AEFloatConverter.m
// The Amazing Audio Engine
//
// Created by Michael Tyson on 25/10/2012.
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
#import "STKFloatConverter.h"
#define checkResult(result,operation) (_checkResult((result),(operation),strrchr(__FILE__, '/')+1,__LINE__))
static inline BOOL _checkResult(OSStatus result, const char *operation, const char* file, int line) {
if ( result != noErr ) {
NSLog(@"%s:%d: %s result %d %08X %4.4s", file, line, operation, (int)result, (int)result, (char*)&result);
return NO;
}
return YES;
}
#define kNoMoreDataErr -2222
struct complexInputDataProc_t {
AudioBufferList *sourceBuffer;
};
@interface STKFloatConverter () {
AudioStreamBasicDescription _sourceAudioDescription;
AudioStreamBasicDescription _floatAudioDescription;
AudioConverterRef _toFloatConverter;
AudioConverterRef _fromFloatConverter;
AudioBufferList *_scratchFloatBufferList;
}
static OSStatus complexInputDataProc(AudioConverterRef inAudioConverter,
UInt32 *ioNumberDataPackets,
AudioBufferList *ioData,
AudioStreamPacketDescription **outDataPacketDescription,
void *inUserData);
@end
@implementation STKFloatConverter
@synthesize sourceFormat = _sourceAudioDescription;
-(id)initWithSourceFormat:(AudioStreamBasicDescription)sourceFormat {
if ( !(self = [super init]) ) return nil;
_floatAudioDescription.mFormatID = kAudioFormatLinearPCM;
_floatAudioDescription.mFormatFlags = kAudioFormatFlagIsFloat | kAudioFormatFlagIsPacked | kAudioFormatFlagIsNonInterleaved;
_floatAudioDescription.mChannelsPerFrame = sourceFormat.mChannelsPerFrame;
_floatAudioDescription.mBytesPerPacket = sizeof(float);
_floatAudioDescription.mFramesPerPacket = 1;
_floatAudioDescription.mBytesPerFrame = sizeof(float);
_floatAudioDescription.mBitsPerChannel = 8 * sizeof(float);
_floatAudioDescription.mSampleRate = sourceFormat.mSampleRate;
_sourceAudioDescription = sourceFormat;
if ( memcmp(&sourceFormat, &_floatAudioDescription, sizeof(AudioStreamBasicDescription)) != 0 ) {
checkResult(AudioConverterNew(&sourceFormat, &_floatAudioDescription, &_toFloatConverter), "AudioConverterNew");
checkResult(AudioConverterNew(&_floatAudioDescription, &sourceFormat, &_fromFloatConverter), "AudioConverterNew");
_scratchFloatBufferList = (AudioBufferList*)malloc(sizeof(AudioBufferList) + (_floatAudioDescription.mChannelsPerFrame-1)*sizeof(AudioBuffer));
_scratchFloatBufferList->mNumberBuffers = _floatAudioDescription.mChannelsPerFrame;
for ( int i=0; i<_scratchFloatBufferList->mNumberBuffers; i++ ) {
_scratchFloatBufferList->mBuffers[i].mNumberChannels = 1;
}
}
return self;
}
-(void)dealloc {
if ( _toFloatConverter ) AudioConverterDispose(_toFloatConverter);
if ( _fromFloatConverter ) AudioConverterDispose(_fromFloatConverter);
if ( _scratchFloatBufferList ) free(_scratchFloatBufferList);
// [super dealloc];
}
BOOL STKFloatConverterToFloat(STKFloatConverter* THIS, AudioBufferList *sourceBuffer, float * const * targetBuffers, UInt32 frames) {
if ( frames == 0 ) return YES;
if ( THIS->_toFloatConverter ) {
UInt32 priorDataByteSize = sourceBuffer->mBuffers[0].mDataByteSize;
for ( int i=0; i<sourceBuffer->mNumberBuffers; i++ ) {
sourceBuffer->mBuffers[i].mDataByteSize = frames * THIS->_sourceAudioDescription.mBytesPerFrame;
}
for ( int i=0; i<THIS->_scratchFloatBufferList->mNumberBuffers; i++ ) {
THIS->_scratchFloatBufferList->mBuffers[i].mData = targetBuffers[i];
THIS->_scratchFloatBufferList->mBuffers[i].mDataByteSize = frames * sizeof(float);
}
OSStatus result = AudioConverterFillComplexBuffer(THIS->_toFloatConverter,
complexInputDataProc,
&(struct complexInputDataProc_t) { .sourceBuffer = sourceBuffer },
&frames,
THIS->_scratchFloatBufferList,
NULL);
for ( int i=0; i<sourceBuffer->mNumberBuffers; i++ ) {
sourceBuffer->mBuffers[i].mDataByteSize = priorDataByteSize;
}
if ( !checkResult(result, "AudioConverterConvertComplexBuffer") ) {
return NO;
}
} else {
for ( int i=0; i<sourceBuffer->mNumberBuffers; i++ ) {
memcpy(targetBuffers[i], sourceBuffer->mBuffers[i].mData, frames * sizeof(float));
}
}
return YES;
}
BOOL STKFloatConverterToFloatBufferList(STKFloatConverter* converter, AudioBufferList *sourceBuffer, AudioBufferList *targetBuffer, UInt32 frames) {
assert(targetBuffer->mNumberBuffers == converter->_floatAudioDescription.mChannelsPerFrame);
float *targetBuffers[targetBuffer->mNumberBuffers];
for ( int i=0; i<targetBuffer->mNumberBuffers; i++ ) {
targetBuffers[i] = (float*)targetBuffer->mBuffers[i].mData;
}
return STKFloatConverterToFloat(converter, sourceBuffer, targetBuffers, frames);
}
BOOL STKFloatConverterFromFloat(STKFloatConverter* THIS, float * const * sourceBuffers, AudioBufferList *targetBuffer, UInt32 frames) {
if ( frames == 0 ) return YES;
if ( THIS->_fromFloatConverter ) {
for ( int i=0; i<THIS->_scratchFloatBufferList->mNumberBuffers; i++ ) {
THIS->_scratchFloatBufferList->mBuffers[i].mData = sourceBuffers[i];
THIS->_scratchFloatBufferList->mBuffers[i].mDataByteSize = frames * sizeof(float);
}
UInt32 priorDataByteSize = targetBuffer->mBuffers[0].mDataByteSize;
for ( int i=0; i<targetBuffer->mNumberBuffers; i++ ) {
targetBuffer->mBuffers[i].mDataByteSize = frames * THIS->_sourceAudioDescription.mBytesPerFrame;
}
OSStatus result = AudioConverterFillComplexBuffer(THIS->_fromFloatConverter,
complexInputDataProc,
&(struct complexInputDataProc_t) { .sourceBuffer = THIS->_scratchFloatBufferList },
&frames,
targetBuffer,
NULL);
for ( int i=0; i<targetBuffer->mNumberBuffers; i++ ) {
targetBuffer->mBuffers[i].mDataByteSize = priorDataByteSize;
}
if ( !checkResult(result, "AudioConverterConvertComplexBuffer") ) {
return NO;
}
} else {
for ( int i=0; i<targetBuffer->mNumberBuffers; i++ ) {
memcpy(targetBuffer->mBuffers[i].mData, sourceBuffers[i], frames * sizeof(float));
}
}
return YES;
}
BOOL STKFloatConverterFromFloatBufferList(STKFloatConverter* converter, AudioBufferList *sourceBuffer, AudioBufferList *targetBuffer, UInt32 frames) {
assert(sourceBuffer->mNumberBuffers == converter->_floatAudioDescription.mChannelsPerFrame);
float *sourceBuffers[sourceBuffer->mNumberBuffers];
for ( int i=0; i<sourceBuffer->mNumberBuffers; i++ ) {
sourceBuffers[i] = (float*)sourceBuffer->mBuffers[i].mData;
}
return STKFloatConverterFromFloat(converter, sourceBuffers, targetBuffer, frames);
}
static OSStatus complexInputDataProc(AudioConverterRef inAudioConverter,
UInt32 *ioNumberDataPackets,
AudioBufferList *ioData,
AudioStreamPacketDescription **outDataPacketDescription,
void *inUserData) {
struct complexInputDataProc_t *arg = (struct complexInputDataProc_t*)inUserData;
if ( !arg->sourceBuffer ) {
return kNoMoreDataErr;
}
memcpy(ioData, arg->sourceBuffer, sizeof(AudioBufferList) + (arg->sourceBuffer->mNumberBuffers-1)*sizeof(AudioBuffer));
arg->sourceBuffer = NULL;
return noErr;
}
-(AudioStreamBasicDescription)floatingPointAudioDescription {
return _floatAudioDescription;
}
@end

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -47,7 +47,7 @@
@implementation STKLocalFileDataSource
@synthesize filePath;
-(id) initWithFilePath:(NSString*)filePathIn
-(instancetype) initWithFilePath:(NSString*)filePathIn
{
if (self = [super init])
{

View File

@ -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

View File

@ -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

View File

@ -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>

View File

@ -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>