Skip to content

Commit

Permalink
Merge pull request #1098 from nugu-developers/develop/1.9.1
Browse files Browse the repository at this point in the history
  • Loading branch information
childc authored Oct 27, 2023
2 parents dbf36a0 + c2f07bb commit 2390f67
Show file tree
Hide file tree
Showing 29 changed files with 398 additions and 123 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ final class AudioPlayer {
}

func replacePlayer(_ player: AudioPlayer) {
guard payload.sourceType != .attachment || player.payload.sourceType != .attachment else { return }
guard let internalPlayer = player.internalPlayer else { return }

self.internalPlayer = internalPlayer
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import RxSwift

public final class AudioPlayerAgent: AudioPlayerAgentProtocol {
// CapabilityAgentable
public var capabilityAgentProperty: CapabilityAgentProperty = CapabilityAgentProperty(category: .audioPlayer, version: "1.7")
public var capabilityAgentProperty: CapabilityAgentProperty = CapabilityAgentProperty(category: .audioPlayer, version: "1.8")
private let playSyncProperty = PlaySyncProperty(layerType: .media, contextType: .sound)

// AudioPlayerAgentProtocol
Expand Down Expand Up @@ -162,7 +162,8 @@ public final class AudioPlayerAgent: AudioPlayerAgentProtocol {
DirectiveHandleInfo(namespace: capabilityAgentProperty.name, name: "UpdateMetadata", blockingPolicy: BlockingPolicy(medium: .none, isBlocking: false), directiveHandler: handleUpdateMetadata),
DirectiveHandleInfo(namespace: capabilityAgentProperty.name, name: "ShowLyrics", blockingPolicy: BlockingPolicy(medium: .none, isBlocking: false), directiveHandler: handleShowLyrics),
DirectiveHandleInfo(namespace: capabilityAgentProperty.name, name: "HideLyrics", blockingPolicy: BlockingPolicy(medium: .none, isBlocking: false), directiveHandler: handleHideLyrics),
DirectiveHandleInfo(namespace: capabilityAgentProperty.name, name: "ControlLyricsPage", blockingPolicy: BlockingPolicy(medium: .none, isBlocking: false), directiveHandler: handleControlLyricsPage)
DirectiveHandleInfo(namespace: capabilityAgentProperty.name, name: "ControlLyricsPage", blockingPolicy: BlockingPolicy(medium: .none, isBlocking: false), directiveHandler: handleControlLyricsPage),
DirectiveHandleInfo(namespace: capabilityAgentProperty.name, name: "ShowPlaylist", blockingPolicy: BlockingPolicy(medium: .none, isBlocking: false), directiveHandler: handleShowPlaylist)
]

public init(
Expand Down Expand Up @@ -223,7 +224,8 @@ public final class AudioPlayerAgent: AudioPlayerAgentProtocol {
}

if let playlist = self.currentPlaylist {
payload["playlist"] = playlist.token
payload["playlistToken"] = playlist.token
payload["playlistVisible"] = self.currentPlaylist != nil
}

completion(ContextInfo(contextType: .capability, name: self.capabilityAgentProperty.name, payload: payload.compactMapValues { $0 }))
Expand Down Expand Up @@ -706,6 +708,29 @@ private extension AudioPlayerAgent {
}
}

func handleShowPlaylist() -> HandleDirective {
return { [weak self] directive, completion in
guard let self = self,
let playServiceId = directive.payloadDictionary?["playServiceId"] as? String
else {
completion(.failed("Invalid payload"))
return
}

defer { completion(.finished) }

self.audioPlayerDisplayManager.showPlaylist(playServiceId: playServiceId) { [weak self] isSuccess in
guard let self = self else { return }
self.sendCompactContextEvent(
PlaylistEvent(
typeInfo: isSuccess ? .showPlaylistSucceeded : .showPlaylistFailed(error: ["message": "show Playlist Failed"]),
playServiceId: playServiceId
).rx
)
}
}
}

func handleAttachment() -> HandleAttachment {
return { [weak self] attachment in
self?.audioPlayerDispatchQueue.async { [weak self] in
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,8 @@ public protocol AudioPlayerDisplayDelegate: AnyObject {
/// <#Description#>
/// - Parameter completion: <#completion description#>
func audioPlayerIsLyricsVisible(completion: @escaping (Bool) -> Void)

/// Tells the delegate that the displayed template should show playlist
/// - Parameter completion: Whether succeeded or not
func audioPlayerDisplayShouldShowPlaylist(completion: @escaping (Bool) -> Void)
}
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,15 @@ extension AudioPlayerDisplayManager {
delegate.audioPlayerDisplayShouldControlLyricsPage(direction: payload.direction, completion: completion)
}

func showPlaylist(playServiceId: String, completion: @escaping (Bool) -> Void) {
guard let delegate = delegate,
currentItem?.mediaPayload.playServiceId == playServiceId else {
completion(false)
return
}
delegate.audioPlayerDisplayShouldShowPlaylist(completion: completion)
}

func notifyUserInteraction() {
switch audioPlayerState {
case .stopped, .finished:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
//
// AudioPlayer2Template.swift
// NuguAgents
//
// Created by 박종상님/iOS클라이언트개발팀 on 2023/09/11.
// Copyright © 2023 SK Telecom Co., Ltd. All rights reserved.
//

import Foundation
/// <#Description#>
public struct AudioPlayer2Template: Decodable {
public let template: Template

public struct Template: Decodable {
public let type: String
public let title: Title
public let content: Content
public let grammarGuide: [String]?

public struct Title: Decodable {
public let iconUrl: String?
public let text: String
}

public struct Content: Decodable {
public let title: String
public let subtitle: String
public let subtitle1: String?
public let imageUrl: String?
public let durationSec: String?
public let backgroundColor: String?
public let lyrics: AudioPlayerLyricsTemplate?
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ extension AudioPlayerAgent {
case playlistItemSelected(token: String, postback: [String: AnyHashable])
case playlistFavoriteSelected(token: String, postback: [String: AnyHashable])
case modifyPlaylist(deletedTokens: [String], tokens: [String])

case showPlaylistSucceeded
case showPlaylistFailed(error: [String: String])
}
}
}
Expand All @@ -51,7 +54,12 @@ extension AudioPlayerAgent.PlaylistEvent: Eventable {
case .modifyPlaylist(deletedTokens: let deletedTokens, tokens: let tokens):
eventPayload["deletedTokens"] = deletedTokens
eventPayload["tokens"] = tokens
case .showPlaylistSucceeded:
break
case .showPlaylistFailed(error: let error):
eventPayload["error"] = error
}

return eventPayload
}

Expand All @@ -61,6 +69,10 @@ extension AudioPlayerAgent.PlaylistEvent: Eventable {
return "ElementSelected"
case .modifyPlaylist:
return "ModifyPlaylist"
case .showPlaylistSucceeded:
return "ShowPlaylistSucceeded"
case .showPlaylistFailed:
return "ShowPlaylistFailed"
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ public final class ASRAgent: ASRAgentProtocol {
guard let asrRequest = asrRequest, let asrResult = asrResult else {
asrState = .idle
expectSpeech = nil
log.error("ASRRequest not exist")
log.error("ASR request: \(String(describing: asrRequest)), result: \(String(describing: asrResult))")
return
}
log.info("\(asrResult)")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import NuguCore
import RxSwift

public class PhoneCallAgent: PhoneCallAgentProtocol {
public var capabilityAgentProperty: CapabilityAgentProperty = CapabilityAgentProperty(category: .phoneCall, version: "1.3")
public var capabilityAgentProperty: CapabilityAgentProperty = CapabilityAgentProperty(category: .phoneCall, version: "1.4")

// PhoneCallAgentProtocol
public weak var delegate: PhoneCallAgentDelegate?
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ public struct PhoneCallAgentContext {
/// <#Description#>
public let recipientIntended: PhoneCallRecipientIntended?
/// <#Description#>
public let name: String?
/// <#Description#>
public let candidates: [PhoneCallPerson]?
/// <#Description#>
public let searchScene: String?
Expand All @@ -41,18 +43,21 @@ public struct PhoneCallAgentContext {
/// - intent: <#intent description#>
/// - callType: <#callType description#>
/// - recipientIntended: <#recipientIntended description#>
/// - name: <#name description#>
/// - candidates: <#candidates description#>
/// - searchScene: <#searchScene description#>
public init(
intent: PhoneCallIntent?,
callType: PhoneCallType?,
recipientIntended: PhoneCallRecipientIntended?,
name: String?,
candidates: [PhoneCallPerson]?,
searchScene: String?
) {
self.intent = intent
self.callType = callType
self.recipientIntended = recipientIntended
self.name = name
self.candidates = candidates
self.searchScene = searchScene
}
Expand Down Expand Up @@ -96,18 +101,22 @@ public struct PhoneCallAgentContext {
public let recipient: PhoneCallAgentContext.Recipient?
/// <#Description#>
public let numberBlockable: Bool?
/// <#Description#>
public let aiPhoneUserId: String?

/// The initializer for `PhoneCallAgentContext`.
public init(
state: PhoneCallState,
template: PhoneCallAgentContext.Template?,
recipient: PhoneCallAgentContext.Recipient?,
numberBlockable: Bool?
numberBlockable: Bool?,
aiPhoneUserId: String?
) {
self.state = state
self.template = template
self.recipient = recipient
self.numberBlockable = numberBlockable
self.aiPhoneUserId = aiPhoneUserId
}
}

Expand All @@ -119,6 +128,7 @@ extension PhoneCallAgentContext: Codable {
case template
case recipient
case numberBlockable
case aiPhoneUserId
}

public func encode(to encoder: Encoder) throws {
Expand All @@ -131,6 +141,8 @@ extension PhoneCallAgentContext: Codable {
if let numberBlockableValue = numberBlockable {
try container.encodeIfPresent(numberBlockableValue ? "TRUE": "FALSE", forKey: .numberBlockable)
}

try container.encodeIfPresent(aiPhoneUserId, forKey: .aiPhoneUserId)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public enum PhoneCallAgentDirectivePayload {
/// The candidate searched for play service.
///
/// If nil, there are no search results.
public let candidates: [PhoneCallPerson]?
public var candidates: [PhoneCallPerson]?
/// The scene of search target and display tempate
public let searchScene: String?
/// <#Description#>
Expand Down
24 changes: 14 additions & 10 deletions NuguAgents/Sources/CapabilityAgents/Routine/RoutineExecuter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -344,16 +344,19 @@ private extension RoutineExecuter {
let completion: ((StreamDataState) -> Void) = { [weak self] result in
log.debug(result)
if case .error = result {
self?.doNextAction()
self?.pause()
}
}

if let actionTimeout = action.actionTimeoutInMilliseconds,
.zero < actionTimeout {
state = .suspended
DispatchQueue.global().asyncAfter(deadline: .now() + NuguTimeInterval(milliseconds: actionTimeout).seconds) { [weak self] in

let workItem = DispatchWorkItem { [weak self] in
self?.delegate?.routineExecuterShouldSendActionTriggerTimout(token: action.token)
}
actionWorkItem = workItem
routineDispatchQueue.asyncAfter(deadline: .now() + NuguTimeInterval(milliseconds: actionTimeout).seconds, execute: workItem)
}

log.debug(action.type)
Expand All @@ -364,12 +367,14 @@ private extension RoutineExecuter {
doNextAction()
return
}
if let playServiceId = action.playServiceId {
handlingEvent = textAgent.requestTextInput(text: text, token: action.token, requestType: .specific(playServiceId: playServiceId), completion: completion)

} else {
handlingEvent = textAgent.requestTextInput(text: text, token: action.token, requestType: .normal, completion: completion)
}
let dynamicSource: TextInputSource = .dynamic("DYNAMIC_ROUTINE_ACTION")
handlingEvent = textAgent.requestTextInput(
text: text,
token: action.token,
playServiceId: action.playServiceId,
source: dynamicSource,
completion: completion
)
case .data:
if let eventIdentifier = delegate?.routineExecuterShouldRequestAction(action: action, referrerDialogRequestId: routine.dialogRequestId, completion: completion) {
handlingEvent = eventIdentifier.dialogRequestId
Expand All @@ -380,7 +385,7 @@ private extension RoutineExecuter {
}

func doNextAction() {
guard let action = currentAction else { return }
guard let action = currentAction, state == .playing else { return }
actionWorkItem?.cancel()
if shouldDelayAction, let delay = currentAction?.muteDelay {
log.debug("Delaying action using mute delay, delay: \(delay.dispatchTimeInterval)")
Expand All @@ -390,7 +395,6 @@ private extension RoutineExecuter {
doActionAfter(delay: delay)
} else {
delegate?.routineExecuterDidFinishProcessingAction(action)
guard state == .playing else { return }
guard hasNextAction else {
doFinish()
return
Expand Down
15 changes: 11 additions & 4 deletions NuguAgents/Sources/CapabilityAgents/Session/SessionManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,17 @@ final public class SessionManager: SessionManageable {
public func set(session: Session) {
sessionDispatchQueue.async { [weak self] in
guard let self = self else { return }
log.debug(session.dialogRequestId)
self.sessions[session.dialogRequestId] = session
self.addTimer(session: session)
let dialogRequestId = session.dialogRequestId
log.debug("Set session, session: \(session)")
self.sessions[dialogRequestId] = session

if activeList[dialogRequestId] == nil {
log.debug("Session activeList not exist session, dialogRequestId: \(dialogRequestId)")
self.addTimer(session: session)
} else {
self.addActiveSession(dialogRequestId: session.dialogRequestId)
}

self.addActiveSession(dialogRequestId: session.dialogRequestId)
self.post(NuguAgentNotification.Session.Set(session: session))
}
}
Expand Down Expand Up @@ -101,6 +107,7 @@ final public class SessionManager: SessionManageable {

private extension SessionManager {
func addTimer(session: Session) {
log.debug("Start session remove timer. dialogRequestId: \(session.dialogRequestId)")
activeTimers[session.dialogRequestId] = Single<Int>.timer(SessionConst.sessionTimeout, scheduler: sessionScheduler)
.subscribe(onSuccess: { [weak self] _ in
log.debug("Timer fired. \(session.dialogRequestId)")
Expand Down
Loading

0 comments on commit 2390f67

Please sign in to comment.