Проверьте, действителен ли код для канала MerhodIOS

Программируем под IOS
Ответить
Anonymous
 Проверьте, действителен ли код для канала Merhod

Сообщение Anonymous »

импорт UIKit
импорт Flutter
импорт AVFoundation
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
private var ttsManager = TTSManager()

Код: Выделить всё

override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) ->  Bool {
GeneratedPluginRegistrant.register(with: self)

guard let controller = window?.rootViewController as? FlutterViewController else {
fatalError("RootViewController is not FlutterViewController")
}

let channel = FlutterMethodChannel(
name: "channelname/wifiworks",
binaryMessenger: controller.binaryMessenger
)

channel.setMethodCallHandler { [weak self] call, result in
guard let self = self else { return }
switch call.method {
case "CONVERT_TO_PCM":
self.ttsManager.convertToPCM(arguments: call.arguments, flutterResult: result)
case "disposeTts":
self.ttsManager.cleanup()
result(nil)
default:
result(FlutterMethodNotImplemented)
}
}

return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
// MARK: - TTSManager (Optimized)
конечный класс TTSManager: NSObject, AVSpeechSynthesizerDelegate {
private let Queue = DispatchQueue(label: "com.app.ttsManager", qos: .userInitiated)
частный синтезатор var: AVSpeechSynthesizer?
частная переменная flutterResult: FlutterResult?
частная переменная audioFileURL: URL?
частная переменная isProcessing = false

Код: Выделить всё

// MARK: - Entry Point
func convertToPCM(arguments: Any?, flutterResult: @escaping FlutterResult) {
queue.async {
guard !self.isProcessing else {
flutterResult(FlutterError(code: "BUSY", message: "TTS already in progress", details: nil))
return
}

guard
let args = arguments as? [String: Any],
let text = args["text"] as? String, !text.isEmpty
else {
flutterResult(FlutterError(code: "INVALID_ARGUMENT", message: "Missing or empty text", details: nil))
return
}

self.isProcessing = true
self.flutterResult = flutterResult
self.startSynthesis(
text: text,
language: args["language"] as? String,
rate: args["rate"] as? Float ?? 1.0,
volume: args["volume"] as? Float ?? 1.0,
pitch: args["pitch"] as? Float ?? 1.0,
voiceName: args["voice"] as? String
)
}
}

// MARK: - Synthesis
private func startSynthesis(
text: String,
language: String?,
rate: Float,
volume: Float,
pitch: Float,
voiceName: String?
) {
cleanup() // reset any previous synthesis

let synthesizer = AVSpeechSynthesizer()
synthesizer.delegate = self
self.synthesizer = synthesizer

let utterance = AVSpeechUtterance(string: text)
utterance.voice = selectVoice(language: language, voiceName: voiceName)
utterance.pitchMultiplier = min(max(pitch, 0.5), 2.0)
utterance.volume = min(max(volume, 0.0), 1.0)

// Map [0.0, 2.0] rate to iOS range
let adjustedRate = AVSpeechUtteranceMinimumSpeechRate +
(min(rate, 2.0) * (AVSpeechUtteranceMaximumSpeechRate - AVSpeechUtteranceMinimumSpeechRate) / 2.0)
utterance.rate = adjustedRate

// Save synthesized speech directly to a temporary PCM WAV file
self.audioFileURL = FileManager.default.temporaryDirectory.appendingPathComponent("tts_output.wav")

do {
try AVAudioSession.sharedInstance().setCategory(.playback, options: [.mixWithOthers])
try AVAudioSession.sharedInstance().setActive(true, options: .notifyOthersOnDeactivation)
} catch {
finishWithError(code: "AUDIO_SESSION", message: error.localizedDescription)
return
}

synthesizer.write(utterance) { [weak self] buffer in
guard let self = self else { return }
if let pcmBuffer = buffer as? AVAudioPCMBuffer {
self.appendPCMToFile(buffer: pcmBuffer)
} else if buffer is AVSpeechBufferCallbackEnd {
self.finishWritingToFile()
}
}
}

// MARK: - File Writing
private var fileWriter: AVAudioFile?

private func appendPCMToFile(buffer: AVAudioPCMBuffer) {
do {
if fileWriter == nil {
let format = buffer.format
fileWriter = try AVAudioFile(forWriting: audioFileURL!, settings: format.settings)
}
try fileWriter?.write(from:  buffer)
} catch {
finishWithError(code: "FILE_WRITE", message: error.localizedDescription)
}
}

private func finishWritingToFile() {
fileWriter = nil
guard let url = audioFileURL else {
finishWithError(code: "FILE_MISSING", message: "No PCM data available")
return
}

do {
let data = try Data(contentsOf: url)
DispatchQueue.main.async {
self.flutterResult?(data)
self.flutterResult = nil
}
} catch {
finishWithError(code: "READ_ERROR", message: error.localizedDescription)
}

cleanup()
}

// MARK: - Voice Selection
private func selectVoice(language: String?, voiceName: String?) -> AVSpeechSynthesisVoice? {
if let voiceName = voiceName,
let voice = AVSpeechSynthesisVoice.speechVoices().first(where: { $0.identifier == voiceName }) {
return voice
}
if let language = language,
let voice = AVSpeechSynthesisVoice.speechVoices().first(where: { $0.language == language }) {
return voice
}
return AVSpeechSynthesisVoice(language: AVSpeechSynthesisVoice.currentLanguageCode())
}

// MARK: - Cleanup and Error Handling
func cleanup() {
synthesizer?.stopSpeaking(at: .immediate)
synthesizer?.delegate = nil
synthesizer = nil
fileWriter = nil
audioFileURL = nil
isProcessing = false

do {
try AVAudioSession.sharedInstance().setActive(false, options: .notifyOthersOnDeactivation)
} catch {
NSLog("Failed to deactivate audio session: \(error)")
}
}

private func finishWithError(code: String, message: String) {
DispatchQueue.main.async {
self.flutterResult?(FlutterError(code: code, message: message, details: nil))
self.flutterResult = nil
}
cleanup()
}

// MARK: - AVSpeechSynthesizerDelegate
func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didFinish utterance: AVSpeechUtterance) {
// Not needed — handled by `write` callback end
}

func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didCancel utterance: AVSpeechUtterance) {
finishWithError(code: "CANCELLED", message: "TTS was cancelled")
}


Подробнее здесь: https://stackoverflow.com/questions/798 ... od-channel
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «IOS»