Как получить доступ к голосовым данным из INSendMessageIntent?

Вопрос или проблема

Я пытаюсь добавить поддержку Siri в мое приложение для отправки голосовых сообщений. Я реализовал INSendMessageIntentHandling в основном целевом проекте приложения.

Похоже, что приложение доходит до записи голосового сообщения и передает моему обработчику намерений INSendMessageIntent с аудиофайлом в приложении, но я не могу получить доступ к файлу вложения.

func handle(
  intent: INSendMessageIntent,
  completion: @escaping (INSendMessageIntentResponse) -> Void
) {
  if let attachment = intent.attachments?.first,
     let audioFile = attachment.audioMessageFile,
     let fileURL = audioFile.fileURL
  {
    // Этот блок выполняется
    // fileURL = "file:///var/mobile/tmp/SiriMessages/89F738F7-6092-439A-B4FA-2DD9A99F0EED.caf"
    let result = processMessageAudio(url: fileURL)
    completion(result)
    return
  }

  // Эта строка не выполняется
  completion(.init(code: .failure, userActivity: nil))
}

private func processMessageAudio(url: URL) -> INSendMessageIntentResponse {
  var fileRef: ExtAudioFileRef?
  if url.startAccessingSecurityScopedResource() {
    logDebug("Доступ к файлу разрешен")
  } else {
    // Этот блок выполняется
    logDebug("Доступ к файлу не разрешен")
  }
  defer {
    url.stopAccessingSecurityScopedResource()
  }

  let openStatus = ExtAudioFileOpenURL(url as CFURL, &fileRef)
  // openStatus равен -54 (kAudio_FilePermissionError)

  return INSendMessageIntentResponse(code: .failure, userActivity: nil)
}

Я не уверен, чего мне не хватает. Похоже, что файл с аудио должен быть, и Siri показывает предварительный просмотр аудио для подтверждения.

Ответ или решение

Для доступа к аудиоданным из INSendMessageIntent, вам нужно убедиться, что вы правильно обрабатываете доступ к защищённым ресурсам и сами аудиофайлы. Вы уже на правильном пути, но давайте разберёмся с возможными проблемами и решениями.

  1. Проверка доступа к ресурсу: Вы правильно используете методы startAccessingSecurityScopedResource() и stopAccessingSecurityScopedResource(). Однако возможно, что вы не обращаетесь к файлу в пределах сроков между началом и окончанием доступа. Убедитесь, что все операции с файлом происходят между этими вызовами.

  2. Проверка формата файла: Убедитесь, что файл имеет правильный формат и кодек для обработки. Метод ExtAudioFileOpenURL ожидает поддерживаемый формат, и возможно, вам нужно будет преобразовать файл или его метаданные.

  3. Обработка ошибок: Ваша текущая обработка ошибок ведет к завершению функции с кодом .failure, и это нормально, однако вам стоит логировать более подробные сообщения об ошибках, чтобы лучше понять, где именно происходит сбой.

    Для этого можно использовать os_log или print, чтобы отобразить ошибку получения доступа и состояние обработки файла.

Пример исправленного кода может выглядеть так:

func handle(
  intent: INSendMessageIntent,
  completion: @escaping (INSendMessageIntentResponse) -> Void
) {
  if let attachment = intent.attachments?.first,
     let audioFile = attachment.audioMessageFile,
     let fileURL = audioFile.fileURL {
    // Проверяем доступ к ресурсу
    if url.startAccessingSecurityScopedResource() {
      logDebug("File access allowed")

      let result = processMessageAudio(url: fileURL)
      completion(result)
      // Завершаем доступ после обработки
      url.stopAccessingSecurityScopedResource()
      return
    } else {
      logDebug("File access not allowed")
    }
  }

  // Если доступ не предоставлен, возвращаем ошибку
  completion(.init(code: .failure, userActivity: nil))
}

private func processMessageAudio(url: URL) -> INSendMessageIntentResponse {
  var fileRef: ExtAudioFileRef?

  // Пытаемся открыть файл
  let openStatus = ExtAudioFileOpenURL(url as CFURL, &fileRef)
  if openStatus != noErr {
    logDebug("Error opening audio file: \(openStatus)") // Логирование ошибки
    return INSendMessageIntentResponse(code: .failure, userActivity: nil)
  }

  // Здесь добавьте логику для работы с `fileRef`

  // После завершения работы с файлом
  if let fileRef = fileRef {
    ExtAudioFileDispose(fileRef)
  }

  return INSendMessageIntentResponse(code: .success, userActivity: nil)
}
  1. Права на доступ: Проверьте настройки вашего проекта. Убедитесь, что в Info.plist указаны необходимые разрешения для работы с микрофоном, такими как NSMicrophoneUsageDescription.

Следуя этим рекомендациям и примерам, вы сможете более эффективно работать с аудиофайлами, полученными из INSendMessageIntent. Если проблемы сохраняются, рассмотрите возможность проверки наличия проблемы с доступом к файлу на более низком уровне, возможно, через отладчик или логи.

Оцените материал
Добавить комментарий

Капча загружается...