[Audio Output] Play last track and stop correctly

Play last track up until it actually ends, and stop on command.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
lastfm
Christopher Snowhill 2022-06-25 06:42:56 -07:00
parent 99fad892f0
commit c489d7ca91
5 changed files with 25 additions and 12 deletions

View File

@ -452,11 +452,16 @@
} while(0); } while(0);
if(signalStopped) { if(signalStopped) {
double latency = 0;
if(output) latency = [output latency];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, latency * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
[self stop]; [self stop];
bufferChain = nil; self->bufferChain = nil;
[self notifyPlaybackStopped:nil]; [self notifyPlaybackStopped:nil];
});
return YES; return YES;
} }

View File

@ -51,6 +51,8 @@
- (void)close; - (void)close;
- (void)seek:(double)time; - (void)seek:(double)time;
- (double)latency;
- (AudioChunk *)readChunk:(size_t)amount; - (AudioChunk *)readChunk:(size_t)amount;
- (void)setFormat:(AudioStreamBasicDescription *)f channelConfig:(uint32_t)channelConfig; - (void)setFormat:(AudioStreamBasicDescription *)f channelConfig:(uint32_t)channelConfig;

View File

@ -186,4 +186,8 @@
[controller restartPlaybackAtCurrentPosition]; [controller restartPlaybackAtCurrentPosition];
} }
- (double)latency {
return [output latency];
}
@end @end

View File

@ -50,7 +50,6 @@ using std::atomic_long;
BOOL started; BOOL started;
BOOL paused; BOOL paused;
BOOL restarted; BOOL restarted;
BOOL stopFlush;
BOOL commandStop; BOOL commandStop;
BOOL eqEnabled; BOOL eqEnabled;
@ -122,6 +121,8 @@ using std::atomic_long;
- (void)resume; - (void)resume;
- (void)stop; - (void)stop;
- (double)latency;
- (void)setVolume:(double)v; - (void)setVolume:(double)v;
- (void)setEqualizerEnabled:(BOOL)enabled; - (void)setEqualizerEnabled:(BOOL)enabled;

View File

@ -325,7 +325,6 @@ current_device_listener(AudioObjectID inObjectID, UInt32 inNumberAddresses, cons
running = YES; running = YES;
started = NO; started = NO;
secondsLatency = 1.0; secondsLatency = 1.0;
stopFlush = NO;
while(!stopping) { while(!stopping) {
if([outputController shouldReset]) { if([outputController shouldReset]) {
@ -361,7 +360,6 @@ current_device_listener(AudioObjectID inObjectID, UInt32 inNumberAddresses, cons
CFRelease(bufferRef); CFRelease(bufferRef);
} else { } else {
stopFlush = YES;
break; break;
} }
} }
@ -1021,6 +1019,11 @@ current_device_listener(AudioObjectID inObjectID, UInt32 inNumberAddresses, cons
eqEnabled = enabled; eqEnabled = enabled;
} }
- (double)latency {
if(secondsLatency > 0) return secondsLatency;
else return 0;
}
- (void)start { - (void)start {
[self threadEntry:nil]; [self threadEntry:nil];
} }
@ -1032,13 +1035,9 @@ current_device_listener(AudioObjectID inObjectID, UInt32 inNumberAddresses, cons
- (void)doStop { - (void)doStop {
if(stopInvoked) { if(stopInvoked) {
stopFlush = NO;
return; return;
} }
@synchronized(self) { @synchronized(self) {
if(commandStop) {
stopFlush = NO;
}
stopInvoked = YES; stopInvoked = YES;
if(observersapplied) { if(observersapplied) {
[[NSUserDefaultsController sharedUserDefaultsController] removeObserver:self forKeyPath:@"values.outputDevice" context:kOutputAVFoundationContext]; [[NSUserDefaultsController sharedUserDefaultsController] removeObserver:self forKeyPath:@"values.outputDevice" context:kOutputAVFoundationContext];
@ -1074,14 +1073,16 @@ current_device_listener(AudioObjectID inObjectID, UInt32 inNumberAddresses, cons
} }
if(renderSynchronizer || audioRenderer) { if(renderSynchronizer || audioRenderer) {
if(renderSynchronizer) { if(renderSynchronizer) {
if(stopFlush) { if(!commandStop) {
int compareVal = 0; int compareVal = 0;
double secondsLatency = self->secondsLatency >= 0 ? self->secondsLatency : 0;
int compareMax = (((1000000 / 5000) * secondsLatency) + (10000 / 5000)); // latency plus 10ms, divide by sleep intervals
do { do {
[currentPtsLock lock]; [currentPtsLock lock];
compareVal = CMTimeCompare(outputPts, currentPts); compareVal = CMTimeCompare(outputPts, currentPts);
[currentPtsLock unlock]; [currentPtsLock unlock];
usleep(5000); usleep(5000);
} while(stopFlush && compareVal > 0); } while(!commandStop && compareVal > 0 && compareMax-- > 0);
} }
[self removeSynchronizerBlock]; [self removeSynchronizerBlock];
[renderSynchronizer setRate:0]; [renderSynchronizer setRate:0];