[Mono-osx] P/invoking the OS X speech API?

Nolan Darilek nolan at thewordnerd.info
Wed Feb 22 11:47:08 EST 2006


Ok, I've gotten rid of the segfault. Thanks for that tip.

I am, however, still not receiving speech, and I'm wondering if this  
is perhaps due to the fact that I'm passing in a String where a void  
* is expected, or perhaps there's some other magic I need to perform  
to account for the fact that NewSpeechChannel accepts a pointer to a  
SpeechChannel to populate whereas SpeakText expects the SpeechChannel  
itself, and I'm using an IntPtr in both places. I initially tried  
converting it to an Int32 (thinking that if the NewSpeechChannel  
wanted a pointer to a struct and worked well with a pointer to an int  
then perhaps a method that just wants the struct just might take an  
int instead) but I suspected that was wrong even before I tried it,  
and it doesn't appear to have worked besides. :)


Thoughts? Wrapping my mind around p/invoke is tying it into all kinds  
of knots. :) Here's my new revision of the Channel class:

using System;
using System.Runtime.InteropServices;

namespace Meridian.Tts.Osx {

	public class Channel {

		private IntPtr _id;

		protected const string _applicationServicesPath = "/System/Library/ 
Frameworks/ApplicationServices.framework/Versions/Current/ 
ApplicationServices";

		[DllImport(_applicationServicesPath)]
		private static extern short NewSpeechChannel(IntPtr voice, ref  
IntPtr channel);

		[DllImport(_applicationServicesPath)]
		private static extern short SpeakText(IntPtr channel, String text,  
long length);

	public Channel() {
	NewSpeechChannel((IntPtr)null, ref _id);
		Speak("Hello, world.");
	}

	public bool Speak(String text) {
		short rc = SpeakText(_id, text, (long)text.Length);
		return (rc == 0);
	}

	}
}


On Feb 21, 2006, at 11:51 PM, kangaroo wrote:

> Nolan,
>
>   It appears your problem is misunderstanding the C code (at least  
> from my quick glance);
>
> SpeechChannel is a pointer to SpeechChannelRecord; meaning that the  
> SpeechChannel* expected in NewSpeechChannel is in fact a  
> SpeechChannelRecord** which you have collapsed to the structure.
>
> I'm also concerned about where the popuplation of the SpeechChannel  
> is happening; I assume it is happening in native land in which case  
> you probably want to use IntPtr and just pass the IntPtr around as  
> needed rather than dealing with the structure.  There is no point  
> in bringing in that data if you dont need to.
>
> -kangaroo
>
> On 21-Feb-06, at 11:05 PM, Nolan Darilek wrote:
>
>> using System;
>> using System.Runtime.InteropServices;
>>
>> namespace Meridian.Tts.Osx {
>>
>> 	[StructLayout(LayoutKind.Sequential)]
>> 	struct SpeechChannel {
>> 		[MarshalAs(UnmanagedType.ByValArray, SizeConst=1)]
>> 				long[] data;
>> 	}
>>
>> 	public class Channel {
>>
>> 		private SpeechChannel _id;
>>
>> 		protected const string _applicationServicesPath = "/System/ 
>> Library/Frameworks/ApplicationServices.framework/Versions/Current/ 
>> ApplicationServices";
>>
>> 		[DllImport(_applicationServicesPath)]
>> 		private static extern short NewSpeechChannel(IntPtr voice, ref  
>> SpeechChannel channel);
>>
>> 		[DllImport(_applicationServicesPath)]
>> 		private static extern short SpeakText(SpeechChannel channel,  
>> String text, long length);
>>
>> 	public Channel() {
>> 	short rc = NewSpeechChannel((IntPtr)null, ref _id);
>> 		Console.WriteLine(rc);
>> 		Speak("Hello, world.");
>> 	}
>>
>> 	public bool Speak(String text) {
>> 		short rc = SpeakText(_id, text, (long)text.Length);
>> 		return (rc == 0);
>> 	}
>>
>> 	}
>> }
>



More information about the Mono-osx mailing list