Examples : Audio feeding
「Text-to-speech, play music or GUI sound effects in CIOS, the functionalities are all provided by this audio feeding section.
If you want to handle all the processes, in order to use play function in CIOS Audio Core, you will need to handle the following five major sections:
- Create your own audio conduit
- Select audio device
- Audio parameters setting
- Start the Host API interface
- Stream activities handling
virtual bool Play (Conduit * conduit ,
CaDeviceIndex deviceId , int channelCount ,
CaSampleFormat sampleFormat ,
int sampleRate ,
int frameCount ,
CaStreamFlags streamFlags = 0 ,
int sleepInterval = 50 ) ;
Parameter |
Explain |
conduit |
Conduit |
deviceId |
Audio device ID |
channelCount |
Audio channel numbers |
sampleFormat |
Sampling format. Please read <CaSampleFormat>. |
sampleRate |
Sampling rate. CIOS Audio Core supports range from 8000 to 192000. Some devices might not support specific sampling rates. |
frameCount |
The block number of each sampling
interval. Suggested values are 0.1 ~ 0.2
second. If your sampling rate is 44100 or 48000, then frameCount is suggested to be 4410, 8820 or 4800, 9600. |
streamFlags |
Stream flags, normally it is 0. Except for specific Host API functionalities, you don't need to care about this flag. |
sleepInterval |
Interval to detect the status of
stream. Suggested value are 50~250 ms, not
to set a big value if possible. |
Example
Core core ;MyOwnConduit * conduit = new MyOwnConduit () ;
...
core . Play ( conduit , 1 , 2 , cafInt16 , 44100 , 4410 , 0 , 100 ) ;
...
If you need a non-blocking recording, please read <Play audio files with FFmpeg> for thread implementation.
Create your own audio conduit
Conduit is one of the most important concept in CIOS Audio Core. The concept was widely adapted all over the CIOS.If you want to supply audio stream into audio output device by yourself, then you will have to inherit a conduit class, implement one of your own. A complete details about creating audio conduit, please read <Create an inherit audio conduit>, <LinearConduit>, or <BridgeConduit>.
If you want to supply audio output stream, what you need is to inherit two functions, put function just return Complete:
virtual int obtain (void) = 0 ;
virtual void finish (ConduitDirection direction = NoDirection ,FinishCondition condition = Correct ) = 0 ;
obtain function handles StreamIO Output, the way it does as following:
int MyOwnConduit::obtain (void)
{
if ( ... condition is ready for audio feeding ... ) {
... copy your audio feeding into Output.Buffer ...
// example code in BridgeConduit.cpp : Buffer . get ( Output . Buffer , Output . Total ( ) ) ;
return Continue ;
}
if ( ... condition is audio feeding is completely empty ... ) {
return Complete ;
}
if ( ... condition has something unexpected ... ) {
return Abort ;
}
return Postpone ;
}
When the whole stream is completely stopped, stream wiil give a shot to call finish.
void MyOwnConduit::finish (ConduitDirection direction,FinishCondition condition = Correct)
{
if ( OutputDirection != direction ) return ;
... handle your own finishing conditions here ...
}
Select audio device
You will have to obtain the information inside DeviceInfo to know about the details of the audio device. Please read <DeviceInfo> for details.If you want to know the audio device name:
GetDeviceInfo((CaDeviceIndex)deviceId)->name
In case you like to know the encoding of this device name:
HostApi * hostApi = NULL ;
DeviceInfo * deviceInfo = NULL ;
deviceInfo = core . GetDeviceInfo (deviceId) ;
if ( NULL != deviceInfo ) {
core . GetHostApi ( &hostAPi , deviceInfo -> hostType ) ;
if ( NULL != hostApi ) {
if ( HostApi::NATIVE == hostApi -> encoding() ) {
// deviceInfo->name is native OS encoding
} else
if ( HostApi::UTF8 == hostApi -> encoding() ) {
// deviceInfo->name is UTF8 encoding
} else
if ( HostApi::UTF16 == hostApi -> encoding() ) {
// deviceInfo->name is UTF16 encoding
}
}
} ;
Example in CaPlay.cpp
void ListOutputDevices(void)
{
Core core ;
core . Initialize ( ) ;
for (int i=0;i<core.DeviceCount();i++) {
DeviceInfo * dev ;
dev = core.GetDeviceInfo((CaDeviceIndex)i) ;
if ( NULL != dev && dev->maxOutputChannels>0) {
printf("%4d : %s\n",i,dev->name) ;
} ;
} ;
core . Terminate ( ) ;
}
Normally, you have to know the output audio device ID before you use it. If you did not set up audio device ID, the system will select by using the following function:
virtual CaDeviceIndex DefaultOutputDevice (void) ;
Due to the underlying implementation, this device might possibly not work properly. Because CIOS Audio Core is using these underlying audio drivers, if the playback device can not work properly, looking for a solution inside CIOS Audio Core is useless.
Audio parameters setting
Set up audio parameters requires to set the values within StreamParameters, please read <StreamParameters> for details.Normally, use the following declaration to set up the parameters:
StreamParameters outputParameters ( deviceId , channelCount , sampleFormat ) ;
Set up sampling rate can be done only when you open a stream, please read <Start the Host API interface>.
Start the Host API interface
Start and stop a Host API interface require the following steps:
Core core ;
...
core . Initialize ( ) ;
//////////////////////////////////////////////////////////////////////////// ... configure output paraments here ... //////////////////////////////////////////////////////////////////////////// rt = core . Open ( &stream , NULL , &outputParameters , sampleRate , frameCount , streamFlags , conduit ) ; if ( ( NoError != rt ) || ( NULL == stream ) ) correct = false ; //////////////////////////////////////////////////////////////////////////// if ( correct ) { rt = core . Start ( stream ) ; if ( NoError != rt ) correct = false ;
////////////////////////////////////////////////////////////////////////// ... handle your stream process here ... ////////////////////////////////////////////////////////////////////////// if ( correct && ( 0 != core.IsStopped ( stream ) ) ) core.Stop ( stream ) ; } core . Close ( stream ) ; core . Terminate ( ) ;
...
Stream activities handling
After audio stream are started, you will have to detect its status. The following two Core functions are what your need:
virtual CaError IsStopped (Stream * stream) ;
virtual CaError IsActive (Stream * stream) ;
Example :
while ( 1 == core . IsActive ( stream ) ) {
Timer :: Sleep ( sleepInterval ) ;
}
Example
/* Play conduit into specific device */ bool Core::Play ( Conduit * conduit , CaDeviceIndex deviceId , int channelCount , CaSampleFormat sampleFormat , int sampleRate , int frameCount , CaStreamFlags streamFlags , int sleepInterval ) { if ( NULL == conduit ) return false ; //////////////////////////////////////////////////////////////////////////// StreamParameters INSP ( deviceId , channelCount , sampleFormat ) ; Stream * stream = NULL ; CaError rt ; bool correct = true ; //////////////////////////////////////////////////////////////////////////// Initialize ( ) ; //////////////////////////////////////////////////////////////////////////// INSP . suggestedLatency = GetDeviceInfo(deviceId)->defaultLowOutputLatency ; //////////////////////////////////////////////////////////////////////////// rt = Open ( &stream , NULL , &INSP , sampleRate , frameCount , streamFlags , conduit ) ; if ( ( NoError != rt ) || ( NULL == stream ) ) correct = false ; //////////////////////////////////////////////////////////////////////////// if ( correct ) { rt = Start ( stream ) ; if ( NoError != rt ) correct = false ; while ( correct && ( 1 == IsActive ( stream ) ) ) { Timer :: Sleep ( sleepInterval ) ; } ; ////////////////////////////////////////////////////////////////////////// if ( correct && ( 0 != IsStopped ( stream ) ) ) Stop ( stream ) ; } ; Close ( stream ) ; Terminate ( ) ; return correct ; }