~ubuntu-branches/ubuntu/wily/sflphone/wily

« back to all changes in this revision

Viewing changes to daemon/libs/pjproject-2.2.1/pjmedia/src/pjmedia-audiodev/audiotest.c

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2015-01-07 14:51:16 UTC
  • mfrom: (4.3.5 sid)
  • Revision ID: package-import@ubuntu.com-20150107145116-yxnafinf4lrdvrmx
Tags: 1.4.1-0.1ubuntu1
* Merge with Debian, remaining changes:
 - Drop soprano, nepomuk build-dep
* Drop ubuntu patches, now upstream

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $Id: audiotest.c 3553 2011-05-05 06:14:19Z nanang $ */
 
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/audiotest.h>
 
21
#include <pjmedia-audiodev/audiodev.h>
 
22
#include <pjlib.h>
 
23
#include <pjlib-util.h>
 
24
 
 
25
#define THIS_FILE           "audiotest.c"
 
26
 
 
27
/* Test duration in msec */
 
28
#define DURATION            10000
 
29
 
 
30
/* Skip the first msec from the calculation */
 
31
#define SKIP_DURATION       1000
 
32
 
 
33
/* Division helper */
 
34
#define DIV_ROUND_UP(a,b) (((a) + ((b) - 1)) / (b))
 
35
#define DIV_ROUND(a,b) (((a) + ((b)/2 - 1)) / (b))
 
36
 
 
37
struct stream_data
 
38
{
 
39
    pj_uint32_t     first_timestamp;
 
40
    pj_uint32_t     last_timestamp;
 
41
    pj_timestamp    last_called;
 
42
    pj_math_stat    delay;
 
43
};
 
44
 
 
45
struct test_data 
 
46
{
 
47
    pj_pool_t                      *pool;
 
48
    const pjmedia_aud_param        *param;
 
49
    pjmedia_aud_test_results       *result;
 
50
    pj_bool_t                       running;
 
51
    pj_bool_t                       has_error;
 
52
    pj_mutex_t                     *mutex;
 
53
 
 
54
    struct stream_data              capture_data;
 
55
    struct stream_data              playback_data;
 
56
};
 
57
 
 
58
static pj_status_t play_cb(void *user_data, pjmedia_frame *frame)
 
59
{
 
60
    struct test_data *test_data = (struct test_data *)user_data;
 
61
    struct stream_data *strm_data = &test_data->playback_data;
 
62
 
 
63
    pj_mutex_lock(test_data->mutex);
 
64
 
 
65
    /* Skip frames when test is not started or test has finished */
 
66
    if (!test_data->running) {
 
67
        pj_bzero(frame->buf, frame->size);
 
68
        pj_mutex_unlock(test_data->mutex);
 
69
        return PJ_SUCCESS;
 
70
    }
 
71
 
 
72
    /* Save last timestamp seen (to calculate drift) */
 
73
    strm_data->last_timestamp = frame->timestamp.u32.lo;
 
74
 
 
75
    if (strm_data->last_called.u64 == 0) {
 
76
        /* Init vars. */
 
77
        pj_get_timestamp(&strm_data->last_called);
 
78
        pj_math_stat_init(&strm_data->delay);
 
79
        strm_data->first_timestamp = frame->timestamp.u32.lo;
 
80
    } else {
 
81
        pj_timestamp now;
 
82
        unsigned delay;
 
83
 
 
84
        /* Calculate frame interval */
 
85
        pj_get_timestamp(&now);
 
86
        delay = pj_elapsed_usec(&strm_data->last_called, &now);
 
87
        strm_data->last_called = now;
 
88
 
 
89
        /* Update frame interval statistic */
 
90
        pj_math_stat_update(&strm_data->delay, delay);
 
91
    }
 
92
 
 
93
    pj_bzero(frame->buf, frame->size);
 
94
 
 
95
    pj_mutex_unlock(test_data->mutex);
 
96
 
 
97
    return PJ_SUCCESS;
 
98
}
 
