mirror of
https://github.com/oxen-io/session-ios.git
synced 2023-12-13 21:30:14 +01:00
WIP: audio activities
This commit is contained in:
parent
14f2b89367
commit
3d022adf4e
|
@ -149,7 +149,7 @@ typedef enum : NSUInteger {
|
||||||
|
|
||||||
@property (nonatomic) TSThread *thread;
|
@property (nonatomic) TSThread *thread;
|
||||||
@property (nonatomic, readonly) YapDatabaseConnection *editingDatabaseConnection;
|
@property (nonatomic, readonly) YapDatabaseConnection *editingDatabaseConnection;
|
||||||
@property (nonatomic, readonly) AudioActivity *voiceNoteAudioActivity;
|
@property (nonatomic, readonly) AudioActivity *recordVoiceNoteAudioActivity;
|
||||||
@property (nonatomic, readonly) NSTimeInterval viewControllerCreatedAt;
|
@property (nonatomic, readonly) NSTimeInterval viewControllerCreatedAt;
|
||||||
|
|
||||||
// These two properties must be updated in lockstep.
|
// These two properties must be updated in lockstep.
|
||||||
|
@ -286,7 +286,7 @@ typedef enum : NSUInteger {
|
||||||
_contactShareViewHelper.delegate = self;
|
_contactShareViewHelper.delegate = self;
|
||||||
|
|
||||||
NSString *audioActivityDescription = [NSString stringWithFormat:@"%@ voice note", self.logTag];
|
NSString *audioActivityDescription = [NSString stringWithFormat:@"%@ voice note", self.logTag];
|
||||||
_voiceNoteAudioActivity = [[AudioActivity alloc] initWithAudioDescription:audioActivityDescription];
|
_recordVoiceNoteAudioActivity = [AudioActivity recordActivityWithAudioDescription:audioActivityDescription];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)addNotificationListeners
|
- (void)addNotificationListeners
|
||||||
|
@ -2223,12 +2223,13 @@ typedef enum : NSUInteger {
|
||||||
// Is this player associated with this media adapter?
|
// Is this player associated with this media adapter?
|
||||||
if (self.audioAttachmentPlayer.owner == viewItem) {
|
if (self.audioAttachmentPlayer.owner == viewItem) {
|
||||||
// Tap to pause & unpause.
|
// Tap to pause & unpause.
|
||||||
[self.audioAttachmentPlayer togglePlayState];
|
[self.audioAttachmentPlayer togglePlayStateWithPlaybackAudioCategory];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
[self.audioAttachmentPlayer stop];
|
[self.audioAttachmentPlayer stop];
|
||||||
self.audioAttachmentPlayer = nil;
|
self.audioAttachmentPlayer = nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.audioAttachmentPlayer =
|
self.audioAttachmentPlayer =
|
||||||
[[OWSAudioPlayer alloc] initWithMediaUrl:attachmentStream.originalMediaURL delegate:viewItem];
|
[[OWSAudioPlayer alloc] initWithMediaUrl:attachmentStream.originalMediaURL delegate:viewItem];
|
||||||
// Associate the player with this media adapter.
|
// Associate the player with this media adapter.
|
||||||
|
@ -3613,7 +3614,7 @@ typedef enum : NSUInteger {
|
||||||
NSURL *fileURL = [NSURL fileURLWithPath:filepath];
|
NSURL *fileURL = [NSURL fileURLWithPath:filepath];
|
||||||
|
|
||||||
// Setup audio session
|
// Setup audio session
|
||||||
BOOL configuredAudio = [OWSAudioSession.shared startRecordingAudioActivity:self.voiceNoteAudioActivity];
|
BOOL configuredAudio = [OWSAudioSession.shared startAudioActivity:self.recordVoiceNoteAudioActivity];
|
||||||
if (!configuredAudio) {
|
if (!configuredAudio) {
|
||||||
OWSFailDebug(@"Couldn't configure audio session");
|
OWSFailDebug(@"Couldn't configure audio session");
|
||||||
[self cancelVoiceMemo];
|
[self cancelVoiceMemo];
|
||||||
|
@ -3714,7 +3715,7 @@ typedef enum : NSUInteger {
|
||||||
- (void)stopRecording
|
- (void)stopRecording
|
||||||
{
|
{
|
||||||
[self.audioRecorder stop];
|
[self.audioRecorder stop];
|
||||||
[OWSAudioSession.shared endAudioActivity:self.voiceNoteAudioActivity];
|
[OWSAudioSession.shared endAudioActivity:self.recordVoiceNoteAudioActivity];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)cancelRecordingVoiceMemo
|
- (void)cancelRecordingVoiceMemo
|
||||||
|
|
|
@ -668,7 +668,7 @@ class MessageDetailViewController: OWSViewController, MediaGalleryDataSourceDele
|
||||||
// Is this player associated with this media adapter?
|
// Is this player associated with this media adapter?
|
||||||
if audioAttachmentPlayer.owner === viewItem {
|
if audioAttachmentPlayer.owner === viewItem {
|
||||||
// Tap to pause & unpause.
|
// Tap to pause & unpause.
|
||||||
audioAttachmentPlayer.togglePlayState()
|
audioAttachmentPlayer.togglePlayStateWithPlaybackAudioCategory()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
audioAttachmentPlayer.stop()
|
audioAttachmentPlayer.stop()
|
||||||
|
|
|
@ -393,7 +393,7 @@ public class MediaMessageView: UIView, OWSAudioPlayerDelegate {
|
||||||
|
|
||||||
@objc
|
@objc
|
||||||
func audioPlayButtonPressed(sender: UIButton) {
|
func audioPlayButtonPressed(sender: UIButton) {
|
||||||
audioPlayer?.togglePlayState()
|
audioPlayer?.togglePlayStateWithPlaybackAudioCategory()
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - OWSAudioPlayerDelegate
|
// MARK: - OWSAudioPlayerDelegate
|
||||||
|
|
|
@ -22,7 +22,7 @@ public class OWSVideoPlayer: NSObject {
|
||||||
|
|
||||||
@objc init(url: URL) {
|
@objc init(url: URL) {
|
||||||
self.avPlayer = AVPlayer(url: url)
|
self.avPlayer = AVPlayer(url: url)
|
||||||
self.audioActivity = AudioActivity(audioDescription: "[OWSVideoPlayer] url:\(url)")
|
self.audioActivity = AudioActivity(audioDescription: "[OWSVideoPlayer] url:\(url)", options: [.playback])
|
||||||
|
|
||||||
super.init()
|
super.init()
|
||||||
|
|
||||||
|
@ -42,7 +42,8 @@ public class OWSVideoPlayer: NSObject {
|
||||||
|
|
||||||
@objc
|
@objc
|
||||||
public func play() {
|
public func play() {
|
||||||
OWSAudioSession.shared.startPlaybackAudioActivity(self.audioActivity)
|
let success = OWSAudioSession.shared.startAudioActivity(self.audioActivity)
|
||||||
|
assert(success)
|
||||||
|
|
||||||
guard let item = avPlayer.currentItem else {
|
guard let item = avPlayer.currentItem else {
|
||||||
owsFailDebug("video player item was unexpectedly nil")
|
owsFailDebug("video player item was unexpectedly nil")
|
||||||
|
|
|
@ -5,22 +5,61 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
import WebRTC
|
import WebRTC
|
||||||
|
|
||||||
|
public struct AudioActivityOptions: OptionSet {
|
||||||
|
public let rawValue: Int
|
||||||
|
|
||||||
|
public init(rawValue: Int) {
|
||||||
|
self.rawValue = rawValue
|
||||||
|
}
|
||||||
|
|
||||||
|
public static let playback = AudioActivityOptions(rawValue: 1 << 0)
|
||||||
|
public static let record = AudioActivityOptions(rawValue: 1 << 1)
|
||||||
|
public static let proximitySwitchesToEarPiece = AudioActivityOptions(rawValue: 1 << 2)
|
||||||
|
}
|
||||||
|
|
||||||
@objc
|
@objc
|
||||||
public class AudioActivity: NSObject {
|
public class AudioActivity: NSObject {
|
||||||
let audioDescription: String
|
let audioDescription: String
|
||||||
|
|
||||||
override public var description: String {
|
let options: AudioActivityOptions
|
||||||
return "<\(self.logTag) audioDescription: \"\(audioDescription)\">"
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc
|
@objc
|
||||||
public init(audioDescription: String) {
|
public init(audioDescription: String) {
|
||||||
self.audioDescription = audioDescription
|
self.audioDescription = audioDescription
|
||||||
|
self.options = []
|
||||||
|
}
|
||||||
|
|
||||||
|
public init(audioDescription: String, options: AudioActivityOptions) {
|
||||||
|
self.audioDescription = audioDescription
|
||||||
|
self.options = options
|
||||||
}
|
}
|
||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
OWSAudioSession.shared.ensureAudioSessionActivationStateAfterDelay()
|
OWSAudioSession.shared.ensureAudioSessionActivationStateAfterDelay()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: Factory Methods
|
||||||
|
|
||||||
|
@objc
|
||||||
|
public class func playbackActivity(audioDescription: String) -> AudioActivity {
|
||||||
|
return AudioActivity(audioDescription: audioDescription, options: .playback)
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc
|
||||||
|
public class func recordActivity(audioDescription: String) -> AudioActivity {
|
||||||
|
return AudioActivity(audioDescription: audioDescription, options: .record)
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc
|
||||||
|
public class func voiceNoteActivity(audioDescription: String) -> AudioActivity {
|
||||||
|
return AudioActivity(audioDescription: audioDescription, options: [.playback, .proximitySwitchesToEarPiece])
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK:
|
||||||
|
|
||||||
|
override public var description: String {
|
||||||
|
return "<\(self.logTag) audioDescription: \"\(audioDescription)\">"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc
|
@objc
|
||||||
|
@ -28,79 +67,88 @@ public class OWSAudioSession: NSObject {
|
||||||
|
|
||||||
// Force singleton access
|
// Force singleton access
|
||||||
@objc public static let shared = OWSAudioSession()
|
@objc public static let shared = OWSAudioSession()
|
||||||
|
|
||||||
private override init() {}
|
private override init() {}
|
||||||
|
|
||||||
|
public func setup() {
|
||||||
|
NotificationCenter.default.addObserver(forName: .UIDeviceProximityStateDidChange,
|
||||||
|
object: nil,
|
||||||
|
queue: nil) { [weak self] _ in
|
||||||
|
self?.ensureProximityState()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: Dependencies
|
||||||
|
|
||||||
private let avAudioSession = AVAudioSession.sharedInstance()
|
private let avAudioSession = AVAudioSession.sharedInstance()
|
||||||
|
|
||||||
|
private let device = UIDevice.current
|
||||||
|
|
||||||
|
// MARK:
|
||||||
|
|
||||||
private var currentActivities: [Weak<AudioActivity>] = []
|
private var currentActivities: [Weak<AudioActivity>] = []
|
||||||
|
var aggregateOptions: AudioActivityOptions {
|
||||||
// Respects hardware mute switch, plays through external speaker, mixes with backround audio
|
return AudioActivityOptions(self.currentActivities.compactMap { $0.value?.options })
|
||||||
// appropriate for foreground sound effects.
|
|
||||||
@objc
|
|
||||||
public func startAmbientAudioActivity(_ audioActivity: AudioActivity) {
|
|
||||||
Logger.debug("")
|
|
||||||
|
|
||||||
objc_sync_enter(self)
|
|
||||||
defer { objc_sync_exit(self) }
|
|
||||||
|
|
||||||
startAudioActivity(audioActivity)
|
|
||||||
guard currentActivities.count == 1 else {
|
|
||||||
// We don't want to clobber the audio capabilities configured by (e.g.) media playback or an in-progress call
|
|
||||||
Logger.info("not touching audio session since another currentActivity exists.")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
do {
|
|
||||||
try avAudioSession.setCategory(AVAudioSessionCategoryAmbient)
|
|
||||||
} catch {
|
|
||||||
owsFailDebug("failed with error: \(error)")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ignores hardware mute switch, plays through external speaker
|
|
||||||
@objc
|
|
||||||
public func startPlaybackAudioActivity(_ audioActivity: AudioActivity) {
|
|
||||||
Logger.debug("")
|
|
||||||
|
|
||||||
objc_sync_enter(self)
|
|
||||||
defer { objc_sync_exit(self) }
|
|
||||||
|
|
||||||
startAudioActivity(audioActivity)
|
|
||||||
|
|
||||||
do {
|
|
||||||
try avAudioSession.setCategory(AVAudioSessionCategoryPlayback)
|
|
||||||
} catch {
|
|
||||||
owsFailDebug("failed with error: \(error)")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc
|
@objc
|
||||||
public func startRecordingAudioActivity(_ audioActivity: AudioActivity) -> Bool {
|
public func startAudioActivity(_ audioActivity: AudioActivity) -> Bool {
|
||||||
Logger.debug("")
|
|
||||||
|
|
||||||
objc_sync_enter(self)
|
|
||||||
defer { objc_sync_exit(self) }
|
|
||||||
|
|
||||||
assert(avAudioSession.recordPermission() == .granted)
|
|
||||||
|
|
||||||
startAudioActivity(audioActivity)
|
|
||||||
|
|
||||||
do {
|
|
||||||
try avAudioSession.setCategory(AVAudioSessionCategoryRecord)
|
|
||||||
return true
|
|
||||||
} catch {
|
|
||||||
owsFailDebug("failed with error: \(error)")
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc
|
|
||||||
public func startAudioActivity(_ audioActivity: AudioActivity) {
|
|
||||||
Logger.debug("with \(audioActivity)")
|
Logger.debug("with \(audioActivity)")
|
||||||
|
|
||||||
objc_sync_enter(self)
|
objc_sync_enter(self)
|
||||||
defer { objc_sync_exit(self) }
|
defer { objc_sync_exit(self) }
|
||||||
|
|
||||||
self.currentActivities.append(Weak(value: audioActivity))
|
self.currentActivities.append(Weak(value: audioActivity))
|
||||||
|
|
||||||
|
do {
|
||||||
|
if aggregateOptions.contains(.record) {
|
||||||
|
assert(avAudioSession.recordPermission() == .granted)
|
||||||
|
try avAudioSession.setCategory(AVAudioSessionCategoryRecord)
|
||||||
|
} else if aggregateOptions.contains(.playback) {
|
||||||
|
try avAudioSession.setCategory(AVAudioSessionCategoryPlayback)
|
||||||
|
} else {
|
||||||
|
Logger.debug("no category option specified. Leaving category untouched.")
|
||||||
|
}
|
||||||
|
|
||||||
|
if aggregateOptions.contains(.proximitySwitchesToEarPiece) {
|
||||||
|
self.device.isProximityMonitoringEnabled = true
|
||||||
|
self.shouldAdjustAudioForProximity = true
|
||||||
|
} else {
|
||||||
|
self.device.isProximityMonitoringEnabled = false
|
||||||
|
self.shouldAdjustAudioForProximity = false
|
||||||
|
}
|
||||||
|
ensureProximityState()
|
||||||
|
|
||||||
|
return true
|
||||||
|
} catch {
|
||||||
|
owsFailDebug("failed with error: \(error)")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
var shouldAdjustAudioForProximity: Bool = false
|
||||||
|
func proximitySensorStateDidChange(notification: Notification) {
|
||||||
|
if shouldAdjustAudioForProximity {
|
||||||
|
ensureProximityState()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: externally modified proximityState monitoring e.g. CallViewController
|
||||||
|
// TODO: make sure we *undo* anything as appropriate if there are concurrent audio activities
|
||||||
|
func ensureProximityState() {
|
||||||
|
if self.device.proximityState {
|
||||||
|
Logger.debug("proximityState: true")
|
||||||
|
|
||||||
|
try! self.avAudioSession.overrideOutputAudioPort(.none)
|
||||||
|
} else {
|
||||||
|
Logger.debug("proximityState: false")
|
||||||
|
do {
|
||||||
|
try self.avAudioSession.overrideOutputAudioPort(.speaker)
|
||||||
|
} catch {
|
||||||
|
Logger.error("error: \(error)")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc
|
@objc
|
||||||
|
@ -111,6 +159,16 @@ public class OWSAudioSession: NSObject {
|
||||||
defer { objc_sync_exit(self) }
|
defer { objc_sync_exit(self) }
|
||||||
|
|
||||||
currentActivities = currentActivities.filter { return $0.value != audioActivity }
|
currentActivities = currentActivities.filter { return $0.value != audioActivity }
|
||||||
|
|
||||||
|
if aggregateOptions.contains(.proximitySwitchesToEarPiece) {
|
||||||
|
self.device.isProximityMonitoringEnabled = true
|
||||||
|
self.shouldAdjustAudioForProximity = true
|
||||||
|
} else {
|
||||||
|
self.device.isProximityMonitoringEnabled = false
|
||||||
|
self.shouldAdjustAudioForProximity = false
|
||||||
|
}
|
||||||
|
ensureProximityState()
|
||||||
|
|
||||||
ensureAudioSessionActivationStateAfterDelay()
|
ensureAudioSessionActivationStateAfterDelay()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -43,7 +43,7 @@ typedef NS_ENUM(NSInteger, AudioPlaybackState) {
|
||||||
|
|
||||||
- (void)pause;
|
- (void)pause;
|
||||||
- (void)stop;
|
- (void)stop;
|
||||||
- (void)togglePlayState;
|
- (void)togglePlayStateWithPlaybackAudioCategory;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,8 @@ NS_ASSUME_NONNULL_BEGIN
|
||||||
@property (nonatomic, readonly) NSURL *mediaUrl;
|
@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;
|
||||||
@property (nonatomic, readonly) AudioActivity *audioActivity;
|
@property (nonatomic, readonly) AudioActivity *playbackAudioActivity;
|
||||||
|
@property (nonatomic, readonly) AudioActivity *currentCategoryAudioActivity;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
@ -62,7 +63,9 @@ NS_ASSUME_NONNULL_BEGIN
|
||||||
_mediaUrl = mediaUrl;
|
_mediaUrl = mediaUrl;
|
||||||
|
|
||||||
NSString *audioActivityDescription = [NSString stringWithFormat:@"%@ %@", self.logTag, self.mediaUrl];
|
NSString *audioActivityDescription = [NSString stringWithFormat:@"%@ %@", self.logTag, self.mediaUrl];
|
||||||
_audioActivity = [[AudioActivity alloc] initWithAudioDescription:audioActivityDescription];
|
// _playbackAudioActivity = [AudioActivity playbackActivityWithAudioDescription:audioActivityDescription];
|
||||||
|
_playbackAudioActivity = [AudioActivity voiceNoteActivityWithAudioDescription:audioActivityDescription];
|
||||||
|
_currentCategoryAudioActivity = [[AudioActivity alloc] initWithAudioDescription:audioActivityDescription];
|
||||||
|
|
||||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||||
selector:@selector(applicationDidEnterBackground:)
|
selector:@selector(applicationDidEnterBackground:)
|
||||||
|
@ -91,22 +94,22 @@ NS_ASSUME_NONNULL_BEGIN
|
||||||
- (void)playWithCurrentAudioCategory
|
- (void)playWithCurrentAudioCategory
|
||||||
{
|
{
|
||||||
OWSAssertIsOnMainThread();
|
OWSAssertIsOnMainThread();
|
||||||
[OWSAudioSession.shared startAudioActivity:self.audioActivity];
|
[self playWithAudioActivity:self.currentCategoryAudioActivity];
|
||||||
|
|
||||||
[self play];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)playWithPlaybackAudioCategory
|
- (void)playWithPlaybackAudioCategory
|
||||||
{
|
{
|
||||||
OWSAssertIsOnMainThread();
|
OWSAssertIsOnMainThread();
|
||||||
[OWSAudioSession.shared startPlaybackAudioActivity:self.audioActivity];
|
[self playWithAudioActivity:self.playbackAudioActivity];
|
||||||
|
|
||||||
[self play];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)play
|
- (void)playWithAudioActivity:(AudioActivity *)audioActivity
|
||||||
{
|
{
|
||||||
OWSAssertIsOnMainThread();
|
OWSAssertIsOnMainThread();
|
||||||
|
|
||||||
|
BOOL success = [OWSAudioSession.shared startAudioActivity:audioActivity];
|
||||||
|
OWSAssertDebug(success);
|
||||||
|
|
||||||
OWSAssertDebug(self.mediaUrl);
|
OWSAssertDebug(self.mediaUrl);
|
||||||
OWSAssertDebug([self.delegate audioPlaybackState] != AudioPlaybackState_Playing);
|
OWSAssertDebug([self.delegate audioPlaybackState] != AudioPlaybackState_Playing);
|
||||||
|
|
||||||
|
@ -157,7 +160,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||||
[self.audioPlayerPoller invalidate];
|
[self.audioPlayerPoller invalidate];
|
||||||
[self.delegate setAudioProgress:(CGFloat)[self.audioPlayer currentTime] duration:(CGFloat)[self.audioPlayer duration]];
|
[self.delegate setAudioProgress:(CGFloat)[self.audioPlayer currentTime] duration:(CGFloat)[self.audioPlayer duration]];
|
||||||
|
|
||||||
[OWSAudioSession.shared endAudioActivity:self.audioActivity];
|
[self endAudioActivities];
|
||||||
[DeviceSleepManager.sharedInstance removeBlockWithBlockObject:self];
|
[DeviceSleepManager.sharedInstance removeBlockWithBlockObject:self];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,18 +173,24 @@ NS_ASSUME_NONNULL_BEGIN
|
||||||
[self.audioPlayerPoller invalidate];
|
[self.audioPlayerPoller invalidate];
|
||||||
[self.delegate setAudioProgress:0 duration:0];
|
[self.delegate setAudioProgress:0 duration:0];
|
||||||
|
|
||||||
[OWSAudioSession.shared endAudioActivity:self.audioActivity];
|
[self endAudioActivities];
|
||||||
[DeviceSleepManager.sharedInstance removeBlockWithBlockObject:self];
|
[DeviceSleepManager.sharedInstance removeBlockWithBlockObject:self];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)togglePlayState
|
- (void)endAudioActivities
|
||||||
|
{
|
||||||
|
[OWSAudioSession.shared endAudioActivity:self.playbackAudioActivity];
|
||||||
|
[OWSAudioSession.shared endAudioActivity:self.currentCategoryAudioActivity];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)togglePlayStateWithPlaybackAudioCategory
|
||||||
{
|
{
|
||||||
OWSAssertIsOnMainThread();
|
OWSAssertIsOnMainThread();
|
||||||
|
|
||||||
if (self.delegate.audioPlaybackState == AudioPlaybackState_Playing) {
|
if (self.delegate.audioPlaybackState == AudioPlaybackState_Playing) {
|
||||||
[self pause];
|
[self pause];
|
||||||
} else {
|
} else {
|
||||||
[self play];
|
[self playWithAudioActivity:self.playbackAudioActivity];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue