|
|
@ -9,7 +9,7 @@ import Foundation |
|
|
/// |
|
|
/// |
|
|
/// The `feedTranslatedAudio` / `feedTranslationResult` paths route to the |
|
|
/// The `feedTranslatedAudio` / `feedTranslationResult` paths route to the |
|
|
/// active handler / bridge, exactly like Android. |
|
|
/// active handler / bridge, exactly like Android. |
|
|
public class TranslationFeature: NSObject { |
|
|
class TranslationFeature: NSObject { |
|
|
|
|
|
|
|
|
weak var server: JieliHomeServer? |
|
|
weak var server: JieliHomeServer? |
|
|
|
|
|
|
|
|
@ -38,7 +38,7 @@ public class TranslationFeature: NSObject { |
|
|
|
|
|
|
|
|
/// Replace the active bridge — used by host code that wants to keep |
|
|
/// Replace the active bridge — used by host code that wants to keep |
|
|
/// audio inside native (mirrors Android `setTranslationBridge`). |
|
|
/// audio inside native (mirrors Android `setTranslationBridge`). |
|
|
public func setBridge(_ bridge: TranslationAudioBridge) { |
|
|
func setBridge(_ bridge: TranslationAudioBridge) { |
|
|
self.bridge = bridge |
|
|
self.bridge = bridge |
|
|
guard let server = server else { return } |
|
|
guard let server = server else { return } |
|
|
handlers = [ |
|
|
handlers = [ |
|
|
@ -53,19 +53,19 @@ public class TranslationFeature: NSObject { |
|
|
|
|
|
|
|
|
// MARK: - Public API |
|
|
// MARK: - Public API |
|
|
|
|
|
|
|
|
public func isWorking() -> Bool { current?.isWorking ?? false } |
|
|
func isWorking() -> Bool { current?.isWorking ?? false } |
|
|
public func currentModeId() -> Int? { |
|
|
func currentModeId() -> Int? { |
|
|
guard let h = current, h.isWorking else { return nil } |
|
|
guard let h = current, h.isWorking else { return nil } |
|
|
return h.modeId |
|
|
return h.modeId |
|
|
} |
|
|
} |
|
|
public func currentInputStreams() -> [String] { |
|
|
func currentInputStreams() -> [String] { |
|
|
current?.isWorking == true ? (current?.inputStreams ?? []) : [] |
|
|
current?.isWorking == true ? (current?.inputStreams ?? []) : [] |
|
|
} |
|
|
} |
|
|
public func currentOutputStreams() -> [String] { |
|
|
func currentOutputStreams() -> [String] { |
|
|
current?.isWorking == true ? (current?.outputStreams ?? []) : [] |
|
|
current?.isWorking == true ? (current?.outputStreams ?? []) : [] |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
public func start(modeId: Int, args: [String: Any]) throws { |
|
|
func start(modeId: Int, args: [String: Any]) throws { |
|
|
// Match Android logic — auto-upgrade mode=3 + OPUS to mode=6 stereo when |
|
|
// Match Android logic — auto-upgrade mode=3 + OPUS to mode=6 stereo when |
|
|
// the device supports it (and caller did not opt out). |
|
|
// the device supports it (and caller did not opt out). |
|
|
let bypassStereo = (args["bypassStereoUpgrade"] as? Bool) ?? false |
|
|
let bypassStereo = (args["bypassStereoUpgrade"] as? Bool) ?? false |
|
|
@ -91,13 +91,13 @@ public class TranslationFeature: NSObject { |
|
|
current = handler |
|
|
current = handler |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
public func stop() { |
|
|
func stop() { |
|
|
current?.stop() |
|
|
current?.stop() |
|
|
current = nil |
|
|
current = nil |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@discardableResult |
|
|
@discardableResult |
|
|
public func feedTranslatedAudio( |
|
|
func feedTranslatedAudio( |
|
|
streamId: String, |
|
|
streamId: String, |
|
|
pcm: Data, |
|
|
pcm: Data, |
|
|
sampleRate: Int, |
|
|
sampleRate: Int, |
|
|
@ -119,7 +119,7 @@ public class TranslationFeature: NSObject { |
|
|
) |
|
|
) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
public func feedTranslationResult( |
|
|
func feedTranslationResult( |
|
|
srcLang: String?, srcText: String?, |
|
|
srcLang: String?, srcText: String?, |
|
|
destLang: String?, destText: String?, |
|
|
destLang: String?, destText: String?, |
|
|
requestId: String? |
|
|
requestId: String? |
|
|
@ -139,7 +139,7 @@ public class TranslationFeature: NSObject { |
|
|
/// `JLDeviceConfigTws.isSupportOpusStereo` flag when available. As a |
|
|
/// `JLDeviceConfigTws.isSupportOpusStereo` flag when available. As a |
|
|
/// pragmatic default we just return `trIsPlayWithA2dp()`, matching the |
|
|
/// pragmatic default we just return `trIsPlayWithA2dp()`, matching the |
|
|
/// demo's `setupModeForCall` heuristic. |
|
|
/// demo's `setupModeForCall` heuristic. |
|
|
public func isSupportCallTranslationWithStereo(address: String?) -> Bool { |
|
|
func isSupportCallTranslationWithStereo(address: String?) -> Bool { |
|
|
#if canImport(JL_BLEKit) |
|
|
#if canImport(JL_BLEKit) |
|
|
guard let server = server else { return false } |
|
|
guard let server = server else { return false } |
|
|
return server.translationCoordinator.manager?.trIsPlayWithA2dp() ?? false |
|
|
return server.translationCoordinator.manager?.trIsPlayWithA2dp() ?? false |
|
|
@ -152,5 +152,5 @@ public class TranslationFeature: NSObject { |
|
|
/// dedicated handler maps to MODE_AUDIO_TRANSLATION which the demo drives |
|
|
/// dedicated handler maps to MODE_AUDIO_TRANSLATION which the demo drives |
|
|
/// by starting recording-and-play. Returns `false` until implemented to |
|
|
/// by starting recording-and-play. Returns `false` until implemented to |
|
|
/// keep the Dart contract intact. |
|
|
/// keep the Dart contract intact. |
|
|
public func feedAudioFilePcm(pcm: Data, sampleRate: Int) -> Bool { false } |
|
|
func feedAudioFilePcm(pcm: Data, sampleRate: Int) -> Bool { false } |
|
|
} |
|
|
} |
|
|
|