99
 
 
100
static pj_status_t rec_cb(void *user_data, pjmedia_frame *frame)
 
101
{
 
102
    struct test_data *test_data = (struct test_data*)user_data;
 
103
    struct stream_data *strm_data = &test_data->capture_data;
 
104
 
 
105
    pj_mutex_lock(test_data->mutex);
 
106
 
 
107
    /* Skip frames when test is not started or test has finished */
 
108
    if (!test_data->running) {
 
109
        pj_mutex_unlock(test_data->mutex);
 
110
        return PJ_SUCCESS;
 
111
    }
 
112
 
 
113
    /* Save last timestamp seen (to calculate drift) */
 
114
    strm_data->last_timestamp = frame->timestamp.u32.lo;
 
115
 
 
116
    if (strm_data->last_called.u64 == 0) {
 
117
        /* Init vars. */
 
118
        pj_get_timestamp(&strm_data->last_called);
 
119
        pj_math_stat_init(&strm_data->delay);
 
120
        strm_data->first_timestamp = frame->timestamp.u32.lo;
 
121
    } else {
 
122
        pj_timestamp now;
 
123
        unsigned delay;
 
124
 
 
125
        /* Calculate frame interval */
 
126
        pj_get_timestamp(&now);
 
127
        delay = pj_elapsed_usec(&strm_data->last_called, &now);
 
128
        strm_data->last_called = now;
 
129
 
 
130
        /* Update frame interval statistic */
 
131
        pj_math_stat_update(&strm_data->delay, delay);
 
132
    }
 
133
 
 
134
    pj_mutex_unlock(test_data->mutex);
 
135
    return PJ_SUCCESS;
 
136
}
 
137
 
 
138
static void app_perror(const char *title, pj_status_t status)
 
139
{
 
140
    char errmsg[PJ_ERR_MSG_SIZE];
 
141
 
 
142
    pj_strerror(status, errmsg, sizeof(errmsg));        
 
143
    printf( "%s: %s (err=%d)\n",
 
144
            title, errmsg, status);
 
145
}
 
146
 
 
147
 
 
148
PJ_DEF(pj_status_t) pjmedia_aud_test( const pjmedia_aud_param *param,
 
149
                                      pjmedia_aud_test_results *result)
 
