Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v3.0 ios #1100

Merged
merged 9 commits into from
Oct 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions binding/ios/Porcupine-iOS.podspec
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Pod::Spec.new do |s|
s.name = 'Porcupine-iOS'
s.module_name = 'Porcupine'
s.version = '2.2.1'
s.version = '3.0.0'
s.license = {:type => 'Apache 2.0'}
s.summary = 'iOS SDK for Picovoice\'s Porcupine wake word engine'
s.description =
Expand All @@ -22,7 +22,7 @@ Pod::Spec.new do |s|
DESC
s.homepage = 'https://github.com/Picovoice/porcupine/tree/master/binding/ios'
s.author = { 'Picovoice' => '[email protected]' }
s.source = { :git => "https://github.com/Picovoice/porcupine.git", :tag => "Porcupine-iOS-v2.2.1" }
s.source = { :git => "https://github.com/Picovoice/porcupine.git", :tag => "Porcupine-iOS-v3.0.0" }
s.ios.deployment_target = '11.0'
s.swift_version = '5.0'
s.vendored_frameworks = 'lib/ios/PvPorcupine.xcframework'
Expand Down
71 changes: 50 additions & 21 deletions binding/ios/Porcupine.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//
// Copyright 2021-2022 Picovoice Inc.
// Copyright 2021-2023 Picovoice Inc.
// You may not use this file except in compliance with the license. A copy of the license is located in the "LICENSE"
// file accompanying this source.
// Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
Expand Down Expand Up @@ -46,14 +46,19 @@ public class Porcupine {
public static let frameLength = UInt32(pv_porcupine_frame_length())
public static let sampleRate = UInt32(pv_sample_rate())
public static let version = String(cString: pv_porcupine_version())
private static var sdk = "ios"

public static func setSdk(sdk: String) {
self.sdk = sdk
}

/// Constructor.
///
/// - Parameters:
/// - accessKey: The AccessKey obtained from Picovoice Console (https://console.picovoice.ai).
/// - keywordPaths: Absolute paths to keyword model files.
/// - modelPath: Absolute path to file containing model parameters.
/// - sensitivities: Sensitivities for detecting keywords. Each value should be a number within [0, 1].
/// - sensitivities: Sensitivities for detecting keywords. Each value should be a number within [0, 1].
/// A higher sensitivity results in fewer misses at the cost of increasing the false alarm rate.
/// - Throws: PorcupineError
public init(
Expand Down Expand Up @@ -103,7 +108,11 @@ public class Porcupine {
keywordPathsArgs.map { UnsafePointer(strdup($0)) },
sensitivitiesArg,
&handle)
try checkStatus(status, "Porcupine init failed")

if status != PV_STATUS_SUCCESS {
let messageStack = try getMessageStack()
throw pvStatusToPorcupineError(status, "Porcupine init failed", messageStack)
}
}

/// Constructor.
Expand Down Expand Up @@ -210,7 +219,10 @@ public class Porcupine {

var result: Int32 = -1
let status = pv_porcupine_process(self.handle, pcm, &result)
try checkStatus(status, "Porcupine process failed")
if status != PV_STATUS_SUCCESS {
let messageStack = try getMessageStack()
throw pvStatusToPorcupineError(status, "Porcupine process failed", messageStack)
}
return result
}

Expand All @@ -231,37 +243,54 @@ public class Porcupine {
"If this is a packaged asset, ensure you have added it to your xcode project.")
}

