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

« back to all changes in this revision

Viewing changes to daemon/libs/pjproject-2.1.0/pjmedia/src/pjmedia/clock_thread.c

  • Committer: Package Import Robot
  • Author(s): Francois Marier, Francois Marier, Mark Purcell
  • Date: 2014-10-18 15:08:50 UTC
  • mfrom: (1.1.12)
  • mto: This revision was merged to the branch mainline in revision 29.
  • Revision ID: package-import@ubuntu.com-20141018150850-2exfk34ckb15pcwi
Tags: 1.4.1-0.1
[ Francois Marier ]
* Non-maintainer upload
* New upstream release (closes: #759576, #741130)
  - debian/rules +PJPROJECT_VERSION := 2.2.1
  - add upstream patch to fix broken TLS support
  - add patch to fix pjproject regression

[ Mark Purcell ]
* Build-Depends:
  - sflphone-daemon + libavformat-dev, libavcodec-dev, libswscale-dev,
  libavdevice-dev, libavutil-dev
  - sflphone-gnome + libclutter-gtk-1.0-dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* $Id: clock_thread.c 4160 2012-06-07 04:10:22Z 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/clock.h>
21
 
#include <pjmedia/errno.h>
22
 
#include <pj/assert.h>
23
 
#include <pj/lock.h>
24
 
#include <pj/os.h>
25
 
#include <pj/pool.h>
26
 
#include <pj/string.h>
27
 
#include <pj/compat/high_precision.h>
28
 
 
29
 
/* API: Init clock source */
30
 
PJ_DEF(pj_status_t) pjmedia_clock_src_init( pjmedia_clock_src *clocksrc,
31
 
                                            pjmedia_type media_type,
32
 
                                            unsigned clock_rate,
33
 
                                            unsigned ptime_usec )
34
 
{
35
 
    PJ_ASSERT_RETURN(clocksrc, PJ_EINVAL);
36
 
 
37
 
    clocksrc->media_type = media_type;
38
 
    clocksrc->clock_rate = clock_rate;
39
 
    clocksrc->ptime_usec = ptime_usec;
40
 
    pj_set_timestamp32(&clocksrc->timestamp, 0, 0);
41
 
    pj_get_timestamp(&clocksrc->last_update);
42
 
 
43
 
    return PJ_SUCCESS;
44
 
}
45
 
 
46
 
/* API: Update clock source */
47
 
PJ_DECL(pj_status_t) pjmedia_clock_src_update( pjmedia_clock_src *clocksrc,
48
 
                                               const pj_timestamp *timestamp )
49
 
{
50
 
    PJ_ASSERT_RETURN(clocksrc, PJ_EINVAL);
51
 
 
52
 
    if (timestamp)
53
 
        pj_memcpy(&clocksrc->timestamp, timestamp, sizeof(pj_timestamp));
54
 
    pj_get_timestamp(&clocksrc->last_update);
55
 
 
56
 
    return PJ_SUCCESS;
57
 
}
58
 
 
59
 
/* API: Get clock source's current timestamp */
60
 
PJ_DEF(pj_status_t)
61
 
pjmedia_clock_src_get_current_timestamp( const pjmedia_clock_src *clocksrc,
62
 
                                         pj_timestamp *timestamp)
63
 
{
64
 
    pj_timestamp now;
65
 
    unsigned elapsed_ms;
66
 
    
67
 
    PJ_ASSERT_RETURN(clocksrc && timestamp, PJ_EINVAL);
68
 
 
69
 
    pj_get_timestamp(&now);
70
 
    elapsed_ms = pj_elapsed_msec(&clocksrc->last_update, &now);
71
 
    pj_memcpy(timestamp, &clocksrc->timestamp, sizeof(pj_timestamp));
72
 
    pj_add_timestamp32(timestamp, elapsed_ms * clocksrc->clock_rate / 1000);
73
 
 
74
 
    return PJ_SUCCESS;
75
 
}
76
 
 
77
 
/* API: Get clock source's time (in ms) */
78
 
PJ_DEF(pj_uint32_t)
79
 
pjmedia_clock_src_get_time_msec( const pjmedia_clock_src *clocksrc )
80
 
{
81
 
    pj_timestamp ts;
82
 
 
83
 
    pjmedia_clock_src_get_current_timestamp(clocksrc, &ts);
84
 
 
85
 
#if PJ_HAS_INT64
86
 
    if (ts.u64 > PJ_UINT64(0x3FFFFFFFFFFFFF))
87
 
        return (pj_uint32_t)(ts.u64 / clocksrc->clock_rate * 1000);
88
 
    else
89
 
        return (pj_uint32_t)(ts.u64 * 1000 / clocksrc->clock_rate);
90
 
#elif PJ_HAS_FLOATING_POINT
91
 
    return (pj_uint32_t)((1.0 * ts.u32.hi * 0xFFFFFFFFUL + ts.u32.lo)
92
 
                         * 1000.0 / clocksrc->clock_rate);
93
 
#else
94
 
    if (ts.u32.lo > 0x3FFFFFUL)
95
 
        return (pj_uint32_t)(0xFFFFFFFFUL / clocksrc->clock_rate * ts.u32.hi 
96
 
                             * 1000UL + ts.u32.lo / clocksrc->clock_rate *
97
 
                             1000UL);
98
 
    else
99
 
        return (pj_uint32_t)(0xFFFFFFFFUL / clocksrc->clock_rate * ts.u32.hi 
100
 
                             * 1000UL + ts.u32.lo * 1000UL /
101
 
                             clocksrc->clock_rate);
102
 
#endif
103
 
}
104
 
 
105
 
 
106
 
/*
107
 
 * Implementation of media clock with OS thread.
108
 
 */
109
 
 
110
 
struct pjmedia_clock
111
 
{
112
 
    pj_pool_t               *pool;
113
 
    pj_timestamp             freq;
114
 
    pj_timestamp             interval;
115
 
    pj_timestamp             next_tick;
116
 
    pj_timestamp             timestamp;
117
 
    unsigned                 timestamp_inc;
118
 
    unsigned                 options;
119
 
    pj_uint64_t              max_jump;
120
 
    pjmedia_clock_callback  *cb;
121
 
    void                    *user_data;
122
 
    pj_thread_t             *thread;
123
 
    pj_bool_t                running;
124
 
    pj_bool_t                quitting;
125
 
    pj_lock_t               *lock;
126
 
};
127
 
 
128
 
 
129
 
static int clock_thread(void *arg);
130
 
 
131
 
#define MAX_JUMP_MSEC   500
132
 
#define USEC_IN_SEC     (pj_uint64_t)1000000
133
 
 
134
 
/*
135
 
 * Create media clock.
136
 
 */
137
 
PJ_DEF(pj_status_t) pjmedia_clock_create( pj_pool_t *pool,
138
 
                                          unsigned clock_rate,
139
 
                                          unsigned channel_count,
140
 
                                          unsigned samples_per_frame,
141
 
                                          unsigned options,
142
 
                                          pjmedia_clock_callback *cb,
143
 
                                          void *user_data,
144
 
                                          pjmedia_clock **p_clock)
145
 
{
146
 
    pjmedia_clock_param param;
147
 
 
148
 
    param.usec_interval = (unsigned)(samples_per_frame * USEC_IN_SEC /
149
 
                                     channel_count / clock_rate);
150
 
    param.clock_rate = clock_rate;
151
 
    return pjmedia_clock_create2(pool, &param, options, cb,
152
 
                                 user_data, p_clock);
153
 
}
154
 
 
155
 
PJ_DEF(pj_status_t) pjmedia_clock_create2(pj_pool_t *pool,
156
 
                                          const pjmedia_clock_param *param,
157
 
                                          unsigned options,
158
 
                                          pjmedia_clock_callback *cb,
159
 
                                          void *user_data,
160
 
                                          pjmedia_clock **p_clock)
161
 
{
162
 
    pjmedia_clock *clock;
163
 
    pj_status_t status;
164
 
 
165
 
    PJ_ASSERT_RETURN(pool && param->usec_interval && param->clock_rate &&
166
 
                     p_clock, PJ_EINVAL);
167
 
 
168
 
    clock = PJ_POOL_ALLOC_T(pool, pjmedia_clock);
169
 
    clock->pool = pj_pool_create(pool->factory, "clock%p", 512, 512, NULL);
170
 
 
171
 
    status = pj_get_timestamp_freq(&clock->freq);
172
 
    if (status != PJ_SUCCESS)
173
 
        return status;
174
 
 
175
 
    clock->interval.u64 = param->usec_interval * clock->freq.u64 /
176
 
                          USEC_IN_SEC;
177
 
    clock->next_tick.u64 = 0;
178
 
    clock->timestamp.u64 = 0;
179
 
    clock->max_jump = MAX_JUMP_MSEC * clock->freq.u64 / 1000;
180
 
    clock->timestamp_inc = (unsigned)(param->usec_interval *
181
 
                                      param->clock_rate /
182
 
                                      USEC_IN_SEC);
183
 
    clock->options = options;
184
 
    clock->cb = cb;
185
 
    clock->user_data = user_data;
186
 
    clock->thread = NULL;
187
 
    clock->running = PJ_FALSE;
188
 
    clock->quitting = PJ_FALSE;
189
 
    
190
 
    /* I don't think we need a mutex, so we'll use null. */
191
 
    status = pj_lock_create_null_mutex(pool, "clock", &clock->lock);
192
 
    if (status != PJ_SUCCESS)
193
 
        return status;
194
 
 
195
 
    *p_clock = clock;
196
 
 
197
 
    return PJ_SUCCESS;
198
 
}
199
 
 
200
 
 
201
 
/*
202
 
 * Start the clock. 
203
 
 */
204
 
PJ_DEF(pj_status_t) pjmedia_clock_start(pjmedia_clock *clock)
205
 
{
206
 
    pj_timestamp now;
207
 
    pj_status_t status;
208
 
 
209
 
    PJ_ASSERT_RETURN(clock != NULL, PJ_EINVAL);
210
 
 
211
 
    if (clock->running)
212
 
        return PJ_SUCCESS;
213
 
 
214
 
    status = pj_get_timestamp(&now);
215
 
    if (status != PJ_SUCCESS)
216
 
        return status;
217
 
 
218
 
    clock->next_tick.u64 = now.u64 + clock->interval.u64;
219
 
    clock->running = PJ_TRUE;
220
 
    clock->quitting = PJ_FALSE;
221
 
 
222
 
    if ((clock->options & PJMEDIA_CLOCK_NO_ASYNC) == 0 && !clock->thread) {
223
 
        status = pj_thread_create(clock->pool, "clock", &clock_thread, clock,
224
 
                                  0, 0, &clock->thread);
225
 
        if (status != PJ_SUCCESS) {
226
 
            clock->running = PJ_FALSE;
227
 
            return status;
228
 
        }
229
 
    }
230
 
 
231
 
    return PJ_SUCCESS;
232
 
}
233
 
 
234
 
 
235
 
/*
236
 
 * Stop the clock. 
237
 
 */
238
 
PJ_DEF(pj_status_t) pjmedia_clock_stop(pjmedia_clock *clock)
239
 
{
240
 
    PJ_ASSERT_RETURN(clock != NULL, PJ_EINVAL);
241
 
 
242
 
    clock->running = PJ_FALSE;
243
 
    clock->quitting = PJ_TRUE;
244
 
 
245
 
    if (clock->thread) {
246
 
        if (pj_thread_join(clock->thread) == PJ_SUCCESS) {
247
 
            pj_thread_destroy(clock->thread);
248
 
            clock->thread = NULL;
249
 
            pj_pool_reset(clock->pool);
250
 
        } else {
251
 
            clock->quitting = PJ_FALSE;
252
 
        }
253
 
    }
254
 
 
255
 
    return PJ_SUCCESS;
256
 
}
257
 
 
258
 
 
259
 
/*
260
 
 * Update the clock. 
261
 
 */
262
 
PJ_DEF(pj_status_t) pjmedia_clock_modify(pjmedia_clock *clock,
263
 
                                         const pjmedia_clock_param *param)
264
 
{
265
 
    clock->interval.u64 = param->usec_interval * clock->freq.u64 /
266
 
                          USEC_IN_SEC;
267
 
    clock->timestamp_inc = (unsigned)(param->usec_interval *
268
 
                                      param->clock_rate /
269
 
                                      USEC_IN_SEC);
270
 
 
271
 
    return PJ_SUCCESS;
272
 
}
273
 
 
274
 
 
275
 
/* Calculate next tick */
276
 
PJ_INLINE(void) clock_calc_next_tick(pjmedia_clock *clock,
277
 
                                     pj_timestamp *now)
278
 
{
279
 
    if (clock->next_tick.u64+clock->max_jump < now->u64) {
280
 
        /* Timestamp has made large jump, adjust next_tick */
281
 
        clock->next_tick.u64 = now->u64;
282
 
    }
283
 
    clock->next_tick.u64 += clock->interval.u64;
284
 
 
285
 
}
286
 
 
287
 
/*
288
 
 * Poll the clock. 
289
 
 */
290
 
PJ_DEF(pj_bool_t) pjmedia_clock_wait( pjmedia_clock *clock,
291
 
                                      pj_bool_t wait,
292
 
                                      pj_timestamp *ts)
293
 
{
294
 
    pj_timestamp now;
295
 
    pj_status_t status;
296
 
 
297
 
    PJ_ASSERT_RETURN(clock != NULL, PJ_FALSE);
298
 
    PJ_ASSERT_RETURN((clock->options & PJMEDIA_CLOCK_NO_ASYNC) != 0,
299
 
                     PJ_FALSE);
300
 
    PJ_ASSERT_RETURN(clock->running, PJ_FALSE);
301
 
 
302
 
    status = pj_get_timestamp(&now);
303
 
    if (status != PJ_SUCCESS)
304
 
        return PJ_FALSE;
305
 
 
306
 
    /* Wait for the next tick to happen */
307
 
    if (now.u64 < clock->next_tick.u64) {
308
 
        unsigned msec;
309
 
 
310
 
        if (!wait)
311
 
            return PJ_FALSE;
312
 
 
313
 
        msec = pj_elapsed_msec(&now, &clock->next_tick);
314
 
        pj_thread_sleep(msec);
315
 
    }
316
 
 
317
 
    /* Call callback, if any */
318
 
    if (clock->cb)
319
 
        (*clock->cb)(&clock->timestamp, clock->user_data);
320
 
 
321
 
    /* Report timestamp to caller */
322
 
    if (ts)
323
 
        ts->u64 = clock->timestamp.u64;
324
 
 
325
 
    /* Increment timestamp */
326
 
    clock->timestamp.u64 += clock->timestamp_inc;
327
 
 
328
 
    /* Calculate next tick */
329
 
    clock_calc_next_tick(clock, &now);
330
 
 
331
 
    /* Done */
332
 
    return PJ_TRUE;
333
 
}
334
 
 
335
 
 
336
 
/*
337
 
 * Clock thread
338
 
 */
339
 
static int clock_thread(void *arg)
340
 
{
341
 
    pj_timestamp now;
342
 
    pjmedia_clock *clock = (pjmedia_clock*) arg;
343
 
 
344
 
    /* Set thread priority to maximum unless not wanted. */
345
 
    if ((clock->options & PJMEDIA_CLOCK_NO_HIGHEST_PRIO) == 0) {
346
 
        int max = pj_thread_get_prio_max(pj_thread_this());
347
 
        if (max > 0)
348
 
            pj_thread_set_prio(pj_thread_this(), max);
349
 
    }
350
 
 
351
 
    /* Get the first tick */
352
 
    pj_get_timestamp(&clock->next_tick);
353
 
    clock->next_tick.u64 += clock->interval.u64;
354
 
 
355
 
 
356
 
    while (!clock->quitting) {
357
 
 
358
 
        pj_get_timestamp(&now);
359
 
 
360
 
        /* Wait for the next tick to happen */
361
 
        if (now.u64 < clock->next_tick.u64) {
362
 
            unsigned msec;
363
 
            msec = pj_elapsed_msec(&now, &clock->next_tick);
364
 
            pj_thread_sleep(msec);
365
 
        }
366
 
 
367
 
        /* Skip if not running */
368
 
        if (!clock->running) {
369
 
            /* Calculate next tick */
370
 
            clock_calc_next_tick(clock, &now);
371
 
            continue;
372
 
        }
373
 
 
374
 
        pj_lock_acquire(clock->lock);
375
 
 
376
 
        /* Call callback, if any */
377
 
        if (clock->cb)
378
 
            (*clock->cb)(&clock->timestamp, clock->user_data);
379
 
 
380
 
        /* Best effort way to detect if we've been destroyed in the callback */
381
 
        if (clock->quitting)
382
 
            break;
383
 
 
384
 
        /* Increment timestamp */
385
 
        clock->timestamp.u64 += clock->timestamp_inc;
386
 
 
387
 
        /* Calculate next tick */
388
 
        clock_calc_next_tick(clock, &now);
389
 
 
390
 
        pj_lock_release(clock->lock);
391
 
    }
392
 
 
393
 
    return 0;
394
 
}
395
 
 
396
 
 
397
 
/*
398
 
 * Destroy the clock. 
399
 
 */
400
 
PJ_DEF(pj_status_t) pjmedia_clock_destroy(pjmedia_clock *clock)
401
 
{
402
 
    PJ_ASSERT_RETURN(clock != NULL, PJ_EINVAL);
403
 
 
404
 
    clock->running = PJ_FALSE;
405
 
    clock->quitting = PJ_TRUE;
406
 
 
407
 
    if (clock->thread) {
408
 
        pj_thread_join(clock->thread);
409
 
        pj_thread_destroy(clock->thread);
410
 
        clock->thread = NULL;
411
 
    }
412
 
 
413
 
    if (clock->lock) {
414
 
        pj_lock_destroy(clock->lock);
415
 
        clock->lock = NULL;
416
 
    }
417
 
 
418
 
    if (clock->pool) {
419
 
        pj_pool_t *pool = clock->pool;
420
 
        clock->pool = NULL;
421
 
        pj_pool_release(pool);
422
 
    }
423
 
    return PJ_SUCCESS;
424
 
}
425
 
 
426