Decouple the audio attachment player from the video attachment adapter.

// FREEBIE
pull/1/head
Matthew Chen 8 years ago
parent 13f408908d
commit 041badd295

@ -2,6 +2,7 @@
// Copyright (c) 2017 Open Whisper Systems. All rights reserved. // Copyright (c) 2017 Open Whisper Systems. All rights reserved.
// //
#import "OWSAudioAttachmentPlayer.h"
#import "OWSMessageEditing.h" #import "OWSMessageEditing.h"
#import "OWSMessageMediaAdapter.h" #import "OWSMessageMediaAdapter.h"
#import <JSQMessagesViewController/JSQVideoMediaItem.h> #import <JSQMessagesViewController/JSQVideoMediaItem.h>
@ -10,22 +11,16 @@ NS_ASSUME_NONNULL_BEGIN
@class TSAttachmentStream; @class TSAttachmentStream;
@interface TSVideoAttachmentAdapter : JSQVideoMediaItem <OWSMessageEditing, OWSMessageMediaAdapter> @interface TSVideoAttachmentAdapter
: JSQVideoMediaItem <OWSMessageEditing, OWSMessageMediaAdapter, OWSAudioAttachmentPlayerDelegate>
@property NSString *attachmentId; @property NSString *attachmentId;
@property (nonatomic, strong) NSString *contentType; @property (nonatomic, strong) NSString *contentType;
@property (nonatomic) BOOL isAudioPlaying;
@property (nonatomic) BOOL isPaused;
- (instancetype)initWithAttachment:(TSAttachmentStream *)attachment incoming:(BOOL)incoming; - (instancetype)initWithAttachment:(TSAttachmentStream *)attachment incoming:(BOOL)incoming;
- (BOOL)isAudio; - (BOOL)isAudio;
- (BOOL)isVideo; - (BOOL)isVideo;
- (void)setAudioProgressFromFloat:(float)progress;
- (void)setAudioIconToPlay;
- (void)setAudioIconToPause;
- (void)setDurationOfAudio:(NSTimeInterval)duration;
- (void)resetAudioDuration;
@end @end

