~ubuntu-branches/ubuntu/trusty/sflphone/trusty

« back to all changes in this revision

Viewing changes to daemon/libs/pjproject-2.0.1/pjmedia/src/pjmedia-audiodev/symb_mda_dev.cpp

  • Committer: Package Import Robot
  • Author(s): Mark Purcell
  • Date: 2014-01-28 18:23:36 UTC
  • mfrom: (4.3.4 sid)
  • Revision ID: package-import@ubuntu.com-20140128182336-jrsv0k9u6cawc068
Tags: 1.3.0-1
* New upstream release 
  - Fixes "New Upstream Release" (Closes: #735846)
  - Fixes "Ringtone does not stop" (Closes: #727164)
  - Fixes "[sflphone-kde] crash on startup" (Closes: #718178)
  - Fixes "sflphone GUI crashes when call is hung up" (Closes: #736583)
* Build-Depends: ensure GnuTLS 2.6
  - libucommon-dev (>= 6.0.7-1.1), libccrtp-dev (>= 2.0.6-3)
  - Fixes "FTBFS Build-Depends libgnutls{26,28}-dev" (Closes: #722040)
* Fix "boost 1.49 is going away" unversioned Build-Depends: (Closes: #736746)
* Add Build-Depends: libsndfile-dev, nepomuk-core-dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* $Id: symb_mda_dev.cpp 3841 2011-10-24 09:28:13Z ming $ */
2
 
/*
3
 
 * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4
 
 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
5
 
 *
6
 
 * This program is free software; you can redistribute it and/or modify
7
 
 * it under the terms of the GNU General Public License as published by
8
 
 * the Free Software Foundation; either version 2 of the License, or
9
 
 * (at your option) any later version.
10
 
 *
11
 
 * This program is distributed in the hope that it will be useful,
12
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 
 * GNU General Public License for more details.
15
 
 *
16
 
 * You should have received a copy of the GNU General Public License
17
 
 * along with this program; if not, write to the Free Software
18
 
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19
 
 */
20
 
#include <pjmedia-audiodev/audiodev_imp.h>
21
 
#include <pjmedia-audiodev/errno.h>
22
 
#include <pjmedia/alaw_ulaw.h>
23
 
#include <pj/assert.h>
24
 
#include <pj/log.h>
25
 
#include <pj/math.h>
26
 
#include <pj/os.h>
27
 
#include <pj/string.h>
28
 
 
29
 
#if PJMEDIA_AUDIO_DEV_HAS_SYMB_MDA
30
 
 
31
 
/*
32
 
 * This file provides sound implementation for Symbian Audio Streaming
33
 
 * device. Application using this sound abstraction must link with:
34
 
 *  - mediaclientaudiostream.lib, and
35
 
 *  - mediaclientaudioinputstream.lib
36
 
 */
37
 
#include <mda/common/audio.h>
38
 
#include <mdaaudiooutputstream.h>
39
 
#include <mdaaudioinputstream.h>
40
 
 
41
 
 
42
 
#define THIS_FILE                       "symb_mda_dev.c"
43
 
#define BITS_PER_SAMPLE                 16
44
 
#define BYTES_PER_SAMPLE                (BITS_PER_SAMPLE/8)
45
 
 
46
 
 
47
 
#if 1
48
 
#   define TRACE_(st) PJ_LOG(3, st)
49
 
#else
50
 
#   define TRACE_(st)
51
 
#endif
52
 
 
53
 
 
54
 
/* MDA factory */
55
 
struct mda_factory
56
 
{
57
 
    pjmedia_aud_dev_factory      base;
58
 
    pj_pool_t                   *pool;
59
 
    pj_pool_factory             *pf;
60
 
    pjmedia_aud_dev_info         dev_info;
61
 
};
62
 
 
63
 
/* Forward declaration of internal engine. */
64
 
class CPjAudioInputEngine;
65
 
class CPjAudioOutputEngine;
66
 
 
67
 
/* MDA stream. */
68
 
struct mda_stream
69
 
{
70
 
    // Base
71
 
    pjmedia_aud_stream   base;                  /**< Base class.        */
72
 
 
73
 
    // Pool
74
 
    pj_pool_t           *pool;                  /**< Memory pool.       */
75
 
 
76
 
    // Common settings.
77
 
    pjmedia_aud_param param;            /**< Stream param.      */
78
 
 
79
 
    // Audio engine
80
 
    CPjAudioInputEngine *in_engine;             /**< Record engine.     */
81
 
    CPjAudioOutputEngine *out_engine;           /**< Playback engine.   */
82
 
};
83
 
 
84
 
 
85
 
/* Prototypes */
86
 
static pj_status_t factory_init(pjmedia_aud_dev_factory *f);
87
 
static pj_status_t factory_destroy(pjmedia_aud_dev_factory *f);
88
 
static pj_status_t factory_refresh(pjmedia_aud_dev_factory *f);
89
 
static unsigned    factory_get_dev_count(pjmedia_aud_dev_factory *f);
90
 
static pj_status_t factory_get_dev_info(pjmedia_aud_dev_factory *f,
91
 
                                        unsigned index,
92
 
                                        pjmedia_aud_dev_info *info);
93
 
static pj_status_t factory_default_param(pjmedia_aud_dev_factory *f,
94
 
                                         unsigned index,
95
 
                                         pjmedia_aud_param *param);
96
 
static pj_status_t factory_create_stream(pjmedia_aud_dev_factory *f,
97
 
                                         const pjmedia_aud_param *param,
98
 
                                         pjmedia_aud_rec_cb rec_cb,
99
 
                                         pjmedia_aud_play_cb play_cb,
100
 
                                         void *user_data,
101
 
                                         pjmedia_aud_stream **p_aud_strm);
102
 
 
103
 
static pj_status_t stream_get_param(pjmedia_aud_stream *strm,
104
 
                                    pjmedia_aud_param *param);
105
 
static pj_status_t stream_get_cap(pjmedia_aud_stream *strm,
106
 
                                  pjmedia_aud_dev_cap cap,
107
 
                                  void *value);
108
 
static pj_status_t stream_set_cap(pjmedia_aud_stream *strm,
109
 
                                  pjmedia_aud_dev_cap cap,
110
 
                                  const void *value);
111
 
static pj_status_t stream_start(pjmedia_aud_stream *strm);
112
 
static pj_status_t stream_stop(pjmedia_aud_stream *strm);
113
 
static pj_status_t stream_destroy(pjmedia_aud_stream *strm);
114
 
 
115
 
 
116
 
/* Operations */
117
 
static pjmedia_aud_dev_factory_op factory_op =
118
 
{
119
 
    &factory_init,
120
 
    &factory_destroy,
121
 
    &factory_get_dev_count,
122
 
    &factory_get_dev_info,
123
 
    &factory_default_param,
124
 
    &factory_create_stream,
125
 
    &factory_refresh
126
 
};
127
 
 
128
 
static pjmedia_aud_stream_op stream_op =
129
 
{
130
 
    &stream_get_param,
131
 
    &stream_get_cap,
132
 
    &stream_set_cap,
133
 
    &stream_start,
134
 
    &stream_stop,
135
 
    &stream_destroy
136
 
};
137
 
 
138
 
 
139
 
/*
140
 
 * Convert clock rate to Symbian's TMdaAudioDataSettings capability.
141
 
 */
142
 
static TInt get_clock_rate_cap(unsigned clock_rate)
143
 
{
144
 
    switch (clock_rate) {
145
 
    case 8000:  return TMdaAudioDataSettings::ESampleRate8000Hz;
146
 
    case 11025: return TMdaAudioDataSettings::ESampleRate11025Hz;
147
 
    case 12000: return TMdaAudioDataSettings::ESampleRate12000Hz;
148
 
    case 16000: return TMdaAudioDataSettings::ESampleRate16000Hz;
149
 
    case 22050: return TMdaAudioDataSettings::ESampleRate22050Hz;
150
 
    case 24000: return TMdaAudioDataSettings::ESampleRate24000Hz;
151
 
    case 32000: return TMdaAudioDataSettings::ESampleRate32000Hz;
152
 
    case 44100: return TMdaAudioDataSettings::ESampleRate44100Hz;
153
 
    case 48000: return TMdaAudioDataSettings::ESampleRate48000Hz;
154
 
    case 64000: return TMdaAudioDataSettings::ESampleRate64000Hz;
155
 
    case 96000: return TMdaAudioDataSettings::ESampleRate96000Hz;
156
 
    default:
157
 
        return 0;
158
 
    }
159
 
}
160
 
 
161
 
/*
162
 
 * Convert number of channels into Symbian's TMdaAudioDataSettings capability.
163
 
 */
164
 
static TInt get_channel_cap(unsigned channel_count)
165
 
{
166
 
    switch (channel_count) {
167
 
    case 1: return TMdaAudioDataSettings::EChannelsMono;
168
 
    case 2: return TMdaAudioDataSettings::EChannelsStereo;
169
 
    default:
170
 
        return 0;
171
 
    }
172
 
}
173
 
 
174
 
/*
175
 
 * Utility: print sound device error
176
 
 */
177
 
static void snd_perror(const char *title, TInt rc)
178
 
{
179
 
    PJ_LOG(1,(THIS_FILE, "%s: error code %d", title, rc));
180
 
}
181
 
 
182
 
//////////////////////////////////////////////////////////////////////////////
183
 
//
184
 
 
185
 
/*
186
 
 * Implementation: Symbian Input Stream.
187
 
 */
188
 
class CPjAudioInputEngine : public CBase, MMdaAudioInputStreamCallback
189
 
{
190
 
public:
191
 
    enum State
192
 
    {
193
 
        STATE_INACTIVE,
194
 
        STATE_ACTIVE,
195
 
    };
196
 
 
197
 
    ~CPjAudioInputEngine();
198
 
 
199
 
    static CPjAudioInputEngine *NewL(struct mda_stream *parent_strm,
200
 
                                     pjmedia_aud_rec_cb rec_cb,
201
 
                                     void *user_data);
202
 
 
203
 
    static CPjAudioInputEngine *NewLC(struct mda_stream *parent_strm,
204
 
                                      pjmedia_aud_rec_cb rec_cb,
205
 
                                      void *user_data);
206
 
 
207
 
    pj_status_t StartRecord();
208
 
    void Stop();
209
 
 
210
 
    pj_status_t SetGain(TInt gain) {
211
 
        if (iInputStream_) {
212
 
            iInputStream_->SetGain(gain);
213
 
            return PJ_SUCCESS;
214
 
        } else
215
 
            return PJ_EINVALIDOP;
216
 
    }
217
 
 
218
 
    TInt GetGain() {
219
 
        if (iInputStream_) {
220
 
            return iInputStream_->Gain();
221
 
        } else
222
 
            return PJ_EINVALIDOP;
223
 
    }
224
 
 
225
 
    TInt GetMaxGain() {
226
 
        if (iInputStream_) {
227
 
            return iInputStream_->MaxGain();
228
 
        } else
229
 
            return PJ_EINVALIDOP;
230
 
    }
231
 
 
232
 
private:
233
 
    State                    state_;
234
 
    struct mda_stream       *parentStrm_;
235
 
    pjmedia_aud_rec_cb       recCb_;
236
 
    void                    *userData_;
237
 
    CMdaAudioInputStream    *iInputStream_;
238
 
    HBufC8                  *iStreamBuffer_;
239
 
    TPtr8                    iFramePtr_;
240
 
    TInt                     lastError_;
241
 
    pj_uint32_t              timeStamp_;
242
 
    CActiveSchedulerWait     startAsw_;
243
 
 
244
 
    // cache variable
245
 
    // to avoid calculating frame length repeatedly
246
 
    TInt                     frameLen_;
247
 
 
248
 
    // sometimes recorded size != requested framesize, so let's
249
 
    // provide a buffer to make sure the rec callback returning
250
 
    // framesize as requested.
251
 
    TUint8                  *frameRecBuf_;
252
 
    TInt                     frameRecBufLen_;
253
 
 
254
 
    CPjAudioInputEngine(struct mda_stream *parent_strm,
255
 
            pjmedia_aud_rec_cb rec_cb,
256
 
                        void *user_data);
257
 
    void ConstructL();
258
 
    TPtr8 & GetFrame();
259
 
 
260
 
public:
261
 
    virtual void MaiscOpenComplete(TInt aError);
262
 
    virtual void MaiscBufferCopied(TInt aError, const TDesC8 &aBuffer);
263
 
    virtual void MaiscRecordComplete(TInt aError);
264
 
 
265
 
};
266
 
 
267
 
 
268
 
CPjAudioInputEngine::CPjAudioInputEngine(struct mda_stream *parent_strm,
269
 
                                         pjmedia_aud_rec_cb rec_cb,
270
 
                                         void *user_data)
271
 
    : state_(STATE_INACTIVE), parentStrm_(parent_strm),
272
 
      recCb_(rec_cb), userData_(user_data),
273
 
      iInputStream_(NULL), iStreamBuffer_(NULL), iFramePtr_(0, 0),
274
 
      lastError_(KErrNone), timeStamp_(0),
275
 
      frameLen_(parent_strm->param.samples_per_frame *
276
 
                BYTES_PER_SAMPLE),
277
 
      frameRecBuf_(NULL), frameRecBufLen_(0)
278
 
{
279
 
}
280
 
 
281
 
CPjAudioInputEngine::~CPjAudioInputEngine()
282
 
{
283
 
    Stop();
284
 
 
285
 
    delete iStreamBuffer_;
286
 
    iStreamBuffer_ = NULL;
287
 
 
288
 
    delete [] frameRecBuf_;
289
 
    frameRecBuf_ = NULL;
290
 
    frameRecBufLen_ = 0;
291
 
}
292
 
 
293
 
void CPjAudioInputEngine::ConstructL()
294
 
{
295
 
    iStreamBuffer_ = HBufC8::NewL(frameLen_);
296
 
    CleanupStack::PushL(iStreamBuffer_);
297
 
 
298
 
    frameRecBuf_ = new TUint8[frameLen_*2];
299
 
    CleanupStack::PushL(frameRecBuf_);
300
 
}
301
 
 
302
 
CPjAudioInputEngine *CPjAudioInputEngine::NewLC(struct mda_stream *parent,
303
 
                                                pjmedia_aud_rec_cb rec_cb,
304
 
                                                void *user_data)
305
 
{
306
 
    CPjAudioInputEngine* self = new (ELeave) CPjAudioInputEngine(parent,
307
 
                                                                 rec_cb,
308
 
                                                                 user_data);
309
 
    CleanupStack::PushL(self);
310
 
    self->ConstructL();
311
 
    return self;
312
 
}
313
 
 
314
 
CPjAudioInputEngine *CPjAudioInputEngine::NewL(struct mda_stream *parent,
315
 
                                               pjmedia_aud_rec_cb rec_cb,
316
 
                                               void *user_data)
317
 
{
318
 
    CPjAudioInputEngine *self = NewLC(parent, rec_cb, user_data);
319
 
    CleanupStack::Pop(self->frameRecBuf_);
320
 
    CleanupStack::Pop(self->iStreamBuffer_);
321
 
    CleanupStack::Pop(self);
322
 
    return self;
323
 
}
324
 
 
325
 
 
326
 
pj_status_t CPjAudioInputEngine::StartRecord()
327
 
{
328
 
 
329
 
    // Ignore command if recording is in progress.
330
 
    if (state_ == STATE_ACTIVE)
331
 
        return PJ_SUCCESS;
332
 
 
333
 
    // According to Nokia's AudioStream example, some 2nd Edition, FP2 devices
334
 
    // (such as Nokia 6630) require the stream to be reconstructed each time
335
 
    // before calling Open() - otherwise the callback never gets called.
336
 
    // For uniform behavior, lets just delete/re-create the stream for all
337
 
    // devices.
338
 
 
339
 
    // Destroy existing stream.
340
 
    if (iInputStream_) delete iInputStream_;
341
 
    iInputStream_ = NULL;
342
 
 
343
 
    // Create the stream.
344
 
    TRAPD(err, iInputStream_ = CMdaAudioInputStream::NewL(*this));
345
 
    if (err != KErrNone)
346
 
        return PJ_RETURN_OS_ERROR(err);
347
 
 
348
 
    // Initialize settings.
349
 
    TMdaAudioDataSettings iStreamSettings;
350
 
    iStreamSettings.iChannels =
351
 
                            get_channel_cap(parentStrm_->param.channel_count);
352
 
    iStreamSettings.iSampleRate =
353
 
                            get_clock_rate_cap(parentStrm_->param.clock_rate);
354
 
 
355
 
    pj_assert(iStreamSettings.iChannels != 0 &&
356
 
              iStreamSettings.iSampleRate != 0);
357
 
 
358
 
    PJ_LOG(4,(THIS_FILE, "Opening sound device for capture, "
359
 
                         "clock rate=%d, channel count=%d..",
360
 
                         parentStrm_->param.clock_rate,
361
 
                         parentStrm_->param.channel_count));
362
 
 
363
 
    // Open stream.
364
 
    lastError_ = KRequestPending;
365
 
    iInputStream_->Open(&iStreamSettings);
366
 
 
367
 
#if defined(PJMEDIA_AUDIO_DEV_MDA_USE_SYNC_START) && \
368
 
    PJMEDIA_AUDIO_DEV_MDA_USE_SYNC_START != 0
369
 
 
370
 
    startAsw_.Start();
371
 
 
372
 
#endif
373
 
 
374
 
    // Success
375
 
    PJ_LOG(4,(THIS_FILE, "Sound capture started."));
376
 
    return PJ_SUCCESS;
377
 
}
378
 
 
379
 
 
380
 
void CPjAudioInputEngine::Stop()
381
 
{
382
 
    // If capture is in progress, stop it.
383
 
    if (iInputStream_ && state_ == STATE_ACTIVE) {
384
 
        lastError_ = KRequestPending;
385
 
        iInputStream_->Stop();
386
 
 
387
 
        // Wait until it's actually stopped
388
 
        while (lastError_ == KRequestPending)
389
 
            pj_symbianos_poll(-1, 100);
390
 
    }
391
 
 
392
 
    if (iInputStream_) {
393
 
        delete iInputStream_;
394
 
        iInputStream_ = NULL;
395
 
    }
396
 
 
397
 
    if (startAsw_.IsStarted()) {
398
 
        startAsw_.AsyncStop();
399
 
    }
400
 
 
401
 
    state_ = STATE_INACTIVE;
402
 
}
403
 
 
404
 
 
405
 
TPtr8 & CPjAudioInputEngine::GetFrame()
406
 
{
407
 
    //iStreamBuffer_->Des().FillZ(frameLen_);
408
 
    iFramePtr_.Set((TUint8*)(iStreamBuffer_->Ptr()), frameLen_, frameLen_);
409
 
    return iFramePtr_;
410
 
}
411
 
 
412
 
void CPjAudioInputEngine::MaiscOpenComplete(TInt aError)
413
 
{
414
 
    if (startAsw_.IsStarted()) {
415
 
        startAsw_.AsyncStop();
416
 
    }
417
 
 
418
 
    lastError_ = aError;
419
 
    if (aError != KErrNone) {
420
 
        snd_perror("Error in MaiscOpenComplete()", aError);
421
 
        return;
422
 
    }
423
 
 
424
 
    /* Apply input volume setting if specified */
425
 
    if (parentStrm_->param.flags &
426
 
        PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING)
427
 
    {
428
 
        stream_set_cap(&parentStrm_->base,
429
 
                       PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING,
430
 
                       &parentStrm_->param.input_vol);
431
 
    }
432
 
 
433
 
    // set stream priority to normal and time sensitive
434
 
    iInputStream_->SetPriority(EPriorityNormal,
435
 
                               EMdaPriorityPreferenceTime);
436
 
 
437
 
    // Read the first frame.
438
 
    TPtr8 & frm = GetFrame();
439
 
    TRAPD(err2, iInputStream_->ReadL(frm));
440
 
    if (err2) {
441
 
        PJ_LOG(4,(THIS_FILE, "Exception in iInputStream_->ReadL()"));
442
 
        lastError_ = err2;
443
 
        return;
444
 
    }
445
 
 
446
 
    // input stream opened succesfully, set status to Active
447
 
    state_ = STATE_ACTIVE;
448
 
}
449
 
 
450
 
void CPjAudioInputEngine::MaiscBufferCopied(TInt aError,
451
 
                                            const TDesC8 &aBuffer)
452
 
{
453
 
    lastError_ = aError;
454
 
    if (aError != KErrNone) {
455
 
        snd_perror("Error in MaiscBufferCopied()", aError);
456
 
        return;
457
 
    }
458
 
 
459
 
    if (frameRecBufLen_ || aBuffer.Length() < frameLen_) {
460
 
        pj_memcpy(frameRecBuf_ + frameRecBufLen_, (void*) aBuffer.Ptr(), aBuffer.Length());
461
 
        frameRecBufLen_ += aBuffer.Length();
462
 
    }
463
 
 
464
 
    if (frameRecBufLen_) {
465
 
        while (frameRecBufLen_ >= frameLen_) {
466
 
            pjmedia_frame f;
467
 
 
468
 
            f.type = PJMEDIA_FRAME_TYPE_AUDIO;
469
 
            f.buf = frameRecBuf_;
470
 
            f.size = frameLen_;
471
 
            f.timestamp.u32.lo = timeStamp_;
472
 
            f.bit_info = 0;
473
 
 
474
 
            // Call the callback.
475
 
            recCb_(userData_, &f);
476
 
            // Increment timestamp.
477
 
            timeStamp_ += parentStrm_->param.samples_per_frame;
478
 
 
479
 
            frameRecBufLen_ -= frameLen_;
480
 
            pj_memmove(frameRecBuf_, frameRecBuf_+frameLen_, frameRecBufLen_);
481
 
        }
482
 
    } else {
483
 
        pjmedia_frame f;
484
 
 
485
 
        f.type = PJMEDIA_FRAME_TYPE_AUDIO;
486
 
        f.buf = (void*)aBuffer.Ptr();
487
 
        f.size = aBuffer.Length();
488
 
        f.timestamp.u32.lo = timeStamp_;
489
 
        f.bit_info = 0;
490
 
 
491
 
        // Call the callback.
492
 
        recCb_(userData_, &f);
493
 
 
494
 
        // Increment timestamp.
495
 
        timeStamp_ += parentStrm_->param.samples_per_frame;
496
 
    }
497
 
 
498
 
    // Record next frame
499
 
    TPtr8 & frm = GetFrame();
500
 
    TRAPD(err2, iInputStream_->ReadL(frm));
501
 
    if (err2) {
502
 
        PJ_LOG(4,(THIS_FILE, "Exception in iInputStream_->ReadL()"));
503
 
    }
504
 
}
505
 
 
506
 
 
507
 
void CPjAudioInputEngine::MaiscRecordComplete(TInt aError)
508
 
{
509
 
    lastError_ = aError;
510
 
    state_ = STATE_INACTIVE;
511
 
    if (aError != KErrNone && aError != KErrCancel) {
512
 
        snd_perror("Error in MaiscRecordComplete()", aError);
513
 
    }
514
 
}
515
 
 
516
 
 
517
 
 
518
 
//////////////////////////////////////////////////////////////////////////////
519
 
//
520
 
 
521
 
/*
522
 
 * Implementation: Symbian Output Stream.
523
 
 */
524
 
 
525
 
class CPjAudioOutputEngine : public CBase, MMdaAudioOutputStreamCallback
526
 
{
527
 
public:
528
 
    enum State
529
 
    {
530
 
        STATE_INACTIVE,
531
 
        STATE_ACTIVE,
532
 
    };
533
 
 
534
 
    ~CPjAudioOutputEngine();
535
 
 
536
 
    static CPjAudioOutputEngine *NewL(struct mda_stream *parent_strm,
537
 
                                      pjmedia_aud_play_cb play_cb,
538
 
                                      void *user_data);
539
 
 
540
 
    static CPjAudioOutputEngine *NewLC(struct mda_stream *parent_strm,
541
 
                                       pjmedia_aud_play_cb rec_cb,
542
 
                                       void *user_data);
543
 
 
544
 
    pj_status_t StartPlay();
545
 
    void Stop();
546
 
 
547
 
    pj_status_t SetVolume(TInt vol) {
548
 
        if (iOutputStream_) {
549
 
            iOutputStream_->SetVolume(vol);
550
 
            return PJ_SUCCESS;
551
 
        } else
552
 
            return PJ_EINVALIDOP;
553
 
    }
554
 
 
555
 
    TInt GetVolume() {
556
 
        if (iOutputStream_) {
557
 
            return iOutputStream_->Volume();
558
 
        } else
559
 
            return PJ_EINVALIDOP;
560
 
    }
561
 
 
562
 
    TInt GetMaxVolume() {
563
 
        if (iOutputStream_) {
564
 
            return iOutputStream_->MaxVolume();
565
 
        } else
566
 
            return PJ_EINVALIDOP;
567
 
    }
568
 
 
569
 
private:
570
 
    State                    state_;
571
 
    struct mda_stream       *parentStrm_;
572
 
    pjmedia_aud_play_cb      playCb_;
573
 
    void                    *userData_;
574
 
    CMdaAudioOutputStream   *iOutputStream_;
575
 
    TUint8                  *frameBuf_;
576
 
    unsigned                 frameBufSize_;
577
 
    TPtrC8                   frame_;
578
 
    TInt                     lastError_;
579
 
    unsigned                 timestamp_;
580
 
    CActiveSchedulerWait     startAsw_;
581
 
 
582
 
    CPjAudioOutputEngine(struct mda_stream *parent_strm,
583
 
                         pjmedia_aud_play_cb play_cb,
584
 
                         void *user_data);
585
 
    void ConstructL();
586
 
 
587
 
    virtual void MaoscOpenComplete(TInt aError);
588
 
    virtual void MaoscBufferCopied(TInt aError, const TDesC8& aBuffer);
589
 
    virtual void MaoscPlayComplete(TInt aError);
590
 
};
591
 
 
592
 
 
593
 
CPjAudioOutputEngine::CPjAudioOutputEngine(struct mda_stream *parent_strm,
594
 
                                           pjmedia_aud_play_cb play_cb,
595
 
                                           void *user_data)
596
 
: state_(STATE_INACTIVE), parentStrm_(parent_strm), playCb_(play_cb),
597
 
  userData_(user_data), iOutputStream_(NULL), frameBuf_(NULL),
598
 
  lastError_(KErrNone), timestamp_(0)
599
 
{
600
 
}
601
 
 
602
 
 
603
 
void CPjAudioOutputEngine::ConstructL()
604
 
{
605
 
    frameBufSize_ = parentStrm_->param.samples_per_frame *
606
 
                    BYTES_PER_SAMPLE;
607
 
    frameBuf_ = new TUint8[frameBufSize_];
608
 
}
609
 
 
610
 
CPjAudioOutputEngine::~CPjAudioOutputEngine()
611
 
{
612
 
    Stop();
613
 
    delete [] frameBuf_;
614
 
}
615
 
 
616
 
CPjAudioOutputEngine *
617
 
CPjAudioOutputEngine::NewLC(struct mda_stream *parent_strm,
618
 
                            pjmedia_aud_play_cb play_cb,
619
 
                            void *user_data)
620
 
{
621
 
    CPjAudioOutputEngine* self = new (ELeave) CPjAudioOutputEngine(parent_strm,
622
 
                                                                   play_cb,
623
 
                                                                   user_data);
624
 
    CleanupStack::PushL(self);
625
 
    self->ConstructL();
626
 
    return self;
627
 
}
628
 
 
629
 
CPjAudioOutputEngine *
630
 
CPjAudioOutputEngine::NewL(struct mda_stream *parent_strm,
631
 
                           pjmedia_aud_play_cb play_cb,
632
 
                           void *user_data)
633
 
{
634
 
    CPjAudioOutputEngine *self = NewLC(parent_strm, play_cb, user_data);
635
 
    CleanupStack::Pop(self);
636
 
    return self;
637
 
}
638
 
 
639
 
pj_status_t CPjAudioOutputEngine::StartPlay()
640
 
{
641
 
    // Ignore command if playing is in progress.
642
 
    if (state_ == STATE_ACTIVE)
643
 
        return PJ_SUCCESS;
644
 
 
645
 
    // Destroy existing stream.
646
 
    if (iOutputStream_) delete iOutputStream_;
647
 
    iOutputStream_ = NULL;
648
 
 
649
 
    // Create the stream
650
 
    TRAPD(err, iOutputStream_ = CMdaAudioOutputStream::NewL(*this));
651
 
    if (err != KErrNone)
652
 
        return PJ_RETURN_OS_ERROR(err);
653
 
 
654
 
    // Initialize settings.
655
 
    TMdaAudioDataSettings iStreamSettings;
656
 
    iStreamSettings.iChannels =
657
 
                            get_channel_cap(parentStrm_->param.channel_count);
658
 
    iStreamSettings.iSampleRate =
659
 
                            get_clock_rate_cap(parentStrm_->param.clock_rate);
660
 
 
661
 
    pj_assert(iStreamSettings.iChannels != 0 &&
662
 
              iStreamSettings.iSampleRate != 0);
663
 
 
664
 
    PJ_LOG(4,(THIS_FILE, "Opening sound device for playback, "
665
 
                         "clock rate=%d, channel count=%d..",
666
 
                         parentStrm_->param.clock_rate,
667
 
                         parentStrm_->param.channel_count));
668
 
 
669
 
    // Open stream.
670
 
    lastError_ = KRequestPending;
671
 
    iOutputStream_->Open(&iStreamSettings);
672
 
 
673
 
#if defined(PJMEDIA_AUDIO_DEV_MDA_USE_SYNC_START) && \
674
 
    PJMEDIA_AUDIO_DEV_MDA_USE_SYNC_START != 0
675
 
 
676
 
    startAsw_.Start();
677
 
 
678
 
#endif
679
 
 
680
 
    // Success
681
 
    PJ_LOG(4,(THIS_FILE, "Sound playback started"));
682
 
    return PJ_SUCCESS;
683
 
 
684
 
}
685
 
 
686
 
void CPjAudioOutputEngine::Stop()
687
 
{
688
 
    // Stop stream if it's playing
689
 
    if (iOutputStream_ && state_ != STATE_INACTIVE) {
690
 
        lastError_ = KRequestPending;
691
 
        iOutputStream_->Stop();
692
 
 
693
 
        // Wait until it's actually stopped
694
 
        while (lastError_ == KRequestPending)
695
 
            pj_symbianos_poll(-1, 100);
696
 
    }
697
 
 
698
 
    if (iOutputStream_) {
699
 
        delete iOutputStream_;
700
 
        iOutputStream_ = NULL;
701
 
    }
702
 
 
703
 
    if (startAsw_.IsStarted()) {
704
 
        startAsw_.AsyncStop();
705
 
    }
706
 
 
707
 
    state_ = STATE_INACTIVE;
708
 
}
709
 
 
710
 
void CPjAudioOutputEngine::MaoscOpenComplete(TInt aError)
711
 
{
712
 
    if (startAsw_.IsStarted()) {
713
 
        startAsw_.AsyncStop();
714
 
    }
715
 
 
716
 
    lastError_ = aError;
717
 
 
718
 
    if (aError==KErrNone) {
719
 
        // set stream properties, 16bit 8KHz mono
720
 
        TMdaAudioDataSettings iSettings;
721
 
        iSettings.iChannels =
722
 
                        get_channel_cap(parentStrm_->param.channel_count);
723
 
        iSettings.iSampleRate =
724
 
                        get_clock_rate_cap(parentStrm_->param.clock_rate);
725
 
 
726
 
        iOutputStream_->SetAudioPropertiesL(iSettings.iSampleRate,
727
 
                                            iSettings.iChannels);
728
 
 
729
 
        /* Apply output volume setting if specified */
730
 
        if (parentStrm_->param.flags &
731
 
            PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING)
732
 
        {
733
 
            stream_set_cap(&parentStrm_->base,
734
 
                           PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING,
735
 
                           &parentStrm_->param.output_vol);
736
 
        } else {
737
 
            // set volume to 1/2th of stream max volume
738
 
            iOutputStream_->SetVolume(iOutputStream_->MaxVolume()/2);
739
 
        }
740
 
 
741
 
        // set stream priority to normal and time sensitive
742
 
        iOutputStream_->SetPriority(EPriorityNormal,
743
 
                                    EMdaPriorityPreferenceTime);
744
 
 
745
 
        // Call callback to retrieve frame from upstream.
746
 
        pjmedia_frame f;
747
 
        pj_status_t status;
748
 
 
749
 
        f.type = PJMEDIA_FRAME_TYPE_AUDIO;
750
 
        f.buf = frameBuf_;
751
 
        f.size = frameBufSize_;
752
 
        f.timestamp.u32.lo = timestamp_;
753
 
        f.bit_info = 0;
754
 
 
755
 
        status = playCb_(this->userData_, &f);
756
 
        if (status != PJ_SUCCESS) {
757
 
            this->Stop();
758
 
            return;
759
 
        }
760
 
 
761
 
        if (f.type != PJMEDIA_FRAME_TYPE_AUDIO)
762
 
            pj_bzero(frameBuf_, frameBufSize_);
763
 
 
764
 
        // Increment timestamp.
765
 
        timestamp_ += (frameBufSize_ / BYTES_PER_SAMPLE);
766
 
 
767
 
        // issue WriteL() to write the first audio data block,
768
 
        // subsequent calls to WriteL() will be issued in
769
 
        // MMdaAudioOutputStreamCallback::MaoscBufferCopied()
770
 
        // until whole data buffer is written.
771
 
        frame_.Set(frameBuf_, frameBufSize_);
772
 
        iOutputStream_->WriteL(frame_);
773
 
 
774
 
        // output stream opened succesfully, set status to Active
775
 
        state_ = STATE_ACTIVE;
776
 
    } else {
777
 
        snd_perror("Error in MaoscOpenComplete()", aError);
778
 
    }
779
 
}
780
 
 
781
 
void CPjAudioOutputEngine::MaoscBufferCopied(TInt aError,
782
 
                                             const TDesC8& aBuffer)
783
 
{
784
 
    PJ_UNUSED_ARG(aBuffer);
785
 
 
786
 
    if (aError==KErrNone) {
787
 
        // Buffer successfully written, feed another one.
788
 
 
789
 
        // Call callback to retrieve frame from upstream.
790
 
        pjmedia_frame f;
791
 
        pj_status_t status;
792
 
 
793
 
        f.type = PJMEDIA_FRAME_TYPE_AUDIO;
794
 
        f.buf = frameBuf_;
795
 
        f.size = frameBufSize_;
796
 
        f.timestamp.u32.lo = timestamp_;
797
 
        f.bit_info = 0;
798
 
 
799
 
        status = playCb_(this->userData_, &f);
800
 
        if (status != PJ_SUCCESS) {
801
 
            this->Stop();
802
 
            return;
803
 
        }
804
 
 
805
 
        if (f.type != PJMEDIA_FRAME_TYPE_AUDIO)
806
 
            pj_bzero(frameBuf_, frameBufSize_);
807
 
 
808
 
        // Increment timestamp.
809
 
        timestamp_ += (frameBufSize_ / BYTES_PER_SAMPLE);
810
 
 
811
 
        // Write to playback stream.
812
 
        frame_.Set(frameBuf_, frameBufSize_);
813
 
        iOutputStream_->WriteL(frame_);
814
 
 
815
 
    } else if (aError==KErrAbort) {
816
 
        // playing was aborted, due to call to CMdaAudioOutputStream::Stop()
817
 
        state_ = STATE_INACTIVE;
818
 
    } else  {
819
 
        // error writing data to output
820
 
        lastError_ = aError;
821
 
        state_ = STATE_INACTIVE;
822
 
        snd_perror("Error in MaoscBufferCopied()", aError);
823
 
    }
824
 
}
825
 
 
826
 
void CPjAudioOutputEngine::MaoscPlayComplete(TInt aError)
827
 
{
828
 
    lastError_ = aError;
829
 
    state_ = STATE_INACTIVE;
830
 
    if (aError != KErrNone && aError != KErrCancel) {
831
 
        snd_perror("Error in MaoscPlayComplete()", aError);
832
 
    }
833
 
}
834
 
 
835
 
/****************************************************************************
836
 
 * Factory operations
837
 
 */
838
 
 
839
 
/*
840
 
 * C compatible declaration of MDA factory.
841
 
 */
842
 
PJ_BEGIN_DECL
843
 
PJ_DECL(pjmedia_aud_dev_factory*) pjmedia_symb_mda_factory(pj_pool_factory *pf);
844
 
PJ_END_DECL
845
 
 
846
 
/*
847
 
 * Init Symbian audio driver.
848
 
 */
849
 
pjmedia_aud_dev_factory* pjmedia_symb_mda_factory(pj_pool_factory *pf)
850
 
{
851
 
    struct mda_factory *f;
852
 
    pj_pool_t *pool;
853
 
 
854
 
    pool = pj_pool_create(pf, "symb_aud", 1000, 1000, NULL);
855
 
    f = PJ_POOL_ZALLOC_T(pool, struct mda_factory);
856
 
    f->pf = pf;
857
 
    f->pool = pool;
858
 
    f->base.op = &factory_op;
859
 
 
860
 
    return &f->base;
861
 
}
862
 
 
863
 
/* API: init factory */
864
 
static pj_status_t factory_init(pjmedia_aud_dev_factory *f)
865
 
{
866
 
    struct mda_factory *af = (struct mda_factory*)f;
867
 
 
868
 
    pj_ansi_strcpy(af->dev_info.name, "Symbian Audio");
869
 
    af->dev_info.default_samples_per_sec = 8000;
870
 
    af->dev_info.caps = PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING |
871
 
                        PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING;
872
 
    af->dev_info.input_count = 1;
873
 
    af->dev_info.output_count = 1;
874
 
 
875
 
    PJ_LOG(4, (THIS_FILE, "Symb Mda initialized"));
876
 
 
877
 
    return PJ_SUCCESS;
878
 
}
879
 
 
880
 
/* API: destroy factory */
881
 
static pj_status_t factory_destroy(pjmedia_aud_dev_factory *f)
882
 
{
883
 
    struct mda_factory *af = (struct mda_factory*)f;
884
 
    pj_pool_t *pool = af->pool;
885
 
 
886
 
    af->pool = NULL;
887
 
    pj_pool_release(pool);
888
 
 
889
 
    PJ_LOG(4, (THIS_FILE, "Symbian Mda destroyed"));
890
 
 
891
 
    return PJ_SUCCESS;
892
 
}
893
 
 
894
 
/* API: refresh the device list */
895
 
static pj_status_t factory_refresh(pjmedia_aud_dev_factory *f)
896
 
{
897
 
    PJ_UNUSED_ARG(f);
898
 
    return PJ_ENOTSUP;
899
 
}
900
 
 
901
 
/* API: get number of devices */
902
 
static unsigned factory_get_dev_count(pjmedia_aud_dev_factory *f)
903
 
{
904
 
    PJ_UNUSED_ARG(f);
905
 
    return 1;
906
 
}
907
 
 
908
 
/* API: get device info */
909
 
static pj_status_t factory_get_dev_info(pjmedia_aud_dev_factory *f,
910
 
                                        unsigned index,
911
 
                                        pjmedia_aud_dev_info *info)
912
 
{
913
 
    struct mda_factory *af = (struct mda_factory*)f;
914
 
 
915
 
    PJ_ASSERT_RETURN(index == 0, PJMEDIA_EAUD_INVDEV);
916
 
 
917
 
    pj_memcpy(info, &af->dev_info, sizeof(*info));
918
 
 
919
 
    return PJ_SUCCESS;
920
 
}
921
 
 
922
 
/* API: create default device parameter */
923
 
static pj_status_t factory_default_param(pjmedia_aud_dev_factory *f,
924
 
                                         unsigned index,
925
 
                                         pjmedia_aud_param *param)
926
 
{
927
 
    struct mda_factory *af = (struct mda_factory*)f;
928
 
 
929
 
    PJ_ASSERT_RETURN(index == 0, PJMEDIA_EAUD_INVDEV);
930
 
 
931
 
    pj_bzero(param, sizeof(*param));
932
 
    param->dir = PJMEDIA_DIR_CAPTURE_PLAYBACK;
933
 
    param->rec_id = index;
934
 
    param->play_id = index;
935
 
    param->clock_rate = af->dev_info.default_samples_per_sec;
936
 
    param->channel_count = 1;
937
 
    param->samples_per_frame = af->dev_info.default_samples_per_sec * 20 / 1000;
938
 
    param->bits_per_sample = BITS_PER_SAMPLE;
939
 
    // Don't set the flags without specifying the flags value.
940
 
    //param->flags = af->dev_info.caps;
941
 
 
942
 
    return PJ_SUCCESS;
943
 
}
944
 
 
945
 
 
946
 
/* API: create stream */
947
 
static pj_status_t factory_create_stream(pjmedia_aud_dev_factory *f,
948
 
                                         const pjmedia_aud_param *param,
949
 
                                         pjmedia_aud_rec_cb rec_cb,
950
 
                                         pjmedia_aud_play_cb play_cb,
951
 
                                         void *user_data,
952
 
                                         pjmedia_aud_stream **p_aud_strm)
953
 
{
954
 
    struct mda_factory *mf = (struct mda_factory*)f;
955
 
    pj_pool_t *pool;
956
 
    struct mda_stream *strm;
957
 
 
958
 
    /* Can only support 16bits per sample raw PCM format. */
959
 
    PJ_ASSERT_RETURN(param->bits_per_sample == BITS_PER_SAMPLE, PJ_EINVAL);
960
 
    PJ_ASSERT_RETURN((param->flags & PJMEDIA_AUD_DEV_CAP_EXT_FORMAT)==0 ||
961
 
                     param->ext_fmt.id == PJMEDIA_FORMAT_L16,
962
 
                     PJ_ENOTSUP);
963
 
 
964
 
    /* It seems that MDA recorder only supports for mono channel. */
965
 
    PJ_ASSERT_RETURN(param->channel_count == 1, PJ_EINVAL);
966
 
 
967
 
    /* Create and Initialize stream descriptor */
968
 
    pool = pj_pool_create(mf->pf, "symb_aud_dev", 1000, 1000, NULL);
969
 
    PJ_ASSERT_RETURN(pool, PJ_ENOMEM);
970
 
 
971
 
    strm = PJ_POOL_ZALLOC_T(pool, struct mda_stream);
972
 
    strm->pool = pool;
973
 
    strm->param = *param;
974
 
 
975
 
    // Create the output stream.
976
 
    if (strm->param.dir & PJMEDIA_DIR_PLAYBACK) {
977
 
        TRAPD(err, strm->out_engine = CPjAudioOutputEngine::NewL(strm, play_cb,
978
 
                                                                 user_data));
979
 
        if (err != KErrNone) {
980
 
            pj_pool_release(pool);
981
 
            return PJ_RETURN_OS_ERROR(err);
982
 
        }
983
 
    }
984
 
 
985
 
    // Create the input stream.
986
 
    if (strm->param.dir & PJMEDIA_DIR_CAPTURE) {
987
 
        TRAPD(err, strm->in_engine = CPjAudioInputEngine::NewL(strm, rec_cb,
988
 
                                                               user_data));
989
 
        if (err != KErrNone) {
990
 
            strm->in_engine = NULL;
991
 
            delete strm->out_engine;
992
 
            strm->out_engine = NULL;
993
 
            pj_pool_release(pool);
994
 
            return PJ_RETURN_OS_ERROR(err);
995
 
        }
996
 
    }
997
 
 
998
 
    /* Done */
999
 
    strm->base.op = &stream_op;
1000
 
    *p_aud_strm = &strm->base;
1001
 
 
1002
 
    return PJ_SUCCESS;
1003
 
}
1004
 
 
1005
 
/* API: Get stream info. */
1006
 
static pj_status_t stream_get_param(pjmedia_aud_stream *s,
1007
 
                                    pjmedia_aud_param *pi)
1008
 
{
1009
 
    struct mda_stream *strm = (struct mda_stream*)s;
1010
 
 
1011
 
    PJ_ASSERT_RETURN(strm && pi, PJ_EINVAL);
1012
 
 
1013
 
    pj_memcpy(pi, &strm->param, sizeof(*pi));
1014
 
 
1015
 
    /* Update the output volume setting */
1016
 
    if (stream_get_cap(s, PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING,
1017
 
                       &pi->output_vol) == PJ_SUCCESS)
1018
 
    {
1019
 
        pi->flags |= PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING;
1020
 
    }
1021
 
 
1022
 
    /* Update the input volume setting */
1023
 
    if (stream_get_cap(s, PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING,
1024
 
                       &pi->input_vol) == PJ_SUCCESS)
1025
 
    {
1026
 
        pi->flags |= PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING;
1027
 
    }
1028
 
 
1029
 
    return PJ_SUCCESS;
1030
 
}
1031
 
 
1032
 
/* API: get capability */
1033
 
static pj_status_t stream_get_cap(pjmedia_aud_stream *s,
1034
 
                                  pjmedia_aud_dev_cap cap,
1035
 
                                  void *pval)
1036
 
{
1037
 
    struct mda_stream *strm = (struct mda_stream*)s;
1038
 
    pj_status_t status = PJ_ENOTSUP;
1039
 
 
1040
 
    PJ_ASSERT_RETURN(s && pval, PJ_EINVAL);
1041
 
 
1042
 
    switch (cap) {
1043
 
    case PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING:
1044
 
        if (strm->param.dir & PJMEDIA_DIR_CAPTURE) {
1045
 
            PJ_ASSERT_RETURN(strm->in_engine, PJ_EINVAL);
1046
 
 
1047
 
            TInt max_gain = strm->in_engine->GetMaxGain();
1048
 
            TInt gain = strm->in_engine->GetGain();
1049
 
 
1050
 
            if (max_gain > 0 && gain >= 0) {
1051
 
                *(unsigned*)pval = gain * 100 / max_gain;
1052
 
                status = PJ_SUCCESS;
1053
 
            } else {
1054
 
                status = PJMEDIA_EAUD_NOTREADY;
1055
 
            }
1056
 
        }
1057
 
        break;
1058
 
    case PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING:
1059
 
        if (strm->param.dir & PJMEDIA_DIR_PLAYBACK) {
1060
 
            PJ_ASSERT_RETURN(strm->out_engine, PJ_EINVAL);
1061
 
 
1062
 
            TInt max_vol = strm->out_engine->GetMaxVolume();
1063
 
            TInt vol = strm->out_engine->GetVolume();
1064
 
 
1065
 
            if (max_vol > 0 && vol >= 0) {
1066
 
                *(unsigned*)pval = vol * 100 / max_vol;
1067
 
                status = PJ_SUCCESS;
1068
 
            } else {
1069
 
                status = PJMEDIA_EAUD_NOTREADY;
1070
 
            }
1071
 
        }
1072
 
        break;
1073
 
    default:
1074
 
        break;
1075
 
    }
1076
 
 
1077
 
    return status;
1078
 
}
1079
 
 
1080
 
/* API: set capability */
1081
 
static pj_status_t stream_set_cap(pjmedia_aud_stream *s,
1082
 
                                  pjmedia_aud_dev_cap cap,
1083
 
                                  const void *pval)
1084
 
{
1085
 
    struct mda_stream *strm = (struct mda_stream*)s;
1086
 
    pj_status_t status = PJ_ENOTSUP;
1087
 
 
1088
 
    PJ_ASSERT_RETURN(s && pval, PJ_EINVAL);
1089
 
 
1090
 
    switch (cap) {
1091
 
    case PJMEDIA_AUD_DEV_CAP_INPUT_VOLUME_SETTING:
1092
 
        if (strm->param.dir & PJMEDIA_DIR_CAPTURE) {
1093
 
            PJ_ASSERT_RETURN(strm->in_engine, PJ_EINVAL);
1094
 
 
1095
 
            TInt max_gain = strm->in_engine->GetMaxGain();
1096
 
            if (max_gain > 0) {
1097
 
                TInt gain;
1098
 
 
1099
 
                gain = *(unsigned*)pval * max_gain / 100;
1100
 
                status = strm->in_engine->SetGain(gain);
1101
 
            } else {
1102
 
                status = PJMEDIA_EAUD_NOTREADY;
1103
 
            }
1104
 
        }
1105
 
        break;
1106
 
    case PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING:
1107
 
        if (strm->param.dir & PJMEDIA_DIR_PLAYBACK) {
1108
 
            PJ_ASSERT_RETURN(strm->out_engine, PJ_EINVAL);
1109
 
 
1110
 
            TInt max_vol = strm->out_engine->GetMaxVolume();
1111
 
            if (max_vol > 0) {
1112
 
                TInt vol;
1113
 
 
1114
 
                vol = *(unsigned*)pval * max_vol / 100;
1115
 
                status = strm->out_engine->SetVolume(vol);
1116
 
            } else {
1117
 
                status = PJMEDIA_EAUD_NOTREADY;
1118
 
            }
1119
 
        }
1120
 
        break;
1121
 
    default:
1122
 
        break;
1123
 
    }
1124
 
 
1125
 
    return status;
1126
 
}
1127
 
 
1128
 
/* API: Start stream. */
1129
 
static pj_status_t stream_start(pjmedia_aud_stream *strm)
1130
 
{
1131
 
    struct mda_stream *stream = (struct mda_stream*)strm;
1132
 
 
1133
 
    PJ_ASSERT_RETURN(stream, PJ_EINVAL);
1134
 
 
1135
 
    if (stream->out_engine) {
1136
 
        pj_status_t status;
1137
 
        status = stream->out_engine->StartPlay();
1138
 
        if (status != PJ_SUCCESS)
1139
 
            return status;
1140
 
    }
1141
 
 
1142
 
    if (stream->in_engine) {
1143
 
        pj_status_t status;
1144
 
        status = stream->in_engine->StartRecord();
1145
 
        if (status != PJ_SUCCESS)
1146
 
            return status;
1147
 
    }
1148
 
 
1149
 
    return PJ_SUCCESS;
1150
 
}
1151
 
 
1152
 
/* API: Stop stream. */
1153
 
static pj_status_t stream_stop(pjmedia_aud_stream *strm)
1154
 
{
1155
 
    struct mda_stream *stream = (struct mda_stream*)strm;
1156
 
 
1157
 
    PJ_ASSERT_RETURN(stream, PJ_EINVAL);
1158
 
 
1159
 
    if (stream->in_engine) {
1160
 
        stream->in_engine->Stop();
1161
 
    }
1162
 
 
1163
 
    if (stream->out_engine) {
1164
 
        stream->out_engine->Stop();
1165
 
    }
1166
 
 
1167
 
    return PJ_SUCCESS;
1168
 
}
1169
 
 
1170
 
 
1171
 
/* API: Destroy stream. */
1172
 
static pj_status_t stream_destroy(pjmedia_aud_stream *strm)
1173
 
{
1174
 
    struct mda_stream *stream = (struct mda_stream*)strm;
1175
 
 
1176
 
    PJ_ASSERT_RETURN(stream, PJ_EINVAL);
1177
 
 
1178
 
    stream_stop(strm);
1179
 
 
1180
 
    delete stream->in_engine;
1181
 
    stream->in_engine = NULL;
1182
 
 
1183
 
    delete stream->out_engine;
1184
 
    stream->out_engine = NULL;
1185
 
 
1186
 
    pj_pool_t *pool;
1187
 
    pool = stream->pool;
1188
 
    if (pool) {
1189
 
        stream->pool = NULL;
1190
 
        pj_pool_release(pool);
1191
 
    }
1192
 
 
1193
 
    return PJ_SUCCESS;
1194
 
}
1195
 
 
1196
 
#endif /* PJMEDIA_AUDIO_DEV_HAS_SYMB_MDA */