private func checkStatus(_ status: pv_status_t, _ message: String) throws {
if status == PV_STATUS_SUCCESS {
return
}

private func pvStatusToPorcupineError(
_ status: pv_status_t,
_ message: String,
_ messageStack: [String] = []) -> PorcupineError {
switch status {
case PV_STATUS_OUT_OF_MEMORY:
throw PorcupineMemoryError(message)
return PorcupineMemoryError(message, messageStack)
case PV_STATUS_IO_ERROR:
throw PorcupineIOError(message)
return PorcupineIOError(message, messageStack)
case PV_STATUS_INVALID_ARGUMENT:
throw PorcupineInvalidArgumentError(message)
return PorcupineInvalidArgumentError(message, messageStack)
case PV_STATUS_STOP_ITERATION:
throw PorcupineStopIterationError(message)
return PorcupineStopIterationError(message, messageStack)
case PV_STATUS_KEY_ERROR:
throw PorcupineKeyError(message)
return PorcupineKeyError(message, messageStack)
case PV_STATUS_INVALID_STATE:
throw PorcupineInvalidStateError(message)
return PorcupineInvalidStateError(message, messageStack)
case PV_STATUS_RUNTIME_ERROR:
throw PorcupineRuntimeError(message)
return PorcupineRuntimeError(message, messageStack)
case PV_STATUS_ACTIVATION_ERROR:
throw PorcupineActivationError(message)
return PorcupineActivationError(message, messageStack)
case PV_STATUS_ACTIVATION_LIMIT_REACHED:
throw PorcupineActivationLimitError(message)
return PorcupineActivationLimitError(message, messageStack)
case PV_STATUS_ACTIVATION_THROTTLED:
throw PorcupineActivationThrottledError(message)
return PorcupineActivationThrottledError(message, messageStack)
case PV_STATUS_ACTIVATION_REFUSED:
throw PorcupineActivationRefusedError(message)
return PorcupineActivationRefusedError(message, messageStack)
default:
let pvStatusString = String(cString: pv_status_to_string(status))
throw PorcupineError("\(pvStatusString): \(message)")
return PorcupineError("\(pvStatusString): \(message)", messageStack)
}
}

private func getMessageStack() throws -> [String] {
var messageStackRef: UnsafeMutablePointer<UnsafeMutablePointer<Int8>?>?
var messageStackDepth: Int32 = 0
let status = pv_get_error_stack(&messageStackRef, &messageStackDepth)
if status != PV_STATUS_SUCCESS {
throw pvStatusToPorcupineError(status, "Unable to get Porcupine error state")
}

var messageStack: [String] = []
for i in 0..<messageStackDepth {
messageStack.append(String(cString: messageStackRef!.advanced(by: Int(i)).pointee!))
}

pv_free_error_stack(messageStackRef)

return messageStack
}
}
6 changes: 3 additions & 3 deletions binding/ios/PorcupineAppTest/Podfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ source 'https://cdn.cocoapods.org/'
platform :ios, '11.0'

target 'PorcupineAppTest' do
pod 'Porcupine-iOS', '~> 2.2.1'
pod 'Porcupine-iOS', :podspec => 'https://raw.githubusercontent.com/Picovoice/porcupine/v3.0-ios/binding/ios/Porcupine-iOS.podspec'
end

target 'PorcupineAppTestUITests' do
pod 'Porcupine-iOS', '~> 2.2.1'
pod 'Porcupine-iOS', :podspec => 'https://raw.githubusercontent.com/Picovoice/porcupine/v3.0-ios/binding/ios/Porcupine-iOS.podspec'
end

target 'PerformanceTest' do
pod 'Porcupine-iOS', '~> 2.2.1'
pod 'Porcupine-iOS', :podspec => 'https://raw.githubusercontent.com/Picovoice/porcupine/v3.0-ios/binding/ios/Porcupine-iOS.podspec'
end
13 changes: 8 additions & 5 deletions binding/ios/PorcupineAppTest/Podfile.lock
Original file line number Diff line number Diff line change
@@ -1,20 +1,23 @@
PODS:
- ios-voice-processor (1.1.0)
- Porcupine-iOS (2.2.1):
- Porcupine-iOS (3.0.0):
- ios-voice-processor (~> 1.1.0)

DEPENDENCIES:
- Porcupine-iOS (~> 2.2.1)
- Porcupine-iOS (from `https://raw.githubusercontent.com/Picovoice/porcupine/v3.0-ios/binding/ios/Porcupine-iOS.podspec`)

SPEC REPOS:
trunk:
- ios-voice-processor
- Porcupine-iOS

EXTERNAL SOURCES:
Porcupine-iOS:
:podspec: https://raw.githubusercontent.com/Picovoice/porcupine/v3.0-ios/binding/ios/Porcupine-iOS.podspec

