Example #1
0
void exit() {

	uae_quit();

	if(ctrlstate == UADE_R_STATE) {
		__android_log_print(ANDROID_LOG_VERBOSE, "UADE", "We are in R STATE ?!");
		if (uade_receive_message(um, sizeof(space), &uadeipc) <= 0)
			__android_log_print(ANDROID_LOG_VERBOSE, "UADE", "Can not receive events from uade");
		else
			__android_log_print(ANDROID_LOG_VERBOSE, "UADE", "Got msg %d", um->msgtype);
	}

	 if (uade_send_short_message(UADE_COMMAND_REBOOT, &state.ipc)) {
		 __android_log_print(ANDROID_LOG_VERBOSE, "UADEPlugin", "Send reboot failed");
	 }
	__android_log_print(ANDROID_LOG_VERBOSE, "UADEPlugin", "Waiting for UAE to exit");
	int rc = pthread_join(thread, NULL);
	__android_log_print(ANDROID_LOG_VERBOSE, "UADEPlugin", "Exit with %d", rc);
	thread = 0;

	if(soundBuffer)
		free(soundBuffer);
	soundBuffer = 0;

}
Example #2
0
static int wait_token()
{
	do
	{
		int ret = uade_receive_message(um, sizeof(space), &uadeipc);
		if(ret < 0)
		{
			__android_log_print(ANDROID_LOG_VERBOSE, "UADE", "\nCan not receive events (TOKEN) from uade.\n");
			return 0;
		}
		if (ret == 0)
		{
			__android_log_print(ANDROID_LOG_VERBOSE, "UADE", "\nEnd of input after reboot.\n");
			return 0;
		}
	} while (um->msgtype != UADE_COMMAND_TOKEN);
	return 1;
}
Example #3
0
/* this is called for each played song from newcpu.c/m68k_reset() */
void uade_reset(void)
{
  /* don't load anything under 0x1000 (execbase top at $1000) */
  const int modnameaddr = 0x00400;
  const int scoreaddr   = 0x01000;
  const int userstack   = 0x08500;
  const int superstack  = 0x08f00;
  const int playeraddr  = 0x09000;
  int relocaddr;
  int modaddr;
  int len;
  FILE *file;
  int bytesread;

  uint8_t command[UADE_MAX_MESSAGE_SIZE];
  struct uade_msg *um = (struct uade_msg *) command;

  int ret;

 nextsong:

  /* IMPORTANT:
     It seems that certain players don't work totally reliably if memory
     contains trash from previous songs. To be certain that each song is
     played from the same initial state of emulator we clear the memory
     from 0x400 to 'uade_highmem' each time a new song is played */
  uade_highmem = 0;
  while (uade_highmem < 0x800000) {
    if (!valid_address(0, uade_highmem + 0x10000))
      break;
    uade_highmem += 0x10000;
  }
  if (uade_highmem < 0x80000) {
    fprintf(stderr, "uadecore: There must be at least 512 KiB of amiga memory (%d bytes found).\n", uade_highmem);
    exit(-1);
  }
  if (uade_highmem < 0x200000) {
    fprintf(stderr, "uadecore: Warning: highmem == 0x%x (< 0x200000)!\n", uade_highmem);
  }
  memset(get_real_address(0), 0, uade_highmem);

  song.cur_subsong = song.min_subsong = song.max_subsong = 0;

  ret = uade_receive_string(song.scorename, UADE_COMMAND_SCORE, sizeof(song.scorename), &uadeipc);
  if (ret == 0) {
    fprintf(stderr, "uadecore: No more songs to play.\n");
    exit(0);
  } else if (ret < 0) {
    fprintf(stderr, "uadecore: Invalid input. Expected score name.\n");
    exit(-1);
  }
//	printf("got scorename %s\n",song.scorename);

  ret = uade_receive_string(song.playername, UADE_COMMAND_PLAYER, sizeof(song.playername), &uadeipc);
  if (ret == 0) {
    printf("uadecore: Expected player name. Got nothing.\n");
    exit(-1);
  } else if (ret < 0) {
    printf( "uadecore: Invalid input. Expected player name.\n");
    exit(-1);
  }
//	printf("got playername %s\n",song.playername);

  if (uade_dirname(uade_player_dir, song.playername, sizeof(uade_player_dir)) == NULL) {
    printf( "uadecore: Invalid dirname with player: %s\n", song.playername);
    exit(-1);
  }

  ret = uade_receive_message(um, sizeof command, &uadeipc);
  if (ret == 0) {
    printf("uadecore: Expected module name. Got nothing.\n");
    exit(-1);
  } else if (ret < 0) {
    printf( "uadecore: Invalid input. Expected module name.\n");
    exit(-1);
  }
  assert(um->msgtype == UADE_COMMAND_MODULE);
  if (um->size == 0) {
    song.modulename[0] = 0;
  } else {
    assert(um->size == (strlen((char *) um->data) + 1));
    strlcpy(song.modulename, (char *) um->data, sizeof(song.modulename));
  }
//	printf("got modulename %s\n",song.modulename);

  uade_set_automatic_song_end(1);

  uade_put_long(SCORE_EXEC_DEBUG, uade_execdebugboolean ? 0x12345678 : 0);
  uade_put_long(SCORE_VOLUME_TEST, voltestboolean);
  uade_put_long(SCORE_DMA_WAIT, uade_dmawait);
  uade_put_long(SCORE_MODULECHANGE, disable_modulechange);

  bytesread = uade_safe_load_name(playeraddr, song.playername, "player", uade_highmem - playeraddr);

  if (bytesread > (uade_highmem - playeraddr)) {
    fprintf (stderr, "uadecore: Player %s too big a file (%d bytes).\n", song.playername, bytesread);
    goto skiptonextsong;
  }
  if (bytesread == 0) {
    goto skiptonextsong;
  }

  /* fprintf(stderr, "uadecore: player '%s' (%d bytes)\n", song.playername, bytesread); */

  /* set player executable address for relocator */
  uade_put_long(SCORE_PLAYER_ADDR, playeraddr);
  len = uade_calc_reloc_size((uae_u32 *) get_real_address(playeraddr),
			     (uae_u32 *) get_real_address(playeraddr + bytesread));
  if (!len) {
    fprintf(stderr, "uadecore: Problem with reloc calculation.\n");
    goto skiptonextsong;
  }
  relocaddr  = ((playeraddr + bytesread) & 0x7FFFF000) + 0x4000;
  /* + 0x4000 for hippel coso (wasseremu) */
  modaddr = ((relocaddr + len) & 0x7FFFF000) + 0x2000;

  if (modaddr <= relocaddr) {
    /* this is very bad because sound core memory allocation will fail */
    fprintf(stderr, "uadecore: Warning: modaddr <= relocaddr: 0x%x <= 0x%x\n", modaddr, relocaddr);
  }

  uade_put_long(SCORE_RELOC_ADDR, relocaddr);  /*address for relocated player*/
  uade_put_long(SCORE_MODULE_ADDR, modaddr);   /* set module address */
  uade_put_long(SCORE_MODULE_LEN, 0);          /* set module size to zero */
  uade_put_long(SCORE_MODULE_NAME_ADDR, 0);    /* mod name address pointer */

  /* load the module if available */
  if (song.modulename[0]) {
    bytesread = uade_safe_load_name(modaddr, song.modulename, "module", uade_highmem - modaddr);
    if (bytesread > (uade_highmem - playeraddr)) {
      fprintf (stderr, "uadecore: Module %s too big a file (%d bytes).\n", song.modulename, bytesread);
      goto skiptonextsong;
    }
    if (bytesread == 0) {
      goto skiptonextsong;
    }

    uade_put_long(SCORE_MODULE_LEN, bytesread);

    if (!valid_address(modnameaddr, strlen(song.modulename) + 1)) {
      fprintf(stderr, "uadecore: Invalid address for modulename.\n");
      goto skiptonextsong;
    }

    strlcpy((char *) get_real_address(modnameaddr), song.modulename, 1024);
    uade_put_long(SCORE_MODULE_NAME_ADDR, modnameaddr);

  } else {

    if (!valid_address(modnameaddr, strlen(song.playername) + 1)) {
      fprintf(stderr, "uadecore: Invalid address for playername.\n");
      goto skiptonextsong;
    }

    strlcpy((char *) get_real_address(modnameaddr), song.playername, 1024);
    uade_put_long(SCORE_MODULE_NAME_ADDR, modnameaddr);

    bytesread = 0;
  }

  /* load sound core (score) */
  if ((file = fopen(song.scorename, "rb"))) {
    bytesread = uade_safe_load(scoreaddr, file, uade_highmem - scoreaddr);
    fclose(file);
  } else {
    fprintf (stderr, "uadecore: Can not load score (%s).\n", song.scorename);
    goto skiptonextsong;
  }

  m68k_areg(regs,7) = scoreaddr;
  m68k_setpc(scoreaddr);

  /* obey player format checking */
  uade_put_long(SCORE_FORCE, 0);
  /* set default subsong */
  uade_put_long(SCORE_SET_SUBSONG, 0);
  uade_put_long(SCORE_SUBSONG, 0);
  /* set PAL mode */
  uade_set_ntsc(0);

  /* pause bits (don't care!), for debugging purposes only */
  uade_put_long(SCORE_PREPAUSE, 0);
  uade_put_long(SCORE_POSTPAUSE, 0);
  /* set user and supervisor stack pointers */
  uade_put_long(SCORE_USER_STACK, userstack);
  uade_put_long(SCORE_SUPER_STACK, superstack);
  /* no message for score */
  uade_put_long(SCORE_OUTPUT_MSG, 0);
  if ((userstack - (scoreaddr + bytesread)) < 0x1000)
    fprintf(stderr, "uadecore: Amiga stack overrun warning.\n");

  flush_sound();

  /* note that uade_speed_hack can be negative (meaning that uade never uses
     speed hack, even if it's requested by the amiga player)! */
  uade_time_critical = 0;
  if (uade_speed_hack > 0) {
    uade_time_critical = 1;
  }

  uade_reboot = 0;

  uade_audio_output = 0;
  uade_audio_skip = 0;

  old_ledstate = gui_ledstate;

  if (uade_receive_short_message(UADE_COMMAND_TOKEN, &uadeipc)) {
    fprintf(stderr, "uadecore: Can not receive token in uade_reset().\n");
    exit(-1);
  }

  if (uade_send_short_message(UADE_REPLY_CAN_PLAY, &uadeipc)) {
    fprintf(stderr, "uadecore: Can not send 'CAN_PLAY' reply.\n");
    exit(-1);
  }
  if (uade_send_short_message(UADE_COMMAND_TOKEN, &uadeipc)) {
    fprintf(stderr, "uadecore: Can not send token from uade_reset().\n");
    exit(-1);
  }

  set_sound_freq(UADE_DEFAULT_FREQUENCY);
  epoptionsize = 0;

  return;

 skiptonextsong:
  fprintf(stderr, "uadecore: Can not play. Reboot.\n");

  if (uade_receive_short_message(UADE_COMMAND_TOKEN, &uadeipc)) {
    fprintf(stderr, "uadecore: Can not receive token in uade_reset().\n");
    exit(-1);
  }

  if (uade_send_short_message(UADE_REPLY_CANT_PLAY, &uadeipc)) {
    fprintf(stderr, "uadecore: Can not send 'CANT_PLAY' reply.\n");
    exit(-1);
  }
  if (uade_send_short_message(UADE_COMMAND_TOKEN, &uadeipc)) {
    fprintf(stderr, "uadecore: Can not send token from uade_reset().\n");
    exit(-1);
  }
  goto nextsong;
}
Example #4
0
void uade_handle_r_state(void)
{
  uint8_t space[UADE_MAX_MESSAGE_SIZE];
  struct uade_msg *um = (struct uade_msg *) space;
  int ret;
  uint32_t x, y;

  while (1) {

    ret = uade_receive_message(um, sizeof(space), &uadeipc);
    if (ret == 0) {
      fprintf(stderr, "uadecore: No more input. Exiting succesfully.\n");
		exit(0);
    } else if (ret < 0) {
      fprintf(stderr, "uadecore: Error on input. Exiting with error.\n");
		exit(-1);
    }

    if (um->msgtype == UADE_COMMAND_TOKEN)break;

    switch (um->msgtype) {
	case UADE_EXIT:
			//uade_reboot = 1;
			quit_program=1;
			break;
			
    case UADE_COMMAND_ACTIVATE_DEBUGGER:
      fprintf(stderr, "uadecore: Received activate debugger message.\n");
      activate_debugger();
      uade_debug = 1;
      break;

    case UADE_COMMAND_CHANGE_SUBSONG:
      if (uade_parse_u32_message(&x, um)) {
	fprintf(stderr, "uadecore: Invalid size with change subsong.\n");
	exit(-1);
      }
      change_subsong(x);
      break;

    case UADE_COMMAND_FILTER:
      if (uade_parse_two_u32s_message(&x, &y, um)) {
	fprintf(stderr, "uadecore: Invalid size with filter command\n");
	exit(-1);
      }
      audio_set_filter(x, y);
      break;

    case UADE_COMMAND_IGNORE_CHECK:
      /* override bit for sound format checking */
      uade_put_long(SCORE_FORCE, 1);
      break;

    case UADE_COMMAND_SET_FREQUENCY:
      if (uade_parse_u32_message(&x, um)) {
	fprintf(stderr, "Invalid frequency message size: %u\n", um->size);
	exit(-1);
      }
      set_sound_freq(x);
      break;

    case UADE_COMMAND_SET_PLAYER_OPTION:
      uade_check_fix_string(um, 256);
      add_ep_option((char *) um->data);
      break;

    case UADE_COMMAND_SET_RESAMPLING_MODE:
      uade_check_fix_string(um, 16);
      audio_set_resampler((char *) um->data);
      break;

    case UADE_COMMAND_SPEED_HACK:
      uade_time_critical = 1;
      break;

    case UADE_COMMAND_READ:
      if (uade_read_size != 0) {
	fprintf(stderr, "uadecore: Read not allowed when uade_read_size > 0.\n");
	exit(-1);
      }
      if (uade_parse_u32_message(&x, um)) {
	fprintf(stderr, "uadecore: Invalid size on read command.\n");
	exit(-1);
      }
      uade_read_size = x;
      if (uade_read_size == 0 || uade_read_size > MAX_SOUND_BUF_SIZE || (uade_read_size & 3) != 0) {
	fprintf(stderr, "uadecore: Invalid read size: %d\n", uade_read_size);
	exit(-1);
      }
      break;

    case UADE_COMMAND_REBOOT:
      uade_reboot = 1;
      break;

    case UADE_COMMAND_SET_NTSC:
      fprintf(stderr, "\nuadecore: Changing to NTSC mode.\n");
      uade_set_ntsc(1);
      break;

    case UADE_COMMAND_SONG_END_NOT_POSSIBLE:
      uade_set_automatic_song_end(0);
      break;

    case UADE_COMMAND_SET_SUBSONG:
      if (uade_parse_u32_message(&x, um)) {
	fprintf(stderr, "uadecore: Invalid size on set subsong command.\n");
	exit(-1);
      }
      uade_put_long(SCORE_SET_SUBSONG, 1);
      uade_put_long(SCORE_SUBSONG, x);
      break;

    case UADE_COMMAND_USE_TEXT_SCOPE:
      audio_use_text_scope();
      break;

    default:
      fprintf(stderr, "uadecore: Received invalid command %d\n", um->msgtype);
      exit(-1);
    }
  }
	
}
Example #5
0
static int run_client()
{

	// __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "UADE STATE %d", ctrlstate);

	if(ctrlstate == UADE_S_STATE)
	{
		if(uade_song_end_trigger) {
			__android_log_print(ANDROID_LOG_VERBOSE, "UADE", "song_end_trigger");
			return -1;
		}
		/*if(uade_song_end_trigger)
		{
			next_song = 1;
			if(uade_send_short_message(UADE_COMMAND_REBOOT, &uadeipc))
			{
				__android_log_print(ANDROID_LOG_VERBOSE, "UADE", "\nCan not send reboot\n");
				return 0;
			}
		}
		else */

		if(new_subsong >= 0)
		{
			state.song->cur_subsong = state.song->min_subsong + new_subsong;
			__android_log_print(ANDROID_LOG_VERBOSE, "UADE", "New subsong %d", state.song->cur_subsong);
			uade_change_subsong(&state);
			//uade_change_subsong(new_subsong, &uadeipc);
			new_subsong = -1;
		}

		if(state.config.no_filter_set) {
			uade_send_filter_command(&state);
			state.config.no_filter_set = 0;
		}

		if(state.config.panning_enable_set || state.config.panning_set) {
			uade_set_effects(&state);
			state.config.no_filter_set = 0;
			state.config.panning_set = 0;
			state.config.panning_enable_set = 0;
		}

		//if(state.config.use_ntsc_set) {
		//	uade_set_effects(&state);
		//	state.config.use_ntsc_set = 0;
		//}


		left = uade_read_request(&uadeipc); /* Request another batch of sample data from uadecore */

		if(uade_send_short_message(UADE_COMMAND_TOKEN, &uadeipc))
		{
			__android_log_print(ANDROID_LOG_VERBOSE, "UADE", "\nCan not send token\n");
			return 0;
		}
		ctrlstate = UADE_R_STATE;
	}

	/* receive ctrlstate */
	if(ctrlstate == UADE_R_STATE)
	{
		uint16_t *sm;

		if (uade_receive_message(um, sizeof(space), &uadeipc) <= 0)
		{
			__android_log_print(ANDROID_LOG_VERBOSE, "UADE", "\nCan not receive events from uade\n");
			return 0;
		}

		//__android_log_print(ANDROID_LOG_VERBOSE, "UADE", "Got msg %d", um->msgtype);

		switch (um->msgtype)
		{
		case UADE_COMMAND_TOKEN:
			ctrlstate = UADE_S_STATE;
			//__android_log_print(ANDROID_LOG_VERBOSE, "UADE", "Got token");
			break;

		case UADE_REPLY_DATA:
			sm = (uint16_t *)um->data;

			if(!soundPtr) {
				__android_log_print(ANDROID_LOG_VERBOSE, "UADE", "No soundPtr");
				return -1;
			}

			if(subsong_end)
			{
				playbytes = tailbytes; /* Determined by UADE_REPLY_SONG_END */
				tailbytes = 0;
			}
			else
				playbytes = um->size;


			if(1) //plugin.freq == 44100)
			{
				for (int i = 0; i < um->size/2; i++)
					soundPtr[i] = ntohs(sm[i]);

				soundPtr += (playbytes/2);
			}
			else
			if(0) // plugin.freq == 22050)
			{
				for (int i = 0; i < um->size/2; i+=4)
				{
					soundPtr[i/2] = (ntohs(sm[i]) + ntohs(sm[i+2])) / 2;
					soundPtr[i/2+1] = (ntohs(sm[i+1]) + ntohs(sm[i+3])) / 2;
				}

				soundPtr += (playbytes/4);
			}

			//dbprintf("Got %d bytes sampledata\n", playbytes);
			//__android_log_print(ANDROID_LOG_VERBOSE, "UADEPlugin", "Got %d bytes sampledata\n", playbytes);

//			time_bytes += playbytes;
			//assert(left >= um->size);
			left -= um->size;

			return 1;

			break;

		case UADE_REPLY_FORMATNAME:
			uade_check_fix_string(um, MAX_LEN);
			__android_log_print(ANDROID_LOG_VERBOSE, "UADE", "Format name: %s\n", (char*) um->data);
			strcpy(current_format, (char *)um->data);
			break;

		case UADE_REPLY_MODULENAME:
			uade_check_fix_string(um, MAX_LEN);
			__android_log_print(ANDROID_LOG_VERBOSE, "UADE", "Module name: %s\n", (char*) um->data);
			break;

		case UADE_REPLY_MSG:
			uade_check_fix_string(um, MAX_LEN);
			__android_log_print(ANDROID_LOG_VERBOSE, "UADE", "Message: %s\n", (char *) um->data);
			break;

		case UADE_REPLY_PLAYERNAME:
			uade_check_fix_string(um, MAX_LEN);
			__android_log_print(ANDROID_LOG_VERBOSE, "UADE", "Player name: %s\n", (char*) um->data);
			strcpy(current_format, (char *)um->data);
			break;

		case UADE_REPLY_SONG_END:
			if (um->size < 9)
			{
				__android_log_print(ANDROID_LOG_VERBOSE, "UADE", "Invalid song end reply\n");
				//exit(-1);
				return -1;
			}

			tailbytes = ntohl(((uint32_t *) um->data)[0]);
			uade_song_end_trigger = 1;
			__android_log_print(ANDROID_LOG_VERBOSE, "UADE", "Song end: %s", (char*)um->data+8);
			break;

		case UADE_REPLY_SUBSONG_INFO:
			if(um->size != 12)
			{
				__android_log_print(ANDROID_LOG_VERBOSE, "UADE", "subsong info: too short a message\n");
			}
			{
				unsigned int *u32ptr = (unsigned int *)um->data;
				int min_sub = ntohl(u32ptr[0]);
				int max_sub = ntohl(u32ptr[1]);
				int cur_sub = ntohl(u32ptr[2]);

				state.song->min_subsong = min_sub;
				state.song->max_subsong = max_sub;
				state.song->cur_subsong = cur_sub;
				startSong = cur_sub - min_sub;

				__android_log_print(ANDROID_LOG_VERBOSE, "UADE", "subsong: %d from range [%d, %d]\n", cur_sub, min_sub, max_sub);
			}
			break;
		case UADE_REPLY_CANT_PLAY:
		case UADE_REPLY_CAN_PLAY:
		default:
			__android_log_print(ANDROID_LOG_VERBOSE, "UADE", "Expected sound data. got %d.\n", um->msgtype);
			return 0;
		}
	}
	return 0;
}
Example #6
0
int play_loop(struct uade_state *state)
{
  uint16_t *sm;
  int i;
  uint32_t *u32ptr;

  uint8_t space[UADE_MAX_MESSAGE_SIZE];
  struct uade_msg *um = (struct uade_msg *) space;

  uint8_t sampledata[UADE_MAX_MESSAGE_SIZE];
  int left = 0;
  int what_was_left = 0;

  int subsong_end = 0;
  int next_song = 0;
  int ret;
  int new_sub;
  int tailbytes = 0;
  int playbytes;
  char *reason;
  int64_t skip_bytes;

  int record_playtime = 1;

  int64_t subsong_bytes = 0;
  int deciseconds;
  int jump_sub = 0;
  int have_subsong_info = 0;

  const int framesize = UADE_BYTES_PER_SAMPLE * UADE_CHANNELS;
  const int bytes_per_second = UADE_BYTES_PER_FRAME * state->config.frequency;

  enum uade_control_state controlstate = UADE_S_STATE;

  int plistdir = UADE_PLAY_NEXT;

  struct uade_ipc *ipc = &state->ipc;
  struct uade_song *us = state->song;
  struct uade_effect *ue = &state->effects;
  struct uade_config *uc = &state->config;

  uade_effect_reset_internals();

  /* Skip bytes must be a multiple of audio frame size */
  skip_bytes = uade_jump_pos * bytes_per_second;
  skip_bytes = (skip_bytes / framesize) * framesize;

  test_song_end_trigger(); /* clear a pending SIGINT */

  while (next_song == 0) {

    if (uade_terminated) {
      if (!uade_no_text_output)
	tprintf("\n");

      return UADE_PLAY_FAILURE;
    }

    if (controlstate == UADE_S_STATE) {

      if (skip_bytes == 0) {
	deciseconds = subsong_bytes * 10 / bytes_per_second;
	if (!uade_no_text_output) {
	  if (us->playtime >= 0) {
	    int ptimesecs = us->playtime / 1000;
	    int ptimesubsecs = (us->playtime / 100) % 10;
	    tprintf("Playing time position %d.%ds in subsong %d (all subs %d.%ds)  \r", deciseconds / 10, deciseconds % 10, us->cur_subsong == -1 ? 0 : us->cur_subsong, ptimesecs, ptimesubsecs);
	  } else {
	    tprintf("Playing time position %d.%ds in subsong %d                \r", deciseconds / 10, deciseconds % 10,  us->cur_subsong == -1 ? 0 : us->cur_subsong);
	  }
	  fflush(stdout);
	}
      }

      if (uc->action_keys) {
	switch ((ret = poll_terminal())) {
	case 0:
	  break;
	case '<':
	  plistdir = UADE_PLAY_PREVIOUS;
	  uade_song_end_trigger = 1;
	  record_playtime = 0;
	  break;
	case '.':
	  if (skip_bytes == 0) {
	    __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "\nSkipping 10 seconds\n");
	    skip_bytes = bytes_per_second * 10;
	  }
	  break;
	case ' ':
	case 'b':
	  subsong_end = 1;
	  record_playtime = 0;
	  break;
	case 'c':
	  pause_terminal();
	  break;
	case 'f':
	  uade_set_config_option(uc, UC_FORCE_LED, uc->led_state ? "off" : "on");
	  tprintf("\nForcing LED %s\n", (uc->led_state & 1) ? "ON" : "OFF");
	  uade_send_filter_command(state);
	  break;
	case 'g':
	  uade_effect_toggle(ue, UADE_EFFECT_GAIN);
	  tprintf("\nGain effect %s %s\n", uade_effect_is_enabled(ue, UADE_EFFECT_GAIN) ? "ON" : "OFF", (uade_effect_is_enabled(ue, UADE_EFFECT_ALLOW) == 0 && uade_effect_is_enabled(ue, UADE_EFFECT_GAIN)) ? "(Remember to turn ON postprocessing!)" : "");
	  break;
	case 'h':
	  tprintf("\n\n");
	  print_action_keys();
	  tprintf("\n");
	  break;
	case 'H':
	  uade_effect_toggle(ue, UADE_EFFECT_HEADPHONES);
	  tprintf("\nHeadphones effect %s %s\n", uade_effect_is_enabled(ue, UADE_EFFECT_HEADPHONES) ? "ON" : "OFF", (uade_effect_is_enabled(ue, UADE_EFFECT_ALLOW) == 0 && uade_effect_is_enabled(ue, UADE_EFFECT_HEADPHONES) == 1) ? "(Remember to turn ON postprocessing!)" : "");
	  break;
	case 'i':
	  if (!uade_no_text_output)
	    print_song_info(us, UADE_MODULE_INFO);
	  break;
	case 'I':
	  if (!uade_no_text_output)
	    print_song_info(us, UADE_HEX_DUMP_INFO);
	  break;
	case '\n':
	case 'n':
	  uade_song_end_trigger = 1;
	  record_playtime = 0;
	  break;
	case 'N':
	  uade_effect_toggle(ue, UADE_EFFECT_NORMALISE);
	  tprintf("\nNormalise effect %s\n", uade_effect_is_enabled(ue, UADE_EFFECT_NORMALISE) ? "ON" : "OFF");
	  break;
	case 'p':
	  uade_effect_toggle(ue, UADE_EFFECT_ALLOW);
	  tprintf("\nPostprocessing effects %s\n", uade_effect_is_enabled(ue, UADE_EFFECT_ALLOW) ? "ON" : "OFF");
	  break;
	case 'P':
	  uade_effect_toggle(ue, UADE_EFFECT_PAN);
	  tprintf("\nPanning effect %s %s\n", uade_effect_is_enabled(ue, UADE_EFFECT_PAN) ? "ON" : "OFF", (uade_effect_is_enabled(ue, UADE_EFFECT_ALLOW) == 0 && uade_effect_is_enabled(ue, UADE_EFFECT_PAN) == 1) ? "(Remember to turn ON postprocessing!)" : "");
	  break;

	case 'q':
	  tprintf("\n");
	  return UADE_PLAY_EXIT;

	case 's':
	  playlist_random(&uade_playlist, -1);
	  tprintf("\n%s mode\n", uade_playlist.randomize ? "Shuffle" : "Normal");
	  break;
	case 'v':
	  uc->verbose ^= 1;
	  tprintf("\nVerbose mode %s\n", uc->verbose ? "ON" : "OFF");
	  break;
	case 'x':
	  us->cur_subsong--;
	  subsong_end = 1;
	  jump_sub = 1;
	  record_playtime = 0;
	  break;
	case 'z':
	  record_playtime = 0;
	  if (us->cur_subsong == 0 ||
	      (us->min_subsong >= 0 && us->cur_subsong == us->min_subsong)) {
	    plistdir = UADE_PLAY_PREVIOUS;
	    uade_song_end_trigger = 1;
	    break;
	  }
	  new_sub = us->cur_subsong - 2;
	  if (new_sub < 0)
	    new_sub = -1;
	  if (us->min_subsong >= 0 && new_sub < us->min_subsong)
	    new_sub = us->min_subsong - 1;
	  us->cur_subsong = new_sub;
	  subsong_end = 1;
	  jump_sub = 1;
	  break;
	default:
	  if (isdigit(ret)) {
	    new_sub = ret - '0';
	    if (us->min_subsong >= 0 && new_sub < us->min_subsong) {
	      __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "\ntoo low a subsong number\n");
	      break;
	    }
	    if (us->max_subsong >= 0 && new_sub > us->max_subsong) {
	      __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "\ntoo high a subsong number\n");
	      break;
	    }
	    us->cur_subsong = new_sub - 1;
	    subsong_end = 1;
	    jump_sub = 1;
	    us->out_bytes = 0; /* to prevent timeout */
	    record_playtime = 0; /* to not record playtime */
	  } else if (!isspace(ret)) {
	    __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "\n%c is not a valid command\n", ret);
	  }
	}
      }

      if (uade_debug_trigger == 1) {
	if (uade_send_short_message(UADE_COMMAND_ACTIVATE_DEBUGGER, ipc)) {
	  __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "\nCan not active debugger\n");
	  return UADE_PLAY_FAILURE;
	}
	uade_debug_trigger = 0;
      }
      
      if (uade_info_mode && have_subsong_info) {
	/* we assume that subsong info is the last info we get */
	uade_song_end_trigger = 1;
	subsong_end = 0;
      }

      if (uade_song_end_trigger)
	record_playtime = 0;

      if (subsong_end && uade_song_end_trigger == 0) {

	if (jump_sub || (uc->one_subsong == 0 && us->cur_subsong != -1 && us->max_subsong != -1)) {

	  us->cur_subsong++;

	  jump_sub = 0;

	  if (us->cur_subsong > us->max_subsong) {
	    uade_song_end_trigger = 1;
	  } else {
	    subsong_end = 0;
	    subsong_bytes = 0;

	    uade_change_subsong(state);

	    __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "\nChanging to subsong %d from range [%d, %d]\n", us->cur_subsong, us->min_subsong, us->max_subsong);
	  }
	} else {
	  uade_song_end_trigger = 1;
	}
      }

      if (uade_song_end_trigger) {
	next_song = 1;
	if (uade_send_short_message(UADE_COMMAND_REBOOT, ipc)) {
	  __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "\nCan not send reboot\n");
	  return UADE_PLAY_FAILURE;
	}
	goto sendtoken;
      }

      left = uade_read_request(ipc);

    sendtoken:
      if (uade_send_short_message(UADE_COMMAND_TOKEN, ipc)) {
	__android_log_print(ANDROID_LOG_VERBOSE, "UADE", "\nCan not send token\n");
	return UADE_PLAY_FAILURE;
      }

      controlstate = UADE_R_STATE;

      if (what_was_left) {
	if (subsong_end) {
	  /* We can only rely on 'tailbytes' amount which was determined
	     earlier when UADE_REPLY_SONG_END happened */
	  playbytes = tailbytes;
	  tailbytes = 0;
	} else {
	  playbytes = what_was_left;
	}

	if (subsong_end == 0 && uade_song_end_trigger == 0 &&
	    uade_test_silence(um->data, playbytes, state)) {
	    
	  __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "\nsilence detected (%d seconds)\n", uc->silence_timeout);
	  subsong_end = 1;
	}

	us->out_bytes += playbytes;
	subsong_bytes += playbytes;

	if (skip_bytes > 0) {
	  if (playbytes <= skip_bytes) {
	    skip_bytes -= playbytes;
	    playbytes = 0;
	  } else {
	    playbytes -= skip_bytes;
	    memmove(sampledata, sampledata + skip_bytes, playbytes);
	    skip_bytes = 0;
	  }
	}

	uade_effect_run(ue, (int16_t *) sampledata, playbytes / framesize);

	if (!audio_play(sampledata, playbytes)) {
	  __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "\nlibao error detected.\n");
	  return UADE_PLAY_FAILURE;
	}

	if (uc->timeout != -1 && uc->use_timeouts) {
	  if (uade_song_end_trigger == 0) {
	    if (us->out_bytes / bytes_per_second >= uc->timeout) {
	      __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "\nSong end (timeout %ds)\n", uc->timeout);
	      uade_song_end_trigger = 1;
	      record_playtime = 0;
	    }
	  }
	}

	if (uc->subsong_timeout != -1 && uc->use_timeouts) {
	  if (subsong_end == 0 && uade_song_end_trigger == 0) {
	    if (subsong_bytes / bytes_per_second >= uc->subsong_timeout) {
	      __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "\nSong end (subsong timeout %ds)\n", uc->subsong_timeout);
	      subsong_end = 1;
	      record_playtime = 0;
	    }
	  }
	}
      }

    } else {

      /* receive state */

      if (uade_receive_message(um, sizeof(space), ipc) <= 0) {
	__android_log_print(ANDROID_LOG_VERBOSE, "UADE", "\nCan not receive events from uade\n");
	return UADE_PLAY_FAILURE;
      }
      
      switch (um->msgtype) {

      case UADE_COMMAND_TOKEN:
	controlstate = UADE_S_STATE;
	break;

      case UADE_REPLY_DATA:
	sm = (uint16_t *) um->data;
	for (i = 0; i < um->size; i += 2) {
	  *sm = ntohs(*sm);
	  sm++;
	}

	assert (left == um->size);
	assert (sizeof sampledata >= um->size);

	memcpy(sampledata, um->data, um->size);

	what_was_left = left;
	left = 0;
	break;
	
      case UADE_REPLY_FORMATNAME:
	uade_check_fix_string(um, 128);
	debug(uc->verbose, "\nFormat name: %s\n", (uint8_t *) um->data);
	if (uade_info_mode)
	  tprintf("formatname: %s\n", (char *) um->data);
	break;
	
      case UADE_REPLY_MODULENAME:
	uade_check_fix_string(um, 128);
	debug(uc->verbose, "\nModule name: %s\n", (uint8_t *) um->data);
	if (uade_info_mode)
	  tprintf("modulename: %s\n", (char *) um->data);
	break;

      case UADE_REPLY_MSG:
	uade_check_fix_string(um, 128);
	debug(uc->verbose, "\nMessage: %s\n", (char *) um->data);
	break;

      case UADE_REPLY_PLAYERNAME:
	uade_check_fix_string(um, 128);
	debug(uc->verbose, "\nPlayer name: %s\n", (uint8_t *) um->data);
	if (uade_info_mode)
	  tprintf("playername: %s\n", (char *) um->data);
	break;

      case UADE_REPLY_SONG_END:
	if (um->size < 9) {
	  __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "\nInvalid song end reply\n");
	  exit(-1);
	}
	tailbytes = ntohl(((uint32_t *) um->data)[0]);
	/* next ntohl() is only there for a principle. it is not useful */
	if (ntohl(((uint32_t *) um->data)[1]) == 0) {
	  /* normal happy song end. go to next subsong if any */
	  subsong_end = 1;
	} else {
	  /* unhappy song end (error in the 68k side). skip to next song
	     ignoring possible subsongs */
	  uade_song_end_trigger = 1;
	}
	i = 0;
	reason = (char *) &um->data[8];
	while (reason[i] && i < (um->size - 8))
	  i++;
	if (reason[i] != 0 || (i != (um->size - 9))) {
	  __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "\nbroken reason string with song end notice\n");
	  exit(-1);
	}
	__android_log_print(ANDROID_LOG_VERBOSE, "UADE", "\nSong end (%s)\n", reason);
	break;

      case UADE_REPLY_SUBSONG_INFO:
	if (um->size != 12) {
	  __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "\nsubsong info: too short a message\n");
	  exit(-1);
	}

	u32ptr = (uint32_t *) um->data;
	us->min_subsong = ntohl(u32ptr[0]);
	us->max_subsong = ntohl(u32ptr[1]);
	us->cur_subsong = ntohl(u32ptr[2]);

	debug(uc->verbose, "\nsubsong: %d from range [%d, %d]\n", us->cur_subsong, us->min_subsong, us->max_subsong);

	if (!(-1 <= us->min_subsong && us->min_subsong <= us->cur_subsong && us->cur_subsong <= us->max_subsong)) {
	  int tempmin = us->min_subsong, tempmax = us->max_subsong;
	  __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "\nThe player is broken. Subsong info does not match.\n");
	  us->min_subsong = tempmin <= tempmax ? tempmin : tempmax;
	  us->max_subsong = tempmax >= tempmin ? tempmax : tempmin;
	  if (us->cur_subsong > us->max_subsong)
	    us->max_subsong = us->cur_subsong;
	  else if (us->cur_subsong < us->min_subsong)
	    us->min_subsong = us->cur_subsong;
	}

	if ((us->max_subsong - us->min_subsong) != 0)
	  __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "\nThere are %d subsongs in range [%d, %d].\n", 1 + us->max_subsong - us->min_subsong, us->min_subsong, us->max_subsong);

	uade_lookup_volume_normalisation(state);

	have_subsong_info = 1;

	if (uade_info_mode)
	  tprintf("subsong_info: %d %d %d (cur, min, max)\n", us->cur_subsong, us->min_subsong, us->max_subsong);
	break;
	
      default:
	__android_log_print(ANDROID_LOG_VERBOSE, "UADE", "\nExpected sound data. got %u.\n", (unsigned int) um->msgtype);
	return UADE_PLAY_FAILURE;
      }
    }
  }

  if (record_playtime && us->md5[0] != 0) {
    uint32_t playtime = (us->out_bytes * 1000) / bytes_per_second;
    uade_add_playtime(us->md5, playtime);
  }

  do {
    ret = uade_receive_message(um, sizeof(space), ipc);
    if (ret < 0) {
      __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "\nCan not receive events (TOKEN) from uade.\n");
      return UADE_PLAY_FAILURE;
    }
    if (ret == 0) {
      __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "\nEnd of input after reboot.\n");
      return UADE_PLAY_FAILURE;
    }
  } while (um->msgtype != UADE_COMMAND_TOKEN);

  tprintf("\n");

  return plistdir;
}
Example #7
0
static void *play_loop(void *arg)
{
  enum uade_control_state controlstate = UADE_S_STATE;
  int ret;
  int left = 0;
  uint8_t space[UADE_MAX_MESSAGE_SIZE];
  struct uade_msg *um = (struct uade_msg *) space;
  int subsong_end = 0;
  uint16_t *sm;
  int i;
  unsigned int play_bytes, tailbytes = 0;
  uint64_t subsong_bytes = 0;
  char *reason;
  uint32_t *u32ptr;
  int writeoffs;
  int framesize = UADE_CHANNELS * UADE_BYTES_PER_SAMPLE;
  int song_end_trigger = 0;
  int64_t skip_bytes = 0;

  uade_lock();
  record_playtime = 1;
  uade_unlock();

  while (1) {
    if (controlstate == UADE_S_STATE) {

      assert(left == 0);

      if (abort_playing) {
    uade_lock();
    record_playtime = 0;
    uade_unlock();
    break;
      }

      uade_lock();
      if (uade_seek_forward) {
    skip_bytes += uade_seek_forward * UADE_BYTES_PER_FRAME * state.config.frequency;
    uade_ip.output->flush(uade_ip.output->written_time() + uade_seek_forward * 1000);
    uade_seek_forward = 0;
      }
      if (uade_select_sub != -1) {
    state.song->cur_subsong = uade_select_sub;

    uade_change_subsong(&state);

    uade_ip.output->flush(0);
    uade_select_sub = -1;
    subsong_end = 0;
    subsong_bytes = 0;

    /* we do this to avoid timeout, and to not record playtime */
    state.song->out_bytes = 0;
    record_playtime = 0;

    uade_info_string();
      }

      if (subsong_end && song_end_trigger == 0) {

    if (state.song->cur_subsong == -1 || state.song->max_subsong == -1) {
      song_end_trigger = 1;

    } else {

      state.song->cur_subsong++;

      if (state.song->cur_subsong > state.song->max_subsong) {
        song_end_trigger = 1;
      } else {
        int x = 0;

        uade_change_subsong(&state);

        while (uade_ip.output->buffer_playing()) {
          /* Sleep at most 5 secs */
          if (x >= 500) {
        __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "UADE: blocking work-around activated.\n");
        break;
          }
          x++;
          xmms_usleep(10000);
        }
        uade_ip.output->flush(0);
        subsong_end = 0;
        subsong_bytes = 0;

        uade_gui_subsong_changed(state.song->cur_subsong);

        uade_info_string();
      }
    }
      }
      uade_unlock();

      if (song_end_trigger) {
    /* We must drain the audio fast if abort_playing happens (e.g.
       the user changes song when we are here waiting the sound device) */
    while (uade_ip.output->buffer_playing() && abort_playing == 0)

      xmms_usleep(10000);
    break;
      }

      left = uade_read_request(&state.ipc);

      if (uade_send_short_message(UADE_COMMAND_TOKEN, &state.ipc)) {
    __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "Can not send token.\n");
    return NULL;
      }
      controlstate = UADE_R_STATE;

    } else {

      if (uade_receive_message(um, sizeof(space), &state.ipc) <= 0) {
    __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "Can not receive events from uade\n");
    exit(1);
      }

      switch (um->msgtype) {

      case UADE_COMMAND_TOKEN:
    controlstate = UADE_S_STATE;
    break;

      case UADE_REPLY_DATA:
    sm = (uint16_t *) um->data;
    for (i = 0; i < um->size; i += 2) {
      *sm = ntohs(*sm);
      sm++;
    }

    if (subsong_end) {
      play_bytes = tailbytes;
      tailbytes = 0;
    } else {
      play_bytes = um->size;
    }

    if (subsong_end == 0 && song_end_trigger == 0 &&
        uade_test_silence(um->data, play_bytes, &state)) {
      subsong_end = 1;
    }

    subsong_bytes += play_bytes;
    uade_lock();
    state.song->out_bytes += play_bytes;
    uade_unlock();

    if (skip_bytes > 0) {
      if (play_bytes <= skip_bytes) {
        skip_bytes -= play_bytes;
        play_bytes = 0;
      } else {
        play_bytes -= skip_bytes;
        skip_bytes = 0;
      }
    }

    uade_effect_run(&state.effects, (int16_t *) um->data, play_bytes / framesize);
    uade_ip.add_vis_pcm(uade_ip.output->written_time(), sample_format, UADE_CHANNELS, play_bytes, um->data);

    writeoffs = 0;
    while (writeoffs < play_bytes) {
      int writable;
      while ((writable = uade_ip.output->buffer_free()) <= 0) {
        if (abort_playing)
          goto nowrite;
        xmms_usleep(10000);
      }

      if (writable > (play_bytes - writeoffs))
        writable = play_bytes - writeoffs;

      uade_ip.output->write_audio(&um->data[writeoffs], writable);

      writeoffs += writable;
    }


      nowrite:

    if (state.config.timeout != -1 && state.config.use_timeouts) {
      if (song_end_trigger == 0) {
        uade_lock();
        if (state.song->out_bytes / (UADE_BYTES_PER_FRAME * state.config.frequency) >= state.config.timeout) {
          song_end_trigger = 1;
          record_playtime = 0;
        }
        uade_unlock();
      }
    }

    if (state.config.subsong_timeout != -1 && state.config.use_timeouts) {
      if (subsong_end == 0 && song_end_trigger == 0) {
        if (subsong_bytes / (UADE_BYTES_PER_FRAME * state.config.frequency) >= state.config.subsong_timeout) {
          subsong_end = 1;
          record_playtime = 0;
        }
      }
    }

    assert (left >= um->size);
    left -= um->size;
    break;

      case UADE_REPLY_FORMATNAME:
    uade_check_fix_string(um, 128);
    strlcpy(gui_formatname, (char *) um->data, sizeof gui_formatname);
    strlcpy(state.song->formatname, (char *) um->data, sizeof state.song->formatname);
    break;

      case UADE_REPLY_MODULENAME:
    uade_check_fix_string(um, 128);
    strlcpy(gui_modulename, (char *) um->data, sizeof gui_modulename);
    strlcpy(state.song->modulename, (char *) um->data, sizeof state.song->modulename);
    break;

      case UADE_REPLY_MSG:
    uade_check_fix_string(um, 128);
    plugindebug("Message: %s\n", (char *) um->data);
    break;

      case UADE_REPLY_PLAYERNAME:
    uade_check_fix_string(um, 128);
    strlcpy(gui_playername, (char *) um->data, sizeof gui_playername);
    strlcpy(state.song->playername, (char *) um->data, sizeof state.song->playername);
    break;

      case UADE_REPLY_SONG_END:
    if (um->size < 9) {
      __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "Invalid song end reply\n");
      exit(1);
    }
    tailbytes = ntohl(((uint32_t *) um->data)[0]);
    /* next ntohl() is only there for a principle. it is not useful */
    if (ntohl(((uint32_t *) um->data)[1]) == 0) {
      /* normal happy song end. go to next subsong if any */
      subsong_end = 1;
    } else {
      /* unhappy song end (error in the 68k side). skip to next song
         ignoring possible subsongs */
      song_end_trigger = 1;
    }
    i = 0;
    reason = (char *) &um->data[8];
    while (reason[i] && i < (um->size - 8))
      i++;
    if (reason[i] != 0 || (i != (um->size - 9))) {
      __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "Broken reason string with song end notice\n");
      exit(1);
    }
    break;

      case UADE_REPLY_SUBSONG_INFO:
    if (um->size != 12) {
      __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "subsong info: too short a message\n");
      exit(1);
    }
    u32ptr = (uint32_t *) um->data;
    uade_lock();
    state.song->min_subsong = ntohl(u32ptr[0]);
    state.song->max_subsong = ntohl(u32ptr[1]);
    state.song->cur_subsong = ntohl(u32ptr[2]);

    if (!(-1 <= state.song->min_subsong && state.song->min_subsong <= state.song->cur_subsong && state.song->cur_subsong <= state.song->max_subsong)) {
      int tempmin = state.song->min_subsong, tempmax = state.song->max_subsong;
      __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "uade: The player is broken. Subsong info does not match with %s.\n", gui_filename);
      state.song->min_subsong = tempmin <= tempmax ? tempmin : tempmax;
      state.song->max_subsong = tempmax >= tempmin ? tempmax : tempmin;
      if (state.song->cur_subsong > state.song->max_subsong)
        state.song->max_subsong = state.song->cur_subsong;
      else if (state.song->cur_subsong < state.song->min_subsong)
        state.song->min_subsong = state.song->cur_subsong;
    }
    uade_unlock();
    break;

      default:
    __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "Expected sound data. got %d.\n", um->msgtype);
    plugin_disabled = 1;
    return NULL;
      }
    }
  }

  last_beat_played = 1;

  if (uade_send_short_message(UADE_COMMAND_REBOOT, &state.ipc)) {
    __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "Can not send reboot.\n");
    return NULL;
  }

  if (uade_send_short_message(UADE_COMMAND_TOKEN, &state.ipc)) {
    __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "Can not send token.\n");
    return NULL;
  }

  do {
    ret = uade_receive_message(um, sizeof(space), &state.ipc);
    if (ret < 0) {
      __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "Can not receive events from uade.\n");
      return NULL;
    }
    if (ret == 0) {
      __android_log_print(ANDROID_LOG_VERBOSE, "UADE", "End of input after reboot.\n");
      return NULL;
    }
  } while (um->msgtype != UADE_COMMAND_TOKEN);

  return NULL;
}