Пример #1
0
int mpeg_tell(int fd, int *pos, int *len)
{
    int rv = -1;
    if((handle != NULL) && (fd != -1))
    {
        off_t sample_off = 0;
        off_t frame_off = 0;
        double time_off = 0;
        double time_per_frame = 0;
        int samples_per_frame = 0;
        time_per_frame = mpg123_tpf(handle->mh);
        samples_per_frame = mpg123_spf(handle->mh);

        /* Determine current position */
        frame_off = mpg123_tellframe(handle->mh);
        time_off = frame_off * (double)time_per_frame;
        *pos = (int) time_off;

        /* Determine track duration */
        sample_off = mpg123_length(handle->mh);
        if(samples_per_frame != 0)
        {
            frame_off = sample_off / samples_per_frame;
            time_off = frame_off * (double)time_per_frame;
            *len = (int) time_off;
        }

        rv = 0;
    }
    return rv;
}
Пример #2
0
/* Go back to the start for the cyclic pausing. */
void pause_recycle(mpg123_handle *fr)
{
	/* Take care not to go backwards in time in steps of 1 frame
		 That is what the +1 is for. */
	pause_cycle=(int)(LOOP_CYCLES/mpg123_tpf(fr));
	offset-=pause_cycle;
}
Пример #3
0
int mp3file_determineStats(MP3File *mp3) {
	if (mp3 == NULL)
		return;

	int encoding;
	mpg123_handle* mh = mp3->handle;
	int err = mpg123_getformat(mh, &mp3->rate, &mp3->channels, &encoding);
	if (err == MPG123_NEED_MORE)
		return err;
	if (err != MPG123_OK) {
		printerr("mpg123_getformat", err);
		return err;
	}

	mpg123_format_none(mh);
	mpg123_format(mh, mp3->rate, mp3->channels, encoding);

	mp3->num_samples = mpg123_length(mh);
	mp3->samples_per_frame = mpg123_spf(mh);
	mp3->secs_per_frame = mpg123_tpf(mh);

	if (mp3->num_samples == MPG123_ERR || mp3->samples_per_frame < 0)
		mp3->num_frames = 0;
	else
		mp3->num_frames = mp3->num_samples / mp3->samples_per_frame;

	if (mp3->num_samples == MPG123_ERR || mp3->samples_per_frame < 0 || mp3->secs_per_frame < 0)
		mp3->duration = 0;
	else
		mp3->duration = mp3->num_samples / mp3->samples_per_frame * mp3->secs_per_frame;
	return err;
}
Пример #4
0
JNIEXPORT void JNICALL Java_com_axelby_mp3decoders_MPG123_feed
	(JNIEnv *env, jclass c, jlong handle, jbyteArray in_buffer, jint in_size)
{
	MP3File *mp3 = (MP3File*)handle;
	mpg123_handle *mh = mp3->handle;
	jboolean isCopy;
	jbyte* b = (*env)->GetByteArrayElements(env, in_buffer, &isCopy);

	int err = mpg123_feed(mh, b, in_size);
	if (err != MPG123_OK)
		__android_log_print(ANDROID_LOG_INFO, "podax-jni", "mpg123_feed error: %s", mpg123_plain_strerror(err));
	(*env)->ReleaseByteArrayElements(env, in_buffer, b, JNI_ABORT);

	if (mp3->rate == 0) {
		off_t frame_offset;
		unsigned char* audio;
		size_t bytes_done;
		err = mpg123_decode_frame(mh, &frame_offset, &audio, &bytes_done);
		if (err == MPG123_NEW_FORMAT) {
			int encoding;
			err = mpg123_getformat(mh, &mp3->rate, &mp3->channels, &encoding);
			if (err != MPG123_NEED_MORE && err != MPG123_OK) {
				printerr("mpg123_getformat", err);
				return;
			}

			mp3->samples_per_frame = mpg123_spf(mh);
			mp3->secs_per_frame = mpg123_tpf(mh);
		}
		if (err != MPG123_OK && err != MPG123_NEED_MORE)
			__android_log_print(ANDROID_LOG_INFO, "podax-jni", "cannot get rate: %s", mpg123_plain_strerror(err));
	}
}
Пример #5
0
JNIEXPORT jlong JNICALL Java_com_axelby_podax_player_MPG123_openFile
	(JNIEnv *env, jclass c, jstring filename)
{
    int err = MPG123_OK;
    mpg123_handle *mh = mpg123_new(NULL, &err);
    if (err == MPG123_OK && mh != NULL)
    {
        MP3File* mp3 = mp3file_init(mh);
        const char* fileString = (*env)->GetStringUTFChars(env, filename, NULL);
        err = mpg123_open(mh, fileString);
        (*env)->ReleaseStringUTFChars(env, filename, fileString);

        if (err == MPG123_OK)
        {
            int encoding;
            if (mpg123_getformat(mh, &mp3->rate, &mp3->channels, &encoding) == MPG123_OK)
            {
                if(encoding == MPG123_ENC_SIGNED_16)
                {
                    // Signed 16 is the default output format anyway;
                    // it would actually by only different if we forced it.
                    // So this check is here just for this explanation.

                    // Ensure that this output format will not change
                    // (it could, when we allow it).
                    mpg123_format_none(mh);
                    mpg123_format(mh, mp3->rate, mp3->channels, encoding);

                    mp3->buffer_size = mpg123_outblock(mh);
                    mp3->buffer = (unsigned char*)malloc(mp3->buffer_size);

                    mp3->num_samples = mpg123_length(mh);
					mp3->samples_per_frame = mpg123_spf(mh);
					mp3->secs_per_frame = mpg123_tpf(mh);

                    if (mp3->num_samples == MPG123_ERR || mp3->samples_per_frame < 0)
                        mp3->num_frames = 0;
                    else
                        mp3->num_frames = mp3->num_samples / mp3->samples_per_frame;

					if (mp3->num_samples == MPG123_ERR || mp3->samples_per_frame < 0 || mp3->secs_per_frame < 0)
						mp3->duration = 0;
					else
						mp3->duration = mp3->num_samples / mp3->samples_per_frame * mp3->secs_per_frame;

                    return (jlong)mp3;
                }
            }
        }
        mp3file_delete(mp3);
    } else {
		__android_log_write(ANDROID_LOG_INFO, "podax-jni", mpg123_plain_strerror(err));
	}
    return 0;
}
Пример #6
0
Файл: mp3.c Проект: XanClic/xply
static bool is_mp3(FILE *fp, struct file_type **ft)
{
    mpg123_init();

    int err;
    mpg123_handle *mh = mpg123_new(NULL, &err);

    if (mh == NULL)
    {
        fprintf(stderr, "Could not create mpg123 handle: %s\n", mpg123_plain_strerror(err));
        return false;
    }

    long pos = ftell(fp);

    if (mpg123_open_fd(mh, fileno(fp)) != MPG123_OK)
    {
        fseek(fp, pos, SEEK_SET);
        return false;
    }

    mpg123_scan(mh);

    struct mpg123_frameinfo fi;
    mpg123_info(mh, &fi);

    if (mpg123_format(mh, fi.rate, MPG123_STEREO, MPG123_ENC_SIGNED_16) != MPG123_OK)
    {
        fseek(fp, pos, SEEK_SET);
        return false;
    }

    off_t length = mpg123_length(mh);

    struct mp3_format *fmt = calloc(sizeof(*fmt), 1);
    *ft = &fmt->ft;
    fmt->mh = mh;
    fmt->tpf = mpg123_tpf(mh);
    fmt->ft.channels = 2;
    fmt->ft.position = 0;
    fmt->ft.length = (length + (fi.rate / 2)) / fi.rate;
    fmt->ft.sample_rate = fi.rate;
    fmt->ft.sample_size = 2;
    fmt->ft.sample_type = ST_SIGNED_INTEGER_LE;
    fmt->ft.bitrate = (double)fi.abr_rate;

    return true;
}
Пример #7
0
static void term_handle_key(mpg123_handle *fr, out123_handle *ao, char val)
{
	debug1("term_handle_key: %c", val);
	switch(tolower(val))
	{
	case MPG123_BACK_KEY:
		out123_pause(ao);
		out123_drop(ao);
		if(paused) pause_cycle=(int)(LOOP_CYCLES/mpg123_tpf(fr));

		if(mpg123_seek_frame(fr, 0, SEEK_SET) < 0)
		error1("Seek to begin failed: %s", mpg123_strerror(fr));

		framenum=0;
	break;
	case MPG123_NEXT_KEY:
		out123_pause(ao);
		out123_drop(ao);
		next_track();
	break;
	case MPG123_NEXT_DIR_KEY:
		out123_pause(ao);
		out123_drop(ao);
		next_dir();
	break;
	case MPG123_QUIT_KEY:
		debug("QUIT");
		if(stopped)
		{
			stopped = 0;
			out123_pause(ao); /* no chance for annoying underrun warnings */
			out123_drop(ao);
		}
		set_intflag();
		offset = 0;
	break;
	case MPG123_PAUSE_KEY:
		paused=1-paused;
		out123_pause(ao); /* underrun awareness */
		out123_drop(ao);
		if(paused)
		{
			/* Not really sure if that is what is wanted
				 This jumps in audio output, but has direct reaction to pausing loop. */
			out123_param_float(ao, OUT123_PRELOAD, 0.);
			pause_recycle(fr);
		}
		else
			out123_param_float(ao, OUT123_PRELOAD, param.preload);
		if(stopped)
			stopped=0;
		if(param.verbose)
			print_stat(fr, 0, ao);
		else
			fprintf(stderr, "%s", (paused) ? MPG123_PAUSED_STRING : MPG123_EMPTY_STRING);
	break;
	case MPG123_STOP_KEY:
	case ' ':
		/* TODO: Verify/ensure that there is no "chirp from the past" when
		   seeking while stopped. */
		stopped=1-stopped;
		if(paused) {
			paused=0;
			offset -= pause_cycle;
		}
		if(stopped)
			out123_pause(ao);
		else
		{
			if(offset) /* If position changed, old is outdated. */
				out123_drop(ao);
			/* No out123_continue(), that's triggered by out123_play(). */
		}
		if(param.verbose)
			print_stat(fr, 0, ao);
		else
			fprintf(stderr, "%s", (stopped) ? MPG123_STOPPED_STRING : MPG123_EMPTY_STRING);
	break;
	case MPG123_FINE_REWIND_KEY:
		seekmode(fr, ao);
		offset--;
	break;
	case MPG123_FINE_FORWARD_KEY:
		seekmode(fr, ao);
		offset++;
	break;
	case MPG123_REWIND_KEY:
		seekmode(fr, ao);
		  offset-=10;
	break;
	case MPG123_FORWARD_KEY:
		seekmode(fr, ao);
		offset+=10;
	break;
	case MPG123_FAST_REWIND_KEY:
		seekmode(fr, ao);
		offset-=50;
	break;
	case MPG123_FAST_FORWARD_KEY:
		seekmode(fr, ao);
		offset+=50;
	break;
	case MPG123_VOL_UP_KEY:
		mpg123_volume_change(fr, 0.02);
	break;
	case MPG123_VOL_DOWN_KEY:
		mpg123_volume_change(fr, -0.02);
	break;
	case MPG123_PITCH_UP_KEY:
	case MPG123_PITCH_BUP_KEY:
	case MPG123_PITCH_DOWN_KEY:
	case MPG123_PITCH_BDOWN_KEY:
	case MPG123_PITCH_ZERO_KEY:
	{
		double new_pitch = param.pitch;
		switch(val) /* Not tolower here! */
		{
			case MPG123_PITCH_UP_KEY:    new_pitch += MPG123_PITCH_VAL;  break;
			case MPG123_PITCH_BUP_KEY:   new_pitch += MPG123_PITCH_BVAL; break;
			case MPG123_PITCH_DOWN_KEY:  new_pitch -= MPG123_PITCH_VAL;  break;
			case MPG123_PITCH_BDOWN_KEY: new_pitch -= MPG123_PITCH_BVAL; break;
			case MPG123_PITCH_ZERO_KEY:  new_pitch = 0.0; break;
		}
		set_pitch(fr, ao, new_pitch);
		fprintf(stderr, "New pitch: %f\n", param.pitch);
	}
	break;
	case MPG123_VERBOSE_KEY:
		param.verbose++;
		if(param.verbose > VERBOSE_MAX)
		{
			param.verbose = 0;
			clear_stat();
		}
		mpg123_param(fr, MPG123_VERBOSE, param.verbose, 0);
	break;
	case MPG123_RVA_KEY:
		if(++param.rva > MPG123_RVA_MAX) param.rva = 0;
		if(param.verbose)
			fprintf(stderr, "\n");
		mpg123_param(fr, MPG123_RVA, param.rva, 0);
		mpg123_volume_change(fr, 0.);
	break;
	case MPG123_PREV_KEY:
		out123_pause(ao);
		out123_drop(ao);

		prev_track();
	break;
	case MPG123_PREV_DIR_KEY:
		out123_pause(ao);
		out123_drop(ao);
		prev_dir();
	break;
	case MPG123_PLAYLIST_KEY:
		fprintf(stderr, "%s\nPlaylist (\">\" indicates current track):\n", param.verbose ? "\n" : "");
		print_playlist(stderr, 1);
		fprintf(stderr, "\n");
	break;
	case MPG123_TAG_KEY:
		fprintf(stderr, "%s\n", param.verbose ? "\n" : "");
		print_id3_tag(fr, param.long_id3, stderr);
		fprintf(stderr, "\n");
	break;
	case MPG123_MPEG_KEY:
		if(param.verbose) print_stat(fr,0,ao); /* Make sure that we are talking about the correct frame. */
		fprintf(stderr, "\n");
		if(param.verbose > 1)
			print_header(fr);
		else
			print_header_compact(fr);
		fprintf(stderr, "\n");
	break;
	case MPG123_HELP_KEY:
	{ /* This is more than the one-liner before, but it's less spaghetti. */
		int i;
		fprintf(stderr,"\n\n -= terminal control keys =-\n");
		for(i=0; i<(sizeof(term_help)/sizeof(struct keydef)); ++i)
		{
			if(term_help[i].key2) fprintf(stderr, "[%c] or [%c]", term_help[i].key, term_help[i].key2);
			else fprintf(stderr, "[%c]", term_help[i].key);

			fprintf(stderr, "\t%s\n", term_help[i].desc);
		}
		fprintf(stderr, "\nAlso, the number row (starting at 1, ending at 0) gives you jump points into the current track at 10%% intervals.\n");
		fprintf(stderr, "\n");
	}
	break;
	case MPG123_FRAME_INDEX_KEY:
	case MPG123_VARIOUS_INFO_KEY:
		if(param.verbose) fprintf(stderr, "\n");
		switch(val) /* because of tolower() ... */
		{
			case MPG123_FRAME_INDEX_KEY:
			print_index(fr);
			{
				long accurate;
				if(mpg123_getstate(fr, MPG123_ACCURATE, &accurate, NULL) == MPG123_OK)
				fprintf(stderr, "Accurate position: %s\n", (accurate == 0 ? "no" : "yes"));
				else
				error1("Unable to get state: %s", mpg123_strerror(fr));
			}
			break;
			case MPG123_VARIOUS_INFO_KEY:
			{
				const char* curdec = mpg123_current_decoder(fr);
				if(curdec == NULL) fprintf(stderr, "Cannot get decoder info!\n");
				else fprintf(stderr, "Active decoder: %s\n", curdec);
			}
		}
	break;
	case '0':
	case '1':
	case '2':
	case '3':
	case '4':
	case '5':
	case '6':
	case '7':
	case '8':
	case '9':
	{
		off_t len;
		int num;
		num = val == '0' ? 10 : val - '0';
		--num; /* from 0 to 9 */

		/* Do not swith to seekmode() here, as we are jumping once to a
		   specific position. Dropping buffer contents is enough and there
		   is no race filling the buffer or waiting for more incremental
		   seek orders. */
		len = mpg123_length(fr);
		out123_pause(ao);
		out123_drop(ao);
		if(len > 0)
			mpg123_seek(fr, (off_t)( (num/10.)*len ), SEEK_SET);
	}
	break;
	case MPG123_BOOKMARK_KEY:
		continue_msg("BOOKMARK");
	break;
	default:
		;
	}
}
Пример #8
0
static void term_handle_input(mpg123_handle *fr, audio_output_t *ao, int do_delay)
{
  int n = 1;
  /* long offset = 0; */
  
  while(n > 0) {
    fd_set r;
    struct timeval t;
    char val;

    t.tv_sec=0;
    t.tv_usec=(do_delay) ? 10*1000 : 0;
    
    FD_ZERO(&r);
    FD_SET(0,&r);
    n = select(1,&r,NULL,NULL,&t);
    if(n > 0 && FD_ISSET(0,&r)) {
      if(read(0,&val,1) <= 0)
        break;

      switch(tolower(val)) {
	case MPG123_BACK_KEY:
        if(!param.usebuffer) ao->flush(ao);
				else buffer_resync();
		if(paused) pause_cycle=(int)(LOOP_CYCLES/mpg123_tpf(fr));

		if(mpg123_seek_frame(fr, 0, SEEK_SET) < 0)
		error1("Seek to begin failed: %s", mpg123_strerror(fr));

		framenum=0;
		break;
	case MPG123_NEXT_KEY:
		if(!param.usebuffer) ao->flush(ao);
		else buffer_resync(); /* was: plain_buffer_resync */
	  next_track();
	  break;
	case MPG123_QUIT_KEY:
		debug("QUIT");
		if(stopped)
		{
			stopped = 0;
			if(param.usebuffer)
			{
				buffer_resync();
				buffer_start();
			}
		}
		set_intflag();
		offset = 0;
	  break;
	case MPG123_PAUSE_KEY:
  	  paused=1-paused;
	  if(paused) {
			/* Not really sure if that is what is wanted
			   This jumps in audio output, but has direct reaction to pausing loop. */
			if(param.usebuffer) buffer_resync();

			pause_recycle(fr);
	  }
		if(stopped)
		{
			stopped=0;
			if(param.usebuffer) buffer_start();
		}
	  fprintf(stderr, "%s", (paused) ? MPG123_PAUSED_STRING : MPG123_EMPTY_STRING);
	  break;
	case MPG123_STOP_KEY:
	case ' ':
		/* when seeking while stopped and then resuming, I want to prevent the chirp from the past */
		if(!param.usebuffer) ao->flush(ao);
	  stopped=1-stopped;
	  if(paused) {
		  paused=0;
		  offset -= pause_cycle;
	  }
		if(param.usebuffer)
		{
			if(stopped) buffer_stop();
			else
			{
				/* When we stopped buffer for seeking, we must resync. */
				if(offset) buffer_resync();

				buffer_start();
			}
		}
	  fprintf(stderr, "%s", (stopped) ? MPG123_STOPPED_STRING : MPG123_EMPTY_STRING);
	  break;
	case MPG123_FINE_REWIND_KEY:
	  if(param.usebuffer) seekmode();
	  offset--;
	  break;
	case MPG123_FINE_FORWARD_KEY:
	  seekmode();
	  offset++;
	  break;
	case MPG123_REWIND_KEY:
	  seekmode();
  	  offset-=10;
	  break;
	case MPG123_FORWARD_KEY:
	  seekmode();
	  offset+=10;
	  break;
	case MPG123_FAST_REWIND_KEY:
	  seekmode();
	  offset-=50;
	  break;
	case MPG123_FAST_FORWARD_KEY:
	  seekmode();
	  offset+=50;
	  break;
	case MPG123_VOL_UP_KEY:
		mpg123_volume_change(fr, 0.02);
	break;
	case MPG123_VOL_DOWN_KEY:
		mpg123_volume_change(fr, -0.02);
	break;
	case MPG123_PITCH_UP_KEY:
	case MPG123_PITCH_BUP_KEY:
	case MPG123_PITCH_DOWN_KEY:
	case MPG123_PITCH_BDOWN_KEY:
	case MPG123_PITCH_ZERO_KEY:
	{
		double new_pitch = param.pitch;
		switch(val) /* Not tolower here! */
		{
			case MPG123_PITCH_UP_KEY:    new_pitch += MPG123_PITCH_VAL;  break;
			case MPG123_PITCH_BUP_KEY:   new_pitch += MPG123_PITCH_BVAL; break;
			case MPG123_PITCH_DOWN_KEY:  new_pitch -= MPG123_PITCH_VAL;  break;
			case MPG123_PITCH_BDOWN_KEY: new_pitch -= MPG123_PITCH_BVAL; break;
			case MPG123_PITCH_ZERO_KEY:  new_pitch = 0.0; break;
		}
		set_pitch(fr, ao, new_pitch);
		fprintf(stderr, "New pitch: %f\n", param.pitch);
	}
	break;
	case MPG123_VERBOSE_KEY:
		param.verbose++;
		if(param.verbose > VERBOSE_MAX)
		{
			param.verbose = 0;
			clear_stat();
		}
		mpg123_param(fr, MPG123_VERBOSE, param.verbose, 0);
	break;
	case MPG123_RVA_KEY:
		if(++param.rva > MPG123_RVA_MAX) param.rva = 0;
		mpg123_param(fr, MPG123_RVA, param.rva, 0);
		mpg123_volume_change(fr, 0.);
	break;
	case MPG123_PREV_KEY:
		if(!param.usebuffer) ao->flush(ao);
		else buffer_resync(); /* was: plain_buffer_resync */

		prev_track();
	break;
	case MPG123_PLAYLIST_KEY:
		fprintf(stderr, "%s\nPlaylist (\">\" indicates current track):\n", param.verbose ? "\n" : "");
		print_playlist(stderr, 1);
		fprintf(stderr, "\n");
	break;
	case MPG123_TAG_KEY:
		fprintf(stderr, "%s\n", param.verbose ? "\n" : "");
		print_id3_tag(fr, param.long_id3, stderr);
		fprintf(stderr, "\n");
	break;
	case MPG123_MPEG_KEY:
		if(param.verbose) print_stat(fr,0,0); /* Make sure that we are talking about the correct frame. */
		fprintf(stderr, "\n");
		print_header(fr);
		fprintf(stderr, "\n");
	break;
	case MPG123_HELP_KEY:
	{ /* This is more than the one-liner before, but it's less spaghetti. */
		int i;
		fprintf(stderr,"\n\n -= terminal control keys =-\n");
		for(i=0; i<(sizeof(term_help)/sizeof(struct keydef)); ++i)
		{
			if(term_help[i].key2) fprintf(stderr, "[%c] or [%c]", term_help[i].key, term_help[i].key2);
			else fprintf(stderr, "[%c]", term_help[i].key);

			fprintf(stderr, "\t%s\n", term_help[i].desc);
		}
		fprintf(stderr, "\n");
	}
	break;
	case MPG123_FRAME_INDEX_KEY:
	case MPG123_VARIOUS_INFO_KEY:
		if(param.verbose) fprintf(stderr, "\n");
		switch(val) /* because of tolower() ... */
		{
			case MPG123_FRAME_INDEX_KEY:
			print_index(fr);
			{
				long accurate;
				if(mpg123_getstate(fr, MPG123_ACCURATE, &accurate, NULL) == MPG123_OK)
				fprintf(stderr, "Accurate position: %s\n", (accurate == 0 ? "no" : "yes"));
				else
				error1("Unable to get state: %s", mpg123_strerror(fr));
			}
			break;
			case MPG123_VARIOUS_INFO_KEY:
			{
				const char* curdec = mpg123_current_decoder(fr);
				if(curdec == NULL) fprintf(stderr, "Cannot get decoder info!\n");
				else fprintf(stderr, "Active decoder: %s\n", curdec);
			}
		}
	break;
	default:
	  ;
      }
    }
  }
}
Пример #9
0
VALUE rb_mpg123_tpf(VALUE self)
{
  return rb_float_new(mpg123_tpf(DATA_PTR(self)));
}
Пример #10
0
void* player_thread(void* _mp3_info) 
{
  log_debug("player thread started");
  
  mp3_t* mp3_info = (mp3_t* ) _mp3_info;
  long current_position_in_ms = 0;
  long previous_position_in_ms = -1; 
  long guard_position_in_ms = -1;
  el_bool playing = el_false;
  pthread_t thread_id;
  int no_count = 0;
  
  post_event(mp3_info->client_notification, AUDIO_READY, current_position_in_ms);
 
  audio_event_t *event;
  event = audio_event_fifo_dequeue(mp3_info->player_control);
  while (event->state != INTERNAL_CMD_DESTROY) {
    
    if (event->state != INTERNAL_CMD_NONE) {
      log_debug4("event = %s, %ld, %s", audio_event_name(event->state), event->position_in_ms, mp3_info->file_or_url);
    }
    
    audio_state_t event_state = event->state;
    long event_position = event->position_in_ms;
    audio_event_destroy(event);
    
    switch (event_state) {
      case INTERNAL_CMD_LOAD_FILE: {
        playing = el_false;
        
        // Stop stream, if playing
        if (!mp3_info->is_file) {
          mp3_info->continue_streaming = el_false;
          psem_wait(mp3_info->stream_ready);
        }
        
        if (mp3_info->is_open) {
          mpg123_close(mp3_info->handle);
          aodev_close(mp3_info->ao_handle);
        }
        mpg123_open(mp3_info->handle, mp3_info->file_or_url);
        mpg123_getformat(mp3_info->handle, &mp3_info->rate, &mp3_info->channels, &mp3_info->encoding);
        mp3_info->buffer_size = mpg123_outblock(mp3_info->handle);
        mc_free(mp3_info->buffer);
        mp3_info->buffer = mc_malloc(mp3_info->buffer_size * sizeof(char) );
        int bytes_per_sample = get_encsize(mp3_info->encoding);
        aodev_set_format(mp3_info->ao_handle, bytes_per_sample * 8, mp3_info->rate, mp3_info->channels);
        aodev_open(mp3_info->ao_handle);
        mp3_info->is_open = el_true;
        mp3_info->is_file = el_true;
        mp3_info->can_seek = el_true;
        current_position_in_ms = 0;
        guard_position_in_ms = -1; 
        {
          off_t l = mpg123_length(mp3_info->handle);
          if (l == MPG123_ERR) {
            mp3_info->length = -1; 
          } else {
            mp3_info->length = (l * 1000) / mp3_info->rate;
          }
          psem_post(mp3_info->length_set);
        }
      }
      break;
      case INTERNAL_CMD_LOAD_URL: {
        playing = el_false;
        log_debug2("loading url %s", mp3_info->file_or_url);
        // Wait for feeding streams to end
        if (!mp3_info->is_file) {
          mp3_info->continue_streaming = el_false;
          psem_wait(mp3_info->stream_ready);
        }
        mp3_info->is_file = el_false;
        log_debug("current stream ended");
        
        if (mp3_info->is_open) {
          mpg123_close(mp3_info->handle);
          aodev_close(mp3_info->ao_handle);
          mp3_info->is_open = el_false;
        }
        log_debug("aodev closed");
        
        mpg123_open_feed(mp3_info->handle);
        log_debug("feed opened");
        
        pthread_create(&thread_id, NULL, stream_thread, mp3_info);
        log_debug("stream thread started");
        
        mp3_info->is_open = el_true;
        mp3_info->can_seek = el_false;
        current_position_in_ms = 0;
        guard_position_in_ms = -1;
        mp3_info->length = 0;
        mp3_info->continue_streaming = el_true;
        
        psem_post(mp3_info->length_set);
      }
      break;
      case INTERNAL_CMD_SEEK: {
        off_t pos = mpg123_timeframe(mp3_info->handle, (event_position / 1000.0));
        mpg123_seek_frame(mp3_info->handle, pos, SEEK_SET);
      }
      break;
      case INTERNAL_CMD_PLAY: {
        playing = el_true;
      }
      break;
      case INTERNAL_CMD_PAUSE: {
        playing = el_false;
      }
      break;
      case INTERNAL_CMD_GUARD: {
        guard_position_in_ms = event_position;
      }
      break;
      case INTERNAL_CMD_SET_VOLUME: {
        double volume = ((double) event_position) / 1000.0;
        mpg123_volume(mp3_info->handle, volume);
      }
      case INTERNAL_CMD_NONE:
      break;
      default:
      break;
    }
    
    //log_debug3("guard = %d, playing = %d", guard_position_in_ms, playing);
    if (guard_position_in_ms >= 0 && current_position_in_ms >= guard_position_in_ms) {

      guard_position_in_ms = -1;
      post_event(mp3_info->client_notification, AUDIO_GUARD_REACHED, current_position_in_ms);
      
    } else if (playing) {

      if (mp3_info->is_file) {  
        size_t bytes;
        int res = mpg123_read(mp3_info->handle, mp3_info->buffer, mp3_info->buffer_size, &bytes);
        if (res == MPG123_OK) {
          aodev_play_buffer(mp3_info->ao_handle, mp3_info->buffer, bytes);
          off_t frame = mpg123_tellframe(mp3_info->handle);
          double time_per_frame = (mpg123_tpf(mp3_info->handle)*1000.0);
          //static int prt = 1;
          //if (prt) { printf("tpf=%.6lf\n",time_per_frame);prt=0; }
          current_position_in_ms = (long) (frame * time_per_frame);    // 1 frame is about 26 milliseconds
          if (previous_position_in_ms == -1) previous_position_in_ms = current_position_in_ms;
          if ((current_position_in_ms - previous_position_in_ms) >= STATE_REPORT_THRESHOLD) {
            post_event(mp3_info->client_notification, AUDIO_PLAYING, current_position_in_ms);
          }
          previous_position_in_ms = current_position_in_ms;
        } else if (res == MPG123_DONE) {
          post_event(mp3_info->client_notification, AUDIO_EOS, current_position_in_ms);
          playing = el_false;
        } else {
          post_event(mp3_info->client_notification, AUDIO_STATE_ERROR, current_position_in_ms);
          playing = el_false;
        }
      } else { // Stream playing
        
        if (mp3_stream_fifo_peek(mp3_info->stream_fifo) != NULL) {
          el_bool go_on = el_true; 
          while (go_on && mp3_stream_fifo_peek(mp3_info->stream_fifo) != NULL) {
            memblock_t* blk = mp3_stream_fifo_dequeue(mp3_info->stream_fifo);
            
            mpg123_feed(mp3_info->handle, (const unsigned char*) memblock_as_str(blk), memblock_size(blk));
            memblock_destroy(blk);
            
            size_t done;
            int err;
            unsigned char *audio;
            off_t frame_offset;
            
            do {
              err = mpg123_decode_frame(mp3_info->handle, &frame_offset, &audio, &done);
              switch(err) {
                case MPG123_NEW_FORMAT:
                  mpg123_getformat(mp3_info->handle, &mp3_info->rate, &mp3_info->channels, &mp3_info->encoding);
                  if (aodev_is_open(mp3_info->ao_handle)) {
                    aodev_close(mp3_info->ao_handle);
                  }
                  aodev_set_format(mp3_info->ao_handle, get_encsize(mp3_info->encoding) * 8, mp3_info->rate, mp3_info->channels);
                  aodev_open(mp3_info->ao_handle);
                break;
                case MPG123_OK:
                  //log_debug2("playing buffer %d", done);
                  aodev_play_buffer(mp3_info->ao_handle, audio, done);
                  off_t frame = mpg123_tellframe(mp3_info->handle);
                  double time_per_frame = (mpg123_tpf(mp3_info->handle)*1000.0);
                  current_position_in_ms = (long) (frame * time_per_frame);    // 1 frame is about 26 milliseconds
                  if (previous_position_in_ms == -1) previous_position_in_ms = current_position_in_ms;
                  if ((current_position_in_ms - previous_position_in_ms) >= STATE_REPORT_THRESHOLD) {
                    post_event(mp3_info->client_notification, AUDIO_PLAYING, current_position_in_ms);
                  }
                  previous_position_in_ms = current_position_in_ms;
                  go_on = el_false;
                  break;
                case MPG123_NEED_MORE:
                  break;
                default:
                  break;
              }
            } while (done > 0);
          }
        } else {
          // no streaming data, prevent race conditions
          // sleep for a small time (50 ms);
          no_count += 1;
          if (no_count > 10) { 
            post_event(mp3_info->client_notification, AUDIO_BUFFERING, current_position_in_ms);
          }
          sleep_ms(50);
        }
      } 
    }
    
    if (playing) {
      if (audio_event_fifo_peek(mp3_info->player_control) != NULL) {
        event = audio_event_fifo_dequeue(mp3_info->player_control);
      } else {
        event = (audio_event_t*) mc_malloc(sizeof(audio_event_t));
        event->state = INTERNAL_CMD_NONE;
        event->position_in_ms = -1;
      }
    } else {
      //log_debug("waiting for next event");
      event = audio_event_fifo_dequeue(mp3_info->player_control);
    }
  }

  // destroy event received
  log_debug("destroy event received");
  
  // Kill playing streams
  if (mp3_info->streaming) {
    mp3_info->continue_streaming = el_false;
    psem_wait(mp3_info->stream_ready);
  }
  
  audio_event_destroy(event);

  // exit thread  
  return NULL;
}