97
static pj_status_t factory_init(pjmedia_aud_dev_factory *f);
98
static pj_status_t factory_destroy(pjmedia_aud_dev_factory *f);
99
static unsigned factory_get_dev_count(pjmedia_aud_dev_factory *f);
100
static pj_status_t factory_get_dev_info(pjmedia_aud_dev_factory *f,
102
pjmedia_aud_dev_info *info);
103
static pj_status_t factory_default_param(pjmedia_aud_dev_factory *f,
105
pjmedia_aud_param *param);
106
static pj_status_t factory_create_stream(pjmedia_aud_dev_factory *f,
107
const pjmedia_aud_param *param,
108
pjmedia_aud_rec_cb rec_cb,
109
pjmedia_aud_play_cb play_cb,
111
pjmedia_aud_stream **p_aud_strm);
95
static pj_status_t factory_init (pjmedia_aud_dev_factory *f);
96
static pj_status_t factory_destroy (pjmedia_aud_dev_factory *f);
97
static unsigned factory_get_dev_count (pjmedia_aud_dev_factory *f);
98
static pj_status_t factory_get_dev_info (pjmedia_aud_dev_factory *f,
100
pjmedia_aud_dev_info *info);
101
static pj_status_t factory_default_param (pjmedia_aud_dev_factory *f,
103
pjmedia_aud_param *param);
104
static pj_status_t factory_create_stream (pjmedia_aud_dev_factory *f,
105
const pjmedia_aud_param *param,
106
pjmedia_aud_rec_cb rec_cb,
107
pjmedia_aud_play_cb play_cb,
109
pjmedia_aud_stream **p_aud_strm);
113
static pj_status_t stream_get_param(pjmedia_aud_stream *strm,
114
pjmedia_aud_param *param);
115
static pj_status_t stream_get_cap(pjmedia_aud_stream *strm,
116
pjmedia_aud_dev_cap cap,
118
static pj_status_t stream_set_cap(pjmedia_aud_stream *strm,
119
pjmedia_aud_dev_cap cap,
121
static pj_status_t stream_start(pjmedia_aud_stream *strm);
122
static pj_status_t stream_stop(pjmedia_aud_stream *strm);
123
static pj_status_t stream_destroy(pjmedia_aud_stream *strm);
111
static pj_status_t stream_get_param (pjmedia_aud_stream *strm,
112
pjmedia_aud_param *param);
113
static pj_status_t stream_get_cap (pjmedia_aud_stream *strm,
114
pjmedia_aud_dev_cap cap,
116
static pj_status_t stream_set_cap (pjmedia_aud_stream *strm,
117
pjmedia_aud_dev_cap cap,
119
static pj_status_t stream_start (pjmedia_aud_stream *strm);
120
static pj_status_t stream_stop (pjmedia_aud_stream *strm);
121
static pj_status_t stream_destroy (pjmedia_aud_stream *strm);
127
static pjmedia_aud_dev_factory_op factory_op =
125
static pjmedia_aud_dev_factory_op factory_op = {
130
127
&factory_destroy,
131
128
&factory_get_dev_count,
149
145
* Convert clock rate to Symbian's TMdaAudioDataSettings capability.
151
static TInt get_clock_rate_cap(unsigned clock_rate)
147
static TInt get_clock_rate_cap (unsigned clock_rate)
153
149
switch (clock_rate) {
154
case 8000: return TMdaAudioDataSettings::ESampleRate8000Hz;
155
case 11025: return TMdaAudioDataSettings::ESampleRate11025Hz;
156
case 12000: return TMdaAudioDataSettings::ESampleRate12000Hz;
157
case 16000: return TMdaAudioDataSettings::ESampleRate16000Hz;
158
case 22050: return TMdaAudioDataSettings::ESampleRate22050Hz;
159
case 24000: return TMdaAudioDataSettings::ESampleRate24000Hz;
160
case 32000: return TMdaAudioDataSettings::ESampleRate32000Hz;
161
case 44100: return TMdaAudioDataSettings::ESampleRate44100Hz;
162
case 48000: return TMdaAudioDataSettings::ESampleRate48000Hz;
163
case 64000: return TMdaAudioDataSettings::ESampleRate64000Hz;
164
case 96000: return TMdaAudioDataSettings::ESampleRate96000Hz;
151
return TMdaAudioDataSettings::ESampleRate8000Hz;
153
return TMdaAudioDataSettings::ESampleRate11025Hz;
155
return TMdaAudioDataSettings::ESampleRate12000Hz;
157
return TMdaAudioDataSettings::ESampleRate16000Hz;
159
return TMdaAudioDataSettings::ESampleRate22050Hz;
161
return TMdaAudioDataSettings::ESampleRate24000Hz;
163
return TMdaAudioDataSettings::ESampleRate32000Hz;
165
return TMdaAudioDataSettings::ESampleRate44100Hz;
167
return TMdaAudioDataSettings::ESampleRate48000Hz;
169
return TMdaAudioDataSettings::ESampleRate64000Hz;
171
return TMdaAudioDataSettings::ESampleRate96000Hz;
171
178
* Convert number of channels into Symbian's TMdaAudioDataSettings capability.
173
static TInt get_channel_cap(unsigned channel_count)
180
static TInt get_channel_cap (unsigned channel_count)
175
182
switch (channel_count) {
176
case 1: return TMdaAudioDataSettings::EChannelsMono;
177
case 2: return TMdaAudioDataSettings::EChannelsStereo;
184
return TMdaAudioDataSettings::EChannelsMono;
186
return TMdaAudioDataSettings::EChannelsStereo;
184
193
* Utility: print sound device error
186
static void snd_perror(const char *title, TInt rc)
195
static void snd_perror (const char *title, TInt rc)
188
PJ_LOG(1,(THIS_FILE, "%s: error code %d", title, rc));
197
PJ_LOG (1, (THIS_FILE, "%s: error code %d", title, rc));
191
200
//////////////////////////////////////////////////////////////////////////////
197
206
class CPjAudioInputEngine : public CBase, MMdaAudioInputStreamCallback
206
~CPjAudioInputEngine();
208
static CPjAudioInputEngine *NewL(struct mda_stream *parent_strm,
209
pjmedia_aud_rec_cb rec_cb,
212
static CPjAudioInputEngine *NewLC(struct mda_stream *parent_strm,
213
pjmedia_aud_rec_cb rec_cb,
216
pj_status_t StartRecord();
219
pj_status_t SetGain(TInt gain) {
221
iInputStream_->SetGain(gain);
224
return PJ_EINVALIDOP;
229
return iInputStream_->Gain();
231
return PJ_EINVALIDOP;
236
return iInputStream_->MaxGain();
238
return PJ_EINVALIDOP;
243
struct mda_stream *parentStrm_;
244
pjmedia_aud_rec_cb recCb_;
246
CMdaAudioInputStream *iInputStream_;
247
HBufC8 *iStreamBuffer_;
250
pj_uint32_t timeStamp_;
253
// to avoid calculating frame length repeatedly
256
// sometimes recorded size != requested framesize, so let's
257
// provide a buffer to make sure the rec callback returning
258
// framesize as requested.
259
TUint8 *frameRecBuf_;
260
TInt frameRecBufLen_;
262
CPjAudioInputEngine(struct mda_stream *parent_strm,
263
pjmedia_aud_rec_cb rec_cb,
269
virtual void MaiscOpenComplete(TInt aError);
270
virtual void MaiscBufferCopied(TInt aError, const TDesC8 &aBuffer);
271
virtual void MaiscRecordComplete(TInt aError);
214
~CPjAudioInputEngine();
216
static CPjAudioInputEngine *NewL (struct mda_stream *parent_strm,
217
pjmedia_aud_rec_cb rec_cb,
220
static CPjAudioInputEngine *NewLC (struct mda_stream *parent_strm,
221
pjmedia_aud_rec_cb rec_cb,
224
pj_status_t StartRecord();
227
pj_status_t SetGain (TInt gain) {
229
iInputStream_->SetGain (gain);
232
return PJ_EINVALIDOP;
237
return iInputStream_->Gain();
239
return PJ_EINVALIDOP;
244
return iInputStream_->MaxGain();
246
return PJ_EINVALIDOP;
251
struct mda_stream *parentStrm_;
252
pjmedia_aud_rec_cb recCb_;
254
CMdaAudioInputStream *iInputStream_;
255
HBufC8 *iStreamBuffer_;
258
pj_uint32_t timeStamp_;
261
// to avoid calculating frame length repeatedly
264
// sometimes recorded size != requested framesize, so let's
265
// provide a buffer to make sure the rec callback returning
266
// framesize as requested.
267
TUint8 *frameRecBuf_;
268
TInt frameRecBufLen_;
270
CPjAudioInputEngine (struct mda_stream *parent_strm,
271
pjmedia_aud_rec_cb rec_cb,
277
virtual void MaiscOpenComplete (TInt aError);
278
virtual void MaiscBufferCopied (TInt aError, const TDesC8 &aBuffer);
279
virtual void MaiscRecordComplete (TInt aError);
276
CPjAudioInputEngine::CPjAudioInputEngine(struct mda_stream *parent_strm,
277
pjmedia_aud_rec_cb rec_cb,
279
: state_(STATE_INACTIVE), parentStrm_(parent_strm),
280
recCb_(rec_cb), userData_(user_data),
281
iInputStream_(NULL), iStreamBuffer_(NULL), iFramePtr_(0, 0),
282
lastError_(KErrNone), timeStamp_(0),
283
frameLen_(parent_strm->param.samples_per_frame *
285
frameRecBuf_(NULL), frameRecBufLen_(0)
284
CPjAudioInputEngine::CPjAudioInputEngine (struct mda_stream *parent_strm,
285
pjmedia_aud_rec_cb rec_cb,
287
: state_ (STATE_INACTIVE), parentStrm_ (parent_strm),
288
recCb_ (rec_cb), userData_ (user_data),
289
iInputStream_ (NULL), iStreamBuffer_ (NULL), iFramePtr_ (0, 0),
290
lastError_ (KErrNone), timeStamp_ (0),
291
frameLen_ (parent_strm->param.samples_per_frame *
293
frameRecBuf_ (NULL), frameRecBufLen_ (0)
301
309
void CPjAudioInputEngine::ConstructL()
303
iStreamBuffer_ = HBufC8::NewL(frameLen_);
304
CleanupStack::PushL(iStreamBuffer_);
311
iStreamBuffer_ = HBufC8::NewL (frameLen_);
312
CleanupStack::PushL (iStreamBuffer_);
306
314
frameRecBuf_ = new TUint8[frameLen_*2];
307
CleanupStack::PushL(frameRecBuf_);
315
CleanupStack::PushL (frameRecBuf_);
310
CPjAudioInputEngine *CPjAudioInputEngine::NewLC(struct mda_stream *parent,
311
pjmedia_aud_rec_cb rec_cb,
318
CPjAudioInputEngine *CPjAudioInputEngine::NewLC (struct mda_stream *parent,
319
pjmedia_aud_rec_cb rec_cb,
314
CPjAudioInputEngine* self = new (ELeave) CPjAudioInputEngine(parent,
317
CleanupStack::PushL(self);
322
CPjAudioInputEngine* self = new (ELeave) CPjAudioInputEngine (parent,
325
CleanupStack::PushL (self);
318
326
self->ConstructL();
322
CPjAudioInputEngine *CPjAudioInputEngine::NewL(struct mda_stream *parent,
323
pjmedia_aud_rec_cb rec_cb,
330
CPjAudioInputEngine *CPjAudioInputEngine::NewL (struct mda_stream *parent,
331
pjmedia_aud_rec_cb rec_cb,
326
CPjAudioInputEngine *self = NewLC(parent, rec_cb, user_data);
327
CleanupStack::Pop(self->frameRecBuf_);
328
CleanupStack::Pop(self->iStreamBuffer_);
329
CleanupStack::Pop(self);
334
CPjAudioInputEngine *self = NewLC (parent, rec_cb, user_data);
335
CleanupStack::Pop (self->frameRecBuf_);
336
CleanupStack::Pop (self->iStreamBuffer_);
337
CleanupStack::Pop (self);
337
345
// Ignore command if recording is in progress.
338
346
if (state_ == STATE_ACTIVE)
341
349
// According to Nokia's AudioStream example, some 2nd Edition, FP2 devices
342
// (such as Nokia 6630) require the stream to be reconstructed each time
350
// (such as Nokia 6630) require the stream to be reconstructed each time
343
351
// before calling Open() - otherwise the callback never gets called.
344
352
// For uniform behavior, lets just delete/re-create the stream for all
347
355
// Destroy existing stream.
348
356
if (iInputStream_) delete iInputStream_;
349
358
iInputStream_ = NULL;
351
360
// Create the stream.
352
TRAPD(err, iInputStream_ = CMdaAudioInputStream::NewL(*this));
361
TRAPD (err, iInputStream_ = CMdaAudioInputStream::NewL (*this));
353
363
if (err != KErrNone)
354
return PJ_RETURN_OS_ERROR(err);
364
return PJ_RETURN_OS_ERROR (err);
356
366
// Initialize settings.
357
367
TMdaAudioDataSettings iStreamSettings;
358
iStreamSettings.iChannels =
359
get_channel_cap(parentStrm_->param.channel_count);
360
iStreamSettings.iSampleRate =
361
get_clock_rate_cap(parentStrm_->param.clock_rate);
363
pj_assert(iStreamSettings.iChannels != 0 &&
364
iStreamSettings.iSampleRate != 0);
366
PJ_LOG(4,(THIS_FILE, "Opening sound device for capture, "
367
"clock rate=%d, channel count=%d..",
368
parentStrm_->param.clock_rate,
369
parentStrm_->param.channel_count));
368
iStreamSettings.iChannels =
369
get_channel_cap (parentStrm_->param.channel_count);
370
iStreamSettings.iSampleRate =
371
get_clock_rate_cap (parentStrm_->param.clock_rate);
373
pj_assert (iStreamSettings.iChannels != 0 &&
374
iStreamSettings.iSampleRate != 0);
376
PJ_LOG (4, (THIS_FILE, "Opening sound device for capture, "
377
"clock rate=%d, channel count=%d..",
378
parentStrm_->param.clock_rate,
379
parentStrm_->param.channel_count));
372
382
lastError_ = KRequestPending;
373
iInputStream_->Open(&iStreamSettings);
383
iInputStream_->Open (&iStreamSettings);
376
PJ_LOG(4,(THIS_FILE, "Sound capture started."));
386
PJ_LOG (4, (THIS_FILE, "Sound capture started."));
377
387
return PJ_SUCCESS;
383
393
// If capture is in progress, stop it.
384
394
if (iInputStream_ && state_ == STATE_ACTIVE) {
385
lastError_ = KRequestPending;
386
iInputStream_->Stop();
395
lastError_ = KRequestPending;
396
iInputStream_->Stop();
388
// Wait until it's actually stopped
389
while (lastError_ == KRequestPending)
390
pj_symbianos_poll(-1, 100);
398
// Wait until it's actually stopped
399
while (lastError_ == KRequestPending)
400
pj_symbianos_poll (-1, 100);
393
403
if (iInputStream_) {
394
delete iInputStream_;
395
iInputStream_ = NULL;
404
delete iInputStream_;
405
iInputStream_ = NULL;
398
408
state_ = STATE_INACTIVE;
402
TPtr8 & CPjAudioInputEngine::GetFrame()
412
TPtr8 & CPjAudioInputEngine::GetFrame()
404
414
//iStreamBuffer_->Des().FillZ(frameLen_);
405
iFramePtr_.Set((TUint8*)(iStreamBuffer_->Ptr()), frameLen_, frameLen_);
415
iFramePtr_.Set ( (TUint8*) (iStreamBuffer_->Ptr()), frameLen_, frameLen_);
406
416
return iFramePtr_;
409
void CPjAudioInputEngine::MaiscOpenComplete(TInt aError)
419
void CPjAudioInputEngine::MaiscOpenComplete (TInt aError)
411
421
lastError_ = aError;
412
423
if (aError != KErrNone) {
413
snd_perror("Error in MaiscOpenComplete()", aError);
424
snd_perror ("Error in MaiscOpenComplete()", aError);
417
428
// set stream priority to normal and time sensitive
418
iInputStream_->SetPriority(EPriorityNormal,
419
EMdaPriorityPreferenceTime);
429
iInputStream_->SetPriority (EPriorityNormal,
430
EMdaPriorityPreferenceTime);
421
432
// Read the first frame.
422
433
TPtr8 & frm = GetFrame();
423
TRAPD(err2, iInputStream_->ReadL(frm));
434
TRAPD (err2, iInputStream_->ReadL (frm));
425
PJ_LOG(4,(THIS_FILE, "Exception in iInputStream_->ReadL()"));
437
PJ_LOG (4, (THIS_FILE, "Exception in iInputStream_->ReadL()"));
429
void CPjAudioInputEngine::MaiscBufferCopied(TInt aError,
430
const TDesC8 &aBuffer)
441
void CPjAudioInputEngine::MaiscBufferCopied (TInt aError,
442
const TDesC8 &aBuffer)
432
444
lastError_ = aError;
433
446
if (aError != KErrNone) {
434
snd_perror("Error in MaiscBufferCopied()", aError);
447
snd_perror ("Error in MaiscBufferCopied()", aError);
438
451
if (frameRecBufLen_ || aBuffer.Length() < frameLen_) {
439
pj_memcpy(frameRecBuf_ + frameRecBufLen_, (void*) aBuffer.Ptr(), aBuffer.Length());
440
frameRecBufLen_ += aBuffer.Length();
452
pj_memcpy (frameRecBuf_ + frameRecBufLen_, (void*) aBuffer.Ptr(), aBuffer.Length());
453
frameRecBufLen_ += aBuffer.Length();
443
456
if (frameRecBufLen_) {
444
while (frameRecBufLen_ >= frameLen_) {
447
f.type = PJMEDIA_FRAME_TYPE_AUDIO;
448
f.buf = frameRecBuf_;
450
f.timestamp.u32.lo = timeStamp_;
453
// Call the callback.
454
recCb_(userData_, &f);
455
// Increment timestamp.
456
timeStamp_ += parentStrm_->param.samples_per_frame;
458
frameRecBufLen_ -= frameLen_;
459
pj_memmove(frameRecBuf_, frameRecBuf_+frameLen_, frameRecBufLen_);
457
while (frameRecBufLen_ >= frameLen_) {
460
f.type = PJMEDIA_FRAME_TYPE_AUDIO;
461
f.buf = frameRecBuf_;
463
f.timestamp.u32.lo = timeStamp_;
466
// Call the callback.
467
recCb_ (userData_, &f);
468
// Increment timestamp.
469
timeStamp_ += parentStrm_->param.samples_per_frame;
471
frameRecBufLen_ -= frameLen_;
472
pj_memmove (frameRecBuf_, frameRecBuf_+frameLen_, frameRecBufLen_);
464
f.type = PJMEDIA_FRAME_TYPE_AUDIO;
465
f.buf = (void*)aBuffer.Ptr();
466
f.size = aBuffer.Length();
467
f.timestamp.u32.lo = timeStamp_;
470
// Call the callback.
471
recCb_(userData_, &f);
473
// Increment timestamp.
474
timeStamp_ += parentStrm_->param.samples_per_frame;
477
f.type = PJMEDIA_FRAME_TYPE_AUDIO;
478
f.buf = (void*) aBuffer.Ptr();
479
f.size = aBuffer.Length();
480
f.timestamp.u32.lo = timeStamp_;
483
// Call the callback.
484
recCb_ (userData_, &f);
486
// Increment timestamp.
487
timeStamp_ += parentStrm_->param.samples_per_frame;
477
490
// Record next frame
478
491
TPtr8 & frm = GetFrame();
479
TRAPD(err2, iInputStream_->ReadL(frm));
492
TRAPD (err2, iInputStream_->ReadL (frm));
481
PJ_LOG(4,(THIS_FILE, "Exception in iInputStream_->ReadL()"));
495
PJ_LOG (4, (THIS_FILE, "Exception in iInputStream_->ReadL()"));
486
void CPjAudioInputEngine::MaiscRecordComplete(TInt aError)
500
void CPjAudioInputEngine::MaiscRecordComplete (TInt aError)
488
502
lastError_ = aError;
489
503
state_ = STATE_INACTIVE;
490
505
if (aError != KErrNone && aError != KErrCancel) {
491
snd_perror("Error in MaiscRecordComplete()", aError);
506
snd_perror ("Error in MaiscRecordComplete()", aError);
504
519
class CPjAudioOutputEngine : public CBase, MMdaAudioOutputStreamCallback
513
~CPjAudioOutputEngine();
515
static CPjAudioOutputEngine *NewL(struct mda_stream *parent_strm,
516
pjmedia_aud_play_cb play_cb,
519
static CPjAudioOutputEngine *NewLC(struct mda_stream *parent_strm,
520
pjmedia_aud_play_cb rec_cb,
523
pj_status_t StartPlay();
526
pj_status_t SetVolume(TInt vol) {
527
if (iOutputStream_) {
528
iOutputStream_->SetVolume(vol);
531
return PJ_EINVALIDOP;
535
if (iOutputStream_) {
536
return iOutputStream_->Volume();
538
return PJ_EINVALIDOP;
541
TInt GetMaxVolume() {
542
if (iOutputStream_) {
543
return iOutputStream_->MaxVolume();
545
return PJ_EINVALIDOP;
550
struct mda_stream *parentStrm_;
551
pjmedia_aud_play_cb playCb_;
553
CMdaAudioOutputStream *iOutputStream_;
555
unsigned frameBufSize_;
560
CPjAudioOutputEngine(struct mda_stream *parent_strm,
561
pjmedia_aud_play_cb play_cb,
565
virtual void MaoscOpenComplete(TInt aError);
566
virtual void MaoscBufferCopied(TInt aError, const TDesC8& aBuffer);
567
virtual void MaoscPlayComplete(TInt aError);
527
~CPjAudioOutputEngine();
529
static CPjAudioOutputEngine *NewL (struct mda_stream *parent_strm,
530
pjmedia_aud_play_cb play_cb,
533
static CPjAudioOutputEngine *NewLC (struct mda_stream *parent_strm,
534
pjmedia_aud_play_cb rec_cb,
537
pj_status_t StartPlay();
540
pj_status_t SetVolume (TInt vol) {
541
if (iOutputStream_) {
542
iOutputStream_->SetVolume (vol);
545
return PJ_EINVALIDOP;
549
if (iOutputStream_) {
550
return iOutputStream_->Volume();
552
return PJ_EINVALIDOP;
555
TInt GetMaxVolume() {
556
if (iOutputStream_) {
557
return iOutputStream_->MaxVolume();
559
return PJ_EINVALIDOP;
564
struct mda_stream *parentStrm_;
565
pjmedia_aud_play_cb playCb_;
567
CMdaAudioOutputStream *iOutputStream_;
569
unsigned frameBufSize_;
574
CPjAudioOutputEngine (struct mda_stream *parent_strm,
575
pjmedia_aud_play_cb play_cb,
579
virtual void MaoscOpenComplete (TInt aError);
580
virtual void MaoscBufferCopied (TInt aError, const TDesC8& aBuffer);
581
virtual void MaoscPlayComplete (TInt aError);
571
CPjAudioOutputEngine::CPjAudioOutputEngine(struct mda_stream *parent_strm,
572
pjmedia_aud_play_cb play_cb,
574
: state_(STATE_INACTIVE), parentStrm_(parent_strm), playCb_(play_cb),
575
userData_(user_data), iOutputStream_(NULL), frameBuf_(NULL),
576
lastError_(KErrNone), timestamp_(0)
585
CPjAudioOutputEngine::CPjAudioOutputEngine (struct mda_stream *parent_strm,
586
pjmedia_aud_play_cb play_cb,
588
: state_ (STATE_INACTIVE), parentStrm_ (parent_strm), playCb_ (play_cb),
589
userData_ (user_data), iOutputStream_ (NULL), frameBuf_ (NULL),
590
lastError_ (KErrNone), timestamp_ (0)
581
595
void CPjAudioOutputEngine::ConstructL()
583
597
frameBufSize_ = parentStrm_->param.samples_per_frame *
585
599
frameBuf_ = new TUint8[frameBufSize_];
588
602
CPjAudioOutputEngine::~CPjAudioOutputEngine()
594
608
CPjAudioOutputEngine *
595
CPjAudioOutputEngine::NewLC(struct mda_stream *parent_strm,
596
pjmedia_aud_play_cb play_cb,
609
CPjAudioOutputEngine::NewLC (struct mda_stream *parent_strm,
610
pjmedia_aud_play_cb play_cb,
599
CPjAudioOutputEngine* self = new (ELeave) CPjAudioOutputEngine(parent_strm,
602
CleanupStack::PushL(self);
613
CPjAudioOutputEngine* self = new (ELeave) CPjAudioOutputEngine (parent_strm,
616
CleanupStack::PushL (self);
603
617
self->ConstructL();
607
621
CPjAudioOutputEngine *
608
CPjAudioOutputEngine::NewL(struct mda_stream *parent_strm,
609
pjmedia_aud_play_cb play_cb,
622
CPjAudioOutputEngine::NewL (struct mda_stream *parent_strm,
623
pjmedia_aud_play_cb play_cb,
612
CPjAudioOutputEngine *self = NewLC(parent_strm, play_cb, user_data);
613
CleanupStack::Pop(self);
626
CPjAudioOutputEngine *self = NewLC (parent_strm, play_cb, user_data);
627
CleanupStack::Pop (self);
619
633
// Ignore command if playing is in progress.
620
634
if (state_ == STATE_ACTIVE)
623
637
// Destroy existing stream.
624
638
if (iOutputStream_) delete iOutputStream_;
625
640
iOutputStream_ = NULL;
627
642
// Create the stream
628
TRAPD(err, iOutputStream_ = CMdaAudioOutputStream::NewL(*this));
643
TRAPD (err, iOutputStream_ = CMdaAudioOutputStream::NewL (*this));
629
645
if (err != KErrNone)
630
return PJ_RETURN_OS_ERROR(err);
646
return PJ_RETURN_OS_ERROR (err);
632
648
// Initialize settings.
633
649
TMdaAudioDataSettings iStreamSettings;
634
iStreamSettings.iChannels =
635
get_channel_cap(parentStrm_->param.channel_count);
636
iStreamSettings.iSampleRate =
637
get_clock_rate_cap(parentStrm_->param.clock_rate);
639
pj_assert(iStreamSettings.iChannels != 0 &&
640
iStreamSettings.iSampleRate != 0);
642
PJ_LOG(4,(THIS_FILE, "Opening sound device for playback, "
643
"clock rate=%d, channel count=%d..",
644
parentStrm_->param.clock_rate,
645
parentStrm_->param.channel_count));
650
iStreamSettings.iChannels =
651
get_channel_cap (parentStrm_->param.channel_count);
652
iStreamSettings.iSampleRate =
653
get_clock_rate_cap (parentStrm_->param.clock_rate);
655
pj_assert (iStreamSettings.iChannels != 0 &&
656
iStreamSettings.iSampleRate != 0);
658
PJ_LOG (4, (THIS_FILE, "Opening sound device for playback, "
659
"clock rate=%d, channel count=%d..",
660
parentStrm_->param.clock_rate,
661
parentStrm_->param.channel_count));
648
664
lastError_ = KRequestPending;
649
iOutputStream_->Open(&iStreamSettings);
665
iOutputStream_->Open (&iStreamSettings);
652
PJ_LOG(4,(THIS_FILE, "Sound playback started"));
668
PJ_LOG (4, (THIS_FILE, "Sound playback started"));
653
669
return PJ_SUCCESS;
659
675
// Stop stream if it's playing
660
676
if (iOutputStream_ && state_ != STATE_INACTIVE) {
661
lastError_ = KRequestPending;
662
iOutputStream_->Stop();
664
// Wait until it's actually stopped
665
while (lastError_ == KRequestPending)
666
pj_symbianos_poll(-1, 100);
669
if (iOutputStream_) {
670
delete iOutputStream_;
671
iOutputStream_ = NULL;
677
lastError_ = KRequestPending;
678
iOutputStream_->Stop();
680
// Wait until it's actually stopped
681
while (lastError_ == KRequestPending)
682
pj_symbianos_poll (-1, 100);
685
if (iOutputStream_) {
686
delete iOutputStream_;
687
iOutputStream_ = NULL;
674
690
state_ = STATE_INACTIVE;
677
void CPjAudioOutputEngine::MaoscOpenComplete(TInt aError)
693
void CPjAudioOutputEngine::MaoscOpenComplete (TInt aError)
679
695
lastError_ = aError;
681
697
if (aError==KErrNone) {
682
// output stream opened succesfully, set status to Active
683
state_ = STATE_ACTIVE;
685
// set stream properties, 16bit 8KHz mono
686
TMdaAudioDataSettings iSettings;
687
iSettings.iChannels =
688
get_channel_cap(parentStrm_->param.channel_count);
689
iSettings.iSampleRate =
690
get_clock_rate_cap(parentStrm_->param.clock_rate);
692
iOutputStream_->SetAudioPropertiesL(iSettings.iSampleRate,
693
iSettings.iChannels);
695
// set volume to 1/2th of stream max volume
696
iOutputStream_->SetVolume(iOutputStream_->MaxVolume()/2);
698
// set stream priority to normal and time sensitive
699
iOutputStream_->SetPriority(EPriorityNormal,
700
EMdaPriorityPreferenceTime);
702
// Call callback to retrieve frame from upstream.
706
f.type = PJMEDIA_FRAME_TYPE_AUDIO;
708
f.size = frameBufSize_;
709
f.timestamp.u32.lo = timestamp_;
712
status = playCb_(this->userData_, &f);
713
if (status != PJ_SUCCESS) {
718
if (f.type != PJMEDIA_FRAME_TYPE_AUDIO)
719
pj_bzero(frameBuf_, frameBufSize_);
721
// Increment timestamp.
722
timestamp_ += (frameBufSize_ / BYTES_PER_SAMPLE);
724
// issue WriteL() to write the first audio data block,
725
// subsequent calls to WriteL() will be issued in
726
// MMdaAudioOutputStreamCallback::MaoscBufferCopied()
727
// until whole data buffer is written.
728
frame_.Set(frameBuf_, frameBufSize_);
729
iOutputStream_->WriteL(frame_);
698
// output stream opened succesfully, set status to Active
699
state_ = STATE_ACTIVE;
701
// set stream properties, 16bit 8KHz mono
702
TMdaAudioDataSettings iSettings;
703
iSettings.iChannels =
704
get_channel_cap (parentStrm_->param.channel_count);
705
iSettings.iSampleRate =
706
get_clock_rate_cap (parentStrm_->param.clock_rate);
708
iOutputStream_->SetAudioPropertiesL (iSettings.iSampleRate,
709
iSettings.iChannels);
711
// set volume to 1/2th of stream max volume
712
iOutputStream_->SetVolume (iOutputStream_->MaxVolume() /2);
714
// set stream priority to normal and time sensitive
715
iOutputStream_->SetPriority (EPriorityNormal,
716
EMdaPriorityPreferenceTime);
718
// Call callback to retrieve frame from upstream.
722
f.type = PJMEDIA_FRAME_TYPE_AUDIO;
724
f.size = frameBufSize_;
725
f.timestamp.u32.lo = timestamp_;
728
status = playCb_ (this->userData_, &f);
730
if (status != PJ_SUCCESS) {
735
if (f.type != PJMEDIA_FRAME_TYPE_AUDIO)
736
pj_bzero (frameBuf_, frameBufSize_);
738
// Increment timestamp.
739
timestamp_ += (frameBufSize_ / BYTES_PER_SAMPLE);
741
// issue WriteL() to write the first audio data block,
742
// subsequent calls to WriteL() will be issued in
743
// MMdaAudioOutputStreamCallback::MaoscBufferCopied()
744
// until whole data buffer is written.
745
frame_.Set (frameBuf_, frameBufSize_);
746
iOutputStream_->WriteL (frame_);
731
snd_perror("Error in MaoscOpenComplete()", aError);
748
snd_perror ("Error in MaoscOpenComplete()", aError);
735
void CPjAudioOutputEngine::MaoscBufferCopied(TInt aError,
736
const TDesC8& aBuffer)
752
void CPjAudioOutputEngine::MaoscBufferCopied (TInt aError,
753
const TDesC8& aBuffer)
738
PJ_UNUSED_ARG(aBuffer);
755
PJ_UNUSED_ARG (aBuffer);
740
757
if (aError==KErrNone) {
741
// Buffer successfully written, feed another one.
743
// Call callback to retrieve frame from upstream.
747
f.type = PJMEDIA_FRAME_TYPE_AUDIO;
749
f.size = frameBufSize_;
750
f.timestamp.u32.lo = timestamp_;
753
status = playCb_(this->userData_, &f);
754
if (status != PJ_SUCCESS) {
759
if (f.type != PJMEDIA_FRAME_TYPE_AUDIO)
760
pj_bzero(frameBuf_, frameBufSize_);
762
// Increment timestamp.
763
timestamp_ += (frameBufSize_ / BYTES_PER_SAMPLE);
765
// Write to playback stream.
766
frame_.Set(frameBuf_, frameBufSize_);
767
iOutputStream_->WriteL(frame_);
758
// Buffer successfully written, feed another one.
760
// Call callback to retrieve frame from upstream.
764
f.type = PJMEDIA_FRAME_TYPE_AUDIO;
766
f.size = frameBufSize_;
767
f.timestamp.u32.lo = timestamp_;
770
status = playCb_ (this->userData_, &f);
772
if (status != PJ_SUCCESS) {
777
if (f.type != PJMEDIA_FRAME_TYPE_AUDIO)
778
pj_bzero (frameBuf_, frameBufSize_);
780
// Increment timestamp.
781
timestamp_ += (frameBufSize_ / BYTES_PER_SAMPLE);
783
// Write to playback stream.
784
frame_.Set (frameBuf_, frameBufSize_);
785
iOutputStream_->WriteL (frame_);
769
787
} else if (aError==KErrAbort) {
770
// playing was aborted, due to call to CMdaAudioOutputStream::Stop()
771
state_ = STATE_INACTIVE;
788
// playing was aborted, due to call to CMdaAudioOutputStream::Stop()
789
state_ = STATE_INACTIVE;
773
// error writing data to output
775
state_ = STATE_INACTIVE;
776
snd_perror("Error in MaoscBufferCopied()", aError);
791
// error writing data to output
793
state_ = STATE_INACTIVE;
794
snd_perror ("Error in MaoscBufferCopied()", aError);
780
void CPjAudioOutputEngine::MaoscPlayComplete(TInt aError)
798
void CPjAudioOutputEngine::MaoscPlayComplete (TInt aError)
782
800
lastError_ = aError;
783
801
state_ = STATE_INACTIVE;
784
803
if (aError != KErrNone && aError != KErrCancel) {
785
snd_perror("Error in MaoscPlayComplete()", aError);
804
snd_perror ("Error in MaoscPlayComplete()", aError);
817
836
/* API: init factory */
818
static pj_status_t factory_init(pjmedia_aud_dev_factory *f)
837
static pj_status_t factory_init (pjmedia_aud_dev_factory *f)
820
struct mda_factory *af = (struct mda_factory*)f;
839
struct mda_factory *af = (struct mda_factory*) f;
822
pj_ansi_strcpy(af->dev_info.name, "Symbian Audio");
841
pj_ansi_strcpy (af->dev_info.name, "Symbian Audio");
823
842
af->dev_info.default_samples_per_sec = 8000;
824
843
af->dev_info.caps = PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING |
825
PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING;
844
PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING;
826
845
af->dev_info.input_count = 1;
827
846
af->dev_info.output_count = 1;
829
PJ_LOG(4, (THIS_FILE, "Symb Mda initialized"));
848
PJ_LOG (4, (THIS_FILE, "Symb Mda initialized"));
831
850
return PJ_SUCCESS;
834
853
/* API: destroy factory */
835
static pj_status_t factory_destroy(pjmedia_aud_dev_factory *f)
854
static pj_status_t factory_destroy (pjmedia_aud_dev_factory *f)
837
struct mda_factory *af = (struct mda_factory*)f;
856
struct mda_factory *af = (struct mda_factory*) f;
838
857
pj_pool_t *pool = af->pool;
841
pj_pool_release(pool);
843
PJ_LOG(4, (THIS_FILE, "Symbian Mda destroyed"));
860
pj_pool_release (pool);
862
PJ_LOG (4, (THIS_FILE, "Symbian Mda destroyed"));
845
864
return PJ_SUCCESS;
848
867
/* API: get number of devices */
849
static unsigned factory_get_dev_count(pjmedia_aud_dev_factory *f)
868
static unsigned factory_get_dev_count (pjmedia_aud_dev_factory *f)
855
874
/* API: get device info */
856
static pj_status_t factory_get_dev_info(pjmedia_aud_dev_factory *f,
858
pjmedia_aud_dev_info *info)
875
static pj_status_t factory_get_dev_info (pjmedia_aud_dev_factory *f,
877
pjmedia_aud_dev_info *info)
860
struct mda_factory *af = (struct mda_factory*)f;
862
PJ_ASSERT_RETURN(index == 0, PJMEDIA_EAUD_INVDEV);
864
pj_memcpy(info, &af->dev_info, sizeof(*info));
879
struct mda_factory *af = (struct mda_factory*) f;
881
PJ_ASSERT_RETURN (index == 0, PJMEDIA_EAUD_INVDEV);
883
pj_memcpy (info, &af->dev_info, sizeof (*info));
866
885
return PJ_SUCCESS;
869
888
/* API: create default device parameter */
870
static pj_status_t factory_default_param(pjmedia_aud_dev_factory *f,
872
pjmedia_aud_param *param)
889
static pj_status_t factory_default_param (pjmedia_aud_dev_factory *f,
891
pjmedia_aud_param *param)
874
struct mda_factory *af = (struct mda_factory*)f;
876
PJ_ASSERT_RETURN(index == 0, PJMEDIA_EAUD_INVDEV);
878
pj_bzero(param, sizeof(*param));
893
struct mda_factory *af = (struct mda_factory*) f;
895
PJ_ASSERT_RETURN (index == 0, PJMEDIA_EAUD_INVDEV);
897
pj_bzero (param, sizeof (*param));
879
898
param->dir = PJMEDIA_DIR_CAPTURE_PLAYBACK;
880
899
param->rec_id = index;
881
900
param->play_id = index;
892
911
/* API: create stream */
893
static pj_status_t factory_create_stream(pjmedia_aud_dev_factory *f,
894
const pjmedia_aud_param *param,
895
pjmedia_aud_rec_cb rec_cb,
896
pjmedia_aud_play_cb play_cb,
898
pjmedia_aud_stream **p_aud_strm)
912
static pj_status_t factory_create_stream (pjmedia_aud_dev_factory *f,
913
const pjmedia_aud_param *param,
914
pjmedia_aud_rec_cb rec_cb,
915
pjmedia_aud_play_cb play_cb,
917
pjmedia_aud_stream **p_aud_strm)
900
struct mda_factory *mf = (struct mda_factory*)f;
919
struct mda_factory *mf = (struct mda_factory*) f;
902
921
struct mda_stream *strm;
904
923
/* Can only support 16bits per sample raw PCM format. */
905
PJ_ASSERT_RETURN(param->bits_per_sample == BITS_PER_SAMPLE, PJ_EINVAL);
906
PJ_ASSERT_RETURN((param->flags & PJMEDIA_AUD_DEV_CAP_EXT_FORMAT)==0 ||
907
param->ext_fmt.id == PJMEDIA_FORMAT_L16,
924
PJ_ASSERT_RETURN (param->bits_per_sample == BITS_PER_SAMPLE, PJ_EINVAL);
925
PJ_ASSERT_RETURN ( (param->flags & PJMEDIA_AUD_DEV_CAP_EXT_FORMAT) ==0 ||
926
param->ext_fmt.id == PJMEDIA_FORMAT_L16,
910
929
/* It seems that MDA recorder only supports for mono channel. */
911
PJ_ASSERT_RETURN(param->channel_count == 1, PJ_EINVAL);
930
PJ_ASSERT_RETURN (param->channel_count == 1, PJ_EINVAL);
913
932
/* Create and Initialize stream descriptor */
914
pool = pj_pool_create(mf->pf, "symb_aud_dev", 1000, 1000, NULL);
915
PJ_ASSERT_RETURN(pool, PJ_ENOMEM);
933
pool = pj_pool_create (mf->pf, "symb_aud_dev", 1000, 1000, NULL);
934
PJ_ASSERT_RETURN (pool, PJ_ENOMEM);
917
strm = PJ_POOL_ZALLOC_T(pool, struct mda_stream);
936
strm = PJ_POOL_ZALLOC_T (pool, struct mda_stream);
918
937
strm->pool = pool;
919
938
strm->param = *param;
921
940
// Create the output stream.
922
941
if (strm->param.dir & PJMEDIA_DIR_PLAYBACK) {
923
TRAPD(err, strm->out_engine = CPjAudioOutputEngine::NewL(strm, play_cb,
925
if (err != KErrNone) {
926
pj_pool_release(pool);
927
return PJ_RETURN_OS_ERROR(err);
942
TRAPD (err, strm->out_engine = CPjAudioOutputEngine::NewL (strm, play_cb,
945
if (err != KErrNone) {
946
pj_pool_release (pool);
947
return PJ_RETURN_OS_ERROR (err);
931
951
// Create the input stream.
932
952
if (strm->param.dir & PJMEDIA_DIR_CAPTURE) {
933
TRAPD(err, strm->in_engine = CPjAudioInputEngine::NewL(strm, rec_cb,
935
if (err != KErrNone) {
936
strm->in_engine = NULL;
937
delete strm->out_engine;
938
strm->out_engine = NULL;
939
pj_pool_release(pool);
940
return PJ_RETURN_OS_ERROR(err);
953
TRAPD (err, strm->in_engine = CPjAudioInputEngine::NewL (strm, rec_cb,
956
if (err != KErrNone) {
957
strm->in_engine = NULL;
958
delete strm->out_engine;
959
strm->out_engine = NULL;
960
pj_pool_release (pool);
961
return PJ_RETURN_OS_ERROR (err);
945
966
strm->base.op = &stream_op;
946
967
*p_aud_strm = &strm->base;
951
972
/* API: Get stream info. */
952
static pj_status_t stream_get_param(pjmedia_aud_stream *s,
953
pjmedia_aud_param *pi)
973
static pj_status_t stream_get_param (pjmedia_aud_stream *s,
974
pjmedia_aud_param *pi)
955
struct mda_stream *strm = (struct mda_stream*)s;
957
PJ_ASSERT_RETURN(strm && pi, PJ_EINVAL);
959
pj_memcpy(pi, &strm->param, sizeof(*pi));
976
struct mda_stream *strm = (struct mda_stream*) s;
978
PJ_ASSERT_RETURN (strm && pi, PJ_EINVAL);
980
pj_memcpy (pi, &strm->param, sizeof (*pi));
961
982
return PJ_SUCCESS;
964
985
/* API: get capability */
965
static pj_status_t stream_get_cap(pjmedia_aud_stream *s,
966
pjmedia_aud_dev_cap cap,
986
static pj_status_t stream_get_cap (pjmedia_aud_stream *s,
987
pjmedia_aud_dev_cap cap,
969
struct mda_stream *strm = (struct mda_stream*)s;
990
struct mda_stream *strm = (struct mda_stream*) s;
970
991
pj_status_t status = PJ_ENOTSUP;
972
PJ_ASSERT_RETURN(s && pval, PJ_EINVAL);
993
PJ_ASSERT_RETURN (s && pval, PJ_EINVAL);
975
case PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING:
976
if (strm->param.dir & PJMEDIA_DIR_CAPTURE) {
977
PJ_ASSERT_RETURN(strm->in_engine, PJ_EINVAL);
979
TInt max_gain = strm->in_engine->GetMaxGain();
980
TInt gain = strm->in_engine->GetGain();
982
if (max_gain > 0 && gain >= 0) {
983
*(unsigned*)pval = gain * 100 / max_gain;
986
status = PJMEDIA_EAUD_NOTREADY;
990
case PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING:
991
if (strm->param.dir & PJMEDIA_DIR_PLAYBACK) {
992
PJ_ASSERT_RETURN(strm->out_engine, PJ_EINVAL);
994
TInt max_vol = strm->out_engine->GetMaxVolume();
995
TInt vol = strm->out_engine->GetVolume();
997
if (max_vol > 0 && vol >= 0) {
998
*(unsigned*)pval = vol * 100 / max_vol;
1001
status = PJMEDIA_EAUD_NOTREADY;
996
case PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING:
998
if (strm->param.dir & PJMEDIA_DIR_CAPTURE) {
999
PJ_ASSERT_RETURN (strm->in_engine, PJ_EINVAL);
1001
TInt max_gain = strm->in_engine->GetMaxGain();
1002
TInt gain = strm->in_engine->GetGain();
1004
if (max_gain > 0 && gain >= 0) {
1005
* (unsigned*) pval = gain * 100 / max_gain;
1006
status = PJ_SUCCESS;
1008
status = PJMEDIA_EAUD_NOTREADY;
1013
case PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING:
1015
if (strm->param.dir & PJMEDIA_DIR_PLAYBACK) {
1016
PJ_ASSERT_RETURN (strm->out_engine, PJ_EINVAL);
1018
TInt max_vol = strm->out_engine->GetMaxVolume();
1019
TInt vol = strm->out_engine->GetVolume();
1021
if (max_vol > 0 && vol >= 0) {
1022
* (unsigned*) pval = vol * 100 / max_vol;
1023
status = PJ_SUCCESS;
1025
status = PJMEDIA_EAUD_NOTREADY;
1012
1037
/* API: set capability */
1013
static pj_status_t stream_set_cap(pjmedia_aud_stream *s,
1014
pjmedia_aud_dev_cap cap,
1038
static pj_status_t stream_set_cap (pjmedia_aud_stream *s,
1039
pjmedia_aud_dev_cap cap,
1017
struct mda_stream *strm = (struct mda_stream*)s;
1042
struct mda_stream *strm = (struct mda_stream*) s;
1018
1043
pj_status_t status = PJ_ENOTSUP;
1020
PJ_ASSERT_RETURN(s && pval, PJ_EINVAL);
1045
PJ_ASSERT_RETURN (s && pval, PJ_EINVAL);
1023
case PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING:
1024
if (strm->param.dir & PJMEDIA_DIR_CAPTURE) {
1025
PJ_ASSERT_RETURN(strm->in_engine, PJ_EINVAL);
1027
TInt max_gain = strm->in_engine->GetMaxGain();
1031
gain = *(unsigned*)pval * max_gain / 100;
1032
status = strm->in_engine->SetGain(gain);
1034
status = PJMEDIA_EAUD_NOTREADY;
1038
case PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING:
1039
if (strm->param.dir & PJMEDIA_DIR_CAPTURE) {
1040
PJ_ASSERT_RETURN(strm->out_engine, PJ_EINVAL);
1042
TInt max_vol = strm->out_engine->GetMaxVolume();
1046
vol = *(unsigned*)pval * max_vol / 100;
1047
status = strm->out_engine->SetVolume(vol);
1049
status = PJMEDIA_EAUD_NOTREADY;
1048
case PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING:
1050
if (strm->param.dir & PJMEDIA_DIR_CAPTURE) {
1051
PJ_ASSERT_RETURN (strm->in_engine, PJ_EINVAL);
1053
TInt max_gain = strm->in_engine->GetMaxGain();
1058
gain = * (unsigned*) pval * max_gain / 100;
1059
status = strm->in_engine->SetGain (gain);
1061
status = PJMEDIA_EAUD_NOTREADY;
1066
case PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING:
1068
if (strm->param.dir & PJMEDIA_DIR_CAPTURE) {
1069
PJ_ASSERT_RETURN (strm->out_engine, PJ_EINVAL);
1071
TInt max_vol = strm->out_engine->GetMaxVolume();
1076
vol = * (unsigned*) pval * max_vol / 100;
1077
status = strm->out_engine->SetVolume (vol);
1079
status = PJMEDIA_EAUD_NOTREADY;
1060
1091
/* API: Start stream. */
1061
static pj_status_t stream_start(pjmedia_aud_stream *strm)
1092
static pj_status_t stream_start (pjmedia_aud_stream *strm)
1063
struct mda_stream *stream = (struct mda_stream*)strm;
1094
struct mda_stream *stream = (struct mda_stream*) strm;
1065
PJ_ASSERT_RETURN(stream, PJ_EINVAL);
1096
PJ_ASSERT_RETURN (stream, PJ_EINVAL);
1067
1098
if (stream->out_engine) {
1069
status = stream->out_engine->StartPlay();
1070
if (status != PJ_SUCCESS)
1100
status = stream->out_engine->StartPlay();
1102
if (status != PJ_SUCCESS)
1074
1106
if (stream->in_engine) {
1076
status = stream->in_engine->StartRecord();
1077
if (status != PJ_SUCCESS)
1108
status = stream->in_engine->StartRecord();
1110
if (status != PJ_SUCCESS)
1081
1114
return PJ_SUCCESS;
1084
1117
/* API: Stop stream. */
1085
static pj_status_t stream_stop(pjmedia_aud_stream *strm)
1118
static pj_status_t stream_stop (pjmedia_aud_stream *strm)
1087
struct mda_stream *stream = (struct mda_stream*)strm;
1120
struct mda_stream *stream = (struct mda_stream*) strm;
1089
PJ_ASSERT_RETURN(stream, PJ_EINVAL);
1122
PJ_ASSERT_RETURN (stream, PJ_EINVAL);
1091
1124
if (stream->in_engine) {
1092
stream->in_engine->Stop();
1125
stream->in_engine->Stop();
1095
1128
if (stream->out_engine) {
1096
stream->out_engine->Stop();
1129
stream->out_engine->Stop();
1099
1132
return PJ_SUCCESS;