/** * Play audio received from PJMEDIA */ static int pb_thread_func (void *arg) { struct bb10_stream* stream = (struct bb10_stream *) arg; int size = stream->pb_buf_size; unsigned long nframes = stream->pb_frames; void *user_data = stream->user_data; char *buf = stream->pb_buf; pj_timestamp tstamp; int result = 0; int policy; struct sched_param param; TRACE_((THIS_FILE, "pb_thread_func: size = %d ", size)); if (pthread_getschedparam(pthread_self(), &policy, ¶m) == 0) { param.sched_priority = 18; pthread_setschedparam (pthread_self(), policy, ¶m); } pj_bzero (buf, size); tstamp.u64 = 0; /* Do the final initialization now the thread has started. */ if ((result = snd_pcm_plugin_prepare(stream->pb_pcm, SND_PCM_CHANNEL_PLAYBACK)) < 0) { TRACE_((THIS_FILE, "pb_thread_func failed prepare = %d", result)); return PJ_SUCCESS; } while (!stream->quit) { pjmedia_frame frame; frame.type = PJMEDIA_FRAME_TYPE_AUDIO; /* pointer to buffer filled by PJMEDIA */ frame.buf = buf; frame.size = size; frame.timestamp.u64 = tstamp.u64; frame.bit_info = 0; /* Read the audio from pjmedia */ result = stream->pb_cb (user_data, &frame); if (result != PJ_SUCCESS || stream->quit) break; if (frame.type != PJMEDIA_FRAME_TYPE_AUDIO) pj_bzero (buf, size); /* Write 640 to play unit */ result = snd_pcm_plugin_write(stream->pb_pcm,buf,size); if (result != size || result < 0) { /* either the write to output device has failed or not the * full amount of bytes have been written. This usually happens * when audio routing is being changed by another thread * Use a status variable for reading the error */ snd_pcm_channel_status_t status; status.channel = SND_PCM_CHANNEL_PLAYBACK; if (snd_pcm_plugin_status (stream->pb_pcm, &status) < 0) { /* Call has failed nothing we can do except log and * continue */ PJ_LOG(4,(THIS_FILE, "underrun: playback channel status error")); } else { /* The status of the error has been read * RIM say these are expected so we can "re-prepare" the stream */ PJ_LOG(4,(THIS_FILE,"PLAY thread ERROR status = %d", status.status)); if (status.status == SND_PCM_STATUS_READY || status.status == SND_PCM_STATUS_UNDERRUN || status.status == SND_PCM_STATUS_ERROR ) { if (snd_pcm_plugin_prepare (stream->pb_pcm, SND_PCM_CHANNEL_PLAYBACK) < 0) { PJ_LOG(4,(THIS_FILE, "underrun: playback channel prepare error")); } } } } tstamp.u64 += nframes; } flush_play(stream); TRACE_((THIS_FILE, "pb_thread_func: Stopped")); return PJ_SUCCESS; }
/** * Play audio received from PJMEDIA */ static int pb_thread_func (void *arg) { struct bb10_stream* stream = (struct bb10_stream *) arg; /* Handle from bb10_open_playback */ /* Will be 640 */ int size = stream->pb_buf_size; /* 160 frames for 20ms */ unsigned long nframes = stream->pb_frames; void *user_data = stream->user_data; char *buf = stream->pb_buf; pj_timestamp tstamp; int result = 0; pj_bzero (buf, size); tstamp.u64 = 0; TRACE_((THIS_FILE, "pb_thread_func: size = %d ", size)); /* Do the final initialization now the thread has started. */ if ((result = snd_pcm_plugin_prepare(stream->pb_pcm, SND_PCM_CHANNEL_PLAYBACK)) < 0) { close_play_pcm(stream); TRACE_((THIS_FILE, "pb_thread_func failed prepare = %d", result)); return PJ_SUCCESS; } while (!stream->quit) { pjmedia_frame frame; frame.type = PJMEDIA_FRAME_TYPE_AUDIO; /* pointer to buffer filled by PJMEDIA */ frame.buf = buf; frame.size = size; frame.timestamp.u64 = tstamp.u64; frame.bit_info = 0; result = stream->pb_cb (user_data, &frame); if (result != PJ_SUCCESS || stream->quit) break; if (frame.type != PJMEDIA_FRAME_TYPE_AUDIO) pj_bzero (buf, size); /* Write 640 to play unit */ result = snd_pcm_plugin_write(stream->pb_pcm,buf,size); if (result != size || result < 0) { snd_pcm_channel_status_t status; if (snd_pcm_plugin_status (stream->pb_pcm, &status) < 0) { PJ_LOG(4,(THIS_FILE, "underrun: playback channel status error")); continue; } if (status.status == SND_PCM_STATUS_READY || status.status == SND_PCM_STATUS_UNDERRUN) { if (snd_pcm_plugin_prepare (stream->pb_pcm, SND_PCM_CHANNEL_PLAYBACK) < 0) { PJ_LOG(4,(THIS_FILE, "underrun: playback channel prepare error")); continue; } } TRACE_((THIS_FILE, "pb_thread_func failed write = %d", result)); } tstamp.u64 += nframes; } flush_play(stream); close_play_pcm(stream); TRACE_((THIS_FILE, "pb_thread_func: Stopped")); return PJ_SUCCESS; }