static int ps3_audio_start(audio_mode_t *am, audio_fifo_t *af) { prop_sub_t *s_vol; audio_buf_t *ab; u32 port_num; AudioPortConfig config; int ret; int cur_channels = 0; int running = 0; sys_event_queue_t snd_queue; u64 snd_queue_key; int achannels = 0; if(audioInit()) return -1; s_vol = prop_subscribe(PROP_SUB_DIRECT_UPDATE, PROP_TAG_CALLBACK_FLOAT, set_mastervol, NULL, PROP_TAG_ROOT, prop_mastervol, NULL); TRACE(TRACE_DEBUG, "AUDIO", "PS3 audio system initialized"); while(1) { ab = af_deq2(af, !running, am); if(ab == AF_EXIT) { ab = NULL; break; } if(ab != NULL) { if(ab->ab_channels != cur_channels) { if(running) { audioPortStop(port_num); audioRemoveNotifyEventQueue(snd_queue_key); audioPortClose(port_num); sys_event_queue_destroy(snd_queue, 0); running = 0; } cur_channels = ab->ab_channels; AudioOutConfiguration conf; memset(&conf, 0, sizeof(conf)); switch(cur_channels) { case 2: achannels = 2; conf.channel = 2; conf.encoder = AUDIO_OUT_CODING_TYPE_LPCM; break; case 6: achannels = 8; if(max_pcm >= 6) { conf.channel = 6; conf.encoder = AUDIO_OUT_CODING_TYPE_LPCM; } else if(max_dts == 6) { conf.channel = 6; conf.encoder = AUDIO_OUT_CODING_TYPE_DTS; } else if(max_ac3 == 6) { conf.channel = 6; conf.encoder = AUDIO_OUT_CODING_TYPE_AC3; } else { conf.channel = 2; conf.encoder = AUDIO_OUT_CODING_TYPE_LPCM; conf.down_mixer = AUDIO_OUT_DOWNMIXER_TYPE_A; } break; case 7: case 8: achannels = 8; if(max_pcm == 8) { conf.channel = 8; conf.encoder = AUDIO_OUT_CODING_TYPE_LPCM; } else if(max_dts == 6) { conf.channel = 6; conf.encoder = AUDIO_OUT_CODING_TYPE_DTS; conf.down_mixer = AUDIO_OUT_DOWNMIXER_TYPE_B; } else if(max_ac3 == 6) { conf.channel = 6; conf.encoder = AUDIO_OUT_CODING_TYPE_AC3; conf.down_mixer = AUDIO_OUT_DOWNMIXER_TYPE_B; } else { conf.channel = 2; conf.encoder = AUDIO_OUT_CODING_TYPE_LPCM; conf.down_mixer = AUDIO_OUT_DOWNMIXER_TYPE_A; } break; } int r; r = audioOutConfigure(AUDIO_OUT_PRIMARY, &conf, NULL, 1); if(r == 0) { int i; for(i = 0; i < 100;i++) { AudioOutState state; r = audioOutGetState(AUDIO_OUT_PRIMARY, 0, &state ); if(r != 0) break; TRACE(TRACE_DEBUG, "AUDIO", "The state is %d", state.state); if(state.state == 2) continue; usleep(100); break; } } AudioPortParam params; params.numChannels = achannels; params.numBlocks = AUDIO_BLOCK_8; params.attr = 0; params.level = 1; ret = audioPortOpen(¶ms, &port_num); TRACE(TRACE_DEBUG, "AUDIO", "PS3 audio port %d opened", port_num); audioGetPortConfig(port_num, &config); audioCreateNotifyEventQueue(&snd_queue, &snd_queue_key); audioSetNotifyEventQueue(snd_queue_key); sys_event_queue_drain(snd_queue); audioPortStart(port_num); running = 1; } } playOneBlock((u64*)(u64)config.readIndex, (float*)(u64)config.audioDataStart, am, ab, snd_queue, achannels); if(ab != NULL) ab_free(ab); } TRACE(TRACE_DEBUG, "AUDIO", "leaving the loop"); if(running) { audioPortStop(port_num); audioRemoveNotifyEventQueue(snd_queue_key); audioPortClose(port_num); sys_event_queue_destroy(snd_queue, 0); } audioQuit(); prop_unsubscribe(s_vol); return 0; }
static int pa_audio_start(audio_mode_t *am, audio_fifo_t *af) { pa_audio_mode_t *pam = (pa_audio_mode_t *)am; audio_buf_t *ab = NULL; size_t l, length; int64_t pts; media_pipe_t *mp; int r = 0; pa_threaded_mainloop_lock(mainloop); #if PA_API_VERSION >= 12 pa_proplist *pl = pa_proplist_new(); pa_proplist_sets(pl, PA_PROP_APPLICATION_ID, "com.lonelycoder.hts.showtime"); pa_proplist_sets(pl, PA_PROP_APPLICATION_NAME, "Showtime"); /* Create a new connection context */ pam->context = pa_context_new_with_proplist(api, "Showtime", pl); pa_proplist_free(pl); #else pam->context = pa_context_new(api, "Showtime"); #endif if(pam->context == NULL) { pa_threaded_mainloop_unlock(mainloop); return -1; } pa_context_set_state_callback(pam->context, context_state_callback, pam); /* Connect the context */ if(pa_context_connect(pam->context, NULL, 0, NULL) < 0) { TRACE(TRACE_ERROR, "PA", "pa_context_connect() failed: %s", pa_strerror(pa_context_errno(pam->context))); pa_threaded_mainloop_unlock(mainloop); return -1; } /* Need at least one packet of audio */ /* Subscribe to updates of master volume */ pam->sub_mvol = prop_subscribe(PROP_SUB_DIRECT_UPDATE, PROP_TAG_CALLBACK_FLOAT, set_mastervol, pam, PROP_TAG_ROOT, prop_mastervol, PROP_TAG_EXTERNAL_LOCK, mainloop, prop_pa_lockmgr, NULL); /* Subscribe to updates of master volume mute */ pam->sub_mute = prop_subscribe(PROP_SUB_DIRECT_UPDATE, PROP_TAG_CALLBACK_INT, set_mastermute, pam, PROP_TAG_ROOT, prop_mastermute, PROP_TAG_EXTERNAL_LOCK, mainloop, prop_pa_lockmgr, NULL); while(1) { if(ab == NULL) { pa_threaded_mainloop_unlock(mainloop); ab = af_deq2(af, 1, am); pa_threaded_mainloop_lock(mainloop); if(ab == AF_EXIT) { ab = NULL; break; } } if(pa_context_get_state(pam->context) == PA_CONTEXT_TERMINATED || pa_context_get_state(pam->context) == PA_CONTEXT_FAILED) { r = -1; break; } if(pam->stream != NULL && (pam->cur_format != ab->ab_format || pam->cur_rate != ab->ab_samplerate || pam->cur_isfloat != ab->ab_isfloat)) { stream_destroy(pam); } if(pam->stream == NULL && pa_context_get_state(pam->context) == PA_CONTEXT_READY) { /* Context is ready, but we don't have a stream yet, set it up */ stream_setup(pam, ab); } if(pam->stream == NULL) { pa_threaded_mainloop_wait(mainloop); continue; } switch(pa_stream_get_state(pam->stream)) { case PA_STREAM_UNCONNECTED: case PA_STREAM_CREATING: pa_threaded_mainloop_wait(mainloop); continue; case PA_STREAM_READY: break; case PA_STREAM_TERMINATED: case PA_STREAM_FAILED: pa_stream_unref(pam->stream); pam->stream = NULL; char msg[100]; snprintf(msg, sizeof(msg), "Audio stream disconnected from " "PulseAudio server -- %s.", pa_strerror(pam->stream_error)); mp_flush(ab->ab_mp, 0); mp_enqueue_event(ab->ab_mp, event_create_str(EVENT_INTERNAL_PAUSE, msg)); audio_fifo_purge(af, NULL, NULL); if(ab != NULL) { ab_free(ab); ab = NULL; } continue; } if(ab->ab_flush) { pa_operation *o; o = pa_stream_flush(pam->stream, NULL, NULL); if(o != NULL) pa_operation_unref(o); ab->ab_flush = 0; } l = pa_stream_writable_size(pam->stream); if(l == 0) { pa_threaded_mainloop_wait(mainloop); continue; } length = ab->ab_frames * pa_frame_size(&pam->ss) - ab->ab_tmp; if(l > length) l = length; if((pts = ab->ab_pts) != AV_NOPTS_VALUE && ab->ab_mp != NULL) { int64_t pts; pa_usec_t delay; pts = ab->ab_pts; ab->ab_pts = AV_NOPTS_VALUE; if(!pa_stream_get_latency(pam->stream, &delay, NULL)) { mp = ab->ab_mp; hts_mutex_lock(&mp->mp_clock_mutex); mp->mp_audio_clock = pts - delay; mp->mp_audio_clock_realtime = showtime_get_ts(); mp->mp_audio_clock_epoch = ab->ab_epoch; hts_mutex_unlock(&mp->mp_clock_mutex); } } pa_stream_write(pam->stream, ab->ab_data + ab->ab_tmp, l, NULL, 0LL, PA_SEEK_RELATIVE); ab->ab_tmp += l; assert(ab->ab_tmp <= ab->ab_frames * pa_frame_size(&pam->ss)); if(ab->ab_frames * pa_frame_size(&pam->ss) == ab->ab_tmp) { ab_free(ab); ab = NULL; } } prop_unsubscribe(pam->sub_mvol); prop_unsubscribe(pam->sub_mute); if(pam->stream != NULL) stream_destroy(pam); pa_threaded_mainloop_unlock(mainloop); pa_context_unref(pam->context); if(ab != NULL) { ab_free(ab); ab = NULL; } return r; }