This new method should cause all stops to default to immediate stoppage, and only stops that occur after an end of track signal should indicate to play out the entire buffer. Signed-off-by: Christopher Snowhill <kode54@gmail.com>
205 lines
4 KiB
Objective-C
205 lines
4 KiB
Objective-C
//
|
|
// OutputNode.m
|
|
// Cog
|
|
//
|
|
// Created by Vincent Spader on 8/2/05.
|
|
// Copyright 2005 Vincent Spader. All rights reserved.
|
|
//
|
|
|
|
#import "OutputNode.h"
|
|
#import "AudioPlayer.h"
|
|
#import "BufferChain.h"
|
|
#import "OutputAVFoundation.h"
|
|
|
|
#import "Logging.h"
|
|
|
|
@implementation OutputNode
|
|
|
|
- (void)setup {
|
|
amountPlayed = 0.0;
|
|
amountPlayedInterval = 0.0;
|
|
|
|
paused = YES;
|
|
started = NO;
|
|
intervalReported = NO;
|
|
|
|
output = [[OutputAVFoundation alloc] initWithController:self];
|
|
|
|
[output setup];
|
|
}
|
|
|
|
- (void)seek:(double)time {
|
|
// [output pause];
|
|
[self resetBuffer];
|
|
|
|
amountPlayed = time;
|
|
}
|
|
|
|
- (void)process {
|
|
paused = NO;
|
|
[output start];
|
|
}
|
|
|
|
- (void)pause {
|
|
paused = YES;
|
|
[output pause];
|
|
}
|
|
|
|
- (void)resume {
|
|
paused = NO;
|
|
[output resume];
|
|
}
|
|
|
|
- (void)incrementAmountPlayed:(double)seconds {
|
|
amountPlayed += seconds;
|
|
amountPlayedInterval += seconds;
|
|
if(!intervalReported && amountPlayedInterval >= 60.0) {
|
|
intervalReported = YES;
|
|
[controller reportPlayCount];
|
|
}
|
|
}
|
|
|
|
- (void)resetAmountPlayed {
|
|
amountPlayed = 0;
|
|
}
|
|
|
|
- (void)resetAmountPlayedInterval {
|
|
amountPlayedInterval = 0;
|
|
intervalReported = NO;
|
|
}
|
|
|
|
- (BOOL)selectNextBuffer {
|
|
return [controller selectNextBuffer];
|
|
}
|
|
|
|
- (void)endOfInputPlayed {
|
|
if(!intervalReported) {
|
|
intervalReported = YES;
|
|
[controller reportPlayCount];
|
|
}
|
|
[controller endOfInputPlayed];
|
|
[self resetAmountPlayedInterval];
|
|
}
|
|
|
|
- (BOOL)chainQueueHasTracks {
|
|
return [controller chainQueueHasTracks];
|
|
}
|
|
|
|
- (double)secondsBuffered {
|
|
return [buffer listDuration];
|
|
}
|
|
|
|
- (AudioChunk *)readChunk:(size_t)amount {
|
|
@autoreleasepool {
|
|
[self setPreviousNode:[[controller bufferChain] finalNode]];
|
|
|
|
AudioChunk *ret = [super readChunk:amount];
|
|
|
|
/* if (n == 0) {
|
|
DLog(@"Output Buffer dry!");
|
|
}
|
|
*/
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
- (BOOL)peekFormat:(nonnull AudioStreamBasicDescription *)format channelConfig:(nonnull uint32_t *)config {
|
|
@autoreleasepool {
|
|
[self setPreviousNode:[[controller bufferChain] finalNode]];
|
|
|
|
return [super peekFormat:format channelConfig:config];
|
|
}
|
|
}
|
|
|
|
- (double)amountPlayed {
|
|
return amountPlayed;
|
|
}
|
|
|
|
- (double)amountPlayedInterval {
|
|
return amountPlayedInterval;
|
|
}
|
|
|
|
- (AudioStreamBasicDescription)format {
|
|
return format;
|
|
}
|
|
|
|
- (uint32_t)config {
|
|
return config;
|
|
}
|
|
|
|
- (void)setFormat:(AudioStreamBasicDescription *)f channelConfig:(uint32_t)channelConfig {
|
|
format = *f;
|
|
config = channelConfig;
|
|
// Calculate a ratio and add to double(seconds) instead, as format may change
|
|
// double oldSampleRatio = sampleRatio;
|
|
BufferChain *bufferChain = [controller bufferChain];
|
|
if(bufferChain) {
|
|
ConverterNode *converter = [bufferChain converter];
|
|
if(converter) {
|
|
// This clears the resampler buffer, but not the input buffer
|
|
// We also have to jump the play position ahead accounting for
|
|
// the data we are flushing
|
|
amountPlayed += [[converter buffer] listDuration];
|
|
|
|
AudioStreamBasicDescription inf = [bufferChain inputFormat];
|
|
uint32_t config = [bufferChain inputConfig];
|
|
|
|
format.mChannelsPerFrame = inf.mChannelsPerFrame;
|
|
format.mBytesPerFrame = ((inf.mBitsPerChannel + 7) / 8) * format.mChannelsPerFrame;
|
|
format.mBytesPerPacket = format.mBytesPerFrame * format.mFramesPerPacket;
|
|
channelConfig = config;
|
|
|
|
[converter inputFormatDidChange:[bufferChain inputFormat] inputConfig:[bufferChain inputConfig]];
|
|
}
|
|
}
|
|
}
|
|
|
|
- (void)close {
|
|
[output stop];
|
|
output = nil;
|
|
}
|
|
|
|
- (void)setVolume:(double)v {
|
|
[output setVolume:v];
|
|
}
|
|
|
|
- (void)setShouldContinue:(BOOL)s {
|
|
[super setShouldContinue:s];
|
|
|
|
// if (s == NO)
|
|
// [output stop];
|
|
}
|
|
|
|
- (void)setShouldPlayOutBuffer:(BOOL)s {
|
|
[output setShouldPlayOutBuffer:s];
|
|
}
|
|
|
|
- (BOOL)isPaused {
|
|
return paused;
|
|
}
|
|
|
|
- (void)beginEqualizer:(AudioUnit)eq {
|
|
[controller beginEqualizer:eq];
|
|
}
|
|
|
|
- (void)refreshEqualizer:(AudioUnit)eq {
|
|
[controller refreshEqualizer:eq];
|
|
}
|
|
|
|
- (void)endEqualizer:(AudioUnit)eq {
|
|
[controller endEqualizer:eq];
|
|
}
|
|
|
|
- (void)sustainHDCD {
|
|
[output sustainHDCD];
|
|
}
|
|
|
|
- (void)restartPlaybackAtCurrentPosition {
|
|
[controller restartPlaybackAtCurrentPosition];
|
|
}
|
|
|
|
- (double)latency {
|
|
return [output latency];
|
|
}
|
|
|
|
@end
|