From fff87c17f1edd794fbaa7888871b8129c877dfbf Mon Sep 17 00:00:00 2001 From: Joel Fischer Date: Thu, 30 May 2019 09:58:34 -0400 Subject: [PATCH 1/6] Add audio data queueing to the audio stream manager --- SmartDeviceLink/SDLAudioFile.h | 32 +++++++++++++++++++++++-- SmartDeviceLink/SDLAudioFile.m | 9 +++++++ SmartDeviceLink/SDLAudioStreamManager.h | 7 ++++++ SmartDeviceLink/SDLAudioStreamManager.m | 30 ++++++++++++++++++++++- 4 files changed, 75 insertions(+), 3 deletions(-) diff --git a/SmartDeviceLink/SDLAudioFile.h b/SmartDeviceLink/SDLAudioFile.h index e34c37a8d..794c50cab 100755 --- a/SmartDeviceLink/SDLAudioFile.h +++ b/SmartDeviceLink/SDLAudioFile.h @@ -12,21 +12,49 @@ NS_ASSUME_NONNULL_BEGIN @interface SDLAudioFile : NSObject -@property (copy, nonatomic, readonly) NSURL *inputFileURL; +/** + If initialized with a file URL, the file URL it came from + */ +@property (nullable, copy, nonatomic, readonly) NSURL *inputFileURL; -@property (copy, nonatomic, readonly) NSURL *outputFileURL; +/** + If initialized with a file URL, where the transcoder should produce the transcoded PCM audio file + */ +@property (nullable, copy, nonatomic, readonly) NSURL *outputFileURL; /** In seconds. UINT32_MAX if unknown. */ @property (assign, nonatomic) UInt32 estimatedDuration; +/** + The PCM audio data to be transferred and played + */ @property (copy, nonatomic, readonly) NSData *data; +/** + The size of the PCM audio data in bytes + */ @property (assign, nonatomic, readonly) unsigned long long fileSize; +/** + Initialize an audio file to be queued and played + + @param inputURL The file that exists on the device to be transcoded and queued + @param outputURL The target URL that the transcoded file will be output to + @param duration The duration of the file + @return The audio file object + */ - (instancetype)initWithInputFileURL:(NSURL *)inputURL outputFileURL:(NSURL *)outputURL estimatedDuration:(UInt32)duration; +/** + Initialize a buffer of PCM audio data to be queued and played + + @param data The PCM audio data buffer + @return The audio file object + */ +- (instancetype)initWithData:(NSData *)data; + @end NS_ASSUME_NONNULL_END diff --git a/SmartDeviceLink/SDLAudioFile.m b/SmartDeviceLink/SDLAudioFile.m index 1d0e2ef98..46b50f540 100755 --- a/SmartDeviceLink/SDLAudioFile.m +++ b/SmartDeviceLink/SDLAudioFile.m @@ -32,6 +32,15 @@ - (instancetype)initWithInputFileURL:(NSURL *)inputURL outputFileURL:(NSURL *)ou return self; } +- (instancetype)initWithData:(NSData *)data { + self = [super init]; + if (!self) { return nil; } + + _data = data; + + return self; +} + - (NSData *)data { if (_data.length == 0) { return [NSData dataWithContentsOfURL:_outputFileURL]; diff --git a/SmartDeviceLink/SDLAudioStreamManager.h b/SmartDeviceLink/SDLAudioStreamManager.h index e6608f8e1..bb44ef978 100755 --- a/SmartDeviceLink/SDLAudioStreamManager.h +++ b/SmartDeviceLink/SDLAudioStreamManager.h @@ -66,6 +66,13 @@ typedef NS_ENUM(NSInteger, SDLAudioStreamManagerError) { */ - (void)pushWithFileURL:(NSURL *)fileURL; +/** + Push a new audio buffer onto the queue. Call `playNextWhenReady` to start playing the pushed audio buffer. + + @param data The audio buffer to be pushed onto the queue + */ +- (void)pushWithData:(NSData *)data; + /** Play the next item in the queue. If an item is currently playing, it will continue playing and this item will begin playing after it is completed. diff --git a/SmartDeviceLink/SDLAudioStreamManager.m b/SmartDeviceLink/SDLAudioStreamManager.m index 69312b0b5..f91db09c5 100755 --- a/SmartDeviceLink/SDLAudioStreamManager.m +++ b/SmartDeviceLink/SDLAudioStreamManager.m @@ -46,10 +46,15 @@ - (instancetype)initWithManager:(id)streamManager return self; } +#pragma mark - Getters + - (NSArray *)queue { return [_mutableQueue copy]; } +#pragma mark - Pushing to the Queue +#pragma mark Files + - (void)pushWithFileURL:(NSURL *)fileURL { dispatch_async(_audioQueue, ^{ [self sdl_pushWithContentsOfURL:fileURL]; @@ -79,6 +84,21 @@ - (void)sdl_pushWithContentsOfURL:(NSURL *)fileURL { } } +#pragma mark Raw Data + +- (void)pushWithData:(NSData *)data { + dispatch_async(_audioQueue, ^{ + [self sdl_pushWithData:data]; + }); +} + +- (void)sdl_pushWithData:(NSData *)data { + SDLAudioFile *audioFile = [[SDLAudioFile alloc] initWithData:data]; + [self.mutableQueue addObject:audioFile]; +} + +#pragma mark Playing from the Queue + - (void)playNextWhenReady { dispatch_async(_audioQueue, ^{ [self sdl_playNextWhenReady]; @@ -104,8 +124,14 @@ - (void)sdl_playNextWhenReady { [self.mutableQueue removeObjectAtIndex:0]; // Strip the first bunch of bytes (because of how Apple outputs the data) and send to the audio stream, if we don't do this, it will make a weird click sound + NSData *audioData = nil; + if (file.inputFileURL != nil) { + audioData = [file.data subdataWithRange:NSMakeRange(5760, (file.data.length - 5760))]; + } else { + audioData = file.data; + } + SDLLogD(@"Playing audio file: %@", file); - NSData *audioData = [file.data subdataWithRange:NSMakeRange(5760, (file.data.length - 5760))]; __block BOOL success = [self.streamManager sendAudioData:audioData]; self.playing = YES; @@ -125,6 +151,8 @@ - (void)sdl_playNextWhenReady { }); } +#pragma mark - Stopping Playback + - (void)stop { dispatch_async(_audioQueue, ^{ self.shouldPlayWhenReady = NO; From 0bc09b69b1e6ff98aed152b460f83e5a54c3ad15 Mon Sep 17 00:00:00 2001 From: Joel Fischer Date: Thu, 30 May 2019 10:24:04 -0400 Subject: [PATCH 2/6] Create and call proper audio stream manager delegate methods --- SmartDeviceLink/SDLAudioStreamManager.m | 15 ++++++++++++-- .../SDLAudioStreamManagerDelegate.h | 20 ++++++++++++++++++- 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/SmartDeviceLink/SDLAudioStreamManager.m b/SmartDeviceLink/SDLAudioStreamManager.m index f91db09c5..1ea9ac3ee 100755 --- a/SmartDeviceLink/SDLAudioStreamManager.m +++ b/SmartDeviceLink/SDLAudioStreamManager.m @@ -131,22 +131,33 @@ - (void)sdl_playNextWhenReady { audioData = file.data; } + // Send the audio file, which starts it playing immediately SDLLogD(@"Playing audio file: %@", file); __block BOOL success = [self.streamManager sendAudioData:audioData]; self.playing = YES; + // Determine the length of the audio PCM data and perform a few items once the audio has finished playing float audioLengthSecs = (float)audioData.length / (float)32000.0; __weak typeof(self) weakself = self; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(audioLengthSecs * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ weakself.playing = NO; NSError *error = nil; if (weakself.delegate != nil) { - [weakself.delegate audioStreamManager:weakself fileDidFinishPlaying:file.inputFileURL successfully:success]; + if (file.inputFileURL != nil) { + [weakself.delegate audioStreamManager:weakself fileDidFinishPlaying:file.inputFileURL successfully:success]; + } else if ([weakself.delegate respondsToSelector:@selector(audioStreamManager:dataBufferDidFinishPlayingSuccessfully:)]) { + [weakself.delegate audioStreamManager:weakself dataBufferDidFinishPlayingSuccessfully:success]; + } } + SDLLogD(@"Ending Audio file: %@", file); [[NSFileManager defaultManager] removeItemAtURL:file.outputFileURL error:&error]; if (weakself.delegate != nil && error != nil) { - [weakself.delegate audioStreamManager:weakself errorDidOccurForFile:file.inputFileURL error:error]; + if (file.inputFileURL != nil) { + [weakself.delegate audioStreamManager:weakself errorDidOccurForFile:file.inputFileURL error:error]; + } else if ([weakself.delegate respondsToSelector:@selector(audioStreamManager:errorDidOccurForDataBuffer:)]) { + [weakself.delegate audioStreamManager:weakself errorDidOccurForDataBuffer:error]; + } } }); } diff --git a/SmartDeviceLink/SDLAudioStreamManagerDelegate.h b/SmartDeviceLink/SDLAudioStreamManagerDelegate.h index acad1472c..04235d95d 100755 --- a/SmartDeviceLink/SDLAudioStreamManagerDelegate.h +++ b/SmartDeviceLink/SDLAudioStreamManagerDelegate.h @@ -29,12 +29,30 @@ NS_ASSUME_NONNULL_BEGIN /** Called when a file from the SDLAudioStreamManager could not play - @param audioManager A reference to the audio stream manager + @param audioManager A reference to the audio stream manager @param fileURL The URL that failed @param error The error that occurred */ - (void)audioStreamManager:(SDLAudioStreamManager *)audioManager errorDidOccurForFile:(NSURL *)fileURL error:(NSError *)error; +@optional + +/** + Called when a data buffer from the SDLAudioStreamManager finishes playing + + @param audioManager A reference to the audio stream manager + @param successfully Whether or not the data buffer played successfully + */ +- (void)audioStreamManager:(SDLAudioStreamManager *)audioManager dataBufferDidFinishPlayingSuccessfully:(BOOL)successfully; + +/** + Called when a data buffer from the SDLAudioStreamManager could not play + + @param audioManager A reference to the audio stream manager + @param error The error that occurred + */ +- (void)audioStreamManager:(SDLAudioStreamManager *)audioManager errorDidOccurForDataBuffer:(NSError *)error; + @end NS_ASSUME_NONNULL_END From 09dc70795aede5ab840b27735beb9f2e346a58ae Mon Sep 17 00:00:00 2001 From: Joel Fischer Date: Thu, 30 May 2019 13:58:31 -0400 Subject: [PATCH 3/6] AudioStreamManager tests --- SmartDeviceLink/SDLAudioStreamManager.m | 36 ++++---- .../DevAPISpecs/SDLAudioStreamManagerSpec.m | 82 ++++++++++++++++--- .../SDLStreamingAudioManagerMock.h | 7 +- .../SDLStreamingAudioManagerMock.m | 20 +++-- 4 files changed, 108 insertions(+), 37 deletions(-) diff --git a/SmartDeviceLink/SDLAudioStreamManager.m b/SmartDeviceLink/SDLAudioStreamManager.m index 1ea9ac3ee..ff16f2b16 100755 --- a/SmartDeviceLink/SDLAudioStreamManager.m +++ b/SmartDeviceLink/SDLAudioStreamManager.m @@ -46,6 +46,13 @@ - (instancetype)initWithManager:(id)streamManager return self; } +- (void)stop { + dispatch_async(_audioQueue, ^{ + self.shouldPlayWhenReady = NO; + [self.mutableQueue removeAllObjects]; + }); +} + #pragma mark - Getters - (NSArray *)queue { @@ -140,37 +147,30 @@ - (void)sdl_playNextWhenReady { float audioLengthSecs = (float)audioData.length / (float)32000.0; __weak typeof(self) weakself = self; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(audioLengthSecs * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ - weakself.playing = NO; + __strong typeof(weakself) strongSelf = weakself; + + strongSelf.playing = NO; NSError *error = nil; - if (weakself.delegate != nil) { + if (strongSelf.delegate != nil) { if (file.inputFileURL != nil) { - [weakself.delegate audioStreamManager:weakself fileDidFinishPlaying:file.inputFileURL successfully:success]; - } else if ([weakself.delegate respondsToSelector:@selector(audioStreamManager:dataBufferDidFinishPlayingSuccessfully:)]) { - [weakself.delegate audioStreamManager:weakself dataBufferDidFinishPlayingSuccessfully:success]; + [strongSelf.delegate audioStreamManager:strongSelf fileDidFinishPlaying:file.inputFileURL successfully:success]; + } else if ([strongSelf.delegate respondsToSelector:@selector(audioStreamManager:dataBufferDidFinishPlayingSuccessfully:)]) { + [strongSelf.delegate audioStreamManager:strongSelf dataBufferDidFinishPlayingSuccessfully:success]; } } SDLLogD(@"Ending Audio file: %@", file); [[NSFileManager defaultManager] removeItemAtURL:file.outputFileURL error:&error]; - if (weakself.delegate != nil && error != nil) { + if (strongSelf.delegate != nil && error != nil) { if (file.inputFileURL != nil) { - [weakself.delegate audioStreamManager:weakself errorDidOccurForFile:file.inputFileURL error:error]; - } else if ([weakself.delegate respondsToSelector:@selector(audioStreamManager:errorDidOccurForDataBuffer:)]) { - [weakself.delegate audioStreamManager:weakself errorDidOccurForDataBuffer:error]; + [strongSelf.delegate audioStreamManager:strongSelf errorDidOccurForFile:file.inputFileURL error:error]; + } else if ([strongSelf.delegate respondsToSelector:@selector(audioStreamManager:errorDidOccurForDataBuffer:)]) { + [strongSelf.delegate audioStreamManager:strongSelf errorDidOccurForDataBuffer:error]; } } }); } -#pragma mark - Stopping Playback - -- (void)stop { - dispatch_async(_audioQueue, ^{ - self.shouldPlayWhenReady = NO; - [self.mutableQueue removeAllObjects]; - }); -} - @end NS_ASSUME_NONNULL_END diff --git a/SmartDeviceLinkTests/DevAPISpecs/SDLAudioStreamManagerSpec.m b/SmartDeviceLinkTests/DevAPISpecs/SDLAudioStreamManagerSpec.m index a087ecb5a..320282465 100644 --- a/SmartDeviceLinkTests/DevAPISpecs/SDLAudioStreamManagerSpec.m +++ b/SmartDeviceLinkTests/DevAPISpecs/SDLAudioStreamManagerSpec.m @@ -10,6 +10,7 @@ __block SDLAudioStreamManager *testManager = nil; __block SDLStreamingAudioManagerMock *mockAudioManager = nil; __block NSURL *testAudioFileURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"testAudio" withExtension:@"mp3"]; + __block NSData *testAudioFileData = [NSData dataWithContentsOfURL:testAudioFileURL options:0 error:nil]; beforeEach(^{ mockAudioManager = [[SDLStreamingAudioManagerMock alloc] init]; @@ -27,30 +28,91 @@ }); describe(@"when audio streaming is not connected", ^{ + context(@"with a file URL", ^{ + beforeEach(^{ + mockAudioManager.audioConnected = NO; + [testManager pushWithFileURL:testAudioFileURL]; + + [NSThread sleepForTimeInterval:0.5]; + }); + + describe(@"after attempting to play the file", ^{ + beforeEach(^{ + [mockAudioManager clearData]; + [testManager playNextWhenReady]; + }); + + it(@"should fail to send data", ^{ + expect(mockAudioManager.dataSinceClear.length).to(equal(0)); + expect(mockAudioManager.error.code).toEventually(equal(SDLAudioStreamManagerErrorNotConnected)); + }); + }); + }); + + context(@"with a data buffer", ^{ + beforeEach(^{ + mockAudioManager.audioConnected = NO; + [testManager pushWithData:testAudioFileData]; + + [NSThread sleepForTimeInterval:0.5]; + }); + + describe(@"after attempting to play the file", ^{ + beforeEach(^{ + [mockAudioManager clearData]; + [testManager playNextWhenReady]; + }); + + it(@"should fail to send data", ^{ + expect(mockAudioManager.dataSinceClear.length).to(equal(0)); + expect(mockAudioManager.error.code).toEventually(equal(SDLAudioStreamManagerErrorNotConnected)); + }); + }); + }); + }); + + describe(@"after adding an audio file to the queue", ^{ beforeEach(^{ - mockAudioManager.audioConnected = NO; + mockAudioManager.audioConnected = YES; [testManager pushWithFileURL:testAudioFileURL]; [NSThread sleepForTimeInterval:0.5]; }); + it(@"should have a file in the queue", ^{ + expect(testManager.queue).toNot(beEmpty()); + }); + describe(@"after attempting to play the file", ^{ beforeEach(^{ [mockAudioManager clearData]; [testManager playNextWhenReady]; }); - it(@"should fail to send data", ^{ - expect(mockAudioManager.dataSinceClear.length).to(equal(0)); - expect(mockAudioManager.fileError.code).to(equal(SDLAudioStreamManagerErrorNotConnected)); + fit(@"should be sending data", ^{ + expect(testManager.isPlaying).toEventually(beTrue()); + expect(mockAudioManager.dataSinceClear.length).toEventually(equal(34380)); + + // Fails when it shouldn't, `weakself` goes to nil in `sdl_playNextWhenReady` + expect(mockAudioManager.finishedPlaying).toEventually(beTrue()); + }); + }); + + describe(@"after stopping the manager", ^{ + beforeEach(^{ + [testManager stop]; + }); + + it(@"should have an empty queue", ^{ + expect(testManager.queue).toEventually(beEmpty()); }); }); }); - describe(@"after adding an audio file to the queue", ^{ + describe(@"after adding an audio buffer to the queue", ^{ beforeEach(^{ mockAudioManager.audioConnected = YES; - [testManager pushWithFileURL:testAudioFileURL]; + [testManager pushWithData:testAudioFileData]; [NSThread sleepForTimeInterval:0.5]; }); @@ -59,7 +121,7 @@ expect(testManager.queue).toNot(beEmpty()); }); - describe(@"after attempting to play the file", ^{ + describe(@"after attempting to play the audio buffer", ^{ beforeEach(^{ [mockAudioManager clearData]; [testManager playNextWhenReady]; @@ -67,10 +129,10 @@ it(@"should be sending data", ^{ expect(testManager.isPlaying).toEventually(beTrue()); - expect(mockAudioManager.dataSinceClear.length).toEventually(equal(34380)); + expect(mockAudioManager.dataSinceClear.length).toEventually(equal(14838)); // Fails when it shouldn't, `weakself` goes to nil in `sdl_playNextWhenReady` -// expect(mockAudioManager.fileFinishedPlaying).toEventually(beTrue()); + expect(mockAudioManager.finishedPlaying).toEventually(beTrue()); }); }); @@ -80,7 +142,7 @@ }); it(@"should have an empty queue", ^{ - expect(testManager.queue).to(beEmpty()); + expect(testManager.queue).toEventually(beEmpty()); }); }); }); diff --git a/SmartDeviceLinkTests/SDLStreamingAudioManagerMock.h b/SmartDeviceLinkTests/SDLStreamingAudioManagerMock.h index 2717798a5..0b92d26d5 100644 --- a/SmartDeviceLinkTests/SDLStreamingAudioManagerMock.h +++ b/SmartDeviceLinkTests/SDLStreamingAudioManagerMock.h @@ -21,13 +21,14 @@ #pragma mark SDLStreamingAudioManagerType @property (assign, nonatomic, readonly, getter=isAudioConnected) BOOL audioConnected; - (BOOL)sendAudioData:(NSData *)audioData; - - (void)setAudioConnected:(BOOL)audioConnected; #pragma mark SDLAudioStreamManagerDelegate - (void)audioStreamManager:(SDLAudioStreamManager *)audioManager fileDidFinishPlaying:(SDLAudioFile *)file successfully:(BOOL)successfully; +- (void)audioStreamManager:(SDLAudioStreamManager *)audioManager dataBufferDidFinishPlayingSuccessfully:(BOOL)successfully; - (void)audioStreamManager:(SDLAudioStreamManager *)audioManager errorDidOccurForFile:(SDLAudioFile *)file error:(NSError *)error; -@property (assign, nonatomic, readonly) BOOL fileFinishedPlaying; -@property (strong, nonatomic, readonly) NSError *fileError; +- (void)audioStreamManager:(SDLAudioStreamManager *)audioManager errorDidOccurForDataBuffer:(NSError *)error; +@property (assign, nonatomic, readonly) BOOL finishedPlaying; +@property (strong, nonatomic, readonly) NSError *error; @end diff --git a/SmartDeviceLinkTests/SDLStreamingAudioManagerMock.m b/SmartDeviceLinkTests/SDLStreamingAudioManagerMock.m index 21d1d8732..6d03a7264 100644 --- a/SmartDeviceLinkTests/SDLStreamingAudioManagerMock.m +++ b/SmartDeviceLinkTests/SDLStreamingAudioManagerMock.m @@ -14,8 +14,8 @@ @interface SDLStreamingAudioManagerMock() @property (strong, nonatomic) NSMutableData *mutableDataSinceClear; -@property (assign, nonatomic, readwrite) BOOL fileFinishedPlaying; -@property (strong, nonatomic, readwrite) NSError *fileError; +@property (assign, nonatomic, readwrite) BOOL finishedPlaying; +@property (strong, nonatomic, readwrite) NSError *error; @end @@ -35,8 +35,8 @@ - (void)clearData { _lastSentData = nil; _mutableDataSinceClear = nil; - _fileFinishedPlaying = NO; - _fileError = nil; + _finishedPlaying = NO; + _error = nil; } #pragma mark SDLStreamingAudioManagerType @@ -62,11 +62,19 @@ - (void)setAudioConnected:(BOOL)audioConnected { #pragma mark SDLAudioStreamManagerDelegate - (void)audioStreamManager:(SDLAudioStreamManager *)audioManager fileDidFinishPlaying:(SDLAudioFile *)file successfully:(BOOL)successfully { - _fileFinishedPlaying = successfully; + _finishedPlaying = successfully; +} + +- (void)audioStreamManager:(SDLAudioStreamManager *)audioManager dataBufferDidFinishPlayingSuccessfully:(BOOL)successfully { + _finishedPlaying = successfully; } - (void)audioStreamManager:(SDLAudioStreamManager *)audioManager errorDidOccurForFile:(SDLAudioFile *)file error:(NSError *)error { - _fileError = error; + _error = error; +} + +- (void)audioStreamManager:(SDLAudioStreamManager *)audioManager errorDidOccurForDataBuffer:(NSError *)error { + _error = error; } @end From eab92bbed34a6561eeeb383f149bef4c3c2b7e9d Mon Sep 17 00:00:00 2001 From: Joel Fischer Date: Fri, 31 May 2019 14:28:37 -0400 Subject: [PATCH 4/6] Fix audio stream manager tests --- SmartDeviceLinkTests/DevAPISpecs/SDLAudioStreamManagerSpec.m | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/SmartDeviceLinkTests/DevAPISpecs/SDLAudioStreamManagerSpec.m b/SmartDeviceLinkTests/DevAPISpecs/SDLAudioStreamManagerSpec.m index 320282465..e538122f5 100644 --- a/SmartDeviceLinkTests/DevAPISpecs/SDLAudioStreamManagerSpec.m +++ b/SmartDeviceLinkTests/DevAPISpecs/SDLAudioStreamManagerSpec.m @@ -87,9 +87,11 @@ beforeEach(^{ [mockAudioManager clearData]; [testManager playNextWhenReady]; + + [NSThread sleepForTimeInterval:1.0]; }); - fit(@"should be sending data", ^{ + it(@"should be sending data", ^{ expect(testManager.isPlaying).toEventually(beTrue()); expect(mockAudioManager.dataSinceClear.length).toEventually(equal(34380)); From d99672428978c7d194853023ec512b426b18c99e Mon Sep 17 00:00:00 2001 From: Joel Fischer Date: Wed, 5 Jun 2019 09:59:17 -0400 Subject: [PATCH 5/6] Update documentation on AudioStreamManager --- SmartDeviceLink/SDLAudioStreamManager.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/SmartDeviceLink/SDLAudioStreamManager.h b/SmartDeviceLink/SDLAudioStreamManager.h index bb44ef978..b405cae5d 100755 --- a/SmartDeviceLink/SDLAudioStreamManager.h +++ b/SmartDeviceLink/SDLAudioStreamManager.h @@ -69,6 +69,15 @@ typedef NS_ENUM(NSInteger, SDLAudioStreamManagerError) { /** Push a new audio buffer onto the queue. Call `playNextWhenReady` to start playing the pushed audio buffer. + This data must be of the required PCM format. See SDLSystemCapabilityManager.pcmStreamCapability and SDLAudioPassThruCapability.h. + + This is *an example* of a PCM format used by some head units: + - audioType: PCM + - samplingRate: 16kHZ + - bitsPerSample: 16 bits + + There is generally only one channel to the data. + @param data The audio buffer to be pushed onto the queue */ - (void)pushWithData:(NSData *)data; From fbb94813f916049ffae1b7ec5aa41637b2257f0b Mon Sep 17 00:00:00 2001 From: Joel Fischer Date: Wed, 5 Jun 2019 10:01:18 -0400 Subject: [PATCH 6/6] Note new AudioStreamManager method --- SmartDeviceLink/SDLStreamingMediaManager.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/SmartDeviceLink/SDLStreamingMediaManager.h b/SmartDeviceLink/SDLStreamingMediaManager.h index c306f8550..8e96e7ebb 100644 --- a/SmartDeviceLink/SDLStreamingMediaManager.h +++ b/SmartDeviceLink/SDLStreamingMediaManager.h @@ -170,7 +170,9 @@ NS_ASSUME_NONNULL_BEGIN - (BOOL)sendVideoData:(CVImageBufferRef)imageBuffer presentationTimestamp:(CMTime)presentationTimestamp; /** - * This method receives PCM audio data and will attempt to send that data across to the head unit for immediate playback + * This method receives PCM audio data and will attempt to send that data across to the head unit for immediate playback. + * + * NOTE: See the `.audioManager` (SDLAudioStreamManager) `pushWithData:` method for a more modern API. * * @param audioData The data in PCM audio format, to be played *