diff --git a/AudioStreamer/Categories/NSMutableArray+QueueMethods.h b/AudioStreamer/Categories/NSMutableArray+QueueMethods.h new file mode 100755 index 0000000..1250430 --- /dev/null +++ b/AudioStreamer/Categories/NSMutableArray+QueueMethods.h @@ -0,0 +1,17 @@ +// +// NSMutableArray+QueueMethods.h +// TDAudioPlayer +// +// Created by Tony DiPasquale on 11/12/13. +// Copyright (c) 2013 Tony DiPasquale. The MIT License (MIT). +// + +#import + +@interface NSMutableArray (QueueMethods) + +- (void)pushObject:(id)object; +- (id)popObject; +- (id)topObject; + +@end diff --git a/AudioStreamer/Categories/NSMutableArray+QueueMethods.m b/AudioStreamer/Categories/NSMutableArray+QueueMethods.m new file mode 100755 index 0000000..a7e9c3e --- /dev/null +++ b/AudioStreamer/Categories/NSMutableArray+QueueMethods.m @@ -0,0 +1,38 @@ +// +// NSMutableArray+QueueMethods.m +// TDAudioPlayer +// +// Created by Tony DiPasquale on 11/12/13. +// Copyright (c) 2013 Tony DiPasquale. The MIT License (MIT). +// + +#import "NSMutableArray+QueueMethods.h" + +@implementation NSMutableArray (QueueMethods) + +- (void)pushObject:(id)object +{ + [self addObject:object]; +} + +- (id)popObject +{ + if (self.count > 0) { + id object = self[0]; + [self removeObjectAtIndex:0]; + return object; + } + + return nil; +} + +- (id)topObject +{ + if (self.count > 0) { + return self[0]; + } + + return nil; +} + +@end diff --git a/AudioStreamer/Classes/TDAudioFileStream.h b/AudioStreamer/Classes/TDAudioFileStream.h new file mode 100755 index 0000000..91d5cec --- /dev/null +++ b/AudioStreamer/Classes/TDAudioFileStream.h @@ -0,0 +1,38 @@ +// +// TDAudioFileStream.h +// TDAudioStreamer +// +// Created by Tony DiPasquale on 10/4/13. +// Copyright (c) 2013 Tony DiPasquale. The MIT License (MIT). +// + +#import +#import + +@class TDAudioFileStream; +@protocol TDAudioFileStreamDelegate + +- (void)audioFileStream:(TDAudioFileStream *)audioFileStream didReceiveError:(OSStatus)error; + +@required +- (void)audioFileStreamDidBecomeReady:(TDAudioFileStream *)audioFileStream; +- (void)audioFileStream:(TDAudioFileStream *)audioFileStream didReceiveData:(const void *)data length:(UInt32)length packetDescription:(AudioStreamPacketDescription)packetDescription; +- (void)audioFileStream:(TDAudioFileStream *)audioFileStream didReceiveData:(const void *)data length:(UInt32)length; + +@end + +@interface TDAudioFileStream : NSObject + +@property (assign, nonatomic) AudioStreamBasicDescription basicDescription; +@property (assign, nonatomic) UInt64 totalByteCount; +@property (assign, nonatomic) UInt32 packetBufferSize; +@property (assign, nonatomic) void *magicCookieData; +@property (assign, nonatomic) UInt32 magicCookieLength; +@property (assign, nonatomic) BOOL discontinuous; +@property (assign, nonatomic) id delegate; + +- (instancetype)init; + +- (void)parseData:(const void *)data length:(UInt32)length; + +@end diff --git a/AudioStreamer/Classes/TDAudioFileStream.m b/AudioStreamer/Classes/TDAudioFileStream.m new file mode 100755 index 0000000..4468af2 --- /dev/null +++ b/AudioStreamer/Classes/TDAudioFileStream.m @@ -0,0 +1,112 @@ +// +// TDAudioFileStream.m +// TDAudioStreamer +// +// Created by Tony DiPasquale on 10/4/13. +// Copyright (c) 2013 Tony DiPasquale. The MIT License (MIT). +// + +#import "TDAudioFileStream.h" + +@interface TDAudioFileStream () + +@property (assign, nonatomic) AudioFileStreamID audioFileStreamID; + +- (void)didChangeProperty:(AudioFileStreamPropertyID)propertyID flags:(UInt32 *)flags; +- (void)didReceivePackets:(const void *)packets packetDescriptions:(AudioStreamPacketDescription *)packetDescriptions numberOfPackets:(UInt32)numberOfPackets numberOfBytes:(UInt32)numberOfBytes; + +@end + +void TDAudioFileStreamPropertyListener(void *inClientData, AudioFileStreamID inAudioFileStreamID, AudioFileStreamPropertyID inPropertyID, UInt32 *ioFlags) +{ + TDAudioFileStream *audioFileStream = (__bridge TDAudioFileStream *)inClientData; + [audioFileStream didChangeProperty:inPropertyID flags:ioFlags]; +} + +void TDAudioFileStreamPacketsListener(void *inClientData, UInt32 inNumberBytes, UInt32 inNumberPackets, const void *inInputData, AudioStreamPacketDescription *inPacketDescriptions) +{ + TDAudioFileStream *audioFileStream = (__bridge TDAudioFileStream *)inClientData; + [audioFileStream didReceivePackets:inInputData packetDescriptions:inPacketDescriptions numberOfPackets:inNumberPackets numberOfBytes:inNumberBytes]; +} + +@implementation TDAudioFileStream + +- (instancetype)init +{ + self = [super init]; + if (!self) return nil; + + OSStatus err = AudioFileStreamOpen((__bridge void *)self, TDAudioFileStreamPropertyListener, TDAudioFileStreamPacketsListener, 0, &_audioFileStreamID); + + if (err) return nil; + + self.discontinuous = YES; + + return self; +} + +- (void)didChangeProperty:(AudioFileStreamPropertyID)propertyID flags:(UInt32 *)flags +{ + if (propertyID == kAudioFileStreamProperty_ReadyToProducePackets) { + UInt32 basicDescriptionSize = sizeof(self.basicDescription); + OSStatus err = AudioFileStreamGetProperty(self.audioFileStreamID, kAudioFileStreamProperty_DataFormat, &basicDescriptionSize, &_basicDescription); + + if (err) return [self.delegate audioFileStream:self didReceiveError:err]; + + UInt32 byteCountSize; + AudioFileStreamGetProperty(self.audioFileStreamID, kAudioFileStreamProperty_AudioDataByteCount, &byteCountSize, &_totalByteCount); + + UInt32 sizeOfUInt32 = sizeof(UInt32); + err = AudioFileStreamGetProperty(self.audioFileStreamID, kAudioFileStreamProperty_PacketSizeUpperBound, &sizeOfUInt32, &_packetBufferSize); + + if (err || !self.packetBufferSize) { + AudioFileStreamGetProperty(self.audioFileStreamID, kAudioFileStreamProperty_MaximumPacketSize, &sizeOfUInt32, &_packetBufferSize); + } + + Boolean writeable; + err = AudioFileStreamGetPropertyInfo(self.audioFileStreamID, kAudioFileStreamProperty_MagicCookieData, &_magicCookieLength, &writeable); + + if (!err) { + self.magicCookieData = calloc(1, self.magicCookieLength); + AudioFileStreamGetProperty(self.audioFileStreamID, kAudioFileStreamProperty_MagicCookieData, &_magicCookieLength, self.magicCookieData); + } + + [self.delegate audioFileStreamDidBecomeReady:self]; + } +} + +- (void)didReceivePackets:(const void *)packets packetDescriptions:(AudioStreamPacketDescription *)packetDescriptions numberOfPackets:(UInt32)numberOfPackets numberOfBytes:(UInt32)numberOfBytes +{ + if (packetDescriptions) { + for (NSUInteger i = 0; i < numberOfPackets; i++) { + SInt64 packetOffset = packetDescriptions[i].mStartOffset; + UInt32 packetSize = packetDescriptions[i].mDataByteSize; + + [self.delegate audioFileStream:self didReceiveData:(const void *)(packets + packetOffset) length:packetSize packetDescription:(AudioStreamPacketDescription)packetDescriptions[i]]; + } + } else { + [self.delegate audioFileStream:self didReceiveData:(const void *)packets length:numberOfBytes]; + } +} + +- (void)parseData:(const void *)data length:(UInt32)length +{ + OSStatus err; + + if (self.discontinuous) { + err = AudioFileStreamParseBytes(self.audioFileStreamID, length, data, kAudioFileStreamParseFlag_Discontinuity); + self.discontinuous = NO; + } else { + err = AudioFileStreamParseBytes(self.audioFileStreamID, length, data, 0); + } + + if (err) [self.delegate audioFileStream:self didReceiveError:err]; +} + +- (void)dealloc +{ + AudioFileStreamClose(self.audioFileStreamID); + free(_magicCookieData); +} + +@end diff --git a/AudioStreamer/Classes/TDAudioQueue.h b/AudioStreamer/Classes/TDAudioQueue.h new file mode 100755 index 0000000..46c8233 --- /dev/null +++ b/AudioStreamer/Classes/TDAudioQueue.h @@ -0,0 +1,45 @@ +// +// TDAudioQueue.h +// TDAudioStreamer +// +// Created by Tony DiPasquale on 10/4/13. +// Copyright (c) 2013 Tony DiPasquale. The MIT License (MIT). +// + +#import +#import + +typedef NS_ENUM(NSUInteger, TDAudioQueueState) { + TDAudioQueueStateBuffering, + TDAudioQueueStateStopped, + TDAudioQueueStatePaused, + TDAudioQueueStatePlaying +}; + +@class TDAudioQueue; + +@protocol TDAudioQueueDelegate + +- (void)audioQueueDidFinishPlaying:(TDAudioQueue *)audioQueue; +- (void)audioQueueDidStartPlaying:(TDAudioQueue *)audioQueue; + +@end + +@class TDAudioQueueBuffer; + +@interface TDAudioQueue : NSObject + +@property (assign, nonatomic) TDAudioQueueState state; +@property (assign, nonatomic) id delegate; + +- (instancetype)initWithBasicDescription:(AudioStreamBasicDescription)basicDescription bufferCount:(UInt32)bufferCount bufferSize:(UInt32)bufferSize magicCookieData:(void *)magicCookieData magicCookieSize:(UInt32)magicCookieSize; + +- (TDAudioQueueBuffer *)nextFreeBuffer; +- (void)enqueue; + +- (void)play; +- (void)pause; +- (void)stop; +- (void)finish; + +@end diff --git a/AudioStreamer/Classes/TDAudioQueue.m b/AudioStreamer/Classes/TDAudioQueue.m new file mode 100755 index 0000000..9404b49 --- /dev/null +++ b/AudioStreamer/Classes/TDAudioQueue.m @@ -0,0 +1,141 @@ +// +// TDAudioQueue.m +// TDAudioStreamer +// +// Created by Tony DiPasquale on 10/4/13. +// Copyright (c) 2013 Tony DiPasquale. The MIT License (MIT). +// + +#import "TDAudioQueue.h" +#import "TDAudioQueueBuffer.h" +#import "TDAudioQueueController.h" +#import "TDAudioQueueBufferManager.h" +#import "TDAudioStreamerConstants.h" + +@interface TDAudioQueue () + +@property (assign, nonatomic) AudioQueueRef audioQueue; +@property (strong, nonatomic) TDAudioQueueBufferManager *bufferManager; +@property (strong, nonatomic) NSCondition *waitForFreeBufferCondition; +@property (assign, nonatomic) NSUInteger buffersToFillBeforeStart; + +- (void)didFreeAudioQueueBuffer:(AudioQueueBufferRef)audioQueueBuffer; + +@end + +void TDAudioQueueOutputCallback(void *inUserData, AudioQueueRef inAudioQueue, AudioQueueBufferRef inAudioQueueBuffer) +{ + TDAudioQueue *audioQueue = (__bridge TDAudioQueue *)inUserData; + [audioQueue didFreeAudioQueueBuffer:inAudioQueueBuffer]; +} + +@implementation TDAudioQueue + +- (instancetype)initWithBasicDescription:(AudioStreamBasicDescription)basicDescription bufferCount:(UInt32)bufferCount bufferSize:(UInt32)bufferSize magicCookieData:(void *)magicCookieData magicCookieSize:(UInt32)magicCookieSize +{ + self = [self init]; + if (!self) return nil; + + OSStatus err = AudioQueueNewOutput(&basicDescription, TDAudioQueueOutputCallback, (__bridge void *)self, NULL, NULL, 0, &_audioQueue); + + if (err) return nil; + + self.bufferManager = [[TDAudioQueueBufferManager alloc] initWithAudioQueue:self.audioQueue size:bufferSize count:bufferCount]; + + AudioQueueSetProperty(self.audioQueue, kAudioQueueProperty_MagicCookie, magicCookieData, magicCookieSize); + free(magicCookieData); + + AudioQueueSetParameter(self.audioQueue, kAudioQueueParam_Volume, 1.0); + + self.waitForFreeBufferCondition = [[NSCondition alloc] init]; + self.state = TDAudioQueueStateBuffering; + self.buffersToFillBeforeStart = kTDAudioQueueStartMinimumBuffers; + + return self; +} + +#pragma mark - Audio Queue Events + +- (void)didFreeAudioQueueBuffer:(AudioQueueBufferRef)audioQueueBuffer +{ + [self.bufferManager freeAudioQueueBuffer:audioQueueBuffer]; + + [self.waitForFreeBufferCondition lock]; + [self.waitForFreeBufferCondition signal]; + [self.waitForFreeBufferCondition unlock]; + + if (self.state == TDAudioQueueStateStopped && ![self.bufferManager isProcessingAudioQueueBuffer]) { + [self.delegate audioQueueDidFinishPlaying:self]; + } +} + +#pragma mark - Public Methods + +- (TDAudioQueueBuffer *)nextFreeBuffer +{ + if (![self.bufferManager hasAvailableAudioQueueBuffer]) { + [self.waitForFreeBufferCondition lock]; + [self.waitForFreeBufferCondition wait]; + [self.waitForFreeBufferCondition unlock]; + } + + TDAudioQueueBuffer *nextBuffer = [self.bufferManager nextFreeBuffer]; + + if (!nextBuffer) return [self nextFreeBuffer]; + return nextBuffer; +} + +- (void)enqueue +{ + [self.bufferManager enqueueNextBufferOnAudioQueue:self.audioQueue]; + + if (self.state == TDAudioQueueStateBuffering && --self.buffersToFillBeforeStart == 0) { + AudioQueuePrime(self.audioQueue, 0, NULL); + [self play]; + [self.delegate audioQueueDidStartPlaying:self]; + } +} + +#pragma mark - Audio Queue Controls + +- (void)play +{ + if (self.state == TDAudioQueueStatePlaying) return; + + [TDAudioQueueController playAudioQueue:self.audioQueue]; + self.state = TDAudioQueueStatePlaying; +} + +- (void)pause +{ + if (self.state == TDAudioQueueStatePaused) return; + + [TDAudioQueueController pauseAudioQueue:self.audioQueue]; + self.state = TDAudioQueueStatePaused; +} + +- (void)stop +{ + if (self.state == TDAudioQueueStateStopped) return; + + [TDAudioQueueController stopAudioQueue:self.audioQueue]; + self.state = TDAudioQueueStateStopped; +} + +- (void)finish +{ + if (self.state == TDAudioQueueStateStopped) return; + + [TDAudioQueueController finishAudioQueue:self.audioQueue]; + self.state = TDAudioQueueStateStopped; +} + +#pragma mark - Cleanup + +- (void)dealloc +{ + [self.bufferManager freeBufferMemoryFromAudioQueue:self.audioQueue]; + AudioQueueDispose(self.audioQueue, YES); +} + +@end diff --git a/AudioStreamer/Classes/TDAudioQueueBuffer.h b/AudioStreamer/Classes/TDAudioQueueBuffer.h new file mode 100755 index 0000000..ed15aae --- /dev/null +++ b/AudioStreamer/Classes/TDAudioQueueBuffer.h @@ -0,0 +1,26 @@ +// +// TDAudioQueueBuffer.h +// TDAudioStreamer +// +// Created by Tony DiPasquale on 10/11/13. +// Copyright (c) 2013 Tony DiPasquale. The MIT License (MIT). +// + +#import +#import + +@interface TDAudioQueueBuffer : NSObject + +- (instancetype)initWithAudioQueue:(AudioQueueRef)audioQueue size:(UInt32)size; + +- (NSInteger)fillWithData:(const void *)data length:(UInt32)length offset:(UInt32)offset; +- (BOOL)fillWithData:(const void *)data length:(UInt32)length packetDescription:(AudioStreamPacketDescription)packetDescription; + +- (void)enqueueWithAudioQueue:(AudioQueueRef)auidoQueue; +- (void)reset; + +- (BOOL)isEqual:(AudioQueueBufferRef)audioQueueBuffer; + +- (void)freeFromAudioQueue:(AudioQueueRef)audioQueue; + +@end diff --git a/AudioStreamer/Classes/TDAudioQueueBuffer.m b/AudioStreamer/Classes/TDAudioQueueBuffer.m new file mode 100755 index 0000000..ff04c09 --- /dev/null +++ b/AudioStreamer/Classes/TDAudioQueueBuffer.m @@ -0,0 +1,106 @@ +// +// TDAudioQueueBuffer.m +// TDAudioStreamer +// +// Created by Tony DiPasquale on 10/11/13. +// Copyright (c) 2013 Tony DiPasquale. The MIT License (MIT). +// + +#import "TDAudioQueueBuffer.h" + +const NSUInteger kTDMaxPacketDescriptions = 512; + +@interface TDAudioQueueBuffer () + +@property (assign, nonatomic) AudioQueueBufferRef audioQueueBuffer; +@property (assign, nonatomic) UInt32 size; +@property (assign, nonatomic) UInt32 fillPosition; +@property (assign, nonatomic) AudioStreamPacketDescription *packetDescriptions; +@property (assign, nonatomic) UInt32 numberOfPacketDescriptions; + +@end + +@implementation TDAudioQueueBuffer + +- (instancetype)initWithAudioQueue:(AudioQueueRef)audioQueue size:(UInt32)size +{ + self = [super init]; + if (!self) return nil; + + self.size = size; + self.fillPosition = 0; + self.packetDescriptions = malloc(sizeof(AudioStreamPacketDescription) * kTDMaxPacketDescriptions); + self.numberOfPacketDescriptions = 0; + + OSStatus err = AudioQueueAllocateBuffer(audioQueue, self.size, &_audioQueueBuffer); + + if (err) return nil; + + return self; +} + +- (NSInteger)fillWithData:(const void *)data length:(UInt32)length offset:(UInt32)offset +{ + if (self.fillPosition + length <= self.size) + { + memcpy((char *)(self.audioQueueBuffer->mAudioData + self.fillPosition), (const char *)(data + offset), length); + self.fillPosition += length; + } + else + { + NSUInteger availableSpace = self.size - self.fillPosition; + memcpy((char *)(self.audioQueueBuffer->mAudioData + self.fillPosition), (const char *)data, availableSpace); + self.fillPosition = self.size; + return length - availableSpace; + } + + if (self.fillPosition == self.size) { + return -1; + } + + return 0; +} + +- (BOOL)fillWithData:(const void *)data length:(UInt32)length packetDescription:(AudioStreamPacketDescription)packetDescription +{ + if (self.fillPosition + packetDescription.mDataByteSize > self.size || self.numberOfPacketDescriptions == kTDMaxPacketDescriptions) return NO; + + memcpy((char *)(self.audioQueueBuffer->mAudioData + self.fillPosition), (const char *)(data + packetDescription.mStartOffset), packetDescription.mDataByteSize); + + self.packetDescriptions[self.numberOfPacketDescriptions] = packetDescription; + self.packetDescriptions[self.numberOfPacketDescriptions].mStartOffset = self.fillPosition; + self.numberOfPacketDescriptions++; + + self.fillPosition += packetDescription.mDataByteSize; + + return YES; +} + +- (void)enqueueWithAudioQueue:(AudioQueueRef)audioQueue +{ + self.audioQueueBuffer->mAudioDataByteSize = self.fillPosition; + AudioQueueEnqueueBuffer(audioQueue, self.audioQueueBuffer, self.numberOfPacketDescriptions, self.packetDescriptions); +} + +- (void)reset +{ + self.fillPosition = 0; + self.numberOfPacketDescriptions = 0; +} + +- (BOOL)isEqual:(AudioQueueBufferRef)audioQueueBuffer +{ + return audioQueueBuffer == self.audioQueueBuffer; +} + +- (void)freeFromAudioQueue:(AudioQueueRef)audioQueue +{ + AudioQueueFreeBuffer(audioQueue, self.audioQueueBuffer); +} + +- (void)dealloc +{ + free(_packetDescriptions); +} + +@end diff --git a/AudioStreamer/Classes/TDAudioQueueBufferManager.h b/AudioStreamer/Classes/TDAudioQueueBufferManager.h new file mode 100755 index 0000000..b823c17 --- /dev/null +++ b/AudioStreamer/Classes/TDAudioQueueBufferManager.h @@ -0,0 +1,27 @@ +// +// TDAudioQueueBufferManager.h +// TDAudioStreamer +// +// Created by Tony DiPasquale on 10/29/13. +// Copyright (c) 2013 Tony DiPasquale. The MIT License (MIT). +// + +#import +#import + +@class TDAudioQueueBuffer; + +@interface TDAudioQueueBufferManager : NSObject + +- (instancetype)initWithAudioQueue:(AudioQueueRef)audioQueue size:(UInt32)size count:(UInt32)count; + +- (void)freeAudioQueueBuffer:(AudioQueueBufferRef)audioQueueBuffer; +- (TDAudioQueueBuffer *)nextFreeBuffer; +- (void)enqueueNextBufferOnAudioQueue:(AudioQueueRef)audioQueue; + +- (BOOL)hasAvailableAudioQueueBuffer; +- (BOOL)isProcessingAudioQueueBuffer; + +- (void)freeBufferMemoryFromAudioQueue:(AudioQueueRef)audioQueue; + +@end diff --git a/AudioStreamer/Classes/TDAudioQueueBufferManager.m b/AudioStreamer/Classes/TDAudioQueueBufferManager.m new file mode 100755 index 0000000..fc91760 --- /dev/null +++ b/AudioStreamer/Classes/TDAudioQueueBufferManager.m @@ -0,0 +1,114 @@ +// +// TDAudioQueueBufferManager.m +// TDAudioStreamer +// +// Created by Tony DiPasquale on 10/29/13. +// Copyright (c) 2013 Tony DiPasquale. The MIT License (MIT). +// + +#import "TDAudioQueueBufferManager.h" +#import "TDAudioQueueBuffer.h" +#import "NSMutableArray+QueueMethods.h" + +@interface TDAudioQueueBufferManager () + +@property (assign, nonatomic) UInt32 bufferCount; +@property (assign, nonatomic) UInt32 bufferSize; +@property (strong, nonatomic) NSArray *audioQueueBuffers; +@property (strong, atomic) NSMutableArray *freeBuffers; + +@end + +@implementation TDAudioQueueBufferManager + +- (instancetype)initWithAudioQueue:(AudioQueueRef)audioQueue size:(UInt32)size count:(UInt32)count +{ + self = [super init]; + if (!self) return nil; + + self.bufferCount = count; + self.bufferSize = size; + + self.freeBuffers = [NSMutableArray arrayWithCapacity:self.bufferCount]; + NSMutableArray *audioqueuebuffers = [NSMutableArray arrayWithCapacity:self.bufferCount]; + + for (NSUInteger i = 0; i < self.bufferCount; i++) { + TDAudioQueueBuffer *buffer = [[TDAudioQueueBuffer alloc] initWithAudioQueue:audioQueue size:self.bufferSize]; + + if (!buffer) { + i--; + continue; + } + + audioqueuebuffers[i] = buffer; + [self.freeBuffers pushObject:@(i)]; + } + + self.audioQueueBuffers = [audioqueuebuffers copy]; + + return self; +} + +#pragma mark - Public Methods + +- (void)freeAudioQueueBuffer:(AudioQueueBufferRef)audioQueueBuffer +{ + for (NSUInteger i = 0; i < self.bufferCount; i++) { + if ([(TDAudioQueueBuffer *)self.audioQueueBuffers[i] isEqual:audioQueueBuffer]) { + [(TDAudioQueueBuffer *)self.audioQueueBuffers[i] reset]; + + @synchronized(self) { + [self.freeBuffers pushObject:@(i)]; + } + break; + } + } + +#if DEBUG + if (self.freeBuffers.count > self.bufferCount >> 1) { + NSLog(@"Free Buffers: %lu", (unsigned long)self.freeBuffers.count); + } +#endif +} + +- (TDAudioQueueBuffer *)nextFreeBuffer +{ + if (![self hasAvailableAudioQueueBuffer]) return nil; + @synchronized(self) { + return self.audioQueueBuffers[[[self.freeBuffers topObject] integerValue]]; + } +} + +- (void)enqueueNextBufferOnAudioQueue:(AudioQueueRef)audioQueue +{ + @synchronized(self) { + NSInteger nextBufferIndex = [[self.freeBuffers popObject] integerValue]; + TDAudioQueueBuffer *nextBuffer = self.audioQueueBuffers[nextBufferIndex]; + [nextBuffer enqueueWithAudioQueue:audioQueue]; + } +} + +- (BOOL)hasAvailableAudioQueueBuffer +{ + @synchronized(self) { + return self.freeBuffers.count > 0; + } +} + +- (BOOL)isProcessingAudioQueueBuffer +{ + @synchronized(self) { + return self.freeBuffers.count != self.bufferCount; + } +} + +#pragma mark - Cleanup + +- (void)freeBufferMemoryFromAudioQueue:(AudioQueueRef)audioQueue +{ + for (NSUInteger i = 0; i < self.audioQueueBuffers.count; i++) { + [(TDAudioQueueBuffer *)self.audioQueueBuffers[i] freeFromAudioQueue:audioQueue]; + } +} + +@end diff --git a/AudioStreamer/Classes/TDAudioQueueController.h b/AudioStreamer/Classes/TDAudioQueueController.h new file mode 100755 index 0000000..c2a38b2 --- /dev/null +++ b/AudioStreamer/Classes/TDAudioQueueController.h @@ -0,0 +1,19 @@ +// +// TDAudioQueueController.h +// TDAudioStreamer +// +// Created by Tony DiPasquale on 10/29/13. +// Copyright (c) 2013 Tony DiPasquale. The MIT License (MIT). +// + +#import +#import + +@interface TDAudioQueueController : NSObject + ++ (OSStatus)playAudioQueue:(AudioQueueRef)audioQueue; ++ (OSStatus)pauseAudioQueue:(AudioQueueRef)audioQueue; ++ (OSStatus)stopAudioQueue:(AudioQueueRef)audioQueue; ++ (OSStatus)finishAudioQueue:(AudioQueueRef)audioQueue; + +@end diff --git a/AudioStreamer/Classes/TDAudioQueueController.m b/AudioStreamer/Classes/TDAudioQueueController.m new file mode 100755 index 0000000..0c3c4e2 --- /dev/null +++ b/AudioStreamer/Classes/TDAudioQueueController.m @@ -0,0 +1,38 @@ +// +// TDAudioQueueController.m +// TDAudioStreamer +// +// Created by Tony DiPasquale on 10/29/13. +// Copyright (c) 2013 Tony DiPasquale. The MIT License (MIT). +// + +#import "TDAudioQueueController.h" + +@implementation TDAudioQueueController + ++ (OSStatus)playAudioQueue:(AudioQueueRef)audioQueue +{ + return AudioQueueStart(audioQueue, NULL); +} + ++ (OSStatus)pauseAudioQueue:(AudioQueueRef)audioQueue +{ + return AudioQueuePause(audioQueue); +} + ++ (OSStatus)stopAudioQueue:(AudioQueueRef)audioQueue +{ + return [self stopAudioQueue:audioQueue immediately:YES]; +} + ++ (OSStatus)finishAudioQueue:(AudioQueueRef)audioQueue +{ + return [self stopAudioQueue:audioQueue immediately:NO]; +} + ++ (OSStatus)stopAudioQueue:(AudioQueueRef)audioQueue immediately:(BOOL)immediately +{ + return AudioQueueStop(audioQueue, immediately); +} + +@end diff --git a/AudioStreamer/Classes/TDAudioQueueFiller.h b/AudioStreamer/Classes/TDAudioQueueFiller.h new file mode 100755 index 0000000..96bb958 --- /dev/null +++ b/AudioStreamer/Classes/TDAudioQueueFiller.h @@ -0,0 +1,19 @@ +// +// TDAudioQueueFiller.h +// TDAudioStreamer +// +// Created by Tony DiPasquale on 10/31/13. +// Copyright (c) 2013 Tony DiPasquale. The MIT License (MIT). +// + +#import +#import + +@class TDAudioQueue; + +@interface TDAudioQueueFiller : NSObject + ++ (void)fillAudioQueue:(TDAudioQueue *)audioQueue withData:(const void *)data length:(UInt32)length offset:(UInt32)offset; ++ (void)fillAudioQueue:(TDAudioQueue *)audioQueue withData:(const void *)data length:(UInt32)length packetDescription:(AudioStreamPacketDescription)packetDescription; + +@end diff --git a/AudioStreamer/Classes/TDAudioQueueFiller.m b/AudioStreamer/Classes/TDAudioQueueFiller.m new file mode 100755 index 0000000..7dab000 --- /dev/null +++ b/AudioStreamer/Classes/TDAudioQueueFiller.m @@ -0,0 +1,41 @@ +// +// TDAudioQueueFiller.m +// TDAudioStreamer +// +// Created by Tony DiPasquale on 10/31/13. +// Copyright (c) 2013 Tony DiPasquale. The MIT License (MIT). +// + +#import "TDAudioQueueFiller.h" +#import "TDAudioQueueBuffer.h" +#import "TDAudioQueue.h" + +@implementation TDAudioQueueFiller + ++ (void)fillAudioQueue:(TDAudioQueue *)audioQueue withData:(const void *)data length:(UInt32)length offset:(UInt32)offset +{ + TDAudioQueueBuffer *audioQueueBuffer = [audioQueue nextFreeBuffer]; + + NSInteger leftovers = [audioQueueBuffer fillWithData:data length:length offset:offset]; + + if (leftovers == 0) return; + + [audioQueue enqueue]; + + if (leftovers > 0) + [self fillAudioQueue:audioQueue withData:data length:length offset:(length - (UInt32)leftovers)]; +} + ++ (void)fillAudioQueue:(TDAudioQueue *)audioQueue withData:(const void *)data length:(UInt32)length packetDescription:(AudioStreamPacketDescription)packetDescription +{ + TDAudioQueueBuffer *audioQueueBuffer = [audioQueue nextFreeBuffer]; + + BOOL hasMoreRoomForPackets = [audioQueueBuffer fillWithData:data length:length packetDescription:packetDescription]; + + if (!hasMoreRoomForPackets) { + [audioQueue enqueue]; + [self fillAudioQueue:audioQueue withData:data length:length packetDescription:packetDescription]; + } +} + +@end diff --git a/AudioStreamer/Classes/TDAudioStream.h b/AudioStreamer/Classes/TDAudioStream.h new file mode 100755 index 0000000..1efba36 --- /dev/null +++ b/AudioStreamer/Classes/TDAudioStream.h @@ -0,0 +1,39 @@ +// +// TDAudioStream.h +// TDAudioStreamer +// +// Created by Tony DiPasquale on 10/4/13. +// Copyright (c) 2013 Tony DiPasquale. The MIT License (MIT). +// + +#import + +typedef NS_ENUM(NSUInteger, TDAudioStreamEvent) { + TDAudioStreamEventHasData, + TDAudioStreamEventWantsData, + TDAudioStreamEventEnd, + TDAudioStreamEventError +}; + +@class TDAudioStream; + +@protocol TDAudioStreamDelegate + +@required +- (void)audioStream:(TDAudioStream *)audioStream didRaiseEvent:(TDAudioStreamEvent)event; + +@end + +@interface TDAudioStream : NSObject + +@property (assign, nonatomic) id delegate; + +- (instancetype)initWithInputStream:(NSInputStream *)inputStream; +- (instancetype)initWithOutputStream:(NSOutputStream *)outputStream; + +- (void)open; +- (void)close; +- (UInt32)readData:(uint8_t *)data maxLength:(UInt32)maxLength; +- (UInt32)writeData:(uint8_t *)data maxLength:(UInt32)maxLength; + +@end diff --git a/AudioStreamer/Classes/TDAudioStream.m b/AudioStreamer/Classes/TDAudioStream.m new file mode 100755 index 0000000..e88e2af --- /dev/null +++ b/AudioStreamer/Classes/TDAudioStream.m @@ -0,0 +1,93 @@ +// +// TDAudioStream.m +// TDAudioStreamer +// +// Created by Tony DiPasquale on 10/4/13. +// Copyright (c) 2013 Tony DiPasquale. The MIT License (MIT). +// + +#import "TDAudioStream.h" + +@interface TDAudioStream () + +@property (strong, nonatomic) NSStream *stream; + +@end + +@implementation TDAudioStream + +- (instancetype)initWithInputStream:(NSInputStream *)inputStream +{ + self = [super init]; + if (!self) return nil; + + self.stream = inputStream; + + return self; +} + +- (instancetype)initWithOutputStream:(NSOutputStream *)outputStream +{ + self = [super init]; + if (!self) return nil; + + self.stream = outputStream; + + return self; +} + +- (void)open +{ + self.stream.delegate = self; + [self.stream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; + return [self.stream open]; +} + +- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode +{ + switch (eventCode) { + case NSStreamEventHasBytesAvailable: + [self.delegate audioStream:self didRaiseEvent:TDAudioStreamEventHasData]; + break; + + case NSStreamEventHasSpaceAvailable: + [self.delegate audioStream:self didRaiseEvent:TDAudioStreamEventWantsData]; + break; + + case NSStreamEventEndEncountered: + [self.delegate audioStream:self didRaiseEvent:TDAudioStreamEventEnd]; + break; + + case NSStreamEventErrorOccurred: + [self.delegate audioStream:self didRaiseEvent:TDAudioStreamEventError]; + break; + + default: + break; + } +} + +- (UInt32)readData:(uint8_t *)data maxLength:(UInt32)maxLength +{ + return (UInt32)[(NSInputStream *)self.stream read:data maxLength:maxLength]; +} + +- (UInt32)writeData:(uint8_t *)data maxLength:(UInt32)maxLength +{ + return (UInt32)[(NSOutputStream *)self.stream write:data maxLength:maxLength]; +} + +- (void)close +{ + [self.stream close]; + self.stream.delegate = nil; + [self.stream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; +} + +- (void)dealloc +{ + if (self.stream) + [self close]; +} + +@end diff --git a/AudioStreamer/TDAudioInputStreamer.h b/AudioStreamer/TDAudioInputStreamer.h new file mode 100755 index 0000000..e75e2ef --- /dev/null +++ b/AudioStreamer/TDAudioInputStreamer.h @@ -0,0 +1,24 @@ +// +// TDAudioInputStreamer.h +// TDAudioStreamer +// +// Created by Tony DiPasquale on 10/4/13. +// Copyright (c) 2013 Tony DiPasquale. The MIT License (MIT). +// + +#import + +@interface TDAudioInputStreamer : NSObject + +@property (assign, nonatomic) UInt32 audioStreamReadMaxLength; +@property (assign, nonatomic) UInt32 audioQueueBufferSize; +@property (assign, nonatomic) UInt32 audioQueueBufferCount; + +- (instancetype)initWithInputStream:(NSInputStream *)inputStream; + +- (void)start; +- (void)resume; +- (void)pause; +- (void)stop; + +@end diff --git a/AudioStreamer/TDAudioInputStreamer.m b/AudioStreamer/TDAudioInputStreamer.m new file mode 100755 index 0000000..e66b1ac --- /dev/null +++ b/AudioStreamer/TDAudioInputStreamer.m @@ -0,0 +1,195 @@ +// +// TDAudioInputStreamer.m +// TDAudioStreamer +// +// Created by Tony DiPasquale on 10/4/13. +// Copyright (c) 2013 Tony DiPasquale. The MIT License (MIT). +// + +#import "TDAudioInputStreamer.h" +#import "TDAudioFileStream.h" +#import "TDAudioStream.h" +#import "TDAudioQueue.h" +#import "TDAudioQueueBuffer.h" +#import "TDAudioQueueFiller.h" +#import "TDAudioStreamerConstants.h" + +@interface TDAudioInputStreamer () + +@property (strong, nonatomic) NSThread *audioStreamerThread; +@property (assign, atomic) BOOL isPlaying; + +@property (strong, nonatomic) TDAudioStream *audioStream; +@property (strong, nonatomic) TDAudioFileStream *audioFileStream; +@property (strong, nonatomic) TDAudioQueue *audioQueue; + +@end + +@implementation TDAudioInputStreamer + +- (instancetype)init +{ + self = [super init]; + if (!self) return nil; + + self.audioFileStream = [[TDAudioFileStream alloc] init]; + if (!self.audioFileStream) return nil; + + self.audioFileStream.delegate = self; + + return self; +} + +- (instancetype)initWithInputStream:(NSInputStream *)inputStream +{ + self = [self init]; + if (!self) return nil; + + self.audioStream = [[TDAudioStream alloc] initWithInputStream:inputStream]; + if (!self.audioStream) return nil; + + self.audioStream.delegate = self; + + return self; +} + +- (void)start +{ + if (![[NSThread currentThread] isEqual:[NSThread mainThread]]) { + return [self performSelectorOnMainThread:@selector(start) withObject:nil waitUntilDone:YES]; + } + + self.audioStreamerThread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil]; + [self.audioStreamerThread start]; +} + +- (void)run +{ + @autoreleasepool { + [self.audioStream open]; + + self.isPlaying = YES; + + while (self.isPlaying && [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]) ; + } +} + +#pragma mark - Properties + +- (UInt32)audioStreamReadMaxLength +{ + if (!_audioStreamReadMaxLength) + _audioStreamReadMaxLength = kTDAudioStreamReadMaxLength; + + return _audioStreamReadMaxLength; +} + +- (UInt32)audioQueueBufferSize +{ + if (!_audioQueueBufferSize) + _audioQueueBufferSize = kTDAudioQueueBufferSize; + + return _audioQueueBufferSize; +} + +- (UInt32)audioQueueBufferCount +{ + if (!_audioQueueBufferCount) + _audioQueueBufferCount = kTDAudioQueueBufferCount; + + return _audioQueueBufferCount; +} + +#pragma mark - TDAudioStreamDelegate + +- (void)audioStream:(TDAudioStream *)audioStream didRaiseEvent:(TDAudioStreamEvent)event +{ + switch (event) { + case TDAudioStreamEventHasData: { + uint8_t bytes[self.audioStreamReadMaxLength]; + UInt32 length = [audioStream readData:bytes maxLength:self.audioStreamReadMaxLength]; + [self.audioFileStream parseData:bytes length:length]; + break; + } + + case TDAudioStreamEventEnd: + self.isPlaying = NO; + [self.audioQueue finish]; + break; + + case TDAudioStreamEventError: + [[NSNotificationCenter defaultCenter] postNotificationName:TDAudioStreamDidFinishPlayingNotification object:nil]; + break; + + default: + break; + } +} + +#pragma mark - TDAudioFileStreamDelegate + +- (void)audioFileStreamDidBecomeReady:(TDAudioFileStream *)audioFileStream +{ + UInt32 bufferSize = audioFileStream.packetBufferSize ? audioFileStream.packetBufferSize : self.audioQueueBufferSize; + + self.audioQueue = [[TDAudioQueue alloc] initWithBasicDescription:audioFileStream.basicDescription bufferCount:self.audioQueueBufferCount bufferSize:bufferSize magicCookieData:audioFileStream.magicCookieData magicCookieSize:audioFileStream.magicCookieLength]; + + self.audioQueue.delegate = self; +} + +- (void)audioFileStream:(TDAudioFileStream *)audioFileStream didReceiveError:(OSStatus)error +{ + [[NSNotificationCenter defaultCenter] postNotificationName:TDAudioStreamDidFinishPlayingNotification object:nil]; +} + +- (void)audioFileStream:(TDAudioFileStream *)audioFileStream didReceiveData:(const void *)data length:(UInt32)length +{ + [TDAudioQueueFiller fillAudioQueue:self.audioQueue withData:data length:length offset:0]; +} + +- (void)audioFileStream:(TDAudioFileStream *)audioFileStream didReceiveData:(const void *)data length:(UInt32)length packetDescription:(AudioStreamPacketDescription)packetDescription +{ + [TDAudioQueueFiller fillAudioQueue:self.audioQueue withData:data length:length packetDescription:packetDescription]; +} + +#pragma mark - TDAudioQueueDelegate + +- (void)audioQueueDidFinishPlaying:(TDAudioQueue *)audioQueue +{ + [self performSelectorOnMainThread:@selector(notifyMainThread:) withObject:TDAudioStreamDidFinishPlayingNotification waitUntilDone:NO]; +} + +- (void)audioQueueDidStartPlaying:(TDAudioQueue *)audioQueue +{ + [self performSelectorOnMainThread:@selector(notifyMainThread:) withObject:TDAudioStreamDidStartPlayingNotification waitUntilDone:NO]; +} + +- (void)notifyMainThread:(NSString *)notificationName +{ + [[NSNotificationCenter defaultCenter] postNotificationName:notificationName object:nil]; +} + +#pragma mark - Public Methods + +- (void)resume +{ + [self.audioQueue play]; +} + +- (void)pause +{ + [self.audioQueue pause]; +} + +- (void)stop +{ + [self performSelector:@selector(stopThread) onThread:self.audioStreamerThread withObject:nil waitUntilDone:YES]; +} + +- (void)stopThread +{ + self.isPlaying = NO; + [self.audioQueue stop]; +} + +@end diff --git a/AudioStreamer/TDAudioOutputStreamer.h b/AudioStreamer/TDAudioOutputStreamer.h new file mode 100755 index 0000000..052420a --- /dev/null +++ b/AudioStreamer/TDAudioOutputStreamer.h @@ -0,0 +1,21 @@ +// +// TDAudioOutputStreamer.h +// TDAudioStreamer +// +// Created by Tony DiPasquale on 11/14/13. +// Copyright (c) 2013 Tony DiPasquale. The MIT License (MIT). +// + +#import + +@class AVURLAsset; + +@interface TDAudioOutputStreamer : NSObject + +- (instancetype)initWithOutputStream:(NSOutputStream *)stream; + +- (void)streamAudioFromURL:(NSURL *)url; +- (void)start; +- (void)stop; + +@end diff --git a/AudioStreamer/TDAudioOutputStreamer.m b/AudioStreamer/TDAudioOutputStreamer.m new file mode 100755 index 0000000..7b27d9c --- /dev/null +++ b/AudioStreamer/TDAudioOutputStreamer.m @@ -0,0 +1,144 @@ +// +// TDAudioOutputStreamer.m +// TDAudioStreamer +// +// Created by Tony DiPasquale on 11/14/13. +// Copyright (c) 2013 Tony DiPasquale. The MIT License (MIT). +// + +#import +#import "TDAudioOutputStreamer.h" +#import "TDAudioStream.h" + +@interface TDAudioOutputStreamer () + +@property (strong, nonatomic) TDAudioStream *audioStream; +@property (strong, nonatomic) AVAssetReader *assetReader; +@property (strong, nonatomic) AVAssetReaderTrackOutput *assetOutput; +@property (strong, nonatomic) NSThread *streamThread; + +@property (assign, atomic) BOOL isStreaming; + +@end + +@implementation TDAudioOutputStreamer + +- (instancetype) initWithOutputStream:(NSOutputStream *)stream +{ + self = [super init]; + if (!self) return nil; + + self.audioStream = [[TDAudioStream alloc] initWithOutputStream:stream]; + self.audioStream.delegate = self; + NSLog(@"Init"); + + return self; +} + +- (void)start +{ + if (![[NSThread currentThread] isEqual:[NSThread mainThread]]) { + return [self performSelectorOnMainThread:@selector(start) withObject:nil waitUntilDone:YES]; + } + + NSLog(@"Start"); + self.streamThread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil]; + [self.streamThread start]; +} + +- (void)run +{ + @autoreleasepool { + [self.audioStream open]; + + self.isStreaming = YES; + NSLog(@"Loop"); + + while (self.isStreaming && [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]) ; + + NSLog(@"Done"); + } +} + +- (void)streamAudioFromURL:(NSURL *)url +{ + AVURLAsset *asset = [AVURLAsset URLAssetWithURL:url options:nil]; + NSError *assetError; + + self.assetReader = [AVAssetReader assetReaderWithAsset:asset error:&assetError]; + self.assetOutput = [AVAssetReaderTrackOutput assetReaderTrackOutputWithTrack:asset.tracks[0] outputSettings:nil]; + if (![self.assetReader canAddOutput:self.assetOutput]) return; + + [self.assetReader addOutput:self.assetOutput]; + [self.assetReader startReading]; + NSLog(@"Read Asset"); +} + +- (void)sendDataChunk +{ + CMSampleBufferRef sampleBuffer; + + sampleBuffer = [self.assetOutput copyNextSampleBuffer]; + + if (sampleBuffer == NULL || CMSampleBufferGetNumSamples(sampleBuffer) == 0) { + CFRelease(sampleBuffer); + return; + } + + CMBlockBufferRef blockBuffer; + AudioBufferList audioBufferList; + + OSStatus err = CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer(sampleBuffer, NULL, &audioBufferList, sizeof(AudioBufferList), NULL, NULL, kCMSampleBufferFlag_AudioBufferList_Assure16ByteAlignment, &blockBuffer); + + if (err) { + CFRelease(sampleBuffer); + return; + } + + for (NSUInteger i = 0; i < audioBufferList.mNumberBuffers; i++) { + AudioBuffer audioBuffer = audioBufferList.mBuffers[i]; + [self.audioStream writeData:audioBuffer.mData maxLength:audioBuffer.mDataByteSize]; + NSLog(@"buffer size: %u", (unsigned int)audioBuffer.mDataByteSize); + } + + CFRelease(blockBuffer); + CFRelease(sampleBuffer); +} + +- (void)stop +{ + [self performSelector:@selector(stopThread) onThread:self.streamThread withObject:nil waitUntilDone:YES]; +} + +- (void)stopThread +{ + self.isStreaming = NO; + [self.audioStream close]; + NSLog(@"Stop"); +} + +#pragma mark - TDAudioStreamDelegate + +- (void)audioStream:(TDAudioStream *)audioStream didRaiseEvent:(TDAudioStreamEvent)event +{ + switch (event) { + case TDAudioStreamEventWantsData: + [self sendDataChunk]; + break; + + case TDAudioStreamEventError: + // TODO: shit! + NSLog(@"Stream Error"); + break; + + case TDAudioStreamEventEnd: + // TODO: shit! + NSLog(@"Stream Ended"); + break; + + default: + break; + } +} + +@end diff --git a/AudioStreamer/TDAudioStreamer.h b/AudioStreamer/TDAudioStreamer.h new file mode 100755 index 0000000..6168782 --- /dev/null +++ b/AudioStreamer/TDAudioStreamer.h @@ -0,0 +1,17 @@ +// +// TDAudioStreamer.h +// TDAudioStreamer +// +// Created by Tony DiPasquale on 11/18/13. +// Copyright (c) 2013 Tony DiPasquale. The MIT License (MIT). +// + +#import + +#import "TDAudioStreamerConstants.h" +#import "TDAudioInputStreamer.h" +#import "TDAudioOutputStreamer.h" + +@interface TDAudioStreamer : NSObject + +@end diff --git a/AudioStreamer/TDAudioStreamer.m b/AudioStreamer/TDAudioStreamer.m new file mode 100755 index 0000000..7949356 --- /dev/null +++ b/AudioStreamer/TDAudioStreamer.m @@ -0,0 +1,13 @@ +// +// TDAudioStreamer.m +// TDAudioStreamer +// +// Created by Tony DiPasquale on 11/18/13. +// Copyright (c) 2013 Tony DiPasquale. The MIT License (MIT). +// + +#import "TDAudioStreamer.h" + +@implementation TDAudioStreamer + +@end diff --git a/AudioStreamer/TDAudioStreamerConstants.h b/AudioStreamer/TDAudioStreamerConstants.h new file mode 100755 index 0000000..58fafdd --- /dev/null +++ b/AudioStreamer/TDAudioStreamerConstants.h @@ -0,0 +1,25 @@ +// +// TDAudioStreamerConstants.h +// TDAudioStreamer +// +// Created by Tony DiPasquale on 11/5/13. +// Copyright (c) 2013 Tony DiPasquale. The MIT License (MIT). +// + +#import + +extern NSString *const TDAudioStreamerDidChangeAudioNotification; +extern NSString *const TDAudioStreamerDidPauseNotification; +extern NSString *const TDAudioStreamerDidPlayNotification; +extern NSString *const TDAudioStreamerDidStopNotification; + +extern NSString *const TDAudioStreamerNextTrackRequestNotification; +extern NSString *const TDAudioStreamerPreviousTrackRequestNotification; + +extern NSString *const TDAudioStreamDidFinishPlayingNotification; +extern NSString *const TDAudioStreamDidStartPlayingNotification; + +extern UInt32 const kTDAudioStreamReadMaxLength; +extern UInt32 const kTDAudioQueueBufferSize; +extern UInt32 const kTDAudioQueueBufferCount; +extern UInt32 const kTDAudioQueueStartMinimumBuffers; diff --git a/AudioStreamer/TDAudioStreamerConstants.m b/AudioStreamer/TDAudioStreamerConstants.m new file mode 100755 index 0000000..6186506 --- /dev/null +++ b/AudioStreamer/TDAudioStreamerConstants.m @@ -0,0 +1,25 @@ +// +// TDAudioStreamerConstants.m +// TDAudioStreamer +// +// Created by Tony DiPasquale on 11/5/13. +// Copyright (c) 2013 Tony DiPasquale. The MIT License (MIT). +// + +#import "TDAudioStreamerConstants.h" + +NSString *const TDAudioStreamerDidChangeAudioNotification = @"TDAudioStreamerDidChangeAudioNotification"; +NSString *const TDAudioStreamerDidPauseNotification = @"TDAudioStreamerDidPauseNotification"; +NSString *const TDAudioStreamerDidPlayNotification = @"TDAudioStreamerDidPlayNotification"; +NSString *const TDAudioStreamerDidStopNotification = @"TDAudioStreamerDidStopNotification"; + +NSString *const TDAudioStreamerNextTrackRequestNotification = @"TDAudioStreamerNextTrackRequestNotification"; +NSString *const TDAudioStreamerPreviousTrackRequestNotification = @"TDAudioStreamerPreviousTrackRequestNotification"; + +NSString *const TDAudioStreamDidFinishPlayingNotification = @"TDAudioStreamDidFinishPlayingNotification"; +NSString *const TDAudioStreamDidStartPlayingNotification = @"TDAudioStreamDidStartPlayingNotification"; + +UInt32 const kTDAudioStreamReadMaxLength = 512; +UInt32 const kTDAudioQueueBufferSize = 2048; +UInt32 const kTDAudioQueueBufferCount = 16; +UInt32 const kTDAudioQueueStartMinimumBuffers = 8; diff --git a/GetHip.xcodeproj/project.pbxproj b/GetHip.xcodeproj/project.pbxproj index 834ae03..339fd0c 100644 --- a/GetHip.xcodeproj/project.pbxproj +++ b/GetHip.xcodeproj/project.pbxproj @@ -100,20 +100,18 @@ 3E5BD3161C6C45CE00266B16 /* Party@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3E5BD3131C6C45CE00266B16 /* Party@2x.png */; }; 3E5BD3171C6C45CE00266B16 /* StarPlayer@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3E5BD3141C6C45CE00266B16 /* StarPlayer@2x.png */; }; 3E627FC31C55978E005C0372 /* PartySessionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3E627FC21C55978E005C0372 /* PartySessionManager.swift */; }; - 3E627FE61C55AE35005C0372 /* NSInputStream+URLInitialization.m in Sources */ = {isa = PBXBuildFile; fileRef = 3E627FC81C55AE35005C0372 /* NSInputStream+URLInitialization.m */; }; - 3E627FE71C55AE35005C0372 /* NSMutableArray+QueueMethods.m in Sources */ = {isa = PBXBuildFile; fileRef = 3E627FCA1C55AE35005C0372 /* NSMutableArray+QueueMethods.m */; }; - 3E627FE81C55AE35005C0372 /* TDAudioMetaInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 3E627FCD1C55AE35005C0372 /* TDAudioMetaInfo.m */; }; - 3E627FE91C55AE35005C0372 /* TDAudioPlayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 3E627FCF1C55AE35005C0372 /* TDAudioPlayer.m */; }; - 3E627FEA1C55AE35005C0372 /* TDAudioFileStream.m in Sources */ = {isa = PBXBuildFile; fileRef = 3E627FD31C55AE35005C0372 /* TDAudioFileStream.m */; }; - 3E627FEB1C55AE35005C0372 /* TDAudioQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = 3E627FD51C55AE35005C0372 /* TDAudioQueue.m */; }; - 3E627FEC1C55AE35005C0372 /* TDAudioQueueBuffer.m in Sources */ = {isa = PBXBuildFile; fileRef = 3E627FD71C55AE35005C0372 /* TDAudioQueueBuffer.m */; }; - 3E627FED1C55AE35005C0372 /* TDAudioQueueBufferManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 3E627FD91C55AE35005C0372 /* TDAudioQueueBufferManager.m */; }; - 3E627FEE1C55AE35005C0372 /* TDAudioQueueController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3E627FDB1C55AE35005C0372 /* TDAudioQueueController.m */; }; - 3E627FEF1C55AE35005C0372 /* TDAudioQueueFiller.m in Sources */ = {isa = PBXBuildFile; fileRef = 3E627FDD1C55AE35005C0372 /* TDAudioQueueFiller.m */; }; - 3E627FF01C55AE35005C0372 /* TDAudioStream.m in Sources */ = {isa = PBXBuildFile; fileRef = 3E627FDF1C55AE35005C0372 /* TDAudioStream.m */; }; - 3E627FF11C55AE35005C0372 /* TDAudioInputStreamer.m in Sources */ = {isa = PBXBuildFile; fileRef = 3E627FE11C55AE35005C0372 /* TDAudioInputStreamer.m */; }; - 3E627FF21C55AE35005C0372 /* TDAudioOutputStreamer.m in Sources */ = {isa = PBXBuildFile; fileRef = 3E627FE31C55AE35005C0372 /* TDAudioOutputStreamer.m */; }; - 3E627FF31C55AE35005C0372 /* TDAudioPlayerConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = 3E627FE51C55AE35005C0372 /* TDAudioPlayerConstants.m */; }; + 3E631B3F1CB4D3150050808F /* NSMutableArray+QueueMethods.m in Sources */ = {isa = PBXBuildFile; fileRef = 3E631B271CB4D3150050808F /* NSMutableArray+QueueMethods.m */; }; + 3E631B401CB4D3150050808F /* TDAudioFileStream.m in Sources */ = {isa = PBXBuildFile; fileRef = 3E631B2A1CB4D3150050808F /* TDAudioFileStream.m */; }; + 3E631B411CB4D3150050808F /* TDAudioQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = 3E631B2C1CB4D3150050808F /* TDAudioQueue.m */; }; + 3E631B421CB4D3150050808F /* TDAudioQueueBuffer.m in Sources */ = {isa = PBXBuildFile; fileRef = 3E631B2E1CB4D3150050808F /* TDAudioQueueBuffer.m */; }; + 3E631B431CB4D3150050808F /* TDAudioQueueBufferManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 3E631B301CB4D3150050808F /* TDAudioQueueBufferManager.m */; }; + 3E631B441CB4D3150050808F /* TDAudioQueueController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3E631B321CB4D3150050808F /* TDAudioQueueController.m */; }; + 3E631B451CB4D3150050808F /* TDAudioQueueFiller.m in Sources */ = {isa = PBXBuildFile; fileRef = 3E631B341CB4D3150050808F /* TDAudioQueueFiller.m */; }; + 3E631B461CB4D3150050808F /* TDAudioStream.m in Sources */ = {isa = PBXBuildFile; fileRef = 3E631B361CB4D3150050808F /* TDAudioStream.m */; }; + 3E631B471CB4D3150050808F /* TDAudioInputStreamer.m in Sources */ = {isa = PBXBuildFile; fileRef = 3E631B381CB4D3150050808F /* TDAudioInputStreamer.m */; }; + 3E631B481CB4D3150050808F /* TDAudioOutputStreamer.m in Sources */ = {isa = PBXBuildFile; fileRef = 3E631B3A1CB4D3150050808F /* TDAudioOutputStreamer.m */; }; + 3E631B491CB4D3150050808F /* TDAudioStreamer.m in Sources */ = {isa = PBXBuildFile; fileRef = 3E631B3C1CB4D3150050808F /* TDAudioStreamer.m */; }; + 3E631B4A1CB4D3150050808F /* TDAudioStreamerConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = 3E631B3E1CB4D3150050808F /* TDAudioStreamerConstants.m */; }; 3E6738F51C6E9C7700B47C3E /* LoginController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3E6738F41C6E9C7700B47C3E /* LoginController.swift */; }; 3E6D43861C782E3200CA805F /* Decline@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 3E6D43851C782E3200CA805F /* Decline@2x.png */; }; 3E6D43891C7831B100CA805F /* InvitedToPartyViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3E6D43881C7831B100CA805F /* InvitedToPartyViewController.swift */; }; @@ -248,34 +246,30 @@ 3E5BD3131C6C45CE00266B16 /* Party@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "Party@2x.png"; path = "../../../Dropbox/Gethip/Screens/Song Playing/5 Play Screen/Assets/Party@2x.png"; sourceTree = ""; }; 3E5BD3141C6C45CE00266B16 /* StarPlayer@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "StarPlayer@2x.png"; path = "../../../Dropbox/Gethip/Screens/Song Playing/5 Play Screen/Assets/StarPlayer@2x.png"; sourceTree = ""; }; 3E627FC21C55978E005C0372 /* PartySessionManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PartySessionManager.swift; sourceTree = ""; }; - 3E627FC71C55AE35005C0372 /* NSInputStream+URLInitialization.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSInputStream+URLInitialization.h"; sourceTree = ""; }; - 3E627FC81C55AE35005C0372 /* NSInputStream+URLInitialization.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSInputStream+URLInitialization.m"; sourceTree = ""; }; - 3E627FC91C55AE35005C0372 /* NSMutableArray+QueueMethods.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSMutableArray+QueueMethods.h"; sourceTree = ""; }; - 3E627FCA1C55AE35005C0372 /* NSMutableArray+QueueMethods.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSMutableArray+QueueMethods.m"; sourceTree = ""; }; - 3E627FCC1C55AE35005C0372 /* TDAudioMetaInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TDAudioMetaInfo.h; sourceTree = ""; }; - 3E627FCD1C55AE35005C0372 /* TDAudioMetaInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TDAudioMetaInfo.m; sourceTree = ""; }; - 3E627FCE1C55AE35005C0372 /* TDAudioPlayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TDAudioPlayer.h; sourceTree = ""; }; - 3E627FCF1C55AE35005C0372 /* TDAudioPlayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TDAudioPlayer.m; sourceTree = ""; }; - 3E627FD21C55AE35005C0372 /* TDAudioFileStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TDAudioFileStream.h; sourceTree = ""; }; - 3E627FD31C55AE35005C0372 /* TDAudioFileStream.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TDAudioFileStream.m; sourceTree = ""; }; - 3E627FD41C55AE35005C0372 /* TDAudioQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TDAudioQueue.h; sourceTree = ""; }; - 3E627FD51C55AE35005C0372 /* TDAudioQueue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TDAudioQueue.m; sourceTree = ""; }; - 3E627FD61C55AE35005C0372 /* TDAudioQueueBuffer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TDAudioQueueBuffer.h; sourceTree = ""; }; - 3E627FD71C55AE35005C0372 /* TDAudioQueueBuffer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TDAudioQueueBuffer.m; sourceTree = ""; }; - 3E627FD81C55AE35005C0372 /* TDAudioQueueBufferManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TDAudioQueueBufferManager.h; sourceTree = ""; }; - 3E627FD91C55AE35005C0372 /* TDAudioQueueBufferManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TDAudioQueueBufferManager.m; sourceTree = ""; }; - 3E627FDA1C55AE35005C0372 /* TDAudioQueueController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TDAudioQueueController.h; sourceTree = ""; }; - 3E627FDB1C55AE35005C0372 /* TDAudioQueueController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TDAudioQueueController.m; sourceTree = ""; }; - 3E627FDC1C55AE35005C0372 /* TDAudioQueueFiller.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TDAudioQueueFiller.h; sourceTree = ""; }; - 3E627FDD1C55AE35005C0372 /* TDAudioQueueFiller.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TDAudioQueueFiller.m; sourceTree = ""; }; - 3E627FDE1C55AE35005C0372 /* TDAudioStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TDAudioStream.h; sourceTree = ""; }; - 3E627FDF1C55AE35005C0372 /* TDAudioStream.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TDAudioStream.m; sourceTree = ""; }; - 3E627FE01C55AE35005C0372 /* TDAudioInputStreamer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TDAudioInputStreamer.h; sourceTree = ""; }; - 3E627FE11C55AE35005C0372 /* TDAudioInputStreamer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TDAudioInputStreamer.m; sourceTree = ""; }; - 3E627FE21C55AE35005C0372 /* TDAudioOutputStreamer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TDAudioOutputStreamer.h; sourceTree = ""; }; - 3E627FE31C55AE35005C0372 /* TDAudioOutputStreamer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TDAudioOutputStreamer.m; sourceTree = ""; }; - 3E627FE41C55AE35005C0372 /* TDAudioPlayerConstants.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TDAudioPlayerConstants.h; path = "../../../../Downloads/TDAudioPlayer-master/TDAudioPlayer/AudioPlayerLibrary/TDAudioPlayerConstants.h"; sourceTree = ""; }; - 3E627FE51C55AE35005C0372 /* TDAudioPlayerConstants.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TDAudioPlayerConstants.m; path = "../../../../Downloads/TDAudioPlayer-master/TDAudioPlayer/AudioPlayerLibrary/TDAudioPlayerConstants.m"; sourceTree = ""; }; + 3E631B261CB4D3150050808F /* NSMutableArray+QueueMethods.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSMutableArray+QueueMethods.h"; sourceTree = ""; }; + 3E631B271CB4D3150050808F /* NSMutableArray+QueueMethods.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSMutableArray+QueueMethods.m"; sourceTree = ""; }; + 3E631B291CB4D3150050808F /* TDAudioFileStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TDAudioFileStream.h; sourceTree = ""; }; + 3E631B2A1CB4D3150050808F /* TDAudioFileStream.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TDAudioFileStream.m; sourceTree = ""; }; + 3E631B2B1CB4D3150050808F /* TDAudioQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TDAudioQueue.h; sourceTree = ""; }; + 3E631B2C1CB4D3150050808F /* TDAudioQueue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TDAudioQueue.m; sourceTree = ""; }; + 3E631B2D1CB4D3150050808F /* TDAudioQueueBuffer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TDAudioQueueBuffer.h; sourceTree = ""; }; + 3E631B2E1CB4D3150050808F /* TDAudioQueueBuffer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TDAudioQueueBuffer.m; sourceTree = ""; }; + 3E631B2F1CB4D3150050808F /* TDAudioQueueBufferManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TDAudioQueueBufferManager.h; sourceTree = ""; }; + 3E631B301CB4D3150050808F /* TDAudioQueueBufferManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TDAudioQueueBufferManager.m; sourceTree = ""; }; + 3E631B311CB4D3150050808F /* TDAudioQueueController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TDAudioQueueController.h; sourceTree = ""; }; + 3E631B321CB4D3150050808F /* TDAudioQueueController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TDAudioQueueController.m; sourceTree = ""; }; + 3E631B331CB4D3150050808F /* TDAudioQueueFiller.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TDAudioQueueFiller.h; sourceTree = ""; }; + 3E631B341CB4D3150050808F /* TDAudioQueueFiller.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TDAudioQueueFiller.m; sourceTree = ""; }; + 3E631B351CB4D3150050808F /* TDAudioStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TDAudioStream.h; sourceTree = ""; }; + 3E631B361CB4D3150050808F /* TDAudioStream.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TDAudioStream.m; sourceTree = ""; }; + 3E631B371CB4D3150050808F /* TDAudioInputStreamer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TDAudioInputStreamer.h; sourceTree = ""; }; + 3E631B381CB4D3150050808F /* TDAudioInputStreamer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TDAudioInputStreamer.m; sourceTree = ""; }; + 3E631B391CB4D3150050808F /* TDAudioOutputStreamer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TDAudioOutputStreamer.h; sourceTree = ""; }; + 3E631B3A1CB4D3150050808F /* TDAudioOutputStreamer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TDAudioOutputStreamer.m; sourceTree = ""; }; + 3E631B3B1CB4D3150050808F /* TDAudioStreamer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TDAudioStreamer.h; sourceTree = ""; }; + 3E631B3C1CB4D3150050808F /* TDAudioStreamer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TDAudioStreamer.m; sourceTree = ""; }; + 3E631B3D1CB4D3150050808F /* TDAudioStreamerConstants.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TDAudioStreamerConstants.h; sourceTree = ""; }; + 3E631B3E1CB4D3150050808F /* TDAudioStreamerConstants.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TDAudioStreamerConstants.m; sourceTree = ""; }; 3E6738F41C6E9C7700B47C3E /* LoginController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoginController.swift; sourceTree = ""; }; 3E6D43851C782E3200CA805F /* Decline@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "Decline@2x.png"; path = "../../../Dropbox/gethip/Screens/Invited To Join Party/5 When Invited/When Invited/Assets/Decline@2x.png"; sourceTree = ""; }; 3E6D43881C7831B100CA805F /* InvitedToPartyViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InvitedToPartyViewController.swift; sourceTree = ""; }; @@ -631,76 +625,54 @@ 3E627FC41C55ADDE005C0372 /* TDAudioPlayer.framework */ = { isa = PBXGroup; children = ( - 3E627FC51C55AE35005C0372 /* AudioPlayer */, - 3E627FD01C55AE35005C0372 /* AudioStreamer */, - 3E627FE41C55AE35005C0372 /* TDAudioPlayerConstants.h */, - 3E627FE51C55AE35005C0372 /* TDAudioPlayerConstants.m */, + 3E631B241CB4D3150050808F /* AudioStreamer */, ); name = TDAudioPlayer.framework; sourceTree = ""; }; - 3E627FC51C55AE35005C0372 /* AudioPlayer */ = { + 3E631B241CB4D3150050808F /* AudioStreamer */ = { isa = PBXGroup; children = ( - 3E627FC61C55AE35005C0372 /* Categories */, - 3E627FCB1C55AE35005C0372 /* Classes */, - 3E627FCE1C55AE35005C0372 /* TDAudioPlayer.h */, - 3E627FCF1C55AE35005C0372 /* TDAudioPlayer.m */, + 3E631B251CB4D3150050808F /* Categories */, + 3E631B281CB4D3150050808F /* Classes */, + 3E631B371CB4D3150050808F /* TDAudioInputStreamer.h */, + 3E631B381CB4D3150050808F /* TDAudioInputStreamer.m */, + 3E631B391CB4D3150050808F /* TDAudioOutputStreamer.h */, + 3E631B3A1CB4D3150050808F /* TDAudioOutputStreamer.m */, + 3E631B3B1CB4D3150050808F /* TDAudioStreamer.h */, + 3E631B3C1CB4D3150050808F /* TDAudioStreamer.m */, + 3E631B3D1CB4D3150050808F /* TDAudioStreamerConstants.h */, + 3E631B3E1CB4D3150050808F /* TDAudioStreamerConstants.m */, ); - name = AudioPlayer; - path = "../../../../Downloads/TDAudioPlayer-master/TDAudioPlayer/AudioPlayerLibrary/AudioPlayer"; - sourceTree = ""; + path = AudioStreamer; + sourceTree = SOURCE_ROOT; }; - 3E627FC61C55AE35005C0372 /* Categories */ = { + 3E631B251CB4D3150050808F /* Categories */ = { isa = PBXGroup; children = ( - 3E627FC71C55AE35005C0372 /* NSInputStream+URLInitialization.h */, - 3E627FC81C55AE35005C0372 /* NSInputStream+URLInitialization.m */, - 3E627FC91C55AE35005C0372 /* NSMutableArray+QueueMethods.h */, - 3E627FCA1C55AE35005C0372 /* NSMutableArray+QueueMethods.m */, + 3E631B261CB4D3150050808F /* NSMutableArray+QueueMethods.h */, + 3E631B271CB4D3150050808F /* NSMutableArray+QueueMethods.m */, ); path = Categories; sourceTree = ""; }; - 3E627FCB1C55AE35005C0372 /* Classes */ = { + 3E631B281CB4D3150050808F /* Classes */ = { isa = PBXGroup; children = ( - 3E627FCC1C55AE35005C0372 /* TDAudioMetaInfo.h */, - 3E627FCD1C55AE35005C0372 /* TDAudioMetaInfo.m */, - ); - path = Classes; - sourceTree = ""; - }; - 3E627FD01C55AE35005C0372 /* AudioStreamer */ = { - isa = PBXGroup; - children = ( - 3E627FD11C55AE35005C0372 /* Classes */, - 3E627FE01C55AE35005C0372 /* TDAudioInputStreamer.h */, - 3E627FE11C55AE35005C0372 /* TDAudioInputStreamer.m */, - 3E627FE21C55AE35005C0372 /* TDAudioOutputStreamer.h */, - 3E627FE31C55AE35005C0372 /* TDAudioOutputStreamer.m */, - ); - name = AudioStreamer; - path = "../../../../Downloads/TDAudioPlayer-master/TDAudioPlayer/AudioPlayerLibrary/AudioStreamer"; - sourceTree = ""; - }; - 3E627FD11C55AE35005C0372 /* Classes */ = { - isa = PBXGroup; - children = ( - 3E627FD21C55AE35005C0372 /* TDAudioFileStream.h */, - 3E627FD31C55AE35005C0372 /* TDAudioFileStream.m */, - 3E627FD41C55AE35005C0372 /* TDAudioQueue.h */, - 3E627FD51C55AE35005C0372 /* TDAudioQueue.m */, - 3E627FD61C55AE35005C0372 /* TDAudioQueueBuffer.h */, - 3E627FD71C55AE35005C0372 /* TDAudioQueueBuffer.m */, - 3E627FD81C55AE35005C0372 /* TDAudioQueueBufferManager.h */, - 3E627FD91C55AE35005C0372 /* TDAudioQueueBufferManager.m */, - 3E627FDA1C55AE35005C0372 /* TDAudioQueueController.h */, - 3E627FDB1C55AE35005C0372 /* TDAudioQueueController.m */, - 3E627FDC1C55AE35005C0372 /* TDAudioQueueFiller.h */, - 3E627FDD1C55AE35005C0372 /* TDAudioQueueFiller.m */, - 3E627FDE1C55AE35005C0372 /* TDAudioStream.h */, - 3E627FDF1C55AE35005C0372 /* TDAudioStream.m */, + 3E631B291CB4D3150050808F /* TDAudioFileStream.h */, + 3E631B2A1CB4D3150050808F /* TDAudioFileStream.m */, + 3E631B2B1CB4D3150050808F /* TDAudioQueue.h */, + 3E631B2C1CB4D3150050808F /* TDAudioQueue.m */, + 3E631B2D1CB4D3150050808F /* TDAudioQueueBuffer.h */, + 3E631B2E1CB4D3150050808F /* TDAudioQueueBuffer.m */, + 3E631B2F1CB4D3150050808F /* TDAudioQueueBufferManager.h */, + 3E631B301CB4D3150050808F /* TDAudioQueueBufferManager.m */, + 3E631B311CB4D3150050808F /* TDAudioQueueController.h */, + 3E631B321CB4D3150050808F /* TDAudioQueueController.m */, + 3E631B331CB4D3150050808F /* TDAudioQueueFiller.h */, + 3E631B341CB4D3150050808F /* TDAudioQueueFiller.m */, + 3E631B351CB4D3150050808F /* TDAudioStream.h */, + 3E631B361CB4D3150050808F /* TDAudioStream.m */, ); path = Classes; sourceTree = ""; @@ -897,56 +869,54 @@ files = ( 3E101F081C52E65300C895CA /* PartyServiceManager.swift in Sources */, 3E330B1A1C38502F00276FE4 /* LoginViewController.swift in Sources */, - 3E627FEA1C55AE35005C0372 /* TDAudioFileStream.m in Sources */, 3E1EE6391C6D02EB00F5C5D7 /* InPartyViewController.swift in Sources */, 3E627FC31C55978E005C0372 /* PartySessionManager.swift in Sources */, - 3E627FE61C55AE35005C0372 /* NSInputStream+URLInitialization.m in Sources */, 3E5485B51C69CE2F00E7D5AB /* InvitedCollectionViewCell.swift in Sources */, 3E6D43891C7831B100CA805F /* InvitedToPartyViewController.swift in Sources */, 3E37709E1CAB5EC000A66097 /* ForgotPassViewController.swift in Sources */, 3E3412571C54C31F006226E0 /* SongSelectionViewController.swift in Sources */, - 3E627FE81C55AE35005C0372 /* TDAudioMetaInfo.m in Sources */, 3E6738F51C6E9C7700B47C3E /* LoginController.swift in Sources */, 3E34125B1C54C73A006226E0 /* PartySession.swift in Sources */, + 3E631B451CB4D3150050808F /* TDAudioQueueFiller.m in Sources */, + 3E631B421CB4D3150050808F /* TDAudioQueueBuffer.m in Sources */, 3EBE825A1CB06793004A2730 /* HomeTabController.swift in Sources */, 3E50E0401C74B97300EB9EA9 /* BackToHomeScreenViewController.swift in Sources */, - 3E627FF01C55AE35005C0372 /* TDAudioStream.m in Sources */, - 3E627FE91C55AE35005C0372 /* TDAudioPlayer.m in Sources */, 3EDA82E31C4741C70081ED53 /* FriendDataSource.swift in Sources */, 3EDA82E11C473E900081ED53 /* FriendData.swift in Sources */, - 3E627FF21C55AE35005C0372 /* TDAudioOutputStreamer.m in Sources */, 3EB6B39B1C87B8AE006B674D /* JoiningPartyViewController.swift in Sources */, 3E379F051C3F982900F7BCCD /* FriendsCell.swift in Sources */, 3E1BDA571C37111D00EE3B84 /* ViewController.swift in Sources */, 3E1AAD141C3BD92600809367 /* FriendsListViewController.swift in Sources */, 3E326BCE1C51C77600F785CF /* SettingsCellWrapper.swift in Sources */, - 3E627FF31C55AE35005C0372 /* TDAudioPlayerConstants.m in Sources */, 3E5485B31C69A7DA00E7D5AB /* LoadingPartyViewController.swift in Sources */, + 3E631B411CB4D3150050808F /* TDAudioQueue.m in Sources */, 3E3B14DC1C5BBB3B001C437F /* PendingRequestViewController.swift in Sources */, 3E379EF61C3E646000F7BCCD /* ParseNetDebug.m in Sources */, - 3E627FED1C55AE35005C0372 /* TDAudioQueueBufferManager.m in Sources */, 3EBE976F1C53E6950079B54A /* InviteFriendCell.swift in Sources */, - 3E627FEF1C55AE35005C0372 /* TDAudioQueueFiller.m in Sources */, 3E1BDA551C37111D00EE3B84 /* GetHip.xcdatamodeld in Sources */, 3E326BCC1C51C20000F785CF /* SettingsTableViewController.swift in Sources */, 3EF36C761C71694C00CD0DC0 /* SignInController.swift in Sources */, + 3E631B441CB4D3150050808F /* TDAudioQueueController.m in Sources */, 3EBE97731C5413240079B54A /* TestInviteFriendsCell.swift in Sources */, + 3E631B4A1CB4D3150050808F /* TDAudioStreamerConstants.m in Sources */, 3E101F0A1C52F14A00C895CA /* InviteFriendsView.swift in Sources */, 3E1B5E451C5274E700D1AB62 /* SettingsDetailViewWrapper.swift in Sources */, + 3E631B481CB4D3150050808F /* TDAudioOutputStreamer.m in Sources */, 3EBE97711C540BB80079B54A /* TestInviteFriendsController.swift in Sources */, 3E18D4951C51FAC60012F7DF /* UserParseDataSource.swift in Sources */, - 3E627FEC1C55AE35005C0372 /* TDAudioQueueBuffer.m in Sources */, - 3E627FEB1C55AE35005C0372 /* TDAudioQueue.m in Sources */, 3E3412591C54C6B7006226E0 /* SongCellWrapper.swift in Sources */, 3E1BDA521C37111D00EE3B84 /* AppDelegate.swift in Sources */, - 3E627FF11C55AE35005C0372 /* TDAudioInputStreamer.m in Sources */, 3E4169551C398A5B00B193AF /* SignUpViewController.swift in Sources */, 3E5BD3111C6C424300266B16 /* CurrentlyPlayingViewController.swift in Sources */, - 3E627FEE1C55AE35005C0372 /* TDAudioQueueController.m in Sources */, - 3E627FE71C55AE35005C0372 /* NSMutableArray+QueueMethods.m in Sources */, 3E3B14DE1C5BCC9B001C437F /* FriendRequestViewController.swift in Sources */, + 3E631B491CB4D3150050808F /* TDAudioStreamer.m in Sources */, + 3E631B431CB4D3150050808F /* TDAudioQueueBufferManager.m in Sources */, + 3E631B461CB4D3150050808F /* TDAudioStream.m in Sources */, + 3E631B401CB4D3150050808F /* TDAudioFileStream.m in Sources */, 3E18D4931C51F6230012F7DF /* UserParseData.swift in Sources */, 3E416EEE1C97BE31001EA319 /* NextUpViewController.swift in Sources */, + 3E631B3F1CB4D3150050808F /* NSMutableArray+QueueMethods.m in Sources */, + 3E631B471CB4D3150050808F /* TDAudioInputStreamer.m in Sources */, 3E5952851C39E54A00C88C71 /* HomeScreenViewController.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/GetHip/AppDelegate.swift b/GetHip/AppDelegate.swift index 412f2c4..f572956 100644 --- a/GetHip/AppDelegate.swift +++ b/GetHip/AppDelegate.swift @@ -49,7 +49,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate , CLLocationManagerDelegat if(PFUser.currentUser() == nil){ //var initialViewController = storyboard.instantiateViewControllerWithIdentifier("HomeVC") as! HomeScreenViewController - var initialViewController = storyboard.instantiateViewControllerWithIdentifier("LoginVC") as! UITabBarController + var initialViewController = storyboard.instantiateViewControllerWithIdentifier("LoginVC") as! LoginController self.window?.rootViewController = initialViewController self.window?.makeKeyAndVisible() diff --git a/GetHip/AudioPlayer/Categories/NSInputStream+URLInitialization.h b/GetHip/AudioPlayer/Categories/NSInputStream+URLInitialization.h new file mode 100755 index 0000000..e1c50d3 --- /dev/null +++ b/GetHip/AudioPlayer/Categories/NSInputStream+URLInitialization.h @@ -0,0 +1,15 @@ +// +// NSInputStream+URLInitialization.h +// TDAudioPlayer +// +// Created by Tony DiPasquale on 11/11/13. +// Copyright (c) 2013 Tony DiPasquale. The MIT License (MIT). +// + +#import + +@interface NSInputStream (URLInitialization) + ++ (NSInputStream *)inputStreamWithExternalURL:(NSURL *)url; + +@end diff --git a/GetHip/AudioPlayer/Categories/NSInputStream+URLInitialization.m b/GetHip/AudioPlayer/Categories/NSInputStream+URLInitialization.m new file mode 100755 index 0000000..24c7268 --- /dev/null +++ b/GetHip/AudioPlayer/Categories/NSInputStream+URLInitialization.m @@ -0,0 +1,47 @@ +// +// NSInputStream+URLInitialization.m +// TDAudioPlayer +// +// Created by Tony DiPasquale on 11/11/13. +// Copyright (c) 2013 Tony DiPasquale. The MIT License (MIT). +// + +#import "NSInputStream+URLInitialization.h" + +@implementation NSInputStream (URLInitialization) + ++ (NSInputStream *)inputStreamWithExternalURL:(NSURL *)url +{ + CFHTTPMessageRef message = CFHTTPMessageCreateRequest(NULL, (CFStringRef)@"GET", (__bridge CFURLRef)(url), kCFHTTPVersion1_1); + + if (!message) return nil; + + CFReadStreamRef stream = CFReadStreamCreateForHTTPRequest(NULL, message); + CFRelease(message); + + if (!stream) return nil; + + CFReadStreamSetProperty(stream, kCFStreamPropertyHTTPShouldAutoredirect, kCFBooleanTrue); + + CFDictionaryRef proxySettings = CFNetworkCopySystemProxySettings(); + + CFReadStreamSetProperty(stream, kCFStreamPropertyHTTPProxy, proxySettings); + + CFRelease(proxySettings); + + if ([url.absoluteString rangeOfString:@"https"].location != NSNotFound) { + NSDictionary *sslSettings = @{(NSString *)kCFStreamSSLLevel: (NSString *)kCFStreamSocketSecurityLevelNegotiatedSSL, + (NSString *)kCFStreamSSLAllowsExpiredCertificates: @YES, + (NSString *)kCFStreamSSLAllowsExpiredRoots: @YES, + (NSString *)kCFStreamSSLAllowsAnyRoot: @YES, + (NSString *)kCFStreamSSLValidatesCertificateChain: @NO, + (NSString *)kCFStreamSSLPeerName: [NSNull null]}; + + CFReadStreamSetProperty(stream, kCFStreamPropertySSLSettings, (__bridge CFTypeRef)(sslSettings)); + } + +// CFRetain(stream); + return (__bridge NSInputStream *)stream; +} + +@end diff --git a/GetHip/AudioPlayer/Categories/NSMutableArray+QueueMethods.h b/GetHip/AudioPlayer/Categories/NSMutableArray+QueueMethods.h new file mode 100755 index 0000000..1250430 --- /dev/null +++ b/GetHip/AudioPlayer/Categories/NSMutableArray+QueueMethods.h @@ -0,0 +1,17 @@ +// +// NSMutableArray+QueueMethods.h +// TDAudioPlayer +// +// Created by Tony DiPasquale on 11/12/13. +// Copyright (c) 2013 Tony DiPasquale. The MIT License (MIT). +// + +#import + +@interface NSMutableArray (QueueMethods) + +- (void)pushObject:(id)object; +- (id)popObject; +- (id)topObject; + +@end diff --git a/GetHip/AudioPlayer/Categories/NSMutableArray+QueueMethods.m b/GetHip/AudioPlayer/Categories/NSMutableArray+QueueMethods.m new file mode 100755 index 0000000..a7e9c3e --- /dev/null +++ b/GetHip/AudioPlayer/Categories/NSMutableArray+QueueMethods.m @@ -0,0 +1,38 @@ +// +// NSMutableArray+QueueMethods.m +// TDAudioPlayer +// +// Created by Tony DiPasquale on 11/12/13. +// Copyright (c) 2013 Tony DiPasquale. The MIT License (MIT). +// + +#import "NSMutableArray+QueueMethods.h" + +@implementation NSMutableArray (QueueMethods) + +- (void)pushObject:(id)object +{ + [self addObject:object]; +} + +- (id)popObject +{ + if (self.count > 0) { + id object = self[0]; + [self removeObjectAtIndex:0]; + return object; + } + + return nil; +} + +- (id)topObject +{ + if (self.count > 0) { + return self[0]; + } + + return nil; +} + +@end diff --git a/GetHip/AudioPlayer/Classes/TDAudioMetaInfo.h b/GetHip/AudioPlayer/Classes/TDAudioMetaInfo.h new file mode 100755 index 0000000..52ee695 --- /dev/null +++ b/GetHip/AudioPlayer/Classes/TDAudioMetaInfo.h @@ -0,0 +1,19 @@ +// +// TDAudioMetaInfo.h +// TDAudioPlayer +// +// Created by Tony DiPasquale on 10/16/13. +// Copyright (c) 2013 Tony DiPasquale. The MIT License (MIT). +// + +#import + +@interface TDAudioMetaInfo : NSObject + +@property (strong, nonatomic) NSString *title; +@property (strong, nonatomic) NSString *artist; +@property (strong, nonatomic) NSString *albumArtSmall; +@property (strong, nonatomic) NSString *albumArtLarge; +@property (strong, nonatomic) NSNumber *duration; + +@end diff --git a/GetHip/AudioPlayer/Classes/TDAudioMetaInfo.m b/GetHip/AudioPlayer/Classes/TDAudioMetaInfo.m new file mode 100755 index 0000000..c4ffdc6 --- /dev/null +++ b/GetHip/AudioPlayer/Classes/TDAudioMetaInfo.m @@ -0,0 +1,13 @@ +// +// TDAudioMetaInfo.m +// TDAudioPlayer +// +// Created by Tony DiPasquale on 10/16/13. +// Copyright (c) 2013 Tony DiPasquale. The MIT License (MIT). +// + +#import "TDAudioMetaInfo.h" + +@implementation TDAudioMetaInfo + +@end diff --git a/GetHip/AudioPlayer/TDAudioPlayer.h b/GetHip/AudioPlayer/TDAudioPlayer.h new file mode 100755 index 0000000..3b930e8 --- /dev/null +++ b/GetHip/AudioPlayer/TDAudioPlayer.h @@ -0,0 +1,41 @@ +// +// TDAudioPlayer.h +// TDAudioPlayer +// +// Created by Tony DiPasquale on 10/16/13. +// Copyright (c) 2013 Tony DiPasquale. The MIT License (MIT). +// + +#import +#import + +#import "TDAudioMetaInfo.h" +#import "TDAudioInputStreamer.h" +#import "TDAudioPlayerConstants.h" + +typedef NS_ENUM(NSInteger, TDAudioPlayerState) { + TDAudioPlayerStateStopped, + TDAudioPlayerStateStarting, + TDAudioPlayerStatePlaying, + TDAudioPlayerStatePaused +}; + +@interface TDAudioPlayer : NSObject + +@property (assign, nonatomic, readonly) TDAudioPlayerState state; + ++ (instancetype)sharedAudioPlayer; + +- (void)loadAudioFromURL:(NSURL *)url; +- (void)loadAudioFromURL:(NSURL *)url withMetaData:(TDAudioMetaInfo *)meta; + +- (void)loadAudioFromStream:(NSInputStream *)stream; +- (void)loadAudioFromStream:(NSInputStream *)stream withMetaData:(TDAudioMetaInfo *)meta; + +- (void)play; +- (void)pause; +- (void)stop; + +- (void)handleRemoteControlEvent:(UIEvent *)event; + +@end diff --git a/GetHip/AudioPlayer/TDAudioPlayer.m b/GetHip/AudioPlayer/TDAudioPlayer.m new file mode 100755 index 0000000..39d1f35 --- /dev/null +++ b/GetHip/AudioPlayer/TDAudioPlayer.m @@ -0,0 +1,261 @@ +// +// TDAudioPlayer.m +// TDAudioPlayer +// +// Created by Tony DiPasquale on 10/16/13. +// Copyright (c) 2013 Tony DiPasquale. The MIT License (MIT). +// + +#import +#import + +#import "TDAudioPlayer.h" + +@interface TDAudioPlayer () + +@property (strong, nonatomic) TDAudioInputStreamer *streamer; +@property (strong, nonatomic) NSMutableDictionary *nowPlayingMetaInfo; +@property (assign, nonatomic) TDAudioPlayerState state; + +@property (strong, nonatomic) NSTimer *timer; +@property (assign, nonatomic) NSUInteger elapsedTime; + +@end + +@implementation TDAudioPlayer + ++ (instancetype)sharedAudioPlayer +{ + static TDAudioPlayer *player; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + player = [[TDAudioPlayer alloc] init]; + }); + return player; +} + +- (instancetype)init +{ + self = [super init]; + if (!self) return nil; + + [[AVAudioSession sharedInstance] setActive:YES error:nil]; + [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil]; + + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(audioSessionDidInterrupt:) name:AVAudioSessionInterruptionNotification object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(audioSessionDidChangeRoute:) name:AVAudioSessionRouteChangeNotification object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(audioDidStartPlaying) name:TDAudioStreamDidStartPlayingNotification object:nil]; + + return self; +} + +#pragma mark - Audio Loading + +- (void)loadAudioFromURL:(NSURL *)url +{ + [self loadAudioFromURL:url withMetaData:nil]; +} + +- (void)loadAudioFromURL:(NSURL *)url withMetaData:(TDAudioMetaInfo *)meta +{ + [self reset]; + self.streamer = [[TDAudioInputStreamer alloc] initWithURL:url]; + [self changeAudioMetaInfo:meta]; +} + +- (void)loadAudioFromStream:(NSInputStream *)stream +{ + [self loadAudioFromStream:stream withMetaData:nil]; +} + +- (void)loadAudioFromStream:(NSInputStream *)stream withMetaData:(TDAudioMetaInfo *)meta +{ + [self reset]; + self.streamer = [[TDAudioInputStreamer alloc] initWithInputStream:stream]; + [self changeAudioMetaInfo:meta]; +} + +- (void)reset +{ + [self.streamer stop]; + self.streamer = nil; + + self.state = TDAudioPlayerStateStopped; + self.elapsedTime = 0; + [self clearTimer]; +} + +#pragma mark - Audio Controls + +- (void)play +{ + if (!self.streamer || self.state == TDAudioPlayerStatePlaying) return; + if (self.state == TDAudioPlayerStateStopped) return [self start]; + + [self.streamer resume]; + [self setNowPlayingInfoWithPlaybackRate:@1]; + self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(elapseTime) userInfo:nil repeats:YES]; + self.state = TDAudioPlayerStatePlaying; + [[NSNotificationCenter defaultCenter] postNotificationName:TDAudioPlayerDidPlayNotification object:nil]; +} + +- (void)start +{ + if (self.state == TDAudioPlayerStateStarting) return; + [self.streamer start]; + self.state = TDAudioPlayerStateStarting; + [[NSNotificationCenter defaultCenter] postNotificationName:TDAudioPlayerDidPlayNotification object:nil]; +} + +- (void)pause +{ + if (!self.streamer || self.state == TDAudioPlayerStatePaused) return; + + [self setNowPlayingInfoWithPlaybackRate:@0.000001f]; + [self clearTimer]; + + [self.streamer pause]; + self.state = TDAudioPlayerStatePaused; + [[NSNotificationCenter defaultCenter] postNotificationName:TDAudioPlayerDidPauseNotification object:nil]; +} + +- (void)stop +{ + if (!self.streamer || self.state == TDAudioPlayerStateStopped) return; + [self reset]; + [[NSNotificationCenter defaultCenter] postNotificationName:TDAudioPlayerDidStopNotification object:nil]; +} + +#pragma mark - Remote Events + +- (void)handleRemoteControlEvent:(UIEvent *)event +{ + if (event.type != UIEventTypeRemoteControl) return; + + switch (event.subtype) { + case UIEventSubtypeRemoteControlPause: + [self pause]; + break; + + case UIEventSubtypeRemoteControlPlay: + [self play]; + break; + + case UIEventSubtypeRemoteControlStop: + [self stop]; + break; + + case UIEventSubtypeRemoteControlTogglePlayPause: + if (self.state == TDAudioPlayerStatePlaying) { + [self pause]; + } else { + [self play]; + } + break; + + case UIEventSubtypeRemoteControlNextTrack: + [[NSNotificationCenter defaultCenter] postNotificationName:TDAudioPlayerNextTrackRequestNotification object:nil]; + break; + + case UIEventSubtypeRemoteControlPreviousTrack: + [[NSNotificationCenter defaultCenter] postNotificationName:TDAudioPlayerPreviousTrackRequestNotification object:nil]; + break; + + default: + break; + } +} + +#pragma mark - Timer Helpers + +- (void)elapseTime +{ + self.elapsedTime++; +} + +- (void)clearTimer +{ + [self.timer invalidate]; + self.timer = nil; +} + +#pragma mark - Now Playing Info Helpers + +- (void)changeAudioMetaInfo:(TDAudioMetaInfo *)meta +{ + [self setNowPlayingInfoWithMetaInfo:meta]; + + if (!meta) + return [[NSNotificationCenter defaultCenter] postNotificationName:TDAudioPlayerDidChangeAudioNotification object:nil]; + + [[NSNotificationCenter defaultCenter] postNotificationName:TDAudioPlayerDidChangeAudioNotification object:nil userInfo:@{@"meta": meta}]; +} + +- (void)setNowPlayingInfoWithMetaInfo:(TDAudioMetaInfo *)info +{ + if (!info) { + [MPNowPlayingInfoCenter defaultCenter].nowPlayingInfo = @{}; + return; + } + + if (!self.nowPlayingMetaInfo) + self.nowPlayingMetaInfo = [NSMutableDictionary dictionary]; + else + [self.nowPlayingMetaInfo removeAllObjects]; + + if (info.title) self.nowPlayingMetaInfo[MPMediaItemPropertyTitle] = info.title; + if (info.artist) self.nowPlayingMetaInfo[MPMediaItemPropertyArtist] = info.artist; + + if (info.albumArtLarge) { + MPMediaItemArtwork *artwork = [[MPMediaItemArtwork alloc] initWithImage:[UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:info.albumArtLarge]]]]; + if (artwork) self.nowPlayingMetaInfo[MPMediaItemPropertyArtwork] = artwork; + } + + if (info.duration) self.nowPlayingMetaInfo[MPMediaItemPropertyPlaybackDuration] = info.duration; + + [self setNowPlayingInfoWithPlaybackRate:@0]; +} + +- (void)setNowPlayingInfoWithPlaybackRate:(NSNumber *)rate +{ + if (!self.nowPlayingMetaInfo) return; + + self.nowPlayingMetaInfo[MPNowPlayingInfoPropertyPlaybackRate] = rate; + self.nowPlayingMetaInfo[MPNowPlayingInfoPropertyElapsedPlaybackTime] = @(self.elapsedTime); + + [MPNowPlayingInfoCenter defaultCenter].nowPlayingInfo = self.nowPlayingMetaInfo; +} + +#pragma mark - Notification Handlers + +- (void)audioSessionDidInterrupt:(NSNotification *)notification +{ + NSUInteger type = [notification.userInfo[AVAudioSessionInterruptionTypeKey] unsignedIntegerValue]; + + if (type == AVAudioSessionInterruptionTypeBegan) + [self pause]; +} + +- (void)audioSessionDidChangeRoute:(NSNotification *)notification +{ + NSUInteger reason = [notification.userInfo[AVAudioSessionRouteChangeReasonKey] unsignedIntegerValue]; + + if (reason == AVAudioSessionRouteChangeReasonOldDeviceUnavailable) + [self pause]; +} + +- (void)audioDidStartPlaying +{ + [self setNowPlayingInfoWithPlaybackRate:@1]; + self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(elapseTime) userInfo:nil repeats:YES]; + self.state = TDAudioPlayerStatePlaying; +} + +#pragma mark - Cleanup + +- (void)dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + +@end diff --git a/GetHip/AudioStreamer/Categories/NSMutableArray+QueueMethods.h b/GetHip/AudioStreamer/Categories/NSMutableArray+QueueMethods.h new file mode 100755 index 0000000..1250430 --- /dev/null +++ b/GetHip/AudioStreamer/Categories/NSMutableArray+QueueMethods.h @@ -0,0 +1,17 @@ +// +// NSMutableArray+QueueMethods.h +// TDAudioPlayer +// +// Created by Tony DiPasquale on 11/12/13. +// Copyright (c) 2013 Tony DiPasquale. The MIT License (MIT). +// + +#import + +@interface NSMutableArray (QueueMethods) + +- (void)pushObject:(id)object; +- (id)popObject; +- (id)topObject; + +@end diff --git a/GetHip/AudioStreamer/Categories/NSMutableArray+QueueMethods.m b/GetHip/AudioStreamer/Categories/NSMutableArray+QueueMethods.m new file mode 100755 index 0000000..a7e9c3e --- /dev/null +++ b/GetHip/AudioStreamer/Categories/NSMutableArray+QueueMethods.m @@ -0,0 +1,38 @@ +// +// NSMutableArray+QueueMethods.m +// TDAudioPlayer +// +// Created by Tony DiPasquale on 11/12/13. +// Copyright (c) 2013 Tony DiPasquale. The MIT License (MIT). +// + +#import "NSMutableArray+QueueMethods.h" + +@implementation NSMutableArray (QueueMethods) + +- (void)pushObject:(id)object +{ + [self addObject:object]; +} + +- (id)popObject +{ + if (self.count > 0) { + id object = self[0]; + [self removeObjectAtIndex:0]; + return object; + } + + return nil; +} + +- (id)topObject +{ + if (self.count > 0) { + return self[0]; + } + + return nil; +} + +@end diff --git a/GetHip/AudioStreamer/Classes/TDAudioFileStream.h b/GetHip/AudioStreamer/Classes/TDAudioFileStream.h new file mode 100755 index 0000000..91d5cec --- /dev/null +++ b/GetHip/AudioStreamer/Classes/TDAudioFileStream.h @@ -0,0 +1,38 @@ +// +// TDAudioFileStream.h +// TDAudioStreamer +// +// Created by Tony DiPasquale on 10/4/13. +// Copyright (c) 2013 Tony DiPasquale. The MIT License (MIT). +// + +#import +#import + +@class TDAudioFileStream; +@protocol TDAudioFileStreamDelegate + +- (void)audioFileStream:(TDAudioFileStream *)audioFileStream didReceiveError:(OSStatus)error; + +@required +- (void)audioFileStreamDidBecomeReady:(TDAudioFileStream *)audioFileStream; +- (void)audioFileStream:(TDAudioFileStream *)audioFileStream didReceiveData:(const void *)data length:(UInt32)length packetDescription:(AudioStreamPacketDescription)packetDescription; +- (void)audioFileStream:(TDAudioFileStream *)audioFileStream didReceiveData:(const void *)data length:(UInt32)length; + +@end + +@interface TDAudioFileStream : NSObject + +@property (assign, nonatomic) AudioStreamBasicDescription basicDescription; +@property (assign, nonatomic) UInt64 totalByteCount; +@property (assign, nonatomic) UInt32 packetBufferSize; +@property (assign, nonatomic) void *magicCookieData; +@property (assign, nonatomic) UInt32 magicCookieLength; +@property (assign, nonatomic) BOOL discontinuous; +@property (assign, nonatomic) id delegate; + +- (instancetype)init; + +- (void)parseData:(const void *)data length:(UInt32)length; + +@end diff --git a/GetHip/AudioStreamer/Classes/TDAudioFileStream.m b/GetHip/AudioStreamer/Classes/TDAudioFileStream.m new file mode 100755 index 0000000..4468af2 --- /dev/null +++ b/GetHip/AudioStreamer/Classes/TDAudioFileStream.m @@ -0,0 +1,112 @@ +// +// TDAudioFileStream.m +// TDAudioStreamer +// +// Created by Tony DiPasquale on 10/4/13. +// Copyright (c) 2013 Tony DiPasquale. The MIT License (MIT). +// + +#import "TDAudioFileStream.h" + +@interface TDAudioFileStream () + +@property (assign, nonatomic) AudioFileStreamID audioFileStreamID; + +- (void)didChangeProperty:(AudioFileStreamPropertyID)propertyID flags:(UInt32 *)flags; +- (void)didReceivePackets:(const void *)packets packetDescriptions:(AudioStreamPacketDescription *)packetDescriptions numberOfPackets:(UInt32)numberOfPackets numberOfBytes:(UInt32)numberOfBytes; + +@end + +void TDAudioFileStreamPropertyListener(void *inClientData, AudioFileStreamID inAudioFileStreamID, AudioFileStreamPropertyID inPropertyID, UInt32 *ioFlags) +{ + TDAudioFileStream *audioFileStream = (__bridge TDAudioFileStream *)inClientData; + [audioFileStream didChangeProperty:inPropertyID flags:ioFlags]; +} + +void TDAudioFileStreamPacketsListener(void *inClientData, UInt32 inNumberBytes, UInt32 inNumberPackets, const void *inInputData, AudioStreamPacketDescription *inPacketDescriptions) +{ + TDAudioFileStream *audioFileStream = (__bridge TDAudioFileStream *)inClientData; + [audioFileStream didReceivePackets:inInputData packetDescriptions:inPacketDescriptions numberOfPackets:inNumberPackets numberOfBytes:inNumberBytes]; +} + +@implementation TDAudioFileStream + +- (instancetype)init +{ + self = [super init]; + if (!self) return nil; + + OSStatus err = AudioFileStreamOpen((__bridge void *)self, TDAudioFileStreamPropertyListener, TDAudioFileStreamPacketsListener, 0, &_audioFileStreamID); + + if (err) return nil; + + self.discontinuous = YES; + + return self; +} + +- (void)didChangeProperty:(AudioFileStreamPropertyID)propertyID flags:(UInt32 *)flags +{ + if (propertyID == kAudioFileStreamProperty_ReadyToProducePackets) { + UInt32 basicDescriptionSize = sizeof(self.basicDescription); + OSStatus err = AudioFileStreamGetProperty(self.audioFileStreamID, kAudioFileStreamProperty_DataFormat, &basicDescriptionSize, &_basicDescription); + + if (err) return [self.delegate audioFileStream:self didReceiveError:err]; + + UInt32 byteCountSize; + AudioFileStreamGetProperty(self.audioFileStreamID, kAudioFileStreamProperty_AudioDataByteCount, &byteCountSize, &_totalByteCount); + + UInt32 sizeOfUInt32 = sizeof(UInt32); + err = AudioFileStreamGetProperty(self.audioFileStreamID, kAudioFileStreamProperty_PacketSizeUpperBound, &sizeOfUInt32, &_packetBufferSize); + + if (err || !self.packetBufferSize) { + AudioFileStreamGetProperty(self.audioFileStreamID, kAudioFileStreamProperty_MaximumPacketSize, &sizeOfUInt32, &_packetBufferSize); + } + + Boolean writeable; + err = AudioFileStreamGetPropertyInfo(self.audioFileStreamID, kAudioFileStreamProperty_MagicCookieData, &_magicCookieLength, &writeable); + + if (!err) { + self.magicCookieData = calloc(1, self.magicCookieLength); + AudioFileStreamGetProperty(self.audioFileStreamID, kAudioFileStreamProperty_MagicCookieData, &_magicCookieLength, self.magicCookieData); + } + + [self.delegate audioFileStreamDidBecomeReady:self]; + } +} + +- (void)didReceivePackets:(const void *)packets packetDescriptions:(AudioStreamPacketDescription *)packetDescriptions numberOfPackets:(UInt32)numberOfPackets numberOfBytes:(UInt32)numberOfBytes +{ + if (packetDescriptions) { + for (NSUInteger i = 0; i < numberOfPackets; i++) { + SInt64 packetOffset = packetDescriptions[i].mStartOffset; + UInt32 packetSize = packetDescriptions[i].mDataByteSize; + + [self.delegate audioFileStream:self didReceiveData:(const void *)(packets + packetOffset) length:packetSize packetDescription:(AudioStreamPacketDescription)packetDescriptions[i]]; + } + } else { + [self.delegate audioFileStream:self didReceiveData:(const void *)packets length:numberOfBytes]; + } +} + +- (void)parseData:(const void *)data length:(UInt32)length +{ + OSStatus err; + + if (self.discontinuous) { + err = AudioFileStreamParseBytes(self.audioFileStreamID, length, data, kAudioFileStreamParseFlag_Discontinuity); + self.discontinuous = NO; + } else { + err = AudioFileStreamParseBytes(self.audioFileStreamID, length, data, 0); + } + + if (err) [self.delegate audioFileStream:self didReceiveError:err]; +} + +- (void)dealloc +{ + AudioFileStreamClose(self.audioFileStreamID); + free(_magicCookieData); +} + +@end diff --git a/GetHip/AudioStreamer/Classes/TDAudioQueue.h b/GetHip/AudioStreamer/Classes/TDAudioQueue.h new file mode 100755 index 0000000..46c8233 --- /dev/null +++ b/GetHip/AudioStreamer/Classes/TDAudioQueue.h @@ -0,0 +1,45 @@ +// +// TDAudioQueue.h +// TDAudioStreamer +// +// Created by Tony DiPasquale on 10/4/13. +// Copyright (c) 2013 Tony DiPasquale. The MIT License (MIT). +// + +#import +#import + +typedef NS_ENUM(NSUInteger, TDAudioQueueState) { + TDAudioQueueStateBuffering, + TDAudioQueueStateStopped, + TDAudioQueueStatePaused, + TDAudioQueueStatePlaying +}; + +@class TDAudioQueue; + +@protocol TDAudioQueueDelegate + +- (void)audioQueueDidFinishPlaying:(TDAudioQueue *)audioQueue; +- (void)audioQueueDidStartPlaying:(TDAudioQueue *)audioQueue; + +@end + +@class TDAudioQueueBuffer; + +@interface TDAudioQueue : NSObject + +@property (assign, nonatomic) TDAudioQueueState state; +@property (assign, nonatomic) id delegate; + +- (instancetype)initWithBasicDescription:(AudioStreamBasicDescription)basicDescription bufferCount:(UInt32)bufferCount bufferSize:(UInt32)bufferSize magicCookieData:(void *)magicCookieData magicCookieSize:(UInt32)magicCookieSize; + +- (TDAudioQueueBuffer *)nextFreeBuffer; +- (void)enqueue; + +- (void)play; +- (void)pause; +- (void)stop; +- (void)finish; + +@end diff --git a/GetHip/AudioStreamer/Classes/TDAudioQueue.m b/GetHip/AudioStreamer/Classes/TDAudioQueue.m new file mode 100755 index 0000000..9404b49 --- /dev/null +++ b/GetHip/AudioStreamer/Classes/TDAudioQueue.m @@ -0,0 +1,141 @@ +// +// TDAudioQueue.m +// TDAudioStreamer +// +// Created by Tony DiPasquale on 10/4/13. +// Copyright (c) 2013 Tony DiPasquale. The MIT License (MIT). +// + +#import "TDAudioQueue.h" +#import "TDAudioQueueBuffer.h" +#import "TDAudioQueueController.h" +#import "TDAudioQueueBufferManager.h" +#import "TDAudioStreamerConstants.h" + +@interface TDAudioQueue () + +@property (assign, nonatomic) AudioQueueRef audioQueue; +@property (strong, nonatomic) TDAudioQueueBufferManager *bufferManager; +@property (strong, nonatomic) NSCondition *waitForFreeBufferCondition; +@property (assign, nonatomic) NSUInteger buffersToFillBeforeStart; + +- (void)didFreeAudioQueueBuffer:(AudioQueueBufferRef)audioQueueBuffer; + +@end + +void TDAudioQueueOutputCallback(void *inUserData, AudioQueueRef inAudioQueue, AudioQueueBufferRef inAudioQueueBuffer) +{ + TDAudioQueue *audioQueue = (__bridge TDAudioQueue *)inUserData; + [audioQueue didFreeAudioQueueBuffer:inAudioQueueBuffer]; +} + +@implementation TDAudioQueue + +- (instancetype)initWithBasicDescription:(AudioStreamBasicDescription)basicDescription bufferCount:(UInt32)bufferCount bufferSize:(UInt32)bufferSize magicCookieData:(void *)magicCookieData magicCookieSize:(UInt32)magicCookieSize +{ + self = [self init]; + if (!self) return nil; + + OSStatus err = AudioQueueNewOutput(&basicDescription, TDAudioQueueOutputCallback, (__bridge void *)self, NULL, NULL, 0, &_audioQueue); + + if (err) return nil; + + self.bufferManager = [[TDAudioQueueBufferManager alloc] initWithAudioQueue:self.audioQueue size:bufferSize count:bufferCount]; + + AudioQueueSetProperty(self.audioQueue, kAudioQueueProperty_MagicCookie, magicCookieData, magicCookieSize); + free(magicCookieData); + + AudioQueueSetParameter(self.audioQueue, kAudioQueueParam_Volume, 1.0); + + self.waitForFreeBufferCondition = [[NSCondition alloc] init]; + self.state = TDAudioQueueStateBuffering; + self.buffersToFillBeforeStart = kTDAudioQueueStartMinimumBuffers; + + return self; +} + +#pragma mark - Audio Queue Events + +- (void)didFreeAudioQueueBuffer:(AudioQueueBufferRef)audioQueueBuffer +{ + [self.bufferManager freeAudioQueueBuffer:audioQueueBuffer]; + + [self.waitForFreeBufferCondition lock]; + [self.waitForFreeBufferCondition signal]; + [self.waitForFreeBufferCondition unlock]; + + if (self.state == TDAudioQueueStateStopped && ![self.bufferManager isProcessingAudioQueueBuffer]) { + [self.delegate audioQueueDidFinishPlaying:self]; + } +} + +#pragma mark - Public Methods + +- (TDAudioQueueBuffer *)nextFreeBuffer +{ + if (![self.bufferManager hasAvailableAudioQueueBuffer]) { + [self.waitForFreeBufferCondition lock]; + [self.waitForFreeBufferCondition wait]; + [self.waitForFreeBufferCondition unlock]; + } + + TDAudioQueueBuffer *nextBuffer = [self.bufferManager nextFreeBuffer]; + + if (!nextBuffer) return [self nextFreeBuffer]; + return nextBuffer; +} + +- (void)enqueue +{ + [self.bufferManager enqueueNextBufferOnAudioQueue:self.audioQueue]; + + if (self.state == TDAudioQueueStateBuffering && --self.buffersToFillBeforeStart == 0) { + AudioQueuePrime(self.audioQueue, 0, NULL); + [self play]; + [self.delegate audioQueueDidStartPlaying:self]; + } +} + +#pragma mark - Audio Queue Controls + +- (void)play +{ + if (self.state == TDAudioQueueStatePlaying) return; + + [TDAudioQueueController playAudioQueue:self.audioQueue]; + self.state = TDAudioQueueStatePlaying; +} + +- (void)pause +{ + if (self.state == TDAudioQueueStatePaused) return; + + [TDAudioQueueController pauseAudioQueue:self.audioQueue]; + self.state = TDAudioQueueStatePaused; +} + +- (void)stop +{ + if (self.state == TDAudioQueueStateStopped) return; + + [TDAudioQueueController stopAudioQueue:self.audioQueue]; + self.state = TDAudioQueueStateStopped; +} + +- (void)finish +{ + if (self.state == TDAudioQueueStateStopped) return; + + [TDAudioQueueController finishAudioQueue:self.audioQueue]; + self.state = TDAudioQueueStateStopped; +} + +#pragma mark - Cleanup + +- (void)dealloc +{ + [self.bufferManager freeBufferMemoryFromAudioQueue:self.audioQueue]; + AudioQueueDispose(self.audioQueue, YES); +} + +@end diff --git a/GetHip/AudioStreamer/Classes/TDAudioQueueBuffer.h b/GetHip/AudioStreamer/Classes/TDAudioQueueBuffer.h new file mode 100755 index 0000000..ed15aae --- /dev/null +++ b/GetHip/AudioStreamer/Classes/TDAudioQueueBuffer.h @@ -0,0 +1,26 @@ +// +// TDAudioQueueBuffer.h +// TDAudioStreamer +// +// Created by Tony DiPasquale on 10/11/13. +// Copyright (c) 2013 Tony DiPasquale. The MIT License (MIT). +// + +#import +#import + +@interface TDAudioQueueBuffer : NSObject + +- (instancetype)initWithAudioQueue:(AudioQueueRef)audioQueue size:(UInt32)size; + +- (NSInteger)fillWithData:(const void *)data length:(UInt32)length offset:(UInt32)offset; +- (BOOL)fillWithData:(const void *)data length:(UInt32)length packetDescription:(AudioStreamPacketDescription)packetDescription; + +- (void)enqueueWithAudioQueue:(AudioQueueRef)auidoQueue; +- (void)reset; + +- (BOOL)isEqual:(AudioQueueBufferRef)audioQueueBuffer; + +- (void)freeFromAudioQueue:(AudioQueueRef)audioQueue; + +@end diff --git a/GetHip/AudioStreamer/Classes/TDAudioQueueBuffer.m b/GetHip/AudioStreamer/Classes/TDAudioQueueBuffer.m new file mode 100755 index 0000000..ff04c09 --- /dev/null +++ b/GetHip/AudioStreamer/Classes/TDAudioQueueBuffer.m @@ -0,0 +1,106 @@ +// +// TDAudioQueueBuffer.m +// TDAudioStreamer +// +// Created by Tony DiPasquale on 10/11/13. +// Copyright (c) 2013 Tony DiPasquale. The MIT License (MIT). +// + +#import "TDAudioQueueBuffer.h" + +const NSUInteger kTDMaxPacketDescriptions = 512; + +@interface TDAudioQueueBuffer () + +@property (assign, nonatomic) AudioQueueBufferRef audioQueueBuffer; +@property (assign, nonatomic) UInt32 size; +@property (assign, nonatomic) UInt32 fillPosition; +@property (assign, nonatomic) AudioStreamPacketDescription *packetDescriptions; +@property (assign, nonatomic) UInt32 numberOfPacketDescriptions; + +@end + +@implementation TDAudioQueueBuffer + +- (instancetype)initWithAudioQueue:(AudioQueueRef)audioQueue size:(UInt32)size +{ + self = [super init]; + if (!self) return nil; + + self.size = size; + self.fillPosition = 0; + self.packetDescriptions = malloc(sizeof(AudioStreamPacketDescription) * kTDMaxPacketDescriptions); + self.numberOfPacketDescriptions = 0; + + OSStatus err = AudioQueueAllocateBuffer(audioQueue, self.size, &_audioQueueBuffer); + + if (err) return nil; + + return self; +} + +- (NSInteger)fillWithData:(const void *)data length:(UInt32)length offset:(UInt32)offset +{ + if (self.fillPosition + length <= self.size) + { + memcpy((char *)(self.audioQueueBuffer->mAudioData + self.fillPosition), (const char *)(data + offset), length); + self.fillPosition += length; + } + else + { + NSUInteger availableSpace = self.size - self.fillPosition; + memcpy((char *)(self.audioQueueBuffer->mAudioData + self.fillPosition), (const char *)data, availableSpace); + self.fillPosition = self.size; + return length - availableSpace; + } + + if (self.fillPosition == self.size) { + return -1; + } + + return 0; +} + +- (BOOL)fillWithData:(const void *)data length:(UInt32)length packetDescription:(AudioStreamPacketDescription)packetDescription +{ + if (self.fillPosition + packetDescription.mDataByteSize > self.size || self.numberOfPacketDescriptions == kTDMaxPacketDescriptions) return NO; + + memcpy((char *)(self.audioQueueBuffer->mAudioData + self.fillPosition), (const char *)(data + packetDescription.mStartOffset), packetDescription.mDataByteSize); + + self.packetDescriptions[self.numberOfPacketDescriptions] = packetDescription; + self.packetDescriptions[self.numberOfPacketDescriptions].mStartOffset = self.fillPosition; + self.numberOfPacketDescriptions++; + + self.fillPosition += packetDescription.mDataByteSize; + + return YES; +} + +- (void)enqueueWithAudioQueue:(AudioQueueRef)audioQueue +{ + self.audioQueueBuffer->mAudioDataByteSize = self.fillPosition; + AudioQueueEnqueueBuffer(audioQueue, self.audioQueueBuffer, self.numberOfPacketDescriptions, self.packetDescriptions); +} + +- (void)reset +{ + self.fillPosition = 0; + self.numberOfPacketDescriptions = 0; +} + +- (BOOL)isEqual:(AudioQueueBufferRef)audioQueueBuffer +{ + return audioQueueBuffer == self.audioQueueBuffer; +} + +- (void)freeFromAudioQueue:(AudioQueueRef)audioQueue +{ + AudioQueueFreeBuffer(audioQueue, self.audioQueueBuffer); +} + +- (void)dealloc +{ + free(_packetDescriptions); +} + +@end diff --git a/GetHip/AudioStreamer/Classes/TDAudioQueueBufferManager.h b/GetHip/AudioStreamer/Classes/TDAudioQueueBufferManager.h new file mode 100755 index 0000000..b823c17 --- /dev/null +++ b/GetHip/AudioStreamer/Classes/TDAudioQueueBufferManager.h @@ -0,0 +1,27 @@ +// +// TDAudioQueueBufferManager.h +// TDAudioStreamer +// +// Created by Tony DiPasquale on 10/29/13. +// Copyright (c) 2013 Tony DiPasquale. The MIT License (MIT). +// + +#import +#import + +@class TDAudioQueueBuffer; + +@interface TDAudioQueueBufferManager : NSObject + +- (instancetype)initWithAudioQueue:(AudioQueueRef)audioQueue size:(UInt32)size count:(UInt32)count; + +- (void)freeAudioQueueBuffer:(AudioQueueBufferRef)audioQueueBuffer; +- (TDAudioQueueBuffer *)nextFreeBuffer; +- (void)enqueueNextBufferOnAudioQueue:(AudioQueueRef)audioQueue; + +- (BOOL)hasAvailableAudioQueueBuffer; +- (BOOL)isProcessingAudioQueueBuffer; + +- (void)freeBufferMemoryFromAudioQueue:(AudioQueueRef)audioQueue; + +@end diff --git a/GetHip/AudioStreamer/Classes/TDAudioQueueBufferManager.m b/GetHip/AudioStreamer/Classes/TDAudioQueueBufferManager.m new file mode 100755 index 0000000..fc91760 --- /dev/null +++ b/GetHip/AudioStreamer/Classes/TDAudioQueueBufferManager.m @@ -0,0 +1,114 @@ +// +// TDAudioQueueBufferManager.m +// TDAudioStreamer +// +// Created by Tony DiPasquale on 10/29/13. +// Copyright (c) 2013 Tony DiPasquale. The MIT License (MIT). +// + +#import "TDAudioQueueBufferManager.h" +#import "TDAudioQueueBuffer.h" +#import "NSMutableArray+QueueMethods.h" + +@interface TDAudioQueueBufferManager () + +@property (assign, nonatomic) UInt32 bufferCount; +@property (assign, nonatomic) UInt32 bufferSize; +@property (strong, nonatomic) NSArray *audioQueueBuffers; +@property (strong, atomic) NSMutableArray *freeBuffers; + +@end + +@implementation TDAudioQueueBufferManager + +- (instancetype)initWithAudioQueue:(AudioQueueRef)audioQueue size:(UInt32)size count:(UInt32)count +{ + self = [super init]; + if (!self) return nil; + + self.bufferCount = count; + self.bufferSize = size; + + self.freeBuffers = [NSMutableArray arrayWithCapacity:self.bufferCount]; + NSMutableArray *audioqueuebuffers = [NSMutableArray arrayWithCapacity:self.bufferCount]; + + for (NSUInteger i = 0; i < self.bufferCount; i++) { + TDAudioQueueBuffer *buffer = [[TDAudioQueueBuffer alloc] initWithAudioQueue:audioQueue size:self.bufferSize]; + + if (!buffer) { + i--; + continue; + } + + audioqueuebuffers[i] = buffer; + [self.freeBuffers pushObject:@(i)]; + } + + self.audioQueueBuffers = [audioqueuebuffers copy]; + + return self; +} + +#pragma mark - Public Methods + +- (void)freeAudioQueueBuffer:(AudioQueueBufferRef)audioQueueBuffer +{ + for (NSUInteger i = 0; i < self.bufferCount; i++) { + if ([(TDAudioQueueBuffer *)self.audioQueueBuffers[i] isEqual:audioQueueBuffer]) { + [(TDAudioQueueBuffer *)self.audioQueueBuffers[i] reset]; + + @synchronized(self) { + [self.freeBuffers pushObject:@(i)]; + } + break; + } + } + +#if DEBUG + if (self.freeBuffers.count > self.bufferCount >> 1) { + NSLog(@"Free Buffers: %lu", (unsigned long)self.freeBuffers.count); + } +#endif +} + +- (TDAudioQueueBuffer *)nextFreeBuffer +{ + if (![self hasAvailableAudioQueueBuffer]) return nil; + @synchronized(self) { + return self.audioQueueBuffers[[[self.freeBuffers topObject] integerValue]]; + } +} + +- (void)enqueueNextBufferOnAudioQueue:(AudioQueueRef)audioQueue +{ + @synchronized(self) { + NSInteger nextBufferIndex = [[self.freeBuffers popObject] integerValue]; + TDAudioQueueBuffer *nextBuffer = self.audioQueueBuffers[nextBufferIndex]; + [nextBuffer enqueueWithAudioQueue:audioQueue]; + } +} + +- (BOOL)hasAvailableAudioQueueBuffer +{ + @synchronized(self) { + return self.freeBuffers.count > 0; + } +} + +- (BOOL)isProcessingAudioQueueBuffer +{ + @synchronized(self) { + return self.freeBuffers.count != self.bufferCount; + } +} + +#pragma mark - Cleanup + +- (void)freeBufferMemoryFromAudioQueue:(AudioQueueRef)audioQueue +{ + for (NSUInteger i = 0; i < self.audioQueueBuffers.count; i++) { + [(TDAudioQueueBuffer *)self.audioQueueBuffers[i] freeFromAudioQueue:audioQueue]; + } +} + +@end diff --git a/GetHip/AudioStreamer/Classes/TDAudioQueueController.h b/GetHip/AudioStreamer/Classes/TDAudioQueueController.h new file mode 100755 index 0000000..c2a38b2 --- /dev/null +++ b/GetHip/AudioStreamer/Classes/TDAudioQueueController.h @@ -0,0 +1,19 @@ +// +// TDAudioQueueController.h +// TDAudioStreamer +// +// Created by Tony DiPasquale on 10/29/13. +// Copyright (c) 2013 Tony DiPasquale. The MIT License (MIT). +// + +#import +#import + +@interface TDAudioQueueController : NSObject + ++ (OSStatus)playAudioQueue:(AudioQueueRef)audioQueue; ++ (OSStatus)pauseAudioQueue:(AudioQueueRef)audioQueue; ++ (OSStatus)stopAudioQueue:(AudioQueueRef)audioQueue; ++ (OSStatus)finishAudioQueue:(AudioQueueRef)audioQueue; + +@end diff --git a/GetHip/AudioStreamer/Classes/TDAudioQueueController.m b/GetHip/AudioStreamer/Classes/TDAudioQueueController.m new file mode 100755 index 0000000..0c3c4e2 --- /dev/null +++ b/GetHip/AudioStreamer/Classes/TDAudioQueueController.m @@ -0,0 +1,38 @@ +// +// TDAudioQueueController.m +// TDAudioStreamer +// +// Created by Tony DiPasquale on 10/29/13. +// Copyright (c) 2013 Tony DiPasquale. The MIT License (MIT). +// + +#import "TDAudioQueueController.h" + +@implementation TDAudioQueueController + ++ (OSStatus)playAudioQueue:(AudioQueueRef)audioQueue +{ + return AudioQueueStart(audioQueue, NULL); +} + ++ (OSStatus)pauseAudioQueue:(AudioQueueRef)audioQueue +{ + return AudioQueuePause(audioQueue); +} + ++ (OSStatus)stopAudioQueue:(AudioQueueRef)audioQueue +{ + return [self stopAudioQueue:audioQueue immediately:YES]; +} + ++ (OSStatus)finishAudioQueue:(AudioQueueRef)audioQueue +{ + return [self stopAudioQueue:audioQueue immediately:NO]; +} + ++ (OSStatus)stopAudioQueue:(AudioQueueRef)audioQueue immediately:(BOOL)immediately +{ + return AudioQueueStop(audioQueue, immediately); +} + +@end diff --git a/GetHip/AudioStreamer/Classes/TDAudioQueueFiller.h b/GetHip/AudioStreamer/Classes/TDAudioQueueFiller.h new file mode 100755 index 0000000..96bb958 --- /dev/null +++ b/GetHip/AudioStreamer/Classes/TDAudioQueueFiller.h @@ -0,0 +1,19 @@ +// +// TDAudioQueueFiller.h +// TDAudioStreamer +// +// Created by Tony DiPasquale on 10/31/13. +// Copyright (c) 2013 Tony DiPasquale. The MIT License (MIT). +// + +#import +#import + +@class TDAudioQueue; + +@interface TDAudioQueueFiller : NSObject + ++ (void)fillAudioQueue:(TDAudioQueue *)audioQueue withData:(const void *)data length:(UInt32)length offset:(UInt32)offset; ++ (void)fillAudioQueue:(TDAudioQueue *)audioQueue withData:(const void *)data length:(UInt32)length packetDescription:(AudioStreamPacketDescription)packetDescription; + +@end diff --git a/GetHip/AudioStreamer/Classes/TDAudioQueueFiller.m b/GetHip/AudioStreamer/Classes/TDAudioQueueFiller.m new file mode 100755 index 0000000..7dab000 --- /dev/null +++ b/GetHip/AudioStreamer/Classes/TDAudioQueueFiller.m @@ -0,0 +1,41 @@ +// +// TDAudioQueueFiller.m +// TDAudioStreamer +// +// Created by Tony DiPasquale on 10/31/13. +// Copyright (c) 2013 Tony DiPasquale. The MIT License (MIT). +// + +#import "TDAudioQueueFiller.h" +#import "TDAudioQueueBuffer.h" +#import "TDAudioQueue.h" + +@implementation TDAudioQueueFiller + ++ (void)fillAudioQueue:(TDAudioQueue *)audioQueue withData:(const void *)data length:(UInt32)length offset:(UInt32)offset +{ + TDAudioQueueBuffer *audioQueueBuffer = [audioQueue nextFreeBuffer]; + + NSInteger leftovers = [audioQueueBuffer fillWithData:data length:length offset:offset]; + + if (leftovers == 0) return; + + [audioQueue enqueue]; + + if (leftovers > 0) + [self fillAudioQueue:audioQueue withData:data length:length offset:(length - (UInt32)leftovers)]; +} + ++ (void)fillAudioQueue:(TDAudioQueue *)audioQueue withData:(const void *)data length:(UInt32)length packetDescription:(AudioStreamPacketDescription)packetDescription +{ + TDAudioQueueBuffer *audioQueueBuffer = [audioQueue nextFreeBuffer]; + + BOOL hasMoreRoomForPackets = [audioQueueBuffer fillWithData:data length:length packetDescription:packetDescription]; + + if (!hasMoreRoomForPackets) { + [audioQueue enqueue]; + [self fillAudioQueue:audioQueue withData:data length:length packetDescription:packetDescription]; + } +} + +@end diff --git a/GetHip/AudioStreamer/Classes/TDAudioStream.h b/GetHip/AudioStreamer/Classes/TDAudioStream.h new file mode 100755 index 0000000..1efba36 --- /dev/null +++ b/GetHip/AudioStreamer/Classes/TDAudioStream.h @@ -0,0 +1,39 @@ +// +// TDAudioStream.h +// TDAudioStreamer +// +// Created by Tony DiPasquale on 10/4/13. +// Copyright (c) 2013 Tony DiPasquale. The MIT License (MIT). +// + +#import + +typedef NS_ENUM(NSUInteger, TDAudioStreamEvent) { + TDAudioStreamEventHasData, + TDAudioStreamEventWantsData, + TDAudioStreamEventEnd, + TDAudioStreamEventError +}; + +@class TDAudioStream; + +@protocol TDAudioStreamDelegate + +@required +- (void)audioStream:(TDAudioStream *)audioStream didRaiseEvent:(TDAudioStreamEvent)event; + +@end + +@interface TDAudioStream : NSObject + +@property (assign, nonatomic) id delegate; + +- (instancetype)initWithInputStream:(NSInputStream *)inputStream; +- (instancetype)initWithOutputStream:(NSOutputStream *)outputStream; + +- (void)open; +- (void)close; +- (UInt32)readData:(uint8_t *)data maxLength:(UInt32)maxLength; +- (UInt32)writeData:(uint8_t *)data maxLength:(UInt32)maxLength; + +@end diff --git a/GetHip/AudioStreamer/Classes/TDAudioStream.m b/GetHip/AudioStreamer/Classes/TDAudioStream.m new file mode 100755 index 0000000..e88e2af --- /dev/null +++ b/GetHip/AudioStreamer/Classes/TDAudioStream.m @@ -0,0 +1,93 @@ +// +// TDAudioStream.m +// TDAudioStreamer +// +// Created by Tony DiPasquale on 10/4/13. +// Copyright (c) 2013 Tony DiPasquale. The MIT License (MIT). +// + +#import "TDAudioStream.h" + +@interface TDAudioStream () + +@property (strong, nonatomic) NSStream *stream; + +@end + +@implementation TDAudioStream + +- (instancetype)initWithInputStream:(NSInputStream *)inputStream +{ + self = [super init]; + if (!self) return nil; + + self.stream = inputStream; + + return self; +} + +- (instancetype)initWithOutputStream:(NSOutputStream *)outputStream +{ + self = [super init]; + if (!self) return nil; + + self.stream = outputStream; + + return self; +} + +- (void)open +{ + self.stream.delegate = self; + [self.stream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; + return [self.stream open]; +} + +- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode +{ + switch (eventCode) { + case NSStreamEventHasBytesAvailable: + [self.delegate audioStream:self didRaiseEvent:TDAudioStreamEventHasData]; + break; + + case NSStreamEventHasSpaceAvailable: + [self.delegate audioStream:self didRaiseEvent:TDAudioStreamEventWantsData]; + break; + + case NSStreamEventEndEncountered: + [self.delegate audioStream:self didRaiseEvent:TDAudioStreamEventEnd]; + break; + + case NSStreamEventErrorOccurred: + [self.delegate audioStream:self didRaiseEvent:TDAudioStreamEventError]; + break; + + default: + break; + } +} + +- (UInt32)readData:(uint8_t *)data maxLength:(UInt32)maxLength +{ + return (UInt32)[(NSInputStream *)self.stream read:data maxLength:maxLength]; +} + +- (UInt32)writeData:(uint8_t *)data maxLength:(UInt32)maxLength +{ + return (UInt32)[(NSOutputStream *)self.stream write:data maxLength:maxLength]; +} + +- (void)close +{ + [self.stream close]; + self.stream.delegate = nil; + [self.stream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; +} + +- (void)dealloc +{ + if (self.stream) + [self close]; +} + +@end diff --git a/GetHip/AudioStreamer/TDAudioInputStreamer.h b/GetHip/AudioStreamer/TDAudioInputStreamer.h new file mode 100755 index 0000000..e75e2ef --- /dev/null +++ b/GetHip/AudioStreamer/TDAudioInputStreamer.h @@ -0,0 +1,24 @@ +// +// TDAudioInputStreamer.h +// TDAudioStreamer +// +// Created by Tony DiPasquale on 10/4/13. +// Copyright (c) 2013 Tony DiPasquale. The MIT License (MIT). +// + +#import + +@interface TDAudioInputStreamer : NSObject + +@property (assign, nonatomic) UInt32 audioStreamReadMaxLength; +@property (assign, nonatomic) UInt32 audioQueueBufferSize; +@property (assign, nonatomic) UInt32 audioQueueBufferCount; + +- (instancetype)initWithInputStream:(NSInputStream *)inputStream; + +- (void)start; +- (void)resume; +- (void)pause; +- (void)stop; + +@end diff --git a/GetHip/AudioStreamer/TDAudioInputStreamer.m b/GetHip/AudioStreamer/TDAudioInputStreamer.m new file mode 100755 index 0000000..e66b1ac --- /dev/null +++ b/GetHip/AudioStreamer/TDAudioInputStreamer.m @@ -0,0 +1,195 @@ +// +// TDAudioInputStreamer.m +// TDAudioStreamer +// +// Created by Tony DiPasquale on 10/4/13. +// Copyright (c) 2013 Tony DiPasquale. The MIT License (MIT). +// + +#import "TDAudioInputStreamer.h" +#import "TDAudioFileStream.h" +#import "TDAudioStream.h" +#import "TDAudioQueue.h" +#import "TDAudioQueueBuffer.h" +#import "TDAudioQueueFiller.h" +#import "TDAudioStreamerConstants.h" + +@interface TDAudioInputStreamer () + +@property (strong, nonatomic) NSThread *audioStreamerThread; +@property (assign, atomic) BOOL isPlaying; + +@property (strong, nonatomic) TDAudioStream *audioStream; +@property (strong, nonatomic) TDAudioFileStream *audioFileStream; +@property (strong, nonatomic) TDAudioQueue *audioQueue; + +@end + +@implementation TDAudioInputStreamer + +- (instancetype)init +{ + self = [super init]; + if (!self) return nil; + + self.audioFileStream = [[TDAudioFileStream alloc] init]; + if (!self.audioFileStream) return nil; + + self.audioFileStream.delegate = self; + + return self; +} + +- (instancetype)initWithInputStream:(NSInputStream *)inputStream +{ + self = [self init]; + if (!self) return nil; + + self.audioStream = [[TDAudioStream alloc] initWithInputStream:inputStream]; + if (!self.audioStream) return nil; + + self.audioStream.delegate = self; + + return self; +} + +- (void)start +{ + if (![[NSThread currentThread] isEqual:[NSThread mainThread]]) { + return [self performSelectorOnMainThread:@selector(start) withObject:nil waitUntilDone:YES]; + } + + self.audioStreamerThread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil]; + [self.audioStreamerThread start]; +} + +- (void)run +{ + @autoreleasepool { + [self.audioStream open]; + + self.isPlaying = YES; + + while (self.isPlaying && [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]) ; + } +} + +#pragma mark - Properties + +- (UInt32)audioStreamReadMaxLength +{ + if (!_audioStreamReadMaxLength) + _audioStreamReadMaxLength = kTDAudioStreamReadMaxLength; + + return _audioStreamReadMaxLength; +} + +- (UInt32)audioQueueBufferSize +{ + if (!_audioQueueBufferSize) + _audioQueueBufferSize = kTDAudioQueueBufferSize; + + return _audioQueueBufferSize; +} + +- (UInt32)audioQueueBufferCount +{ + if (!_audioQueueBufferCount) + _audioQueueBufferCount = kTDAudioQueueBufferCount; + + return _audioQueueBufferCount; +} + +#pragma mark - TDAudioStreamDelegate + +- (void)audioStream:(TDAudioStream *)audioStream didRaiseEvent:(TDAudioStreamEvent)event +{ + switch (event) { + case TDAudioStreamEventHasData: { + uint8_t bytes[self.audioStreamReadMaxLength]; + UInt32 length = [audioStream readData:bytes maxLength:self.audioStreamReadMaxLength]; + [self.audioFileStream parseData:bytes length:length]; + break; + } + + case TDAudioStreamEventEnd: + self.isPlaying = NO; + [self.audioQueue finish]; + break; + + case TDAudioStreamEventError: + [[NSNotificationCenter defaultCenter] postNotificationName:TDAudioStreamDidFinishPlayingNotification object:nil]; + break; + + default: + break; + } +} + +#pragma mark - TDAudioFileStreamDelegate + +- (void)audioFileStreamDidBecomeReady:(TDAudioFileStream *)audioFileStream +{ + UInt32 bufferSize = audioFileStream.packetBufferSize ? audioFileStream.packetBufferSize : self.audioQueueBufferSize; + + self.audioQueue = [[TDAudioQueue alloc] initWithBasicDescription:audioFileStream.basicDescription bufferCount:self.audioQueueBufferCount bufferSize:bufferSize magicCookieData:audioFileStream.magicCookieData magicCookieSize:audioFileStream.magicCookieLength]; + + self.audioQueue.delegate = self; +} + +- (void)audioFileStream:(TDAudioFileStream *)audioFileStream didReceiveError:(OSStatus)error +{ + [[NSNotificationCenter defaultCenter] postNotificationName:TDAudioStreamDidFinishPlayingNotification object:nil]; +} + +- (void)audioFileStream:(TDAudioFileStream *)audioFileStream didReceiveData:(const void *)data length:(UInt32)length +{ + [TDAudioQueueFiller fillAudioQueue:self.audioQueue withData:data length:length offset:0]; +} + +- (void)audioFileStream:(TDAudioFileStream *)audioFileStream didReceiveData:(const void *)data length:(UInt32)length packetDescription:(AudioStreamPacketDescription)packetDescription +{ + [TDAudioQueueFiller fillAudioQueue:self.audioQueue withData:data length:length packetDescription:packetDescription]; +} + +#pragma mark - TDAudioQueueDelegate + +- (void)audioQueueDidFinishPlaying:(TDAudioQueue *)audioQueue +{ + [self performSelectorOnMainThread:@selector(notifyMainThread:) withObject:TDAudioStreamDidFinishPlayingNotification waitUntilDone:NO]; +} + +- (void)audioQueueDidStartPlaying:(TDAudioQueue *)audioQueue +{ + [self performSelectorOnMainThread:@selector(notifyMainThread:) withObject:TDAudioStreamDidStartPlayingNotification waitUntilDone:NO]; +} + +- (void)notifyMainThread:(NSString *)notificationName +{ + [[NSNotificationCenter defaultCenter] postNotificationName:notificationName object:nil]; +} + +#pragma mark - Public Methods + +- (void)resume +{ + [self.audioQueue play]; +} + +- (void)pause +{ + [self.audioQueue pause]; +} + +- (void)stop +{ + [self performSelector:@selector(stopThread) onThread:self.audioStreamerThread withObject:nil waitUntilDone:YES]; +} + +- (void)stopThread +{ + self.isPlaying = NO; + [self.audioQueue stop]; +} + +@end diff --git a/GetHip/AudioStreamer/TDAudioOutputStreamer.h b/GetHip/AudioStreamer/TDAudioOutputStreamer.h new file mode 100755 index 0000000..052420a --- /dev/null +++ b/GetHip/AudioStreamer/TDAudioOutputStreamer.h @@ -0,0 +1,21 @@ +// +// TDAudioOutputStreamer.h +// TDAudioStreamer +// +// Created by Tony DiPasquale on 11/14/13. +// Copyright (c) 2013 Tony DiPasquale. The MIT License (MIT). +// + +#import + +@class AVURLAsset; + +@interface TDAudioOutputStreamer : NSObject + +- (instancetype)initWithOutputStream:(NSOutputStream *)stream; + +- (void)streamAudioFromURL:(NSURL *)url; +- (void)start; +- (void)stop; + +@end diff --git a/GetHip/AudioStreamer/TDAudioOutputStreamer.m b/GetHip/AudioStreamer/TDAudioOutputStreamer.m new file mode 100755 index 0000000..7b27d9c --- /dev/null +++ b/GetHip/AudioStreamer/TDAudioOutputStreamer.m @@ -0,0 +1,144 @@ +// +// TDAudioOutputStreamer.m +// TDAudioStreamer +// +// Created by Tony DiPasquale on 11/14/13. +// Copyright (c) 2013 Tony DiPasquale. The MIT License (MIT). +// + +#import +#import "TDAudioOutputStreamer.h" +#import "TDAudioStream.h" + +@interface TDAudioOutputStreamer () + +@property (strong, nonatomic) TDAudioStream *audioStream; +@property (strong, nonatomic) AVAssetReader *assetReader; +@property (strong, nonatomic) AVAssetReaderTrackOutput *assetOutput; +@property (strong, nonatomic) NSThread *streamThread; + +@property (assign, atomic) BOOL isStreaming; + +@end + +@implementation TDAudioOutputStreamer + +- (instancetype) initWithOutputStream:(NSOutputStream *)stream +{ + self = [super init]; + if (!self) return nil; + + self.audioStream = [[TDAudioStream alloc] initWithOutputStream:stream]; + self.audioStream.delegate = self; + NSLog(@"Init"); + + return self; +} + +- (void)start +{ + if (![[NSThread currentThread] isEqual:[NSThread mainThread]]) { + return [self performSelectorOnMainThread:@selector(start) withObject:nil waitUntilDone:YES]; + } + + NSLog(@"Start"); + self.streamThread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil]; + [self.streamThread start]; +} + +- (void)run +{ + @autoreleasepool { + [self.audioStream open]; + + self.isStreaming = YES; + NSLog(@"Loop"); + + while (self.isStreaming && [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]) ; + + NSLog(@"Done"); + } +} + +- (void)streamAudioFromURL:(NSURL *)url +{ + AVURLAsset *asset = [AVURLAsset URLAssetWithURL:url options:nil]; + NSError *assetError; + + self.assetReader = [AVAssetReader assetReaderWithAsset:asset error:&assetError]; + self.assetOutput = [AVAssetReaderTrackOutput assetReaderTrackOutputWithTrack:asset.tracks[0] outputSettings:nil]; + if (![self.assetReader canAddOutput:self.assetOutput]) return; + + [self.assetReader addOutput:self.assetOutput]; + [self.assetReader startReading]; + NSLog(@"Read Asset"); +} + +- (void)sendDataChunk +{ + CMSampleBufferRef sampleBuffer; + + sampleBuffer = [self.assetOutput copyNextSampleBuffer]; + + if (sampleBuffer == NULL || CMSampleBufferGetNumSamples(sampleBuffer) == 0) { + CFRelease(sampleBuffer); + return; + } + + CMBlockBufferRef blockBuffer; + AudioBufferList audioBufferList; + + OSStatus err = CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer(sampleBuffer, NULL, &audioBufferList, sizeof(AudioBufferList), NULL, NULL, kCMSampleBufferFlag_AudioBufferList_Assure16ByteAlignment, &blockBuffer); + + if (err) { + CFRelease(sampleBuffer); + return; + } + + for (NSUInteger i = 0; i < audioBufferList.mNumberBuffers; i++) { + AudioBuffer audioBuffer = audioBufferList.mBuffers[i]; + [self.audioStream writeData:audioBuffer.mData maxLength:audioBuffer.mDataByteSize]; + NSLog(@"buffer size: %u", (unsigned int)audioBuffer.mDataByteSize); + } + + CFRelease(blockBuffer); + CFRelease(sampleBuffer); +} + +- (void)stop +{ + [self performSelector:@selector(stopThread) onThread:self.streamThread withObject:nil waitUntilDone:YES]; +} + +- (void)stopThread +{ + self.isStreaming = NO; + [self.audioStream close]; + NSLog(@"Stop"); +} + +#pragma mark - TDAudioStreamDelegate + +- (void)audioStream:(TDAudioStream *)audioStream didRaiseEvent:(TDAudioStreamEvent)event +{ + switch (event) { + case TDAudioStreamEventWantsData: + [self sendDataChunk]; + break; + + case TDAudioStreamEventError: + // TODO: shit! + NSLog(@"Stream Error"); + break; + + case TDAudioStreamEventEnd: + // TODO: shit! + NSLog(@"Stream Ended"); + break; + + default: + break; + } +} + +@end diff --git a/GetHip/AudioStreamer/TDAudioStreamer.h b/GetHip/AudioStreamer/TDAudioStreamer.h new file mode 100755 index 0000000..6168782 --- /dev/null +++ b/GetHip/AudioStreamer/TDAudioStreamer.h @@ -0,0 +1,17 @@ +// +// TDAudioStreamer.h +// TDAudioStreamer +// +// Created by Tony DiPasquale on 11/18/13. +// Copyright (c) 2013 Tony DiPasquale. The MIT License (MIT). +// + +#import + +#import "TDAudioStreamerConstants.h" +#import "TDAudioInputStreamer.h" +#import "TDAudioOutputStreamer.h" + +@interface TDAudioStreamer : NSObject + +@end diff --git a/GetHip/AudioStreamer/TDAudioStreamer.m b/GetHip/AudioStreamer/TDAudioStreamer.m new file mode 100755 index 0000000..7949356 --- /dev/null +++ b/GetHip/AudioStreamer/TDAudioStreamer.m @@ -0,0 +1,13 @@ +// +// TDAudioStreamer.m +// TDAudioStreamer +// +// Created by Tony DiPasquale on 11/18/13. +// Copyright (c) 2013 Tony DiPasquale. The MIT License (MIT). +// + +#import "TDAudioStreamer.h" + +@implementation TDAudioStreamer + +@end diff --git a/GetHip/AudioStreamer/TDAudioStreamerConstants.h b/GetHip/AudioStreamer/TDAudioStreamerConstants.h new file mode 100755 index 0000000..ac7ed61 --- /dev/null +++ b/GetHip/AudioStreamer/TDAudioStreamerConstants.h @@ -0,0 +1,25 @@ +// +// TDAudioStreamerConstants.h +// TDAudioStreamer +// +// Created by Tony DiPasquale on 11/5/13. +// Copyright (c) 2013 Tony DiPasquale. The MIT License (MIT). +// + +#import "Foundation/Foundation.h" + +extern NSString *const TDAudioStreamerDidChangeAudioNotification; +extern NSString *const TDAudioStreamerDidPauseNotification; +extern NSString *const TDAudioStreamerDidPlayNotification; +extern NSString *const TDAudioStreamerDidStopNotification; + +extern NSString *const TDAudioStreamerNextTrackRequestNotification; +extern NSString *const TDAudioStreamerPreviousTrackRequestNotification; + +extern NSString *const TDAudioStreamDidFinishPlayingNotification; +extern NSString *const TDAudioStreamDidStartPlayingNotification; + +extern UInt32 const kTDAudioStreamReadMaxLength; +extern UInt32 const kTDAudioQueueBufferSize; +extern UInt32 const kTDAudioQueueBufferCount; +extern UInt32 const kTDAudioQueueStartMinimumBuffers; diff --git a/GetHip/AudioStreamer/TDAudioStreamerConstants.m b/GetHip/AudioStreamer/TDAudioStreamerConstants.m new file mode 100755 index 0000000..6186506 --- /dev/null +++ b/GetHip/AudioStreamer/TDAudioStreamerConstants.m @@ -0,0 +1,25 @@ +// +// TDAudioStreamerConstants.m +// TDAudioStreamer +// +// Created by Tony DiPasquale on 11/5/13. +// Copyright (c) 2013 Tony DiPasquale. The MIT License (MIT). +// + +#import "TDAudioStreamerConstants.h" + +NSString *const TDAudioStreamerDidChangeAudioNotification = @"TDAudioStreamerDidChangeAudioNotification"; +NSString *const TDAudioStreamerDidPauseNotification = @"TDAudioStreamerDidPauseNotification"; +NSString *const TDAudioStreamerDidPlayNotification = @"TDAudioStreamerDidPlayNotification"; +NSString *const TDAudioStreamerDidStopNotification = @"TDAudioStreamerDidStopNotification"; + +NSString *const TDAudioStreamerNextTrackRequestNotification = @"TDAudioStreamerNextTrackRequestNotification"; +NSString *const TDAudioStreamerPreviousTrackRequestNotification = @"TDAudioStreamerPreviousTrackRequestNotification"; + +NSString *const TDAudioStreamDidFinishPlayingNotification = @"TDAudioStreamDidFinishPlayingNotification"; +NSString *const TDAudioStreamDidStartPlayingNotification = @"TDAudioStreamDidStartPlayingNotification"; + +UInt32 const kTDAudioStreamReadMaxLength = 512; +UInt32 const kTDAudioQueueBufferSize = 2048; +UInt32 const kTDAudioQueueBufferCount = 16; +UInt32 const kTDAudioQueueStartMinimumBuffers = 8; diff --git a/GetHip/Bridging-Header.h b/GetHip/Bridging-Header.h index 3e9c534..34ded2f 100644 --- a/GetHip/Bridging-Header.h +++ b/GetHip/Bridging-Header.h @@ -17,13 +17,13 @@ #import "ParseNetDebug.h" //TDAudioPlayer -#import "NSInputStream+URLInitialization.h" +//#import "NSInputStream+URLInitialization.h" #import "NSMutableArray+QueueMethods.h" -#import "TDAudioMetaInfo.h" +//#import "TDAudioMetaInfo.h" #import "TDAudioInputStreamer.h" #import "TDAudioOutputStreamer.h" -#import "TDAudioPlayerConstants.h" -#import "TDAudioPlayer.h" +//#import "TDAudioPlayerConstants.h" +//#import "TDAudioPlayer.h" #import "TDAudioFileStream.h" #import "TDAudioQueue.h" #import "TDAudioQueueBuffer.h" diff --git a/GetHip/ForgotPassViewController.swift b/GetHip/ForgotPassViewController.swift index bb80ab7..418ed62 100644 --- a/GetHip/ForgotPassViewController.swift +++ b/GetHip/ForgotPassViewController.swift @@ -8,12 +8,45 @@ import UIKit -class ForgotPassViewController: UIViewController { +class ForgotPassViewController: UIViewController, UITextFieldDelegate { + @IBOutlet weak var emailField: UITextField! + @IBOutlet weak var resestPass: UIButton! + + @IBAction func dismiss(sender:UIBarButtonItem){ + self.dismissViewControllerAnimated(true, completion: nil) + } + @IBAction func sendResetRequest(sender: UIButton){ + PFUser.requestPasswordResetForEmailInBackground(self.emailField.text!) { + (succeeded, error) -> Void in + + if (error == nil){ + let alert = UIAlertController(title: "Success", message: "Check your email to start the password reset cycle.", preferredStyle: .Alert) + alert.addAction(UIAlertAction(title: "OK", style: .Default, handler:{(action: UIAlertAction!) in alert.dismissViewControllerAnimated(true, completion: nil)})) + self.presentViewController(alert, animated: true, completion: nil) + }else{ + let errorMessage = error!.userInfo!["error"] as! NSString + let alert = UIAlertController(title: "Failure", message:( errorMessage as? String)!, preferredStyle: .Alert) + alert.addAction(UIAlertAction(title: "OK", style: .Default, handler:{(action: UIAlertAction!) in alert.dismissViewControllerAnimated(true, completion: nil)})) + self.presentViewController(alert, animated: true, completion: nil) + } + } + } + override func viewDidLoad() { super.viewDidLoad() + //dismisses keyboard when screen is tapped + let tapGesture = UITapGestureRecognizer(target: self, action: Selector("hideKeyboard")) + tapGesture.cancelsTouchesInView = true + self.view.addGestureRecognizer(tapGesture) + + self.emailField.delegate = self + // Do any additional setup after loading the view. + self.resestPass!.layer.borderWidth = 1 + self.resestPass!.layer.cornerRadius = 5 + self.resestPass!.layer.borderColor = UIColor.blackColor().CGColor } override func didReceiveMemoryWarning() { @@ -22,6 +55,15 @@ class ForgotPassViewController: UIViewController { } + func textFieldShouldReturn(textField: UITextField) -> Bool { + self.view.endEditing(true) + return false + } + + func hideKeyboard() { + self.view.endEditing(true) + } + /* // MARK: - Navigation diff --git a/GetHip/FriendData.swift b/GetHip/FriendData.swift index faf4b77..104e0cb 100644 --- a/GetHip/FriendData.swift +++ b/GetHip/FriendData.swift @@ -12,13 +12,15 @@ class FriendData: NSObject, NSCoding { var displayName: String! var profileImg: UIImageView! var status: String! - var username: String! + //var username: String! + var email: String! - init(display: String, status: String, username: String){ + init(display: String, status: String, /*username: String,*/ email: String){ self.displayName = display self.profileImg = nil self.status = status - self.username = username + //self.username = username + self.email = email super.init() } @@ -29,7 +31,8 @@ class FriendData: NSObject, NSCoding { self.displayName = aDecoder.decodeObjectForKey("displayName") as! String self.profileImg = aDecoder.decodeObjectForKey("profileImg") as! UIImageView! self.status = aDecoder.decodeObjectForKey("status") as! String - self.username = aDecoder.decodeObjectForKey("username") as! String + //self.username = aDecoder.decodeObjectForKey("username") as! String + self.email = aDecoder.decodeObjectForKey("email") as! String super.init() } @@ -37,7 +40,8 @@ class FriendData: NSObject, NSCoding { aCoder.encodeObject(self.displayName, forKey: "displayName") aCoder.encodeObject(self.profileImg, forKey: "profileImg") aCoder.encodeObject(self.status, forKey: "status") - aCoder.encodeObject(self.username, forKey: "username") + //aCoder.encodeObject(self.username, forKey: "username") + aCoder.encodeObject(self.email, forKey: "email") } //Mark: NSObject @@ -47,7 +51,8 @@ class FriendData: NSObject, NSCoding { return self.displayName == object.displayName && self.profileImg == object.profileImg && self.status == object.status - && self.username == object.username + // && self.username == object.username + && self.email == object.email }else { return false } diff --git a/GetHip/FriendDataSource.swift b/GetHip/FriendDataSource.swift index 9c1862b..94d6f4c 100644 --- a/GetHip/FriendDataSource.swift +++ b/GetHip/FriendDataSource.swift @@ -30,12 +30,14 @@ class FriendDataSource{ for object in objects! { //var image:UIImage = UIImage() - let userName = object.objectForKey("OtherUser")!.objectForKey("username") as! String + let email = object.objectForKey("OtherUser")!.objectForKey("email") as! String + println(email) let displayName = object.objectForKey("OtherUser")!.objectForKey("displayName") as! String let requestStatus = object.objectForKey("RequestStatus")! as! String - var newFriend: FriendData = FriendData(display: displayName, status: requestStatus, username: userName ) + + var newFriend: FriendData = FriendData(display: displayName, status: requestStatus, email: email ) var img = object.objectForKey("OtherUser")!.objectForKey("profilePicture")! as? PFFile @@ -49,7 +51,7 @@ class FriendDataSource{ }) //print(userName) self.dataSource.append(newFriend) - + println(self.dataSource.count) } NSLog("%d", self.dataSource.count) @@ -65,10 +67,11 @@ class FriendDataSource{ if (error == nil){ for object in objects! { - let userName = object.objectForKey("OtherUser")!.objectForKey("username") as! String + let email = object.objectForKey("OtherUser")!.objectForKey("email") as! String + println(email) let displayName = object.objectForKey("OtherUser")!.objectForKey("displayName") as! String let requestStatus = object.objectForKey("RequestStatus")! as! String - var newFriend: FriendData = FriendData(display: displayName, status: requestStatus, username: userName) + var newFriend: FriendData = FriendData(display: displayName, status: requestStatus, email: email) var img = object.objectForKey("OtherUser")!.objectForKey("profilePicture")! as? PFFile @@ -84,6 +87,7 @@ class FriendDataSource{ //print(userName) self.dataSource.append(newFriend) + println(self.dataSource.count) } NSNotificationCenter.defaultCenter().postNotificationName("refreshTableView", object: nil) diff --git a/GetHip/FriendRequestViewController.swift b/GetHip/FriendRequestViewController.swift index 66e717d..de37461 100644 --- a/GetHip/FriendRequestViewController.swift +++ b/GetHip/FriendRequestViewController.swift @@ -9,8 +9,8 @@ import UIKit class FriendRequestViewController: UIViewController{ - var searchedUsername: String! - var frnds: [String]! + var searchedEmail: String! //contains the searched email address by user + var frnds: [String]! //holds email addresses of current users friends var party: PartyServiceManager! @IBOutlet var displayImage: UIImageView! @@ -20,7 +20,7 @@ class FriendRequestViewController: UIViewController{ @IBAction func sendButtonClicked(sender: AnyObject){ var query = PFQuery(className: "_User") - query.whereKey("username", equalTo: foundName.text!) + query.whereKey("username", equalTo: self.searchedEmail!) dispatch_async(dispatch_get_main_queue(),{ query.getFirstObjectInBackgroundWithBlock({ (object:PFObject?, error: NSError?) -> Void in @@ -135,49 +135,88 @@ extension FriendRequestViewController: UITextFieldDelegate{ } func textFieldDidEndEditing(textField: UITextField) { - self.searchedUsername = searchBar.text var inFriendsList: Bool = false - for name in self.frnds{ - if name == self.searchedUsername{ - inFriendsList = true - break - } - } - if(inFriendsList == false){ - var query = PFQuery(className: "_User") - query.whereKey("username", equalTo: searchedUsername) + - dispatch_async(dispatch_get_main_queue(), {() -> Void in - query.getFirstObjectInBackgroundWithBlock({ - (object: PFObject?, error: NSError?) -> Void in - if(error == nil){ - self.foundName.text = object?.objectForKey("username") as? String + //case where user display name is entered + self.searchedEmail = searchBar.text + + for email in self.frnds{ + if email == self.searchedEmail{ + inFriendsList = true + break + } + } + + if(self.searchedEmail == (self.tabBarController as! HomeTabController).userData[0].email){ + + let alert = UIAlertController(title: "That's You!", message: "Sorry, you can't send a request to yourself.", preferredStyle: .Alert) + alert.addAction(UIAlertAction(title: "OK", style: .Default, handler:{(action: UIAlertAction!) in alert.dismissViewControllerAnimated(true, completion: nil)})) + self.presentViewController(alert, animated: true, completion: nil) + + } + else if(inFriendsList == false){ + + var checkRelation: PFRelation! = PFUser.currentUser()?.relationForKey("FriendRequest") + var checkQuery = checkRelation.query().whereKey("RequestStatus", equalTo: "Awaiting Response") + + checkQuery.whereKey("inRealtionTo", equalTo: self.searchedEmail) + + dispatch_async(dispatch_get_main_queue(), {() -> Void in + checkQuery.getFirstObjectInBackgroundWithBlock({ + (object, error) -> Void in - //download profile imge - var img = object!.objectForKey("profilePicture")! as? PFFile - - dispatch_async(dispatch_get_main_queue(), { - img!.getDataInBackgroundWithBlock({ - (imgData, error) -> Void in - - var downloadedImg = UIImage(data: imgData!) - self.displayImage.image = downloadedImg + //put in the checking code after lab today + if object == nil { + var query = PFQuery(className: "_User") + query.whereKey("username", equalTo: self.searchedEmail) + + dispatch_async(dispatch_get_main_queue(), {() -> Void in + query.getFirstObjectInBackgroundWithBlock({ + (object: PFObject?, error: NSError?) -> Void in + if(error == nil){ + self.foundName.text = object?.objectForKey("displayName") as? String + + //download profile imge + var img = object!.objectForKey("profilePicture")! as? PFFile + + dispatch_async(dispatch_get_main_queue(), { + img!.getDataInBackgroundWithBlock({ + (imgData, error) -> Void in + + var downloadedImg = UIImage(data: imgData!) + self.displayImage.image = downloadedImg + }) + }) + + self.sendRequest.enabled = true + }else{ + self.foundName.text = "No Friend Found :(" + self.sendRequest.enabled = false + } + }) }) - }) + + }else{ + let alert = UIAlertController(title: "Request Already Made", message: "You have already sent a friend request to this user.", preferredStyle: .Alert) + alert.addAction(UIAlertAction(title: "OK", style: .Default, handler:{(action: UIAlertAction!) in alert.dismissViewControllerAnimated(true, completion: nil)})) + self.presentViewController(alert, animated: true, completion: nil) + } - self.sendRequest.enabled = true - }else{ - self.foundName.text = "No Friend Found :(" - self.sendRequest.enabled = false - } + }) }) - }) - }else{ - let alert = UIAlertController(title: "Already Friends", message: "You are already friends with this user!", preferredStyle: .Alert) - alert.addAction(UIAlertAction(title: "OK", style: .Default, handler:{(action: UIAlertAction!) in alert.dismissViewControllerAnimated(true, completion: nil)})) - self.presentViewController(alert, animated: true, completion: nil) - } + + }else{ + + let alert = UIAlertController(title: "Already Friends", message: "You are already friends with this user!", preferredStyle: .Alert) + alert.addAction(UIAlertAction(title: "OK", style: .Default, handler:{(action: UIAlertAction!) in alert.dismissViewControllerAnimated(true, completion: nil)})) + self.presentViewController(alert, animated: true, completion: nil) + } + + + + } diff --git a/GetHip/FriendsListViewController.swift b/GetHip/FriendsListViewController.swift index 2080d88..953816c 100644 --- a/GetHip/FriendsListViewController.swift +++ b/GetHip/FriendsListViewController.swift @@ -30,6 +30,17 @@ class FriendsListViewController: UIViewController, UITableViewDelegate, UITableV self.performSegueWithIdentifier("FriendRequestSegue", sender: nil) } + @IBAction func reloadList(sender: UIBarButtonItem){ + NSNotificationCenter.defaultCenter().addObserver(self, selector: "refreshFriends:", name: "reloadDataF", object: nil) + (self.tabBarController as! HomeTabController).reloadParseData() + } + + func refreshFriends(notification: NSNotification){ + self.viewDidLoad() + self.table.reloadData() + NSNotificationCenter.defaultCenter().removeObserver(self, name: "reloadDataF", object: nil) + } + func setData(frnds:[FriendData], requst: [FriendData], party: PartyServiceManager, user: [UserParseData]){ self.friends = frnds self.request = requst @@ -181,8 +192,8 @@ class FriendsListViewController: UIViewController, UITableViewDelegate, UITableV if (self.friends.count != 0){ for i in 0...self.friends.count-1{ var frends: FriendData! = self.friends[i] as! FriendData - println(frends.displayName!) - frndNames.append(frends.displayName!) + println(frends.email!) + frndNames.append(frends.email!) } } diff --git a/GetHip/HomeTabController.swift b/GetHip/HomeTabController.swift index 1bda57c..aa418a9 100644 --- a/GetHip/HomeTabController.swift +++ b/GetHip/HomeTabController.swift @@ -17,6 +17,7 @@ class HomeTabController: UITabBarController { var userData: [UserParseData] = [] let partyData = PartyServiceManager() var firstTime: Bool = true + private var reloadingData: Bool = false private var firstTimeBrowsing: Bool = true //@IBOutlet weak var CreateAPartyBtn: UIButton! @@ -33,17 +34,22 @@ class HomeTabController: UITabBarController { self.friendData.append(pendingFriend) } } + if(firstTime == true){ + //start browsing for peers + self.partyData.setBrowser() + self.partyData.startBrowser() + //self.partyData.delegate = self + self.firstTime = false + } - //start browsing for peers - self.partyData.setBrowser() - self.partyData.startBrowser() - - //self.partyData.delegate = self - self.firstTime = false NSNotificationCenter.defaultCenter().postNotificationName("dataMark", object: nil) - + if(self.reloadingData == true){ + NSNotificationCenter.defaultCenter().postNotificationName("reloadDataF", object: nil) + NSNotificationCenter.defaultCenter().postNotificationName("reloadDataS", object: nil) + self.reloadingData = false + } } func refreshUserData(notification:NSNotification){ @@ -91,6 +97,20 @@ class HomeTabController: UITabBarController { self.userData = [] self.friendData = [] + self.requestData = [] + dispatch_async(dispatch_get_main_queue(), { + self.usrDataManager = UserParseDataSource() + //self.frndDataManager = FriendDataSource() + + }) + } + + //Parse data refresh methods + func reloadParseData(){ + self.reloadingData = true + self.userData = [] + self.friendData = [] + self.requestData = [] dispatch_async(dispatch_get_main_queue(), { self.usrDataManager = UserParseDataSource() //self.frndDataManager = FriendDataSource() diff --git a/GetHip/InvitedToPartyViewController.swift b/GetHip/InvitedToPartyViewController.swift index 87385e3..81bdac7 100644 --- a/GetHip/InvitedToPartyViewController.swift +++ b/GetHip/InvitedToPartyViewController.swift @@ -37,13 +37,13 @@ class InvitedToPartyViewController: UIViewController , PartyServiceManagerDelega // Do any additional setup after loading the view. var query = PFQuery(className: "_User") - query.whereKey("username", equalTo: self.fromPeer.displayName) + query.whereKey("displayName", equalTo: self.fromPeer.displayName) dispatch_async(dispatch_get_main_queue(), {() -> Void in query.getFirstObjectInBackgroundWithBlock({ (object: PFObject?, error: NSError?) -> Void in if(error == nil){ - self.inviteTxt.text = "You have been invited by " + (object?.objectForKey("username")! as? String)! + " to join a Party!" + self.inviteTxt.text = "You have been invited by " + (object?.objectForKey("displayName")! as? String)! + " to join a Party!" //download profile imge var img = object!.objectForKey("profilePicture")! as? PFFile diff --git a/GetHip/LoadingPartyViewController.swift b/GetHip/LoadingPartyViewController.swift index 9e5ed77..1ea471a 100644 --- a/GetHip/LoadingPartyViewController.swift +++ b/GetHip/LoadingPartyViewController.swift @@ -144,7 +144,7 @@ class LoadingPartyViewController: UIViewController, UICollectionViewDataSource, } } } - var userDat = FriendData(display: self.usr[0].displayName, status: "", username: self.usr[0].username) + var userDat = FriendData(display: self.usr[0].displayName, status: "", email: self.usr[0].email) userDat.profileImg = UIImageView(image: self.usr[0].profileImg.image) currentlyConnected.append(userDat) diff --git a/GetHip/LoginController.swift b/GetHip/LoginController.swift index 38bdb4a..f09257e 100644 --- a/GetHip/LoginController.swift +++ b/GetHip/LoginController.swift @@ -29,7 +29,7 @@ class LoginController: UIViewController, PFLogInViewControllerDelegate, UITextFi (object, error) -> Void in if(object != nil && error == nil){ - PFUser.logInWithUsernameInBackground(object!.objectForKey("username") as! String, password: self.password.text!, block: { + PFUser.logInWithUsernameInBackground(object!.objectForKey("email") as! String, password: self.password.text!, block: { (user, error) -> Void in if(user != nil || error == nil){ @@ -56,7 +56,7 @@ class LoginController: UIViewController, PFLogInViewControllerDelegate, UITextFi }) }) }else{ - let alert = UIAlertController(title: "Invalid Login", message: "Invalid email or password", preferredStyle: .Alert) + var alert = UIAlertController(title: "Invalid Login", message: "Invalid email or password", preferredStyle: .Alert) alert.addAction(UIAlertAction(title: "OK", style: .Default, handler:{(action: UIAlertAction!) in alert.dismissViewControllerAnimated(true, completion: nil)})) self.presentViewController(alert, animated: true, completion: nil) /* diff --git a/GetHip/Main.storyboard b/GetHip/Main.storyboard index 05fdfb6..c2fb319 100644 --- a/GetHip/Main.storyboard +++ b/GetHip/Main.storyboard @@ -129,6 +129,7 @@ + @@ -148,7 +149,7 @@ - - + - - - + + - + - - - - - - - - - - - - - - - - - - - - + + @@ -214,26 +197,34 @@ + + + + + + + + + - - - - - - - + + + + + + + + + - - - + - - - - + + + @@ -245,9 +236,12 @@ + + + @@ -272,7 +266,6 @@ - @@ -614,13 +607,7 @@ - - - - - - - - - - - - - - - - - - - - - - - @@ -735,13 +705,29 @@ - + + + + + + + + + + + + + + + + + @@ -753,13 +739,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + @@ -851,6 +897,11 @@ + + + + + @@ -907,7 +958,7 @@ - + @@ -1101,30 +1152,7 @@ - - - - - - - - - - - - - - + @@ -1199,6 +1227,7 @@ + @@ -1231,11 +1260,11 @@ - + - + - + @@ -1911,17 +1940,17 @@ - + - + - + @@ -2120,12 +2149,12 @@ - + - + - + @@ -2195,7 +2224,65 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -2234,7 +2321,7 @@ - + @@ -2264,9 +2351,9 @@ - - - + + + diff --git a/GetHip/PartyServiceManager.swift b/GetHip/PartyServiceManager.swift index 506d90d..f6aad83 100644 --- a/GetHip/PartyServiceManager.swift +++ b/GetHip/PartyServiceManager.swift @@ -152,8 +152,8 @@ class PartyServiceManager: NSObject, AnyObject { } for peer in dataDictionary["friendData"] as! [FriendData] { - if(peer.username != self.myPeerID.displayName){ - println(peer.username) + if(peer.displayName != self.myPeerID.displayName){ + println(peer.displayName) self.invitedFriends.append(peer) } } diff --git a/GetHip/PendingRequestViewController.swift b/GetHip/PendingRequestViewController.swift index 325b849..66d9130 100644 --- a/GetHip/PendingRequestViewController.swift +++ b/GetHip/PendingRequestViewController.swift @@ -17,11 +17,12 @@ class PendingRequestViewController: UITableViewController { @IBAction func didAcceptFriend(sender: AnyObject?){ var path:NSIndexPath = self.table.indexPathForCell(sender?.superview!!.superview as! PendingFriendCell)! var cell: PendingFriendCell! = self.table.cellForRowAtIndexPath(path) as! PendingFriendCell + let pending = self.requests[path.row] as! FriendData var query: PFQuery! = PFQuery(className: "FriendRequest") query.whereKey("username", equalTo: PFUser.currentUser()!.username!) query.whereKey("RequestStatus", equalTo: "pending") - query.whereKey("inRealtionTo", equalTo: cell.friendName.text!) + query.whereKey("inRealtionTo", equalTo: pending.email) query.includeKey("OtherUser") dispatch_async(dispatch_get_main_queue(), { @@ -61,7 +62,14 @@ class PendingRequestViewController: UITableViewController { object!.save() - + cell.proImg.hidden = true + cell.acceptButton.hidden = true + cell.denyButton.hidden = true + var tempString = cell.friendName.text! + cell.friendName.text = "You added " + tempString + "!!" + NSNotificationCenter.defaultCenter().addObserver(self, selector: "refreshFriendList:", name: "reloadDataF", object: nil) + (self.tabBarController as! HomeTabController).reloadParseData() + } }) }) @@ -75,18 +83,21 @@ class PendingRequestViewController: UITableViewController { }) }) - cell.proImg.hidden = true - cell.acceptButton.hidden = true - cell.denyButton.hidden = true - var tempString = cell.friendName.text! - cell.friendName.text = "You added " + tempString + "!!" - //self.table.reloadData() + } @IBAction func didRejectFriend(sender: AnyObject?){ } + + //local refresh method for friend list view controller table + func refreshFriendList(notification: NSNotification){ + ((self.parentViewController as! UINavigationController).viewControllers[0] as! FriendsListViewController).viewDidLoad() + ((self.parentViewController as! UINavigationController).viewControllers[0] as! FriendsListViewController).table.reloadData() + NSNotificationCenter.defaultCenter().removeObserver(self, name: "reloadDataF", object: nil) + } + override func viewDidLoad() { super.viewDidLoad() self.title = "Friend Requests" @@ -144,6 +155,10 @@ class PendingRequestViewController: UITableViewController { //rounds uiimage and configures UIImageView cell!.proImg.layer.cornerRadius = cell!.proImg.frame.size.width/2 + cell!.acceptButton.layer.cornerRadius = cell!.acceptButton.frame.size.width/2 + cell!.denyButton.layer.cornerRadius = cell!.acceptButton.frame.size.width/2 + cell!.denyButton.clipsToBounds = true + cell!.acceptButton.clipsToBounds = true cell!.proImg.clipsToBounds = true //cell!.proImage.layer.borderColor = UIColor.whiteColor().CGColor //cell!.proImage.layer.masksToBounds = true diff --git a/GetHip/SettingsCellWrapper.swift b/GetHip/SettingsCellWrapper.swift index 18cc87f..e383630 100644 --- a/GetHip/SettingsCellWrapper.swift +++ b/GetHip/SettingsCellWrapper.swift @@ -20,6 +20,7 @@ class DisplayNameCell: UITableViewCell { } } +/* class UserNameCell: UITableViewCell { @IBOutlet var usrName: UILabel! @@ -31,6 +32,7 @@ class UserNameCell: UITableViewCell { super.setSelected(selected, animated: animated) } } +*/ class EmailCell: UITableViewCell { @IBOutlet var email: UILabel! diff --git a/GetHip/SettingsDetailViewWrapper.swift b/GetHip/SettingsDetailViewWrapper.swift index 8e5286e..6a09488 100644 --- a/GetHip/SettingsDetailViewWrapper.swift +++ b/GetHip/SettingsDetailViewWrapper.swift @@ -36,7 +36,9 @@ class DisplayDetailViewController: UIViewController { else if let object = object{ object.setObject(self.possibleName, forKey: "displayName") object.saveInBackground() - //NSNotificationCenter.defaultCenter().postNotificationName("savingName", object: nil) + + NSNotificationCenter.defaultCenter().addObserver(self, selector: "refreshSettings:", name: "reloadDataS", object: nil) + (self.tabBarController as! HomeTabController).reloadParseData() } } @@ -49,10 +51,6 @@ class DisplayDetailViewController: UIViewController { self.displayName = display } - func refreshView(notification: NSNotification){ - - - } override func viewDidLoad() { super.viewDidLoad() @@ -63,7 +61,7 @@ class DisplayDetailViewController: UIViewController { self.ChnDspName.layer.cornerRadius = 5 self.ChnDspName.layer.borderColor = UIColor.blackColor().CGColor // Do any additional setup after loading the view. - NSNotificationCenter.defaultCenter().addObserver(self, selector: "refreshView:", name: "savingName", object: nil) + } override func didReceiveMemoryWarning() { @@ -71,6 +69,12 @@ class DisplayDetailViewController: UIViewController { // Dispose of any resources that can be recreated. } + func refreshSettings(notification: NSNotification){ + ((self.parentViewController as! UINavigationController).viewControllers[0] as! SettingsTableViewController).viewDidLoad() + ((self.parentViewController as! UINavigationController).viewControllers[0] as! SettingsTableViewController).table.reloadData() + NSNotificationCenter.defaultCenter().removeObserver(self, name: "reloadDataS", object: nil) + } + @@ -85,6 +89,7 @@ class DisplayDetailViewController: UIViewController { */ } +/* class EmailDetailViewController: UIViewController { var possibleEmail: String! @@ -97,26 +102,31 @@ class EmailDetailViewController: UIViewController { self.possibleEmail = self.textfield?.text //sanitize and alert for input and success later - - var query = PFUser.query() - var currentUser = PFUser.currentUser() - - query!.whereKey("username", equalTo: (currentUser?.username as String!)) - - query!.getFirstObjectInBackgroundWithBlock { - (object, error) -> Void in + if(contains(self.possibleEmail, "@")){ + var query = PFUser.query() + var currentUser = PFUser.currentUser() - if error != nil || object == nil { - println("Object request failed") - } - else if let object = object{ - object.setObject(self.possibleEmail, forKey: "email") - object.saveInBackground() - NSNotificationCenter.defaultCenter().postNotificationName("savingEmail", object: nil) + query!.whereKey("username", equalTo: (currentUser?.username as String!)) + + query!.getFirstObjectInBackgroundWithBlock { + (object, error) -> Void in + + if error != nil || object == nil { + println("Object request failed") + } + else if let object = object{ + object.setObject(self.possibleEmail, forKey: "email") + object.saveInBackground() + + NSNotificationCenter.defaultCenter().addObserver(self, selector: "refreshSettings:", name: "reloadDataS", object: nil) + (self.tabBarController as! HomeTabController).reloadParseData() + } } + + println(self.possibleEmail) } - - println(self.possibleEmail) + + } @@ -135,7 +145,7 @@ class EmailDetailViewController: UIViewController { self.ChnEmailBtn.layer.cornerRadius = 5 self.ChnEmailBtn.layer.borderColor = UIColor.blackColor().CGColor // Do any additional setup after loading the view. - NSNotificationCenter.defaultCenter().addObserver(self, selector: "refreshView:", name: "savingEmail", object: nil) + } override func didReceiveMemoryWarning() { @@ -143,8 +153,10 @@ class EmailDetailViewController: UIViewController { // Dispose of any resources that can be recreated. } - func refreshView(notification: NSNotification){ - + func refreshSettings(notification: NSNotification){ + ((self.parentViewController as! UINavigationController).viewControllers[0] as! SettingsTableViewController).viewDidLoad() + ((self.parentViewController as! UINavigationController).viewControllers[0] as! SettingsTableViewController).table.reloadData() + NSNotificationCenter.defaultCenter().removeObserver(self, name: "reloadDataS", object: nil) } /* @@ -158,6 +170,69 @@ class EmailDetailViewController: UIViewController { */ } +*/ + +class ResetPassDetailViewController: UIViewController { + @IBOutlet weak var currPass: UITextField! + @IBOutlet weak var newPass: UITextField! + @IBOutlet weak var chgPassBtn: UIButton! + + @IBAction func changePass(sender: UIButton){ + + PFUser.logInWithUsernameInBackground(self.email, password: self.currPass.text! ) { + + (user, error) -> Void in + + if error == nil { + + var query = PFUser.query() + + query!.whereKey("username", equalTo: PFUser.currentUser()!.username!) + + query?.findObjectsInBackgroundWithBlock({ + (objects, error) -> Void in + + for object in objects! { + var obj: PFObject = object as! PFObject + + obj.setObject(self.newPass.text!, forKey: "password") + + obj.save() + + let alert = UIAlertController(title: "Password Changed", message: "Your password has been updated", preferredStyle: .Alert) + alert.addAction(UIAlertAction(title: "OK", style: .Default, handler:{(action: UIAlertAction!) in alert.dismissViewControllerAnimated(true, completion: nil)})) + self.presentViewController(alert, animated: true, completion: nil) + } + + + + }) + + } else { + + let alert = UIAlertController(title: "Incorrect Password", message: "The password you gave as your current password was incorrect. Please enter the correct password.", preferredStyle: .Alert) + alert.addAction(UIAlertAction(title: "OK", style: .Default, handler:{(action: UIAlertAction!) in alert.dismissViewControllerAnimated(true, completion: nil)})) + self.presentViewController(alert, animated: true, completion: nil) + } + } + } + + var email: String! + + func setData(email: String){ + self.email = email + } + + override func viewDidLoad() { + super.viewDidLoad() + + //rounded border for button + self.chgPassBtn.layer.borderWidth = 1 + self.chgPassBtn.layer.cornerRadius = 5 + self.chgPassBtn.layer.borderColor = UIColor.blackColor().CGColor + + } +} class ProfileDetailViewController: UIViewController, UINavigationControllerDelegate, UIImagePickerControllerDelegate { var profileImg: UIImageView! @@ -244,6 +319,31 @@ extension ProfileDetailViewController: UIImagePickerControllerDelegate{ //MARK: -Image Picker Delegate func imagePickerController(picker: UIImagePickerController, didFinishPickingImage image: UIImage!, editingInfo: [NSObject : AnyObject]!) { + var img:PFFile = PFFile(data: UIImageJPEGRepresentation(image, 1.0))! + + var query = PFUser.query() + var currentUser = PFUser.currentUser() + + query!.whereKey("username", equalTo: (currentUser?.username as String!)) + + query!.getFirstObjectInBackgroundWithBlock { + (object, error) -> Void in + + if error != nil || object == nil { + println("Object request failed") + } + else if let object = object{ + object.setObject(img, forKey: "profilePicture") + object.saveInBackground() + //NSNotificationCenter.defaultCenter().postNotificationName("", object: nil) + } + } + self.img.image = image + + var homeController = self.tabBarController as? HomeTabController + homeController?.userData[0].profileImg.image = image + dismissViewControllerAnimated(true, completion: nil) + } func imagePickerControllerDidCancel(picker: UIImagePickerController) { diff --git a/GetHip/SettingsTableViewController.swift b/GetHip/SettingsTableViewController.swift index 794631b..ded4cf2 100644 --- a/GetHip/SettingsTableViewController.swift +++ b/GetHip/SettingsTableViewController.swift @@ -68,7 +68,7 @@ class SettingsTableViewController: UIViewController, UITableViewDataSource, UITa self.navigationController?.navigationBarHidden = false self.table.tableFooterView = UIView(frame: CGRectZero) self.party.delegate = self - //NSNotificationCenter.defaultCenter().addObserver(self, selector: "refreshTable:", name: "refreshSettingsView", object: nil) + NSNotificationCenter.defaultCenter().addObserver(self, selector: "refreshTable:", name: "refreshSettingsView", object: nil) self.table.reloadData() // Uncomment the following line to preserve selection between presentations @@ -96,7 +96,7 @@ class SettingsTableViewController: UIViewController, UITableViewDataSource, UITa func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { // #warning Incomplete method implementation. // Return the number of rows in the section. - return 5 + return 4 } func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { @@ -110,7 +110,7 @@ class SettingsTableViewController: UIViewController, UITableViewDataSource, UITa } return cell - + /* case 1: let cell = (self.table.dequeueReusableCellWithIdentifier("UserNameCell", forIndexPath: indexPath) as? UserNameCell)! @@ -119,8 +119,8 @@ class SettingsTableViewController: UIViewController, UITableViewDataSource, UITa } return cell - - case 2: + */ + case 1: let cell = (self.table.dequeueReusableCellWithIdentifier("EmailCell", forIndexPath: indexPath) as? EmailCell)! if self.user.count > 0 { @@ -128,7 +128,7 @@ class SettingsTableViewController: UIViewController, UITableViewDataSource, UITa } return cell - case 3: + case 2: let cell = (self.table.dequeueReusableCellWithIdentifier("PassCell", forIndexPath: indexPath) as? ResetPassCell)! if self.user.count > 0 { @@ -139,10 +139,6 @@ class SettingsTableViewController: UIViewController, UITableViewDataSource, UITa default: let cell = (self.table.dequeueReusableCellWithIdentifier("PictureCell", forIndexPath: indexPath) as? ProfilePicCell)! - if self.user.count > 0 { - - } - return cell } @@ -161,6 +157,7 @@ class SettingsTableViewController: UIViewController, UITableViewDataSource, UITa } //user name view + /* case 1: if self.user.count > 0 { @@ -169,19 +166,21 @@ class SettingsTableViewController: UIViewController, UITableViewDataSource, UITa } break - + */ //email view - case 2: + case 1: + break + /* if self.user.count > 0 { self.performSegueWithIdentifier("EmailSegue", sender: nil) } - + */ //reset pass - case 3: + case 2: if self.user.count > 0 { - + self.performSegueWithIdentifier("ResetPassSegue", sender: nil) } break @@ -210,20 +209,24 @@ class SettingsTableViewController: UIViewController, UITableViewDataSource, UITa } //email view - case 2: - + case 1: + break + /* if self.user.count > 0 { let vc: EmailDetailViewController = (segue.destinationViewController as? EmailDetailViewController)! vc.setData((self.user[0] as? UserParseData)!.email) println(vc.email) } - + */ //reset pass - case 3: + case 2: if self.user.count > 0 { + let vc: ResetPassDetailViewController = (segue.destinationViewController as? ResetPassDetailViewController)! + vc.setData((self.user[0] as? UserParseData)!.email) + println(vc.email) } //Profile Picture View @@ -241,10 +244,10 @@ class SettingsTableViewController: UIViewController, UITableViewDataSource, UITa } - /* func refreshTable(notification: NSNotification){ - self.user = manager.getUser() + func refreshTable(notification: NSNotification){ + //self.user = manager.getUser() self.table.reloadData() - }*/ + } /* override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { diff --git a/GetHip/SignInController.swift b/GetHip/SignInController.swift index b60cdb3..c3927bd 100644 --- a/GetHip/SignInController.swift +++ b/GetHip/SignInController.swift @@ -10,7 +10,7 @@ import UIKit class SignInController: UIViewController, UINavigationControllerDelegate, UIImagePickerControllerDelegate, UITextFieldDelegate { @IBOutlet var nameField: UITextField! - @IBOutlet var userField: UITextField! + //@IBOutlet var userField: UITextField! @IBOutlet var emailField: UITextField! @IBOutlet var passField: UITextField! @IBOutlet var saveBtn: UIButton! @@ -22,7 +22,7 @@ class SignInController: UIViewController, UINavigationControllerDelegate, UIImag @IBAction func saveNewProfile(sender: UIButton){ if(self.nameField.hasText() == false - || self.userField.hasText() == false + /*|| self.userField.hasText() == false*/ || self.emailField.hasText() == false || self.passField.hasText() == false || self.profilePic.image == nil){ @@ -33,9 +33,9 @@ class SignInController: UIViewController, UINavigationControllerDelegate, UIImag self.presentViewController(alert, animated: true, completion: nil) }else{ - if(!(contains(self.userField.text!, "@") || contains(self.nameField.text!, "@"))){ + if /*(!(contains(self.userField.text!, "@") ||*/ contains(self.nameField.text!, "@"){ - let predicate: NSPredicate = NSPredicate(format: "((username = %@) OR (email = %@))", argumentArray: [self.nameField.text!,self.emailField.text!]) + let predicate: NSPredicate = NSPredicate(format: "(email = %@)", argumentArray: [self.emailField.text!]) var userQuery: PFQuery = PFQuery(className: "_User", predicate: predicate) dispatch_async(dispatch_get_main_queue(), { @@ -49,8 +49,8 @@ class SignInController: UIViewController, UINavigationControllerDelegate, UIImag self.presentViewController(alert, animated: true, completion: nil) }else{ var user = PFUser() - var img:PFFile = PFFile(data: UIImagePNGRepresentation(self.profilePic.image))! - user.username = self.userField.text! + var img:PFFile = PFFile(data: UIImageJPEGRepresentation(self.profilePic.image, 1.0))! + user.username = self.emailField.text! user.password = self.passField.text! user.email = self.emailField.text! user.setObject(self.nameField.text!, forKey: "displayName") @@ -63,7 +63,7 @@ class SignInController: UIViewController, UINavigationControllerDelegate, UIImag if error == nil { //self.performSegueWithIdentifier("SignedUpSegue", sender: self) let storyboard = UIStoryboard(name: "Main", bundle: nil) - let tabBarController = storyboard.instantiateViewControllerWithIdentifier("TabControllerVC") as! UITabBarController + let tabBarController = storyboard.instantiateViewControllerWithIdentifier("TabControlVC") as! UITabBarController let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate appDelegate.window?.rootViewController = tabBarController } @@ -132,7 +132,7 @@ class SignInController: UIViewController, UINavigationControllerDelegate, UIImag self.nameField.delegate = self self.passField.delegate = self - self.userField.delegate = self + //self.userField.delegate = self self.emailField.delegate = self @@ -191,7 +191,7 @@ extension SignInController: UIImagePickerControllerDelegate{ func imagePickerController(picker: UIImagePickerController, didFinishPickingImage image: UIImage!, editingInfo: [NSObject : AnyObject]!) { self.profilePic.image = image - + dismissViewControllerAnimated(true, completion: nil) } func imagePickerControllerDidCancel(picker: UIImagePickerController) { diff --git a/GetHip/TDAudioPlayerConstants.h b/GetHip/TDAudioPlayerConstants.h new file mode 100755 index 0000000..d8c7890 --- /dev/null +++ b/GetHip/TDAudioPlayerConstants.h @@ -0,0 +1,26 @@ +// +// TDAudioPlayerConstants.h +// TDAudioPlayer +// +// Created by Tony DiPasquale on 11/5/13. +// Copyright (c) 2013 Tony DiPasquale. The MIT License (MIT). +// + +#import "Foundation/Foundation.h" + + +extern NSString *const TDAudioPlayerDidChangeAudioNotification; +extern NSString *const TDAudioPlayerDidPauseNotification; +extern NSString *const TDAudioPlayerDidPlayNotification; +extern NSString *const TDAudioPlayerDidStopNotification; + +extern NSString *const TDAudioPlayerNextTrackRequestNotification; +extern NSString *const TDAudioPlayerPreviousTrackRequestNotification; + +extern NSString *const TDAudioStreamDidFinishPlayingNotification; +extern NSString *const TDAudioStreamDidStartPlayingNotification; + +extern UInt32 const kTDAudioStreamReadMaxLength; +extern UInt32 const kTDAudioQueueBufferSize; +extern UInt32 const kTDAudioQueueBufferCount; +extern UInt32 const kTDAudioQueueStartMinimumBuffers; diff --git a/GetHip/TDAudioPlayerConstants.m b/GetHip/TDAudioPlayerConstants.m new file mode 100755 index 0000000..b3a9b9f --- /dev/null +++ b/GetHip/TDAudioPlayerConstants.m @@ -0,0 +1,25 @@ +// +// TDAudioPlayerConstants.m +// TDAudioPlayer +// +// Created by Tony DiPasquale on 11/5/13. +// Copyright (c) 2013 Tony DiPasquale. The MIT License (MIT). +// + +#import "TDAudioPlayerConstants.h" + +NSString *const TDAudioPlayerDidChangeAudioNotification = @"TDAudioPlayerDidChangeAudioNotification"; +NSString *const TDAudioPlayerDidPauseNotification = @"TDAudioPlayerDidPauseNotification"; +NSString *const TDAudioPlayerDidPlayNotification = @"TDAudioPlayerDidPlayNotification"; +NSString *const TDAudioPlayerDidStopNotification = @"TDAudioPlayerDidStopNotification"; + +NSString *const TDAudioPlayerNextTrackRequestNotification = @"TDAudioPlayerNextTrackRequestNotification"; +NSString *const TDAudioPlayerPreviousTrackRequestNotification = @"TDAudioPlayerPreviousTrackRequestNotification"; + +NSString *const TDAudioStreamDidFinishPlayingNotification = @"TDAudioStreamDidFinishPlayingNotification"; +NSString *const TDAudioStreamDidStartPlayingNotification = @"TDAudioStreamDidStartPlayingNotification"; + +UInt32 const kTDAudioStreamReadMaxLength = 512; +UInt32 const kTDAudioQueueBufferSize = 2048; +UInt32 const kTDAudioQueueBufferCount = 16; +UInt32 const kTDAudioQueueStartMinimumBuffers = 8; diff --git a/GetHip/UserParseData.swift b/GetHip/UserParseData.swift index 68b5092..2b65339 100644 --- a/GetHip/UserParseData.swift +++ b/GetHip/UserParseData.swift @@ -11,15 +11,15 @@ import Foundation import Foundation class UserParseData { - var username: String! + //var username: String! var displayName: String! var profileImg: UIImageView! var email: String! - init(usrName: String, dispName: String, email: String){ - self.username = usrName + init(dispName: String, email: String){ + //self.username = usrName self.profileImg = nil //proImage self.displayName = dispName self.email = email diff --git a/GetHip/UserParseDataSource.swift b/GetHip/UserParseDataSource.swift index 96111c1..f0900b7 100644 --- a/GetHip/UserParseDataSource.swift +++ b/GetHip/UserParseDataSource.swift @@ -16,7 +16,7 @@ class UserParseDataSource{ var query = PFUser.query() var currentUser = PFUser.currentUser() - query!.whereKey("username", equalTo: (currentUser?.username as String!)) + query!.whereKey("email", equalTo: (currentUser?.email as String!)) query!.findObjectsInBackgroundWithBlock { (objects, error) -> Void in @@ -25,24 +25,23 @@ class UserParseDataSource{ for object in objects! { var usr: UserParseData - var usrName: String! + //var usrName: String! var profileImage: UIImageView var displayName: String var email: String - usrName = object.objectForKey("username")! as! String + //usrName = object.objectForKey("username")! as! String displayName = object.objectForKey("displayName") as! String - + /* if displayName.isEmpty { displayName = usrName } - + */ email = object.objectForKey("email")! as! String - - usr = UserParseData(usrName: usrName, dispName: displayName, email: email) + usr = UserParseData(dispName: displayName, email: email) var img = object.objectForKey("profilePicture")! as? PFFile