Shazamkit - Exception 'required condition is false: IsFormatSampleRateAndChannelCountValid(format)'

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));
  };
Answered by Engineer in 788571022

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.

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.

Shazamkit - Exception 'required condition is false: IsFormatSampleRateAndChannelCountValid(format)'
 
 
Q