150
{
 
151
    pj_status_t status = PJ_SUCCESS;
 
152
    pjmedia_aud_stream *strm;
 
153
    struct test_data test_data;
 
154
    unsigned ptime, tmp;
 
155
    
 
156
    /*
 
157
     * Init test parameters
 
158
     */
 
159
    pj_bzero(&test_data, sizeof(test_data));
 
160
    test_data.param = param;
 
161
    test_data.result = result;
 
162
 
 
163
    test_data.pool = pj_pool_create(pjmedia_aud_subsys_get_pool_factory(),
 
164
                                    "audtest", 1000, 1000, NULL);
 
165
    pj_mutex_create_simple(test_data.pool, "sndtest", &test_data.mutex); 
 
166
 
 
167
    /*
 
168
     * Open device.
 
169
     */
 
170
    status = pjmedia_aud_stream_create(test_data.param, &rec_cb, &play_cb, 
 
171
                                       &test_data, &strm);
 
172
    if (status != PJ_SUCCESS) {
 
173
        app_perror("Unable to open device", status);
 
174
        pj_pool_release(test_data.pool);
 
175
        return status;
 
176
    }
 
177
 
 
178
 
 
179
    /* Sleep for a while to let sound device "settles" */
 
180
    pj_thread_sleep(200);
 
181
 
 
182
    /*
 
183
     * Start the stream.
 
184
     */
 
185
    status = pjmedia_aud_stream_start(strm);
 
186
    if (status != PJ_SUCCESS) {
 
187
        app_perror("Unable to start capture stream", status);
 
188
        pjmedia_aud_stream_destroy(strm);
 
189
        pj_pool_release(test_data.pool);
 
190
        return status;
 
191
    }
 
192
 
 
193
    PJ_LOG(3,(THIS_FILE,
 
194
              " Please wait while test is in progress (~%d secs)..",
 
195
              (DURATION+SKIP_DURATION)/1000));
 
196
 
 
197
    /* Let the stream runs for few msec/sec to get stable result.
 
198
     * (capture normally begins with frames available simultaneously).
 
199
     */
 
200
    pj_thread_sleep(SKIP_DURATION);
 
201
 
 
202
 
 
203
    /* Begin gather data */
 
204
    test_data.running = 1;
 
205
 
 
206
    /* 
 
207
     * Let the test runs for a while.
 
208
     */
 
209
    pj_thread_sleep(DURATION);
 
210
 
 
211
 
 
212
    /*
 
213
     * Close stream.
 
214
     */
 
215
    test_data.running = 0;
 
216
    pjmedia_aud_stream_destroy(strm);
 
217
    pj_pool_release(test_data.pool);
 
218
 
 
219
 
 
220
    /* 
 
221
     * Gather results
 
222
     */
 
223
    ptime = param->samples_per_frame * 1000 / param->clock_rate;
 
224
 
 
225
    tmp = pj_math_stat_get_stddev(&test_data.capture_data.delay);
 
226
    result->rec.frame_cnt = test_data.capture_data.delay.n;
 
227
    result->rec.min_interval = DIV_ROUND(test_data.capture_data.delay.min, 1000);
 
228
    result->rec.max_interval = DIV_ROUND(test_data.capture_data.delay.max, 1000);
 
229
    result->rec.avg_interval = DIV_ROUND(test_data.capture_data.delay.mean, 1000);
 
230
    result->rec.dev_interval = DIV_ROUND(tmp, 1000);
 
231
    result->rec.max_burst    = DIV_ROUND_UP(result->rec.max_interval, ptime);
 
232
 
 
233
    tmp = pj_math_stat_get_stddev(&test_data.playback_data.delay);
 
234
    result->play.frame_cnt = test_data.playback_data.delay.n;
 
235
    result->play.min_interval = DIV_ROUND(test_data.playback_data.delay.min, 1000);
 
236
    result->play.max_interval = DIV_ROUND(test_data.playback_data.delay.max, 1000);
 
237
    result->play.avg_interval = DIV_ROUND(test_data.playback_data.delay.mean, 1000);
 
238
    result->play.dev_interval = DIV_ROUND(tmp, 1000);
 
239
    result->play.max_burst    = DIV_ROUND_UP(result->play.max_interval, ptime);
 
240
 
 
241
    /* Check drifting */
 
242
    if (param->dir == PJMEDIA_DIR_CAPTURE_PLAYBACK) {
 
243
        int play_diff, cap_diff, drift;
 
244
 
 
245
        play_diff = test_data.playback_data.last_timestamp -
 
246
                    test_data.playback_data.first_timestamp;
 
247
        cap_diff  = test_data.capture_data.last_timestamp -
 
248
                    test_data.capture_data.first_timestamp;
 
249
        drift = play_diff > cap_diff? play_diff - cap_diff :
 
250
                cap_diff - play_diff;
 
251
 
 
252
        /* Allow one frame tolerance for clock drift detection */
 
253
        if (drift < (int)param->samples_per_frame) {
 
254
            result->rec_drift_per_sec = 0;
 
255
        } else {
 
256
            unsigned msec_dur;
 
257
 
 
258
            msec_dur = (test_data.capture_data.last_timestamp - 
 
259
                       test_data.capture_data.first_timestamp) * 1000 /
 
260
                       test_data.param->clock_rate;
 
261
 
 
262
            result->rec_drift_per_sec = drift * 1000 / msec_dur;
 
263
 
 
264
        }
 
265
    }
 
266
 
 
267
    return test_data.has_error? PJ_EUNKNOWN : PJ_SUCCESS;
 
268
}
 
269