static void file_write(void *ptr, gint length) { int len = convert_process (ptr, length); plugin->write(convert_output, len); samples_written += length / FMT_SIZEOF (input.format); }
static int pulse_open(int fmt, int rate, int nch) { pa_sample_spec ss; pa_operation *o = NULL; int success; assert(!mainloop); assert(!context); assert(!stream); assert(!connected); switch(fmt) { case FMT_U8: ss.format = PA_SAMPLE_U8; break; case FMT_S16_LE: ss.format = PA_SAMPLE_S16LE; break; case FMT_S16_BE: ss.format = PA_SAMPLE_S16BE; break; #ifdef PA_SAMPLE_S24_32LE case FMT_S24_LE: ss.format = PA_SAMPLE_S24_32LE; break; case FMT_S24_BE: ss.format = PA_SAMPLE_S24_32BE; break; #endif #ifdef PA_SAMPLE_S32LE case FMT_S32_LE: ss.format = PA_SAMPLE_S32LE; break; case FMT_S32_BE: ss.format = PA_SAMPLE_S32BE; break; #endif case FMT_FLOAT: ss.format = PA_SAMPLE_FLOAT32NE; break; default: return FALSE; } ss.rate = rate; ss.channels = nch; if (!pa_sample_spec_valid(&ss)) return FALSE; if (!(mainloop = pa_threaded_mainloop_new())) { ERROR ("Failed to allocate main loop"); goto fail; } pa_threaded_mainloop_lock(mainloop); if (!(context = pa_context_new(pa_threaded_mainloop_get_api(mainloop), "Audacious"))) { ERROR ("Failed to allocate context"); goto unlock_and_fail; } pa_context_set_state_callback(context, context_state_cb, NULL); pa_context_set_subscribe_callback(context, subscribe_cb, NULL); if (pa_context_connect(context, NULL, 0, NULL) < 0) { ERROR ("Failed to connect to server: %s", pa_strerror(pa_context_errno(context))); goto unlock_and_fail; } if (pa_threaded_mainloop_start(mainloop) < 0) { ERROR ("Failed to start main loop"); goto unlock_and_fail; } /* Wait until the context is ready */ pa_threaded_mainloop_wait(mainloop); if (pa_context_get_state(context) != PA_CONTEXT_READY) { ERROR ("Failed to connect to server: %s", pa_strerror(pa_context_errno(context))); goto unlock_and_fail; } if (!(stream = pa_stream_new(context, "Audacious", &ss, NULL))) { ERROR ("Failed to create stream: %s", pa_strerror(pa_context_errno(context))); goto unlock_and_fail; } pa_stream_set_state_callback(stream, stream_state_cb, NULL); pa_stream_set_write_callback(stream, stream_request_cb, NULL); pa_stream_set_latency_update_callback(stream, stream_latency_update_cb, NULL); /* Connect stream with sink and default volume */ /* Buffer struct */ int aud_buffer = aud_get_int(NULL, "output_buffer_size"); size_t buffer_size = pa_usec_to_bytes(aud_buffer, &ss) * 1000; pa_buffer_attr buffer = {(uint32_t) -1, buffer_size, (uint32_t) -1, (uint32_t) -1, buffer_size}; if (pa_stream_connect_playback(stream, NULL, &buffer, PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE, NULL, NULL) < 0) { ERROR ("Failed to connect stream: %s", pa_strerror(pa_context_errno(context))); goto unlock_and_fail; } /* Wait until the stream is ready */ pa_threaded_mainloop_wait(mainloop); if (pa_stream_get_state(stream) != PA_STREAM_READY) { ERROR ("Failed to connect stream: %s", pa_strerror(pa_context_errno(context))); goto unlock_and_fail; } /* Now subscribe to events */ if (!(o = pa_context_subscribe(context, PA_SUBSCRIPTION_MASK_SINK_INPUT, context_success_cb, &success))) { ERROR ("pa_context_subscribe() failed: %s", pa_strerror(pa_context_errno(context))); goto unlock_and_fail; } success = 0; while (pa_operation_get_state(o) != PA_OPERATION_DONE) { CHECK_DEAD_GOTO(fail, 1); pa_threaded_mainloop_wait(mainloop); } if (!success) { ERROR ("pa_context_subscribe() failed: %s", pa_strerror(pa_context_errno(context))); goto unlock_and_fail; } pa_operation_unref(o); /* Now request the initial stream info */ if (!(o = pa_context_get_sink_input_info(context, pa_stream_get_index(stream), info_cb, NULL))) { ERROR ("pa_context_get_sink_input_info() failed: %s", pa_strerror(pa_context_errno(context))); goto unlock_and_fail; } while (pa_operation_get_state(o) != PA_OPERATION_DONE) { CHECK_DEAD_GOTO(fail, 1); pa_threaded_mainloop_wait(mainloop); } if (!volume_valid) { ERROR ("pa_context_get_sink_input_info() failed: %s", pa_strerror(pa_context_errno(context))); goto unlock_and_fail; } pa_operation_unref(o); do_trigger = 0; written = 0; flush_time = 0; bytes_per_second = FMT_SIZEOF (fmt) * nch * rate; connected = 1; volume_time_event = NULL; pa_threaded_mainloop_unlock(mainloop); return TRUE; unlock_and_fail: if (o) pa_operation_unref(o); pa_threaded_mainloop_unlock(mainloop); fail: pulse_close(); return FALSE; }
static gboolean ffaudio_play (const gchar * filename, VFSFile * file) { AUDDBG ("Playing %s.\n", filename); if (! file) return FALSE; AVPacket pkt = {.data = NULL}; gint errcount; gboolean codec_opened = FALSE; gint out_fmt; gboolean planar; gboolean seekable; gboolean error = FALSE; void *buf = NULL; gint bufsize = 0; AVFormatContext * ic = open_input_file (filename, file); if (! ic) return FALSE; CodecInfo cinfo; if (! find_codec (ic, & cinfo)) { fprintf (stderr, "ffaudio: No codec found for %s.\n", filename); goto error_exit; } AUDDBG("got codec %s for stream index %d, opening\n", cinfo.codec->name, cinfo.stream_idx); if (avcodec_open2 (cinfo.context, cinfo.codec, NULL) < 0) goto error_exit; codec_opened = TRUE; switch (cinfo.context->sample_fmt) { case AV_SAMPLE_FMT_U8: out_fmt = FMT_U8; planar = FALSE; break; case AV_SAMPLE_FMT_S16: out_fmt = FMT_S16_NE; planar = FALSE; break; case AV_SAMPLE_FMT_S32: out_fmt = FMT_S32_NE; planar = FALSE; break; case AV_SAMPLE_FMT_FLT: out_fmt = FMT_FLOAT; planar = FALSE; break; case AV_SAMPLE_FMT_U8P: out_fmt = FMT_U8; planar = TRUE; break; case AV_SAMPLE_FMT_S16P: out_fmt = FMT_S16_NE; planar = TRUE; break; case AV_SAMPLE_FMT_S32P: out_fmt = FMT_S32_NE; planar = TRUE; break; case AV_SAMPLE_FMT_FLTP: out_fmt = FMT_FLOAT; planar = TRUE; break; default: fprintf (stderr, "ffaudio: Unsupported audio format %d\n", (int) cinfo.context->sample_fmt); goto error_exit; } /* Open audio output */ AUDDBG("opening audio output\n"); if (aud_input_open_audio(out_fmt, cinfo.context->sample_rate, cinfo.context->channels) <= 0) { error = TRUE; goto error_exit; } AUDDBG("setting parameters\n"); aud_input_set_bitrate(ic->bit_rate); errcount = 0; seekable = ffaudio_codec_is_seekable(cinfo.codec); while (! aud_input_check_stop ()) { int seek_value = aud_input_check_seek (); if (seek_value >= 0 && seekable) { if (av_seek_frame (ic, -1, (gint64) seek_value * AV_TIME_BASE / 1000, AVSEEK_FLAG_ANY) < 0) { _ERROR("error while seeking\n"); } else errcount = 0; seek_value = -1; } AVPacket tmp; gint ret; /* Read next frame (or more) of data */ if ((ret = av_read_frame(ic, &pkt)) < 0) { if (ret == AVERROR_EOF) { AUDDBG("eof reached\n"); break; } else { if (++errcount > 4) { _ERROR("av_read_frame error %d, giving up.\n", ret); break; } else continue; } } else errcount = 0; /* Ignore any other substreams */ if (pkt.stream_index != cinfo.stream_idx) { av_free_packet(&pkt); continue; } /* Decode and play packet/frame */ memcpy(&tmp, &pkt, sizeof(tmp)); while (tmp.size > 0 && ! aud_input_check_stop ()) { /* Check for seek request and bail out if we have one */ if (seek_value < 0) seek_value = aud_input_check_seek (); if (seek_value >= 0) break; #if CHECK_LIBAVCODEC_VERSION (55, 28, 1) AVFrame * frame = av_frame_alloc (); #else AVFrame * frame = avcodec_alloc_frame (); #endif int decoded = 0; int len = avcodec_decode_audio4 (cinfo.context, frame, & decoded, & tmp); if (len < 0) { fprintf (stderr, "ffaudio: decode_audio() failed, code %d\n", len); break; } tmp.size -= len; tmp.data += len; if (! decoded) continue; gint size = FMT_SIZEOF (out_fmt) * cinfo.context->channels * frame->nb_samples; if (planar) { if (bufsize < size) { buf = g_realloc (buf, size); bufsize = size; } audio_interlace ((const void * *) frame->data, out_fmt, cinfo.context->channels, buf, frame->nb_samples); aud_input_write_audio (buf, size); } else aud_input_write_audio (frame->data[0], size); #if CHECK_LIBAVCODEC_VERSION (55, 28, 1) av_frame_free (& frame); #else avcodec_free_frame (& frame); #endif } if (pkt.data) av_free_packet(&pkt); } error_exit: if (pkt.data) av_free_packet(&pkt); if (codec_opened) avcodec_close(cinfo.context); if (ic != NULL) close_input_file(ic); g_free (buf); return ! error; }
/* * Start playing the given file */ bool_t xs_play_file(const char *filename, VFSFile *file) { xs_tuneinfo_t *tmpTune; int audioBufSize, bufRemaining, tmpLength, subTune = -1; char *audioBuffer = NULL, *oversampleBuffer = NULL; Tuple *tmpTuple; uri_parse (filename, NULL, NULL, NULL, & subTune); /* Get tune information */ pthread_mutex_lock(&xs_status_mutex); if (! (xs_status.tuneInfo = xs_sidplayfp_getinfo (filename))) { pthread_mutex_unlock(&xs_status_mutex); return FALSE; } /* Initialize the tune */ if (! xs_sidplayfp_load (& xs_status, filename)) { pthread_mutex_unlock(&xs_status_mutex); xs_tuneinfo_free(xs_status.tuneInfo); xs_status.tuneInfo = NULL; return FALSE; } bool_t error = FALSE; /* Set general status information */ tmpTune = xs_status.tuneInfo; if (subTune < 1 || subTune > xs_status.tuneInfo->nsubTunes) xs_status.currSong = xs_status.tuneInfo->startTune; else xs_status.currSong = subTune; int channels = xs_status.audioChannels; /* Allocate audio buffer */ audioBufSize = xs_status.audioFrequency * channels * FMT_SIZEOF (FMT_S16_NE); if (audioBufSize < 512) audioBufSize = 512; audioBuffer = (char *) malloc(audioBufSize); if (audioBuffer == NULL) { xs_error("Couldn't allocate memory for audio data buffer!\n"); pthread_mutex_unlock(&xs_status_mutex); goto xs_err_exit; } /* Check minimum playtime */ tmpLength = tmpTune->subTunes[xs_status.currSong - 1].tuneLength; if (xs_cfg.playMinTimeEnable && (tmpLength >= 0)) { if (tmpLength < xs_cfg.playMinTime) tmpLength = xs_cfg.playMinTime; } /* Initialize song */ if (!xs_sidplayfp_initsong(&xs_status)) { xs_error("Couldn't initialize SID-tune '%s' (sub-tune #%i)!\n", tmpTune->sidFilename, xs_status.currSong); pthread_mutex_unlock(&xs_status_mutex); goto xs_err_exit; } /* Open the audio output */ if (!aud_input_open_audio(FMT_S16_NE, xs_status.audioFrequency, channels)) { xs_error("Couldn't open audio output (fmt=%x, freq=%i, nchan=%i)!\n", FMT_S16_NE, xs_status.audioFrequency, channels); pthread_mutex_unlock(&xs_status_mutex); goto xs_err_exit; } /* Set song information for current subtune */ xs_sidplayfp_updateinfo(&xs_status); tmpTuple = tuple_new_from_filename(tmpTune->sidFilename); xs_get_song_tuple_info(tmpTuple, tmpTune, xs_status.currSong); pthread_mutex_unlock(&xs_status_mutex); aud_input_set_tuple(tmpTuple); while (! aud_input_check_stop ()) { bufRemaining = xs_sidplayfp_fillbuffer(&xs_status, audioBuffer, audioBufSize); aud_input_write_audio (audioBuffer, bufRemaining); /* Check if we have played enough */ if (xs_cfg.playMaxTimeEnable) { if (xs_cfg.playMaxTimeUnknown) { if (tmpLength < 0 && aud_input_written_time() >= xs_cfg.playMaxTime * 1000) break; } else { if (aud_input_written_time() >= xs_cfg.playMaxTime * 1000) break; } } if (tmpLength >= 0) { if (aud_input_written_time() >= tmpLength * 1000) break; } } DONE: free(audioBuffer); free(oversampleBuffer); /* Set playing status to false (stopped), thus when * XMMS next calls xs_get_time(), it can return appropriate * value "not playing" status and XMMS knows to move to * next entry in the playlist .. or whatever it wishes. */ pthread_mutex_lock(&xs_status_mutex); /* Free tune information */ xs_sidplayfp_delete(&xs_status); xs_tuneinfo_free(xs_status.tuneInfo); xs_status.tuneInfo = NULL; pthread_mutex_unlock(&xs_status_mutex); /* Exit the playing thread */ return ! error; xs_err_exit: error = TRUE; goto DONE; }