SPEC CHECKSUMS:
ios-voice-processor: 8e32d7f980a06d392d128ef1cd19cf6ddcaca3c1
Porcupine-iOS: df8e4a63d787b6c16bd5f988fd0f2c29a249a4bd
Porcupine-iOS: 517158e02ac294dda15b713a3c6f74a9e877090c

PODFILE CHECKSUM: e5e0f595115debf272bd322931c87f69c0b53d05
PODFILE CHECKSUM: de7c831cba4f716e69f257669fad1956c7ee900b

COCOAPODS: 1.11.3
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//
// Copyright 2022 Picovoice Inc.
// Copyright 2022-2023 Picovoice Inc.
// You may not use this file except in compliance with the license. A copy of the license is located in the "LICENSE"
// file accompanying this source.
// Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
Expand All @@ -9,10 +9,4 @@

import UIKit

class ViewController: UIViewController {

override func viewDidLoad() {
super.viewDidLoad()
}

}
class ViewController: UIViewController { }
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//
// Copyright 2022 Picovoice Inc.
// Copyright 2022-2023 Picovoice Inc.
// You may not use this file except in compliance with the license. A copy of the license is located in the "LICENSE"
// file accompanying this source.
// Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
Expand All @@ -20,10 +20,6 @@ class BaseTest: XCTestCase {
continueAfterFailure = false
}

override func tearDown() {
super.tearDown()
}

func processFile(p: Porcupine, testAudioURL: URL) throws -> [Int32] {
let data = try Data(contentsOf: testAudioURL)
let frameLengthBytes = Int(Porcupine.frameLength) * 2
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//
// Copyright 2022 Picovoice Inc.
// Copyright 2022-2023 Picovoice Inc.
// You may not use this file except in compliance with the license. A copy of the license is located in the "LICENSE"
// file accompanying this source.
// Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
Expand Down Expand Up @@ -245,4 +245,22 @@ class PorcupineAppTestUITests: BaseTest {
XCTAssert(expectedKeyword == keywordDetected)
}
}

func testMessageStack() throws {
var first_error: String = ""
do {
let p = try Porcupine.init(accessKey: "invalid", keyword: Porcupine.BuiltInKeyword.porcupine)
XCTAssertNil(p)
} catch {
first_error = "\(error.localizedDescription)"
XCTAssert(first_error.count < 1024)
}

do {
let p = try Porcupine.init(accessKey: "invalid", keyword: Porcupine.BuiltInKeyword.porcupine)
XCTAssertNil(p)
} catch {
XCTAssert("\(error.localizedDescription)".count == first_error.count)
}
}
}
15 changes: 12 additions & 3 deletions binding/ios/PorcupineErrors.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//
// Copyright 2021 Picovoice Inc.
// Copyright 2021-2023 Picovoice Inc.
// You may not use this file except in compliance with the license. A copy of the license is located in the "LICENSE"
// file accompanying this source.
// Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
Expand All @@ -9,13 +9,22 @@

