Skip to content

Commit

Permalink
init
Browse files Browse the repository at this point in the history
  • Loading branch information
laves committed Aug 8, 2023
1 parent bcb6d2d commit cdd7fe2
Show file tree
Hide file tree
Showing 8 changed files with 83 additions and 80 deletions.
5 changes: 4 additions & 1 deletion binding/flutter/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,7 @@
* Additional language support added (ar, hi, nl, pl, ru, sv, vn, zh)

## [2.2.1] - 2023-06-01
* Expose Rhino properties through RhinoManager class
* Expose Rhino properties through RhinoManager class

## [2.2.2] - 2023-08-08
* Update flutter-voice-processor
112 changes: 56 additions & 56 deletions binding/flutter/lib/rhino_manager.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,13 @@ typedef InferenceCallback = Function(RhinoInference inference);
typedef ProcessErrorCallback = Function(RhinoException error);

class RhinoManager {
final VoiceProcessor? _voiceProcessor;
VoiceProcessor? _voiceProcessor;
Rhino? _rhino;

final InferenceCallback _inferenceCallback;
RemoveListener? _removeVoiceProcessorListener;
RemoveListener? _removeErrorListener;
late VoiceProcessorFrameListener _frameListener;
late VoiceProcessorErrorListener _errorListener;

bool _awaitingStop = false;
bool _isListening;

/// Rhino version string
String? get version => _rhino?.version;
Expand Down Expand Up @@ -91,88 +90,89 @@ class RhinoManager {
}

// private constructor
RhinoManager._(this._rhino, this._inferenceCallback,
RhinoManager._(this._rhino, InferenceCallback inferenceCallback,
ProcessErrorCallback? processErrorCallback)
: _voiceProcessor = VoiceProcessor.getVoiceProcessor(
_rhino!.frameLength, _rhino.sampleRate) {
if (_voiceProcessor == null) {
throw RhinoRuntimeException("flutter_voice_processor not available.");
}
_removeVoiceProcessorListener =
_voiceProcessor!.addListener((buffer) async {
if (_awaitingStop) {
return;
}

// cast from dynamic to int array
List<int> rhinoFrame;
try {
rhinoFrame = (buffer as List<dynamic>).cast<int>();
} on Error {
RhinoException castError = RhinoException(
"flutter_voice_processor sent an unexpected data type.");
processErrorCallback == null
? print(castError.message)
: processErrorCallback(castError);
: _voiceProcessor = VoiceProcessor.instance,
_isListening = false {
_frameListener = (List<int> frame) async {
if (!_isListening) {
return;
}

// process frame with Rhino
try {
RhinoInference? rhinoResult = await _rhino?.process(rhinoFrame);
RhinoInference? rhinoResult = await _rhino?.process(frame);
if ((rhinoResult != null) && (rhinoResult.isFinalized)) {
_awaitingStop = true;

_inferenceCallback(rhinoResult);
// stop audio processing
await _voiceProcessor?.stop();
inferenceCallback(rhinoResult);
await _stop();
}
} on RhinoException catch (error) {
processErrorCallback == null
? print(error.message)
? print("RhinoException: ${error.message}")
: processErrorCallback(error);
} finally {
_awaitingStop = false;
}
});

_removeErrorListener = _voiceProcessor!.addErrorListener((errorMsg) {
RhinoException nativeError = RhinoException(errorMsg as String);
};
_errorListener = (VoiceProcessorException error) {
processErrorCallback == null
? print(nativeError.message)
: processErrorCallback(nativeError);
});
? print("RhinoException: ${error.message}")
: processErrorCallback(RhinoException(error.message));
};
}

Future<void> _stop() async {
if (!_isListening) {
return;
}

_voiceProcessor?.removeErrorListener(_errorListener);
_voiceProcessor?.removeFrameListener(_frameListener);

if (_voiceProcessor?.numFrameListeners == 0) {
try {
await _voiceProcessor?.stop();
} on PlatformException catch (e) {
throw RhinoRuntimeException(
"Failed to stop audio recording: ${e.message}");
}
}

_isListening = false;
}

/// Opens audio input stream and sends audio frames to Rhino until a inference
/// result is sent via inference callback
/// Throws a `RhinoException` if there was a problem starting the audio engine
/// Starts audio recording and processing with the Rhino egine until a
/// inference result is sent via the `inferenceCallback`
/// Throws a `RhinoException` if there was a problem starting audio recording.
Future<void> process() async {
if (_isListening) {
return;
}
if (_rhino == null || _voiceProcessor == null) {
throw RhinoInvalidStateException(
"Cannot start Rhino - resources have already been released");
}

if (await _voiceProcessor?.hasRecordAudioPermission() ?? false) {
_voiceProcessor?.addFrameListener(_frameListener);
_voiceProcessor?.addErrorListener(_errorListener);
try {
await _voiceProcessor!.start();
} on PlatformException {
await _voiceProcessor?.start(_rhino!.frameLength, _rhino!.sampleRate);
} on PlatformException catch (e) {
throw RhinoRuntimeException(
"Audio engine failed to start. Hardware may not be supported.");
"Failed to start audio recording: ${e.message}");
}
} else {
throw RhinoRuntimeException(
"User did not give permission to record audio.");
}

_isListening = true;
}

/// Releases Rhino and audio resources
/// Releases Rhino and audio resources.
/// Throws a `RhinoException` if there was a problem stopping audio recording.
Future<void> delete() async {
if (_voiceProcessor?.isRecording ?? false) {
await _voiceProcessor!.stop();
}
_removeVoiceProcessorListener?.call();
_removeErrorListener?.call();
await _stop();
_voiceProcessor = null;

_rhino?.delete();
_rhino = null;
}
Expand Down
2 changes: 1 addition & 1 deletion binding/flutter/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ packages:
name: flutter_voice_processor
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.10"
version: "1.1.0"
lints:
dependency: "direct dev"
description:
Expand Down
4 changes: 2 additions & 2 deletions binding/flutter/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: rhino_flutter
description: A Flutter plugin for Picovoice's Rhino Speech-to-Intent engine
version: 2.2.1
version: 2.2.2
homepage: https://picovoice.ai/
repository: https://github.com/Picovoice/rhino/
documentation: https://picovoice.ai/docs/rhino/
Expand All @@ -14,7 +14,7 @@ dependencies:
flutter:
sdk: flutter

flutter_voice_processor: ^1.0.10
flutter_voice_processor: ^1.1.0

dev_dependencies:
flutter_test:
Expand Down
15 changes: 8 additions & 7 deletions demo/flutter/ios/Podfile.lock
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
PODS:
- Flutter (1.0.0)
- flutter_voice_processor (1.0.6):
- flutter_voice_processor (1.1.0):
- Flutter
- ios-voice-processor (~> 1.1.0)
- integration_test (0.0.1):
- Flutter
- ios-voice-processor (1.0.3)
- ios-voice-processor (1.1.0)
- path_provider_foundation (0.0.1):
- Flutter
- FlutterMacOS
- Rhino-iOS (2.2.0):
- ios-voice-processor (~> 1.0.2)
- Rhino-iOS (2.2.2):
- ios-voice-processor (~> 1.1.0)
- rhino_flutter (2.2.0):
- Flutter
- Rhino-iOS (~> 2.2.0)
Expand Down Expand Up @@ -40,11 +41,11 @@ EXTERNAL SOURCES:

SPEC CHECKSUMS:
Flutter: 50d75fe2f02b26cc09d224853bb45737f8b3214a
flutter_voice_processor: afb59b604d99397a1ccf15c935ac8f2c2327f09f
flutter_voice_processor: 53afbf59ad3feb82f4a379fea9ed8dc98495210f
integration_test: a1e7d09bd98eca2fc37aefd79d4f41ad37bdbbe5
ios-voice-processor: 65b25a8db69ea25ffba0eeef37bae71a982f34cc
ios-voice-processor: 8e32d7f980a06d392d128ef1cd19cf6ddcaca3c1
path_provider_foundation: c68054786f1b4f3343858c1e1d0caaded73f0be9
Rhino-iOS: 5f6c2edc809a913f7559da93fc92c0e66c7bf711
Rhino-iOS: 0fad86b28d35f67ccb6bd0a2efbbcc0d88b05124
rhino_flutter: 4c3b4bbe00206617c38ea6f7c2f17d23b2879e90

PODFILE CHECKSUM: 7368163408c647b7eb699d0d788ba6718e18fb8d
Expand Down
12 changes: 5 additions & 7 deletions demo/flutter/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -154,10 +154,7 @@ class _MyAppState extends State<MyApp> {
rhinoText = "Listening...";
});
} on RhinoException catch (ex) {
print("Failed to start audio capture: ${ex.message}");
setState(() {
isButtonDisabled = false;
});
errorCallback(ex);
}
}

