static void mem_test(pj_pool_t *pool) { char unused[1024]; short *frame = pj_pool_alloc(pool, 240+4*160); pj_timestamp elapsed, zero, t1, t2; unsigned samples = 0; elapsed.u64 = 0; while (samples < 50000000) { pj_get_timestamp(&t1); pjmedia_move_samples(frame, frame+160, 240+2*160); pj_get_timestamp(&t2); pj_sub_timestamp(&t2, &t1); elapsed.u64 += t2.u64; memset(unused, 0, sizeof(unused)); samples += 160; } zero.u64 = 0; zero.u64 = pj_elapsed_usec(&zero, &elapsed); zero.u64 = samples * PJ_INT64(1000000) / zero.u64; assert(zero.u32.hi == 0); PJ_LOG(3,("test.c", "Processing: %f Msamples per second", zero.u32.lo/1000000.0)); PJ_LOG(3,("test.c", "CPU load for current settings: %f%%", CLOCK_RATE * 100.0 / zero.u32.lo)); }
static int PaPlayerCallback( const void *input, void *output, unsigned long frameCount, const PaStreamCallbackTimeInfo* timeInfo, PaStreamCallbackFlags statusFlags, void *userData ) { struct pa_aud_stream *stream = (struct pa_aud_stream*) userData; pj_status_t status = 0; unsigned nsamples_req = frameCount * stream->channel_count; PJ_UNUSED_ARG(input); PJ_UNUSED_ARG(timeInfo); if (stream->quit_flag) goto on_break; if (output == NULL) return paContinue; /* Known cases of callback's thread: * - The thread may be changed in the middle of a session, e.g: in MacOS * it happens when plugging/unplugging headphone. * - The same thread may be reused in consecutive sessions. The first * session will leave TLS set, but release the TLS data address, * so the second session must re-register the callback's thread. */ if (stream->play_thread_initialized == 0 || !pj_thread_is_registered()) { pj_bzero(stream->play_thread_desc, sizeof(pj_thread_desc)); status = pj_thread_register("portaudio", stream->play_thread_desc, &stream->play_thread); stream->play_thread_initialized = 1; PJ_LOG(5,(THIS_FILE, "Player thread started")); } if (statusFlags & paOutputUnderflow) ++stream->underflow; if (statusFlags & paOutputOverflow) ++stream->overflow; /* Check if any buffered samples */ if (stream->play_buf_count) { /* samples buffered >= requested by sound device */ if (stream->play_buf_count >= nsamples_req) { pjmedia_copy_samples((pj_int16_t*)output, stream->play_buf, nsamples_req); stream->play_buf_count -= nsamples_req; pjmedia_move_samples(stream->play_buf, stream->play_buf + nsamples_req, stream->play_buf_count); nsamples_req = 0; return paContinue; } /* samples buffered < requested by sound device */ pjmedia_copy_samples((pj_int16_t*)output, stream->play_buf, stream->play_buf_count); nsamples_req -= stream->play_buf_count; output = (pj_int16_t*)output + stream->play_buf_count; stream->play_buf_count = 0; } /* Fill output buffer as requested */ while (nsamples_req && status == 0) { if (nsamples_req >= stream->samples_per_frame) { pjmedia_frame frame; frame.type = PJMEDIA_FRAME_TYPE_AUDIO; frame.buf = output; frame.size = stream->samples_per_frame * stream->bytes_per_sample; frame.timestamp.u64 = stream->play_timestamp.u64; frame.bit_info = 0; status = (*stream->play_cb)(stream->user_data, &frame); if (status != PJ_SUCCESS) goto on_break; if (frame.type != PJMEDIA_FRAME_TYPE_AUDIO) pj_bzero(frame.buf, frame.size); nsamples_req -= stream->samples_per_frame; output = (pj_int16_t*)output + stream->samples_per_frame; } else { pjmedia_frame frame; frame.type = PJMEDIA_FRAME_TYPE_AUDIO; frame.buf = stream->play_buf; frame.size = stream->samples_per_frame * stream->bytes_per_sample; frame.timestamp.u64 = stream->play_timestamp.u64; frame.bit_info = 0; status = (*stream->play_cb)(stream->user_data, &frame); if (status != PJ_SUCCESS) goto on_break; if (frame.type != PJMEDIA_FRAME_TYPE_AUDIO) pj_bzero(frame.buf, frame.size); pjmedia_copy_samples((pj_int16_t*)output, stream->play_buf, nsamples_req); stream->play_buf_count = stream->samples_per_frame - nsamples_req; pjmedia_move_samples(stream->play_buf, stream->play_buf+nsamples_req, stream->play_buf_count); nsamples_req = 0; } stream->play_timestamp.u64 += stream->samples_per_frame / stream->channel_count; } if (status==0) return paContinue; on_break: stream->play_thread_exited = 1; return paAbort; }
/* callbacks to get data */ int bdimad_PlaybackCallback(void *buffer, int samples, void *user_data) { pj_status_t status = PJ_SUCCESS; pjmedia_frame frame; struct bd_stream *strm = (struct bd_stream*)user_data; unsigned nsamples_req = samples * strm->channel_count; if(!strm->go) goto on_break; /* Known cases of callback's thread: * - The thread may be changed in the middle of a session, e.g: in MacOS * it happens when plugging/unplugging headphone. * - The same thread may be reused in consecutive sessions. The first * session will leave TLS set, but release the TLS data address, * so the second session must re-register the callback's thread. */ if (strm->play_thread_initialized == 0 || !pj_thread_is_registered()) { pj_bzero(strm->play_thread_desc, sizeof(pj_thread_desc)); status = pj_thread_register("bd_PlaybackCallback", strm->play_thread_desc, &strm->play_thread); if (status != PJ_SUCCESS) goto on_break; strm->play_thread_initialized = 1; PJ_LOG(5,(THIS_FILE, "Player thread started")); } /* PLAY */ if(strm->fmt_id == PJMEDIA_FORMAT_L16) { /* Check if any buffered samples */ if (strm->play_buf_count) { /* samples buffered >= requested by sound device */ if (strm->play_buf_count >= nsamples_req) { pjmedia_copy_samples((pj_int16_t*)buffer, strm->play_buf, nsamples_req); strm->play_buf_count -= nsamples_req; pjmedia_move_samples(strm->play_buf, strm->play_buf + nsamples_req, strm->play_buf_count); return nsamples_req; } /* samples buffered < requested by sound device */ pjmedia_copy_samples((pj_int16_t*)buffer, strm->play_buf, strm->play_buf_count); nsamples_req -= strm->play_buf_count; buffer = (pj_int16_t*)buffer + strm->play_buf_count; strm->play_buf_count = 0; } /* Fill output buffer as requested */ while (nsamples_req && status == 0) { if (nsamples_req >= strm->samples_per_frame) { frame.type = PJMEDIA_FRAME_TYPE_AUDIO; frame.buf = buffer; frame.size = strm->bytes_per_frame; frame.timestamp.u64 = strm->timestampPlayback.u64; frame.bit_info = 0; status = (*strm->play_cb)(strm->user_data, &frame); if (status != PJ_SUCCESS) return 0; if (frame.type != PJMEDIA_FRAME_TYPE_AUDIO) pj_bzero(frame.buf, frame.size); nsamples_req -= strm->samples_per_frame; buffer = (pj_int16_t*)buffer + strm->samples_per_frame; } else { frame.type = PJMEDIA_FRAME_TYPE_AUDIO; frame.buf = strm->play_buf; frame.size = strm->bytes_per_frame; frame.timestamp.u64 = strm->timestampPlayback.u64; frame.bit_info = 0; status = (*strm->play_cb)(strm->user_data, &frame); if (status != PJ_SUCCESS) return 0; if (frame.type != PJMEDIA_FRAME_TYPE_AUDIO) pj_bzero(frame.buf, frame.size); pjmedia_copy_samples((pj_int16_t*)buffer, strm->play_buf, nsamples_req); strm->play_buf_count = strm->samples_per_frame - nsamples_req; pjmedia_move_samples(strm->play_buf, strm->play_buf+nsamples_req, strm->play_buf_count); nsamples_req = 0; } strm->timestampPlayback.u64 += strm->samples_per_frame / strm->channel_count; } } else { pj_assert(!"Frame type not supported"); } if(status != PJ_SUCCESS) { return 0; } strm->timestampPlayback.u64 += strm->param.samples_per_frame / strm->param.channel_count; if (status == 0) return samples; on_break: strm->play_thread_exited = 1; return 0; }