in reply to Re^5: perl->c->perl (Inline::C)
in thread perl->c->perl

Sure,
#!/ASPerl/bin/perl use strict; use Inline 'INFO'; use Inline (C => 'DATA', DIRECTORY => '/tmp', FORCE_BUILD => 1, CLEAN_AFTER_BUILD => 1, CCFLAGS => '-GF -MDd -Zi /W3 -DWIN32 -D_CONSOLE -DNO_STRICT -D +_DEBUG' . ' -DHAVE_DES_FCRYPT -DPERL_IMPLICIT_CONTEXT -DPERL_IMPLICIT_ +SYS' . ' -DUSE_PERLIO -DPERL_MSVCRT_READFIX', LIBS => 'winmm.lib PAStaticWMMED.lib', ); sub my_simpcb { my $in = shift; my $out = $in; return $out; } registercb (\&my_simpcb); portinit (44100, 256); portstart (); pasleep (3000); portstop (); portclose (); exit (0); __DATA__ __C__ #include <portaudio.h> #include <memory.h> #include <string.h> #include <stdio.h> #include <stdlib.h> #include <sys/types.h> static int pacback (void *, void *, unsigned long, PaTimestamp, void * +); static PortAudioStream *pa_stream; typedef struct { SV *isv; SV *cbfn; int runcount; } mybundle; mybundle bundle; void portinit (double sps, int buflen) { bundle.isv = newSVpvn (NULL, buflen); sv_setpvn (bundle.isv, "foo", 3); Pa_Initialize (); Pa_OpenDefaultStream (&pa_stream, 1, 1, paUInt8, sps, buflen, 0, pacback, &bundle); } void registercb (SV *cbfname) { bundle.cbfn = newSVsv (cbfname); } SV * whatiscb () { return bundle.cbfn; } void pasleep (int milisec) { Pa_Sleep (milisec); } void portstart () { bundle.runcount = 0; Pa_StartStream (pa_stream); } void portstop () { warn ("runcount == %d\n", bundle.runcount); Pa_StopStream (pa_stream); } void portclose () { Pa_CloseStream (pa_stream); Pa_Terminate (); } static int pacback (void *invoid, void *outvoid, unsigned long nsamps, PaTimestamp outTime, void *user) { mybundle *intbundle = (mybundle *)user; intbundle->runcount += nsamps; if (!invoid) return 0; sv_setpvn (intbundle->isv, (unsigned char *) invoid, nsamps); memcpy ((unsigned char *)outvoid, (unsigned char *)invoid, nsamps) +; return 0; }
I've further narrowed it down to not reading from the variables is what crashes it, but the "sv_setpvn" that _writes_ to the perl variable is what doesn't work. I verified this by adding a sv_setpvn (intbundle->isv, "foo", 3); to it, which also caused it to crash with the "access violation reading..." error.

I've uploaded the portaudio libraries I link against as well as winmm.lib (which is from the platform sdk) to http://web.mit.edu/fustflum/etcetera/portaudio, incase you care to look.

Thanks for any insights you might have.

Replies are listed 'Best First'.
Re^7: perl->c->perl (thanks, no)
by tye (Sage) on Jan 05, 2006 at 06:15 UTC

    Thanks for posting that code.

    This is mostly just a courtesy note to let you know that I won't have an answer for you, sorry (and I hope it might also increase the visibility of your node, having two "late" replies not just one -- if you get no response within a few days, I'd post a new root node).

    The reason I won't have an answer is that I don't do OO in XS and I'm pretty sure that I never will. OO in XS is quite against my philosophy of XS "best practices".

    So I have very little idea what bundle.isv actually means under the covers. Though, to be honest, I'm not too surprised that this is the source of your problem (well, that's my conclusion, anyway).

    If I were writing this, I'd do all of the OO (and just about anything else I could) in the Perl code (in the *.pm file) and have the XS interfaces be very vanilla C-friendly interfaces (except that some arguments might be of type SV* for the sake of dealing with Perl's total refusal to reasonably deal with memory buffers that it didn't allocate itself).

    - tye        

      Thanks for thinking about it, and in the process, nudging me in the right direction. I've now found what was the original problem in my initial module code, I've fixed it, and I've gotten it to work as I thought it should. Hence, I have no need for the Inline::C approximation. You can expect to see the first module giving perl the ability to do real time, cross platform, sound I/O on CPAN in a few weeks. If you think SDL::Sound satisfies this (it doesn't--it's broken), go ahead, try...

      I also don't do OO in XS (or anywhere else, generally) so I'm not sure what you're referring to. I made a struct to pass in static globals because I wasn't sure if there was a problem being caused by one thread not being able to access the globals in another thread. There's nothing OO about structs, or well, any code I write for fun. :)

      In case you're curious, the problem was that the portaudio callback thread didn't have the context for the perl interpreter. Perl uses some poorly documented dirty global variables in nearly all perlapi calls. When the portaudio rendering thread called the C callback function, it didn't have the perl global variables anymore. I fixed this by using the Perl_get_context() function (which is *not* documented in perlapi and is only mentioned IN PASSING in perlguts.) to get a pointer to the PerlInterpreter, which I pass to the callback and use PERL_SET_CONTEXT to reinitialize.

      It's been a long journey but I'm just glad I can finally do what I initially set out to do: Have a framework in which I can move data from the microphone input to the speaker output, while being modified by a regular expression in real time. :)