Expand Down Expand Up @@ -223,7 +220,7 @@ class _MyAppState extends State<MyApp> {
margin: EdgeInsets.only(right: 10, top: 10),
child: ElevatedButton(
style: buttonStyle,
onPressed: (isButtonDisabled || isError)
onPressed: (isProcessing || isButtonDisabled || isError)
? null
: () {
_showContextInfo(context);
Expand All @@ -249,8 +246,9 @@ class _MyAppState extends State<MyApp> {
height: 130,
child: ElevatedButton(
style: buttonStyle,
onPressed:
(isButtonDisabled || isError) ? null : _startProcessing,
onPressed: (isProcessing || isButtonDisabled || isError)
? null
: _startProcessing,
child: Text(isProcessing ? "..." : "Start",
style: TextStyle(fontSize: 30)),
))),
Expand Down
10 changes: 5 additions & 5 deletions demo/flutter/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ packages:
name: flutter_voice_processor
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.10"
version: "1.1.0"
fuchsia_remote_debug_protocol:
dependency: transitive
description: flutter
Expand Down Expand Up @@ -211,10 +211,10 @@ packages:
rhino_flutter:
dependency: "direct main"
description:
name: rhino_flutter
url: "https://pub.dartlang.org"
source: hosted
version: "2.2.1"
path: "../../binding/flutter"
relative: true
source: path
version: "2.2.2"
sky_engine:
dependency: transitive
description: flutter
Expand Down
3 changes: 2 additions & 1 deletion demo/flutter/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ dependencies:
flutter:
sdk: flutter

rhino_flutter: ^2.2.1
rhino_flutter:
path: ../../binding/flutter

dev_dependencies:
integration_test:
Expand Down

0 comments on commit cdd7fe2

Please sign in to comment.