I'm trying to expose my native shazamkit code to the host react native app. The implementation works fine in a separate swift project but it fails when I try to integrate it into a React Native app.
Exception 'required condition is false: IsFormatSampleRateAndChannelCountValid(format)' was thrown while invoking exposed on target ShazamIOS with params (
1682,
1683
)
callstack: (
0 CoreFoundation 0x00007ff80049b761 __exceptionPreprocess + 242
1 libobjc.A.dylib 0x00007ff800063904 objc_exception_throw + 48
2 CoreFoundation 0x00007ff80049b56b +[NSException raise:format:] + 0
3 AVFAudio 0x00007ff846197929 _Z19AVAE_RaiseExceptionP8NSStringz + 156
4 AVFAudio 0x00007ff8461f2e90 _ZN17AUGraphNodeBaseV318CreateRecordingTapEmjP13AVAudioFormatU13block_pointerFvP16AVAudioPCMBufferP11AVAudioTimeE + 766
5 AVFAudio 0x00007ff84625f703 -[AVAudioNode installTapOnBus:bufferSize:format:block:] + 1456
6 muse 0x000000010a313dd0 $s4muse9ShazamIOSC6record33_35CC2309E4CA22278DC49D01D96C376ALLyyF + 496
7 muse 0x000000010a313210 $s4muse9ShazamIOSC5startyyF + 288
8 muse 0x000000010a312d03 $s4muse9ShazamIOSC7exposed_6rejectyyypSgXE_ySSSg_AGs5Error_pSgtXEtF + 83
9 muse 0x000000010a312e47 $s4muse9ShazamIOSC7exposed_6rejectyyypSgXE_ySSSg_AGs5Error_pSgtXEtFTo + 103
10 CoreFoundation 0x00007ff8004a238c __invoking___ + 140
11 CoreFoundation 0x00007ff80049f6b3 -[NSInvocation invoke] + 302
12 CoreFoundation 0x00007ff80049f923 -[NSInvocation invokeWithTarget:] + 70
13 muse 0x000000010a9210ef -[RCTModuleMethod invokeWithBridge:module:arguments:] + 2495
14 muse 0x000000010a925cb4 _ZN8facebook5reactL11invokeInnerEP9RCTBridgeP13RCTModuleDatajRKN5folly7dynamicEiN12_GLOBAL__N_117SchedulingContextE + 2036
15 muse 0x000000010a925305 _ZZN8facebook5react15RCTNativeModule6invokeEjON5folly7dynamicEiENK3$_0clEv + 133
16 muse 0x000000010a925279 ___ZN8facebook5react15RCTNativeModule6invokeEjON5folly7dynamicEi_block_invoke + 25
17 libdispatch.dylib 0x000000010e577747 _dispatch_call_block_and_release + 12
18 libdispatch.dylib 0x000000010e5789f7 _dispatch_client_callout + 8
19 libdispatch.dylib 0x000000010e5808c9 _dispatch_lane_serial_drain + 1127
20 libdispatch.dylib 0x000000010e581665 _dispatch_lane_invoke + 441
21 libdispatch.dylib 0x000000010e58e76e _dispatch_root_queue_drain_deferred_wlh + 318
22 libdispatch.dylib 0x000000010e58db69 _dispatch_workloop_worker_thread + 590
23 libsystem_pthread.dylib 0x000000010da67b84 _pthread_wqthread + 327
24 libsystem_pthread.dylib 0x000000010da66acf start_wqthread + 15
)
RCTFatal
facebook::react::invokeInner(RCTBridge*, RCTModuleData*, unsigned int, folly::dynamic const&, int, (anonymous namespace)::SchedulingContext)
facebook::react::RCTNativeModule::invoke(unsigned int, folly::dynamic&&, int)::$_0::operator()() const
invocation function for block in facebook::react::RCTNativeModule::invoke(unsigned int, folly::dynamic&&, int)
This is my swift file, error happens in the record function.
import Foundation
import ShazamKit
@objc(ShazamIOS)
class ShazamIOS : NSObject {
@Published var matching: Bool = false
@Published var mediaItem: SHMatchedMediaItem?
@Published var error: Error? {
didSet {
hasError = error != nil
}
}
@Published var hasError: Bool = false
private lazy var audioSession: AVAudioSession = .sharedInstance()
private lazy var session: SHSession = .init()
private lazy var audioEngine: AVAudioEngine = .init()
private lazy var inputNode = self.audioEngine.inputNode
private lazy var bus: AVAudioNodeBus = 0
override init() {
super.init()
session.delegate = self
}
@objc
func exposed(_ resolve:RCTPromiseResolveBlock, reject:RCTPromiseRejectBlock){
start()
resolve("ios code executed")
}
func start() {
switch audioSession.recordPermission {
case .granted:
self.record()
case .denied:
DispatchQueue.main.async {
self.error = ShazamError.recordDenied
}
case .undetermined:
audioSession.requestRecordPermission { granted in
DispatchQueue.main.async {
if granted {
self.record()
}
else {
self.error = ShazamError.recordDenied
}
}
}
@unknown default:
DispatchQueue.main.async {
self.error = ShazamError.unknown
}
}
}
private func record() {
do {
self.matching = true
let format = self.inputNode.outputFormat(forBus: bus)
self.inputNode.installTap(onBus: bus, bufferSize: 8192, format: format) { [weak self] (buffer, time) in
self?.session.matchStreamingBuffer(buffer, at: time)
}
self.audioEngine.prepare()
try self.audioEngine.start()
}
catch {
self.error = error
}
}
func stop() {
self.audioEngine.stop()
self.inputNode.removeTap(onBus: bus)
self.matching = false
}
@objc
static func requiresMainQueueSetup() -> Bool {
return true;
}
}
extension ShazamIOS: SHSessionDelegate {
func session(_ session: SHSession, didFind match: SHMatch) {
DispatchQueue.main.async { [self] in
if let mediaItem = match.mediaItems.first {
self.mediaItem = mediaItem
self.stop()
}
}
}
func session(_ session: SHSession, didNotFindMatchFor signature: SHSignature, error: Error?) {
DispatchQueue.main.async {[self] in
self.error = error
self.stop()
}
}
}
objC file
#import <Foundation/Foundation.h>
#import "React/RCTBridgeModule.h"
@interface RCT_EXTERN_MODULE(ShazamIOS, NSObject);
RCT_EXTERN_METHOD(exposed:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject)
@end
how I consume the exposed function in RN.
const {ShazamModule, ShazamIOS} = NativeModules;
const onPressIOSButton = () => {
ShazamIOS.exposed().then(result => console.log(result)).catch(e => console.log(e.message, e.code));
};
Based on the error message and stack trace, an exception is being raised due to a mismatching format passed to installTap(onBus:bufferSize:format:block:). The format
parameter is optional, so you can also pass a nil
format in the above call.
To make your implementation robust, you should register for the AVAudioEngineConfigurationChange notification and correctly handle any changes to the audio input or output hardware's channel count or sample rate.
Please also see the Matching audio using the built-in microphone article. The configureAudioEngine
function connects the engine's input node to a mixer node, and installs a tap on that mixer node to make sure the audio format is compatible with ShazamKit. In general, the audio format of some microphones and input sources may not be compatible with ShazamKit.