root/ossiedev/branches/0.7.x/platform/AudioDevice/src/AudioDevice.cpp @ 8817

Revision 8817, 14.0 KB (checked in by jgaeddert, 4 years ago)

configuring buffers, callbacks

Line 
1/****************************************************************************
2
3Copyright 2009 Virginia Polytechnic Institute and State University
4
5This file is part of the OSSIE AudioDevice.
6
7OSSIE AudioDevice is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 2 of the License, or
10(at your option) any later version.
11
12OSSIE AudioDevice is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
15Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with OSSIE AudioDevice; if not, write to the Free Software
19Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20
21****************************************************************************/
22
23#include <iostream>
24#include "AudioDevice.h"
25
26#define AUDIODEVICE_PROPID_SAMPLERATERECORD     "DCE:90b8fe0b-3b0b-4aee-bb2b-a9a989d22ba9"
27#define AUDIODEVICE_PROPID_SAMPLERATEPLAYBACK   "DCE:5a9b4f27-c604-4fe8-9661-4bf7a65e4ad4"
28#define AUDIODEVICE_PROPID_BUFFERSIZERECORD     "DCE:849f63b4-9b18-40cb-b318-956bedae94aa"
29#define AUDIODEVICE_PROPID_BUFFERSIZEPLAYBACK   "DCE:f3a3dd1f-b7e2-44a4-ad34-db0a6bea895f"
30
31#define AUDIODEVICE_NUMCHANNELS     (2)
32#define AUDIODEVICE_SAMPLEFORMAT    (paFloat32) // paInt16
33
34// Initializing constructor
35AudioDevice_i::AudioDevice_i(char *uuid, char *label, char *profile, omni_condition *condition)
36  : Device_impl(uuid, label, profile),
37    component_running(condition),
38    isRunning(false)
39{
40    DEBUG(3, AudioDevice, "constructor invoked")
41
42    // set configured flags to false
43    // All properties must be configured before the stream is opened,
44    // after which any change in properties will be ignored
45    configured = false;
46    configured_prop_samplerate_record   = false;
47    configured_prop_samplerate_playback = false;
48    configured_prop_buffersize_record   = false;
49    configured_prop_buffersize_playback = false;
50
51    buffer_playback = NULL;
52    buffer_record   = NULL;
53
54    // Create Port for output sound
55    dataOut = new standardInterfaces_i::complexShort_u("complexShortOut");
56    dataIn  = new standardInterfaces_i::complexShort_p("complexShortIn");
57    // TODO: create port for input sound
58
59    // initialize portaudio stream
60    PaError err = Pa_Initialize();
61    if (err != paNoError) {
62        std::cerr << "ERROR: AudioDevice_i::AudioDevice_i(), could not initialize portaudio" << std::endl;
63        throw 0;
64    }
65
66    // Start the capture_sound thread
67    //capture_thread = new omni_thread(run_capture, (void *) this);
68    //capture_thread->start();
69
70    // Start playback_sound thread
71    //playback_thread = new omni_thread(run_playback, (void *) this);
72    //playback_thread->start();
73}
74
75// Default destructor
76AudioDevice_i::~AudioDevice_i()
77{
78    if (buffer_playback)
79        delete [] buffer_playback;
80    if (buffer_record)
81        delete [] buffer_record;
82
83    PaError err = Pa_Terminate();
84    if (err != paNoError) {
85        std::cerr << "ERROR: AudioDevice_i::~AudioDevice_i(), could not terminate portaudio" << std::endl;
86        throw 0;
87    }
88}
89
90// static function for omni thread
91void AudioDevice_i::run_capture( void * data )
92{
93    ((AudioDevice_i*) data)->capture_sound();
94}
95
96
97// static function for omni thread
98void AudioDevice_i::run_playback( void * data )
99{
100    ((AudioDevice_i*) data)->playback_sound();
101}
102
103void AudioDevice_i::start()
104throw (CF::Resource::StartError, CORBA::SystemException)
105{
106    DEBUG(3, AudioDevice, "start() invoked")
107
108    isRunning = true;
109
110    // start the streams
111    StartStreams();
112}
113
114
115void AudioDevice_i::stop()
116throw (CF::Resource::StopError, CORBA::SystemException)
117{
118    DEBUG(3, AudioDevice, "stop() invoked")
119
120    isRunning = false;
121
122    // stop the streams
123    StopStreams();
124}
125
126CORBA::Object_ptr AudioDevice_i::getPort(const char* portName)
127throw(CF::PortSupplier::UnknownPort, CORBA::SystemException)
128
129{
130    DEBUG(3, AudioDevice, "getPort() invoked with: " << portName)
131
132    CORBA::Object_var u;
133
134    u = dataOut->getPort(portName);
135
136    if (!CORBA::is_nil(u))
137        return u._retn();
138
139    // Port name not found; throw exception
140    throw CF::PortSupplier::UnknownPort();
141}
142
143void AudioDevice_i::initialize()
144throw (CF::LifeCycle::InitializeError, CORBA::SystemException)
145{
146    DEBUG(3, AudioDevice, "initialize() invoked")
147}
148
149void AudioDevice_i::configure(const CF::Properties &props)
150throw (CORBA::SystemException,
151       CF::PropertySet::InvalidConfiguration,
152       CF::PropertySet::PartialConfiguration)
153{
154    DEBUG(3, AudioDevice, "configure() invoked. Number of props = "
155              << props.length() 
156             )
157
158    if (configured) {
159        std::cout << "warning: AudioDevice_i::configure(), "
160                  << "cannot reconfigure once all properties are set"
161                  << std::endl;
162        return;
163    }
164
165    // read properties from .prf
166   
167    CORBA::Short n;
168    for (unsigned int i=0; i<props.length(); i++)
169    {
170        DEBUG(3, AudioDevice, "configure property id : " << props[i].id)
171
172        if (strcmp(props[i].id, AUDIODEVICE_PROPID_SAMPLERATERECORD)==0) {
173            // sample rate: record
174            props[i].value >>= n;
175            samplerate_record = n;
176            configured_prop_samplerate_record = true;
177            DEBUG(3, AudioDevice, "sample rate (record): " << samplerate_record << " Hz")
178
179        } else if (strcmp(props[i].id, AUDIODEVICE_PROPID_SAMPLERATEPLAYBACK)==0) {
180            // sample rate: playback
181            props[i].value >>= n;
182            samplerate_playback = n;
183            configured_prop_samplerate_playback = true;
184            DEBUG(3, AudioDevice, "sample rate (playback): " << samplerate_playback << " Hz")
185
186        } else if (strcmp(props[i].id, AUDIODEVICE_PROPID_BUFFERSIZERECORD)==0) {
187            // buffer size: record
188            props[i].value >>= n;
189            buffersize_record = n;
190            configured_prop_samplerate_record = true;
191            DEBUG(3, AudioDevice, "buffer size (record): " << buffersize_record)
192
193        } else if (strcmp(props[i].id, AUDIODEVICE_PROPID_BUFFERSIZEPLAYBACK)==0) {
194            // buffer size: playback
195            props[i].value >>= n;
196            buffersize_playback = n;
197            configured_prop_buffersize_playback = true;
198            DEBUG(3, AudioDevice, "buffer size (playback): " << buffersize_playback)
199
200        } else {
201            std::cerr << "ERROR AudioDevice_i::configure(): unkown property id "
202                      << props[i].id << std::endl;
203            throw(CF::PropertySet::InvalidConfiguration());
204        }
205
206        // check configured flags
207        if (    configured_prop_samplerate_record   &&
208                configured_prop_samplerate_playback &&
209                configured_prop_buffersize_record   &&
210                configured_prop_buffersize_playback)
211        {
212            configured = true;
213            DEBUG(3, AudioDevice, "configured")
214        }
215    }
216
217    // TODO: reconfigure streams
218    if (!configured)
219        return;
220
221    // configure streams
222    ConfigureStreams();
223
224    // initialize buffers
225    buffer_playback = new float[2*buffersize_playback];
226    buffer_record   = new float[2*buffersize_record];
227}
228
229void AudioDevice_i::releaseObject()
230throw (CF::LifeCycle::ReleaseError, CORBA::SystemException)
231{
232    DEBUG(3, AudioDevice, "releaseObject() invoked")
233
234    component_running->signal();
235}
236
237void AudioDevice_i::OpenStreams()
238    throw (CF::Resource::StartError)
239{
240    // ensure properties have been configured
241    if (!configured) {
242        std::cerr << "ERROR: AudioDevice_i::OpenStreams(), device not configured" << std::endl;
243        throw CF::Resource::StartError();
244    }
245
246    PaError err;
247
248    // open record stream
249    err = Pa_OpenStream(
250            &pa_stream_record,
251            NULL,               // no input
252            &pa_params_record,
253            samplerate_record,
254            buffersize_record,
255            paClipOff,          // disable clipping
256            portaudio_callback_record,
257            (void*)this);
258
259    if (err != paNoError) {
260        std::cerr << "ERROR: AudioDevice_i::OpenStreams(), could not open portaudio stream: record" << std::endl;
261        throw CF::Resource::StartError();
262    }
263
264    // open playback stream
265    err = Pa_OpenStream(
266            &pa_stream_playback,
267            &pa_params_playback,
268            NULL,               // no output
269            samplerate_playback,
270            buffersize_playback,
271            paClipOff,          // disable clipping
272            portaudio_callback_playback,
273            (void*)this);
274
275    if (err != paNoError) {
276        std::cerr << "ERROR: AudioDevice_i::OpenStreams(), could not open portaudio stream: playback" << std::endl;
277        throw CF::Resource::StartError();
278    }
279}
280
281void AudioDevice_i::StartStreams()
282    throw (CF::Resource::StartError)
283{
284    if (!configured) {
285        std::cerr << "ERROR: AudioDevice_i::StartStreams(), device not configured" << std::endl;
286        throw CF::Resource::StartError();
287    }
288
289    // start record, playback threads
290    PaError err;
291
292
293    err = Pa_StartStream(pa_stream_record);
294    if (err != paNoError) {
295        std::cerr << "ERROR: AudioDevice_i::StartStreams(), could not start portaudio stream: record" << std::endl;
296        throw CF::Resource::StartError();
297    }
298
299    err = Pa_StartStream(pa_stream_playback);
300    if (err != paNoError) {
301        std::cerr << "ERROR: AudioDevice_i::StartStreams(), could not start portaudio stream: playback" << std::endl;
302        throw CF::Resource::StartError();
303    }
304}
305
306void AudioDevice_i::StopStreams()
307    throw (CF::Resource::StopError)
308{
309    PaError err;
310
311    err = Pa_StopStream(pa_stream_record);
312    if (err != paNoError) {
313        std::cerr << "ERROR: AudioDevice_i::StopStreams(), could not stop portaudio stream: record" << std::endl;
314        throw CF::Resource::StopError();
315    }
316
317    err = Pa_StopStream(pa_stream_playback);
318    if (err != paNoError) {
319        std::cerr << "ERROR: AudioDevice_i::StopStreams(), could not stop portaudio stream: playback" << std::endl;
320        throw CF::Resource::StopError();
321    }
322
323}
324
325void AudioDevice_i::CloseStreams()
326    throw (CF::Resource::StopError)
327{
328    PaError err;
329   
330    err = Pa_CloseStream(pa_stream_record);
331    if (err != paNoError) {
332        std::cerr << "ERROR: AudioDevice_i::CloseStreams(), could not close portaudio stream: record" << std::endl;
333        throw CF::Resource::StopError();
334    }
335   
336    err = Pa_CloseStream(pa_stream_playback);
337    if (err != paNoError) {
338        std::cerr << "ERROR: AudioDevice_i::CloseStreams(), could not close portaudio stream: playback" << std::endl;
339        throw CF::Resource::StopError();
340    }
341}
342
343void AudioDevice_i::ConfigureStreams()
344{
345    // configure parameters: record
346    pa_params_record.device = Pa_GetDefaultOutputDevice();
347    pa_params_record.channelCount = AUDIODEVICE_NUMCHANNELS;
348    pa_params_record.sampleFormat = AUDIODEVICE_SAMPLEFORMAT;
349    pa_params_record.suggestedLatency =
350        Pa_GetDeviceInfo( pa_params_record.device )->defaultLowOutputLatency;
351    pa_params_record.hostApiSpecificStreamInfo = NULL;
352
353    // configure parameters: playback
354    pa_params_playback.device = Pa_GetDefaultOutputDevice();
355    pa_params_playback.channelCount = AUDIODEVICE_NUMCHANNELS;
356    pa_params_playback.sampleFormat = AUDIODEVICE_SAMPLEFORMAT;
357    pa_params_playback.suggestedLatency =
358        Pa_GetDeviceInfo( pa_params_playback.device )->defaultLowOutputLatency;
359    pa_params_playback.hostApiSpecificStreamInfo = NULL;
360}
361
362void AudioDevice_i::capture_sound()
363{
364    DEBUG(3, AudioDevice, "capture_sound() invoked")
365    PortTypes::ShortSequence L_out, R_out;
366
367    L_out.length(1);
368    R_out.length(1);
369   
370    while(isRunning && configured) {
371        //dataOut->pushPacket(L_out, R_out);
372    }
373}
374
375void AudioDevice_i::playback_sound()
376{
377    DEBUG(3, AudioDevice, "playback_sound() invoked")
378    PortTypes::ShortSequence L_out, R_out;
379
380    L_out.length(1);
381    R_out.length(1);
382   
383    while(isRunning && configured) {
384        //dataOut->pushPacket(L_out, R_out);
385    }
386}
387
388void AudioDevice_i::SetRecordData(float * _data)
389{
390    // copy data to buffer
391    for (unsigned int i=0; i<buffersize_record; i++) {
392        record_data_L[i] = buffer_record[2*i+0];
393        record_data_R[i] = buffer_record[2*i+1];
394    }
395
396    // push data
397    dataOut->pushPacket(record_data_L, record_data_R);
398}
399
400void AudioDevice_i::GetPlaybackData(float ** _data)
401{
402    // wait for data
403    dataIn->getData(playback_data_L, playback_data_R);
404
405    // copy to buffer
406    for (unsigned int i=0; i<buffersize_playback; i++) {
407        buffer_playback[2*i+0] = (*playback_data_L)[i];
408        buffer_playback[2*i+1] = (*playback_data_R)[i];
409    }
410
411    // release input buffer
412    dataIn->bufferEmptied();
413
414    // return pointer to playback buffer
415    _data = &buffer_playback;
416}
417
418int portaudio_callback_record(
419    const void *inputBuffer,
420    void *outputBuffer,
421    unsigned long framesPerBuffer,
422    const PaStreamCallbackTimeInfo* timeInfo,
423    PaStreamCallbackFlags statusFlags,
424    void *userData )
425{
426    //short int * in = (short int*)inputBuffer;
427
428    // prevent unused variable warnings
429    (void) timeInfo;
430    (void) statusFlags;
431    (void) inputBuffer;
432
433    unsigned long int i;
434    for (i=0; i<framesPerBuffer; i++) {
435        // write data to port
436    }
437
438    return paContinue;
439}
440
441int portaudio_callback_playback(
442    const void *inputBuffer,
443    void *outputBuffer,
444    unsigned long framesPerBuffer,
445    const PaStreamCallbackTimeInfo* timeInfo,
446    PaStreamCallbackFlags statusFlags,
447    void *userData )
448{
449    AudioDevice_i * device = (AudioDevice_i*)userData;
450    //short int * out = (short int*)outputBuffer;
451    // wait for data
452    float *data;
453    device->GetPlaybackData(&data);
454
455    // prevent unused variable warnings
456    (void) timeInfo;
457    (void) statusFlags;
458    (void) inputBuffer;
459
460    unsigned long int i;
461    for (i=0; i<framesPerBuffer; i++) {
462        // left
463        //*out++ = device->playback_data_L[i];
464
465        // right
466        //*out++ = device->playback_data_R[i];
467    }
468
469    return paContinue;
470}
471
472
Note: See TracBrowser for help on using the browser.