public class PorcupineError: LocalizedError {
private let message: String
private let messageStack: [String]

public init (_ message: String) {
public init (_ message: String, _ messageStack: [String] = []) {
self.message = message
self.messageStack = messageStack
}

public var errorDescription: String? {
return message
var messageString = message
if messageStack.count > 0 {
messageString += ":"
for i in 0..<messageStack.count {
messageString += "\n [\(i)] \(messageStack[i])"
}
}
return messageString
}

public var name: String {
Expand Down
2 changes: 1 addition & 1 deletion demo/ios/BackgroundService/Podfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ source 'https://cdn.cocoapods.org/'
platform :ios, '11.0'

target 'PorcupineBackgroundServiceDemo' do
pod 'Porcupine-iOS', '~> 2.2.1'
pod 'Porcupine-iOS', :podspec => 'https://raw.githubusercontent.com/Picovoice/porcupine/v3.0-ios/binding/ios/Porcupine-iOS.podspec'
pod 'SwiftySound'
end
13 changes: 8 additions & 5 deletions demo/ios/BackgroundService/Podfile.lock
Original file line number Diff line number Diff line change
@@ -1,24 +1,27 @@
PODS:
- ios-voice-processor (1.1.0)
- Porcupine-iOS (2.2.1):
- Porcupine-iOS (3.0.0):
- ios-voice-processor (~> 1.1.0)
- SwiftySound (1.2.0)

DEPENDENCIES:
- Porcupine-iOS (~> 2.2.1)
- Porcupine-iOS (from `https://raw.githubusercontent.com/Picovoice/porcupine/v3.0-ios/binding/ios/Porcupine-iOS.podspec`)
- SwiftySound

SPEC REPOS:
trunk:
- ios-voice-processor
- Porcupine-iOS
- SwiftySound

EXTERNAL SOURCES:
Porcupine-iOS:
:podspec: https://raw.githubusercontent.com/Picovoice/porcupine/v3.0-ios/binding/ios/Porcupine-iOS.podspec

SPEC CHECKSUMS:
ios-voice-processor: 8e32d7f980a06d392d128ef1cd19cf6ddcaca3c1
Porcupine-iOS: df8e4a63d787b6c16bd5f988fd0f2c29a249a4bd
Porcupine-iOS: 517158e02ac294dda15b713a3c6f74a9e877090c
SwiftySound: 9eb28bb14edb601b40027e44319e0ef8383f88bf

PODFILE CHECKSUM: d37186b09c1e0853cbe460db0bbb3618858e6592
PODFILE CHECKSUM: 28977669b185aa3a95aa3654db491562cca25bd3

COCOAPODS: 1.11.3
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ class ViewController: UIViewController, UITextViewDelegate {
startButton.setTitle("STOP", for: UIControl.State.normal)

} catch let error as PorcupineInvalidArgumentError {
showErrorAlert(message: "\(error.localizedDescription)\nEnsure your accessKey '\(accessKey)' is valid")
showErrorAlert(message: "\(error.localizedDescription)")
} catch is PorcupineActivationError {
showErrorAlert(message: "AccessKey activation error")
} catch is PorcupineActivationRefusedError {
Expand Down
2 changes: 1 addition & 1 deletion demo/ios/ForegroundApp/Podfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ source 'https://cdn.cocoapods.org/'
platform :ios, '11.0'

target 'PorcupineForegroundAppDemo' do
pod 'Porcupine-iOS', '~> 2.2.1'
pod 'Porcupine-iOS', :podspec => 'https://raw.githubusercontent.com/Picovoice/porcupine/v3.0-ios/binding/ios/Porcupine-iOS.podspec'
end
13 changes: 8 additions & 5 deletions demo/ios/ForegroundApp/Podfile.lock
Original file line number Diff line number Diff line change
@@ -1,20 +1,23 @@
PODS:
- ios-voice-processor (1.1.0)
- Porcupine-iOS (2.2.1):
- Porcupine-iOS (3.0.0):
- ios-voice-processor (~> 1.1.0)

DEPENDENCIES:
- Porcupine-iOS (~> 2.2.1)
- Porcupine-iOS (from `https://raw.githubusercontent.com/Picovoice/porcupine/v3.0-ios/binding/ios/Porcupine-iOS.podspec`)

SPEC REPOS:
trunk:
- ios-voice-processor
- Porcupine-iOS

EXTERNAL SOURCES:
Porcupine-iOS:
:podspec: https://raw.githubusercontent.com/Picovoice/porcupine/v3.0-ios/binding/ios/Porcupine-iOS.podspec

SPEC CHECKSUMS:
ios-voice-processor: 8e32d7f980a06d392d128ef1cd19cf6ddcaca3c1
Porcupine-iOS: df8e4a63d787b6c16bd5f988fd0f2c29a249a4bd
Porcupine-iOS: 517158e02ac294dda15b713a3c6f74a9e877090c

PODFILE CHECKSUM: 70adce58df76651ab08c0f3906df414875213fa2
PODFILE CHECKSUM: 783e79b39a3251a402d7c4f12561db4ae8d721b6

COCOAPODS: 1.11.3
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ class ViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSo
isListening = true
startButton.setTitle("STOP", for: UIControl.State.normal)
} catch let error as PorcupineInvalidArgumentError {
showErrorAlert("\(error.localizedDescription)\nEnsure your accessKey '\(accessKey)' is valid")
showErrorAlert("\(error.localizedDescription)")
} catch is PorcupineActivationError {
showErrorAlert("AccessKey activation error")
} catch is PorcupineActivationRefusedError {
Expand Down