@ -28,6 +28,8 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic, nullable) UILabel *durationLabel; @property (nonatomic, nullable) UILabel *durationLabel;
@property (nonatomic) BOOL incoming; @property (nonatomic) BOOL incoming;
@property (nonatomic, nullable) AttachmentUploadView *attachmentUploadView; @property (nonatomic, nullable) AttachmentUploadView *attachmentUploadView;
@property (nonatomic) BOOL isAudioPlaying;
@property (nonatomic) BOOL isPaused;
@end @end
@ -96,16 +98,6 @@ NS_ASSUME_NONNULL_BEGIN
}); });
} }
- (void)resetAudioDuration {
NSError *err;
AVAudioPlayer *player = [[AVAudioPlayer alloc] initWithContentsOfURL:_attachment.mediaURL error:&err];
_durationLabel.text = [self formatDuration:player.duration];
}
- (void)setDurationOfAudio:(NSTimeInterval)duration {
_durationLabel.text = [self formatDuration:duration];
}
- (void)setAudioIconToPlay { - (void)setAudioIconToPlay {
[_audioPlayPauseButton [_audioPlayPauseButton
setBackgroundImage:[UIImage imageNamed:(_incoming ? @"audio_play_button_blue" : @"audio_play_button")] setBackgroundImage:[UIImage imageNamed:(_incoming ? @"audio_play_button_blue" : @"audio_play_button")]

@ -1789,7 +1789,8 @@ typedef enum : NSUInteger {
} }
} else if ([messageMedia isAudio]) { } else if ([messageMedia isAudio]) {
if (self.audioAttachmentPlayer) { if (self.audioAttachmentPlayer) {
if (self.audioAttachmentPlayer.mediaAdapter == messageMedia) { // Is this player associated with this media adapter?
if (self.audioAttachmentPlayer.owner == messageMedia) {
// Tap to pause & unpause. // Tap to pause & unpause.
[self.audioAttachmentPlayer togglePlayState]; [self.audioAttachmentPlayer togglePlayState];
return; return;
@ -1800,6 +1801,8 @@ typedef enum : NSUInteger {
self.audioAttachmentPlayer = self.audioAttachmentPlayer =
[[OWSAudioAttachmentPlayer alloc] initWithMediaAdapter:messageMedia [[OWSAudioAttachmentPlayer alloc] initWithMediaAdapter:messageMedia
databaseConnection:self.uiDatabaseConnection]; databaseConnection:self.uiDatabaseConnection];
// Associate the player with this media adapter.
self.audioAttachmentPlayer.owner = messageMedia;
[self.audioAttachmentPlayer play]; [self.audioAttachmentPlayer play];
} }
} }

@ -9,13 +9,39 @@ NS_ASSUME_NONNULL_BEGIN
@class TSVideoAttachmentAdapter; @class TSVideoAttachmentAdapter;
@class YapDatabaseConnection; @class YapDatabaseConnection;
@protocol OWSAudioAttachmentPlayerDelegate <NSObject>
- (BOOL)isAudioPlaying;
- (void)setIsAudioPlaying:(BOOL)isAudioPlaying;
- (BOOL)isPaused;
- (void)setIsPaused:(BOOL)isPaused;
- (void)setAudioProgressFromFloat:(float)progress;
- (void)setAudioIconToPlay;
- (void)setAudioIconToPause;
@end
#pragma mark -
@interface OWSAudioAttachmentPlayer : NSObject <AVAudioPlayerDelegate> @interface OWSAudioAttachmentPlayer : NSObject <AVAudioPlayerDelegate>
@property (nonatomic, readonly) TSVideoAttachmentAdapter *mediaAdapter; @property (nonatomic, readonly, weak) id<OWSAudioAttachmentPlayerDelegate> delegate;
// This property can be used to associate instances of the player with view
// or model objects.
@property (nonatomic, weak) id owner;
// A convenience initializer for MessagesViewController.
//
// It assumes the delegate (e.g. view) for this player will be the adapter.
- (instancetype)initWithMediaAdapter:(TSVideoAttachmentAdapter *)mediaAdapter - (instancetype)initWithMediaAdapter:(TSVideoAttachmentAdapter *)mediaAdapter
databaseConnection:(YapDatabaseConnection *)databaseConnection; databaseConnection:(YapDatabaseConnection *)databaseConnection;
// An generic initializer.
- (instancetype)initWithMediaUrl:(NSURL *)mediaUrl delegate:(id<OWSAudioAttachmentPlayerDelegate>)delegate;
- (void)play; - (void)play;
- (void)pause; - (void)pause;
- (void)stop; - (void)stop;

@ -13,7 +13,7 @@ NS_ASSUME_NONNULL_BEGIN
@interface OWSAudioAttachmentPlayer () @interface OWSAudioAttachmentPlayer ()
@property (nonatomic) TSAttachmentStream *attachmentStream; @property (nonatomic, readonly) NSURL *mediaUrl;
@property (nonatomic, nullable) AVAudioPlayer *audioPlayer; @property (nonatomic, nullable) AVAudioPlayer *audioPlayer;
@property (nonatomic, nullable) NSTimer *audioPlayerPoller; @property (nonatomic, nullable) NSTimer *audioPlayerPoller;
@ -24,31 +24,49 @@ NS_ASSUME_NONNULL_BEGIN
@implementation OWSAudioAttachmentPlayer @implementation OWSAudioAttachmentPlayer
- (instancetype)initWithMediaAdapter:(TSVideoAttachmentAdapter *)mediaAdapter + (NSURL *)mediaUrlForMediaAdapter:(TSVideoAttachmentAdapter *)mediaAdapter
databaseConnection:(YapDatabaseConnection *)databaseConnection databaseConnection:(YapDatabaseConnection *)databaseConnection
{ {
self = [super init];
if (!self) {
return self;
}
OWSAssert(mediaAdapter); OWSAssert(mediaAdapter);
OWSAssert([mediaAdapter isAudio]); OWSAssert([mediaAdapter isAudio]);
OWSAssert(mediaAdapter.attachmentId); OWSAssert(mediaAdapter.attachmentId);
OWSAssert(databaseConnection); OWSAssert(databaseConnection);
_mediaAdapter = mediaAdapter;
__block TSAttachment *attachment = nil; __block TSAttachment *attachment = nil;
[databaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { [databaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
attachment = [TSAttachment fetchObjectWithUniqueID:mediaAdapter.attachmentId transaction:transaction]; attachment = [TSAttachment fetchObjectWithUniqueID:mediaAdapter.attachmentId transaction:transaction];
}]; }];
OWSAssert(attachment); OWSAssert(attachment);
TSAttachmentStream *attachmentStream = nil;
if ([attachment isKindOfClass:[TSAttachmentStream class]]) { if ([attachment isKindOfClass:[TSAttachmentStream class]]) {
self.attachmentStream = (TSAttachmentStream *)attachment; attachmentStream = (TSAttachmentStream *)attachment;
} }
OWSAssert(self.attachmentStream); OWSAssert(attachmentStream);
return attachmentStream.mediaURL;
}
- (instancetype)initWithMediaAdapter:(TSVideoAttachmentAdapter *)mediaAdapter
databaseConnection:(YapDatabaseConnection *)databaseConnection
{
return [self initWithMediaUrl:[OWSAudioAttachmentPlayer mediaUrlForMediaAdapter:mediaAdapter
databaseConnection:databaseConnection]
delegate:mediaAdapter];
}
- (instancetype)initWithMediaUrl:(NSURL *)mediaUrl delegate:(id<OWSAudioAttachmentPlayerDelegate>)delegate
{
self = [super init];
if (!self) {
return self;
}
OWSAssert(mediaUrl);
OWSAssert(delegate);
_delegate = delegate;
_mediaUrl = mediaUrl;
[[NSNotificationCenter defaultCenter] addObserver:self [[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(applicationDidEnterBackground:) selector:@selector(applicationDidEnterBackground:)
@ -74,20 +92,21 @@ NS_ASSUME_NONNULL_BEGIN
- (void)play - (void)play
{ {
OWSAssert(self.attachmentStream); OWSAssert([NSThread isMainThread]);
OWSAssert(![self.mediaAdapter isAudioPlaying]); OWSAssert(self.mediaUrl);
OWSAssert(![self.delegate isAudioPlaying]);
[ViewControllerUtils setAudioIgnoresHardwareMuteSwitch:YES]; [ViewControllerUtils setAudioIgnoresHardwareMuteSwitch:YES];
[self.audioPlayerPoller invalidate]; [self.audioPlayerPoller invalidate];
self.mediaAdapter.isAudioPlaying = YES; self.delegate.isAudioPlaying = YES;
self.mediaAdapter.isPaused = NO; self.delegate.isPaused = NO;
[self.mediaAdapter setAudioIconToPause]; [self.delegate setAudioIconToPause];
if (!self.audioPlayer) { if (!self.audioPlayer) {
NSError *error; NSError *error;
self.audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:self.attachmentStream.mediaURL error:&error]; self.audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:self.mediaUrl error:&error];
if (error) { if (error) {
DDLogError(@"%@ error: %@", self.tag, error); DDLogError(@"%@ error: %@", self.tag, error);
[self stop]; [self stop];
@ -107,35 +126,34 @@ NS_ASSUME_NONNULL_BEGIN
- (void)pause - (void)pause
{ {
OWSAssert(self.attachmentStream); OWSAssert([NSThread isMainThread]);
self.mediaAdapter.isAudioPlaying = NO; self.delegate.isAudioPlaying = NO;
self.mediaAdapter.isPaused = YES; self.delegate.isPaused = YES;
[self.audioPlayer pause]; [self.audioPlayer pause];
[self.audioPlayerPoller invalidate]; [self.audioPlayerPoller invalidate];
double current = [self.audioPlayer currentTime] / [self.audioPlayer duration]; double current = [self.audioPlayer currentTime] / [self.audioPlayer duration];
[self.mediaAdapter setAudioProgressFromFloat:(float)current]; [self.delegate setAudioProgressFromFloat:(float)current];
[self.mediaAdapter setAudioIconToPlay]; [self.delegate setAudioIconToPlay];
} }
- (void)stop - (void)stop
{ {
OWSAssert(self.attachmentStream); OWSAssert([NSThread isMainThread]);
[self.audioPlayer pause]; [self.audioPlayer pause];
[self.audioPlayerPoller invalidate]; [self.audioPlayerPoller invalidate];
[self.mediaAdapter setAudioProgressFromFloat:0]; [self.delegate setAudioProgressFromFloat:0];
[self.mediaAdapter setDurationOfAudio:self.audioPlayer.duration]; [self.delegate setAudioIconToPlay];
[self.mediaAdapter setAudioIconToPlay]; self.delegate.isAudioPlaying = NO;
self.mediaAdapter.isAudioPlaying = NO; self.delegate.isPaused = NO;
self.mediaAdapter.isPaused = NO;
} }
- (void)togglePlayState - (void)togglePlayState
{ {
OWSAssert(self.attachmentStream); OWSAssert([NSThread isMainThread]);
if (self.mediaAdapter.isAudioPlaying) { if (self.delegate.isAudioPlaying) {
[self pause]; [self pause];
} else { } else {
[self play]; [self play];
@ -146,17 +164,19 @@ NS_ASSUME_NONNULL_BEGIN
- (void)audioPlayerUpdated:(NSTimer *)timer - (void)audioPlayerUpdated:(NSTimer *)timer
{ {
OWSAssert([NSThread isMainThread]);
OWSAssert(self.audioPlayer); OWSAssert(self.audioPlayer);
OWSAssert(self.audioPlayerPoller); OWSAssert(self.audioPlayerPoller);
double current = [self.audioPlayer currentTime] / [self.audioPlayer duration]; double current = [self.audioPlayer currentTime] / [self.audioPlayer duration];
double interval = [self.audioPlayer duration] - [self.audioPlayer currentTime]; [self.delegate setAudioProgressFromFloat:(float)current];
[self.mediaAdapter setDurationOfAudio:interval];
[self.mediaAdapter setAudioProgressFromFloat:(float)current];
} }
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag - (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag
{ {
OWSAssert([NSThread isMainThread]);
[self stop]; [self stop];
} }

Loading…
Cancel
Save