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.
//
#import "OWSAudioAttachmentPlayer.h"
#import "OWSMessageEditing.h"
#import "OWSMessageMediaAdapter.h"
#import <JSQMessagesViewController/JSQVideoMediaItem.h>
@ -10,22 +11,16 @@ NS_ASSUME_NONNULL_BEGIN
@class TSAttachmentStream;
@interface TSVideoAttachmentAdapter : JSQVideoMediaItem <OWSMessageEditing, OWSMessageMediaAdapter>
@interface TSVideoAttachmentAdapter
: JSQVideoMediaItem <OWSMessageEditing, OWSMessageMediaAdapter, OWSAudioAttachmentPlayerDelegate>
@property NSString *attachmentId;
@property (nonatomic, strong) NSString *contentType;
@property (nonatomic) BOOL isAudioPlaying;
@property (nonatomic) BOOL isPaused;
- (instancetype)initWithAttachment:(TSAttachmentStream *)attachment incoming:(BOOL)incoming;
- (BOOL)isAudio;
- (BOOL)isVideo;
- (void)setAudioProgressFromFloat:(float)progress;
- (void)setAudioIconToPlay;
- (void)setAudioIconToPause;
- (void)setDurationOfAudio:(NSTimeInterval)duration;
- (void)resetAudioDuration;
@end

@ -28,6 +28,8 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic, nullable) UILabel *durationLabel;
@property (nonatomic) BOOL incoming;
@property (nonatomic, nullable) AttachmentUploadView *attachmentUploadView;
@property (nonatomic) BOOL isAudioPlaying;
@property (nonatomic) BOOL isPaused;
@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 {
[_audioPlayPauseButton
setBackgroundImage:[UIImage imageNamed:(_incoming ? @"audio_play_button_blue" : @"audio_play_button")]

@ -1789,7 +1789,8 @@ typedef enum : NSUInteger {
}
} else if ([messageMedia isAudio]) {
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.
[self.audioAttachmentPlayer togglePlayState];
return;
@ -1800,6 +1801,8 @@ typedef enum : NSUInteger {
self.audioAttachmentPlayer =
[[OWSAudioAttachmentPlayer alloc] initWithMediaAdapter:messageMedia
databaseConnection:self.uiDatabaseConnection];
// Associate the player with this media adapter.
self.audioAttachmentPlayer.owner = messageMedia;
[self.audioAttachmentPlayer play];
}
}

@ -9,13 +9,39 @@ NS_ASSUME_NONNULL_BEGIN
@class TSVideoAttachmentAdapter;
@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>
@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
databaseConnection:(YapDatabaseConnection *)databaseConnection;
// An generic initializer.
- (instancetype)initWithMediaUrl:(NSURL *)mediaUrl delegate:(id<OWSAudioAttachmentPlayerDelegate>)delegate;
- (void)play;
- (void)pause;
- (void)stop;

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

Loading…
Cancel
Save