Quelqu'un at-il créé une binding MonoTouch pour le Nuance Dragon Mobile Speech SDK pour iOS?

J'ai le SDK Dragon Mobile fonctionnant bien sur Windows Phone 7 et j'aimerais que la fonctionnalité équivalente fonctionne pour iOS. Puisque le SDK enveloppe le microphone, il n'est pas vraiment possible d'utiliser les assemblages .NET dans mon projet MonoTouch (même si j'avais la source). Il semble que la meilleure façon de le faire est de créer une bibliothèque de binding (comme Miguel le décrit ici ).

Cela semble bien sûr beaucoup de travail, et j'aimerais réutiliser plutôt que de réinventer la roue si quelqu'un l'a déjà fait …

Voici quelques détails sur la façon dont j'ai réussi à faire fonctionner cela.

  1. J'ai téléchargé l' échantillon de binding . Vous pourriez être tenté d'ignorer cette étape, mais vous devez vraiment commencer par ce projet si vous voulez que cela fonctionne.
  2. J'ai créé une bibliothèque objective-c avec Xcode (que j'ai appelé SpeechKitLibrary) qui a un double objective – l'un est de définir le SpeechKitApplicationKey (qui est une dépendance externe dont SpeechKit a besoin):

    const unsigned char SpeechKitApplicationKey[] = {...}; 

    et l'autre est de définir une class qui utilise le framework SpeechKit, et des liens avec elle. (dans Xcode, ajoutez le framework SpeechKit dans la section frameworks du projet).

    Le file .m que j'ai écrit ressemble à ceci … (vous pouvez comprendre le file .h – super simple). Je ne suis pas sûr à 100% que vous ayez besoin de tout cela, mais je voulais m'assurer que la bibliothèque d'archives statiques qui sortirait de cette étape importerait les bons symboles. Vous pouvez peut-être éviter cela, mais dans mes expériences, j'ai trouvé que j'avais besoin de faire quelque chose comme ça …

     // the SpeechKitWrapper isn't actually used - rather, it is a way to exercise all the API's that // the binding library needs from the SpeechKit framework, so that those can be linked into the generated .a file. @implementation SpeechKitWrapper @synthesize status; - (id)initWithDelegate:(id <SKRecognizerDelegate>)delegate { self = [super init]; if (self) { del = delegate; [self setStatus:@"initializing"]; SpeechKit setupWithID:@"NMDPTRIAL_ogazitt20120220010133" host:@"sandbox.nmdp.nuancemobility.net" port:443 useSSL:NO delegate:nil]; NSSsortingng *text = [NSSsortingng ssortingngWithFormat:@"initialized. sessionid = %@", [SpeechKit sessionID]]; [self setStatus:text]; SKEarcon* earconStart = [SKEarcon earconWithName:@"beep.wav"]; [SpeechKit setEarcon:earconStart forType:SKStartRecordingEarconType]; voiceSearch = [[SKRecognizer alloc] initWithType:SKDictationRecognizerType detection:SKLongEndOfSpeechDetection language:@"en_US" delegate:delegate]; text = [NSSsortingng ssortingngWithFormat:@"recognizer connecting. sessionid = %@", [SpeechKit sessionID]]; [self setStatus:text]; } return self; } @end 
  3. J'ai ensuite compilé / lié cette archive statique pour les trois architectures différentes – i386, arm6 et arm7. Le Makefile dans le BindingSample est le model pour ce faire. Mais le net est que vous obtenez trois bibliothèques – libSpeechKitLibrary- {i386, arm6, arm7} .a. Le makefile crée ensuite une bibliothèque universelle (libSpeechKitLibraryUniversal.a) en utilisant l'outil OSX lipo (1).

  4. Seulement maintenant êtes-vous prêt à créer une bibliothèque de binding. Vous pouvez réutiliser le AssemblyInfo.cs dans l'exemple de binding (qui montrera comment créer une import sur la bibliothèque universelle pour toutes les architectures – et conduira quelques drapeaux de compilation) …

     [assembly: LinkWith ("libSpeechKitLibraryUniversal.a", LinkTarget.Simulator | LinkTarget.ArmV6 | LinkTarget.ArmV7, ForceLoad = true)] 
  5. Vous comstackz le file ApiDefinition.cs avec btouch selon le Makefile (je pense que je devais répéter certaines informations dans StructsAndEnums.cs pour le faire fonctionner). Note – la seule fonctionnalité que je n'ai pas eu à travailler est le truc "SetEarcon" – puisqu'il s'agit d'une bibliothèque d'archives et non d'un framework, je ne peux pas regrouper un wav comme un file de ressources … et je ne pouvais pas comprendre comment get la méthode SetEarcon pour accepter une ressource hors de mon set d'applications.

     using System; using MonoTouch.Foundation; namespace Nuance.SpeechKit { // SKEarcon.h public enum SKEarconType { SKStartRecordingEarconType = 1, SKStopRecordingEarconType = 2, SKCancelRecordingEarconType = 3, }; // SKRecognizer.h public enum SKEndOfSpeechDetection { SKNoEndOfSpeechDetection = 1, SKShortEndOfSpeechDetection = 2, SKLongEndOfSpeechDetection = 3, }; public static class SKRecognizerType { public static ssortingng SKDictationRecognizerType = "dictation"; public static ssortingng SKWebSearchRecognizerType = "websearch"; }; // SpeechKitErrors.h public enum SpeechKitErrors { SKServerConnectionError = 1, SKServerRetryError = 2, SKRecognizerError = 3, SKVocalizerError = 4, SKCancelledError = 5, }; // SKEarcon.h [BaseType(typeof(NSObject))] interface SKEarcon { [Export("initWithContentsOfFile:")] IntPtr Constructor(ssortingng path); [Static, Export("earconWithName:")] SKEarcon FromName(ssortingng name); } // SKRecognition.h [BaseType(typeof(NSObject))] interface SKRecognition { [Export("results")] ssortingng[] Results { get; } [Export("scores")] NSNumber[] Scores { get; } [Export("suggestion")] ssortingng Suggestion { get; } [Export("firstResult")] ssortingng FirstResult(); } // SKRecognizer.h [BaseType(typeof(NSObject))] interface SKRecognizer { [Export("audioLevel")] float AudioLevel { get; } [Export ("initWithType:detection:language:delegate:")] IntPtr Constructor (ssortingng type, SKEndOfSpeechDetection detection, ssortingng language, SKRecognizerDelegate del); [Export("stopRecording")] void StopRecording(); [Export("cancel")] void Cancel(); /* [Field ("SKSearchRecognizerType", "__Internal")] NSSsortingng SKSearchRecognizerType { get; } [Field ("SKDictationRecognizerType", "__Internal")] NSSsortingng SKDictationRecognizerType { get; } */ } [BaseType(typeof(NSObject))] [Model] interface SKRecognizerDelegate { [Export("recognizerDidBeginRecording:")] void OnRecordingBegin (SKRecognizer recognizer); [Export("recognizerDidFinishRecording:")] void OnRecordingDone (SKRecognizer recognizer); [Export("recognizer:didFinishWithResults:")] [Abstract] void OnResults (SKRecognizer recognizer, SKRecognition results); [Export("recognizer:didFinishWithError:suggestion:")] [Abstract] void OnError (SKRecognizer recognizer, NSError error, ssortingng suggestion); } // speechkit.h [BaseType(typeof(NSObject))] interface SpeechKit { [Static, Export("setupWithID:host:port:useSSL:delegate:")] void Initialize(ssortingng id, ssortingng host, int port, bool useSSL, [NullAllowed] SpeechKitDelegate del); [Static, Export("destroy")] void Destroy(); [Static, Export("sessionID")] ssortingng GetSessionID(); [Static, Export("setEarcon:forType:")] void SetEarcon(SKEarcon earcon, SKEarconType type); } [BaseType(typeof(NSObject))] [Model] interface SpeechKitDelegate { [Export("destroyed")] void Destroyed(); } [BaseType(typeof(NSObject))] interface SpeechKitWrapper { [Export("initWithDelegate:")] IntPtr Constructor(SKRecognizerDelegate del); [Export("status")] ssortingng Status { get; set; } } } 
  6. Vous avez maintenant un assembly qui peut être référencé par votre projet d'application monotouch. L'important maintenant est de se souvenir de lier avec tous les frameworks qui sont des dependencies (pas seulement SpeeckKit, mais aussi les dependencies de SK) – vous le faites en passant à mtouch des arguments supplémentaires:

     -gcc_flags "-F<insert_framework_path_here> -framework SpeechKit -framework SystemConfiguration -framework Security -framework AVFoundation -framework AudioToolbox" 

C'est tout, les amis! J'espère que cela a été utile …

Si quelqu'un (kos ou autre) utilise la méthode SetEarcon, merci de postr une solution 🙂

L'accord SDK de Nuance n'est pas assez permissif pour que quiconque puisse publier des bindings pour son SDK iOS afin de l'utiliser avec MonoTouch. Mais la bibliothèque elle-même devrait fonctionner correctement.

Cela étant dit, le SDK n'a qu'une poignée de types à cartographier et serait assez sortingvial pour RE-faire le travail que quelqu'un d'autre aurait déjà fait. Vous pouvez vérifier comment lier les assemblages en utilisant le guide de reference ici:

http://docs.xamarin.com/ios/advanced_topics/binding_objective-c_types

Il existe également un projet BindingSample qui aide les users à mieux comprendre comment lier les composants natifs à l'aide de btouch:

https://github.com/xamarin/monotouch-samples/tree/master/BindingSample

Merci encore Anuj pour votre réponse. Je pensais que je laisserais un conseil ou deux sur la façon de faire cela. La bibliothèque de binding n'a pas été difficile à build (en la peaufinant encore mais ce n'est pas une tâche difficile).

La partie la plus obscure consistait à find comment relier le framework SpeechKit. Les exemples montrent seulement comment lier un file .a ou .dylib. Après avoir passé un peu de time avec la page de manuel ld (1) sur OSX, il semble que les arguments ld (et donc gcc) pour lier un framework soient les suivants:

 -gcc_flags "-F<insert_framework_path_here> -framework SpeechKit" 

Vous mettez ceci dans une textbox dans les propriétés du projet – sous Build :: iPhone Build :: Additional mtouch arguments

Notez que -L ne fonctionne pas parce que ce n'est pas une bibliothèque; Notez également que -force_load et -ObjC référencé ici n'apparaissent pas nécessaires car, encore une fois, il s'agit d'un framework et non d'une bibliothèque.