Is there a different way that it should be done?
No, that sounds quite right. You still didn't give much information. Maybe you should post some code, otherwise I can only guess.
You mention CheckIO. This is not needed actually. If you call SendIO you know that the request is currently playing. You can call WaitIO to wait for it to finish. Or, if you don't want to block your program while the sample is playing, you can add the message port's signal to your Wait() loop.
You still need to call WaitIO if you received the signal. It is important that every call to SendIO is complemented by a call to WaitIO before you reuse the IORequest.
The call series should be
read buffer1
send req1
read buffer2
send req2
wait for req1
read buffer1
send req1
wait for req2
read buffer2
send req2
wait for req1
and so on...
If you are able to read C code, I attached a working streaming example. It reads raw CDDA data from a file (that is 16bit stereo 44100 Hz big-endian) and streams it using AHI unit 0.