Ejemplo n.º 1
0
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(&params, &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;
}
Ejemplo n.º 2
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;
}