diff options
author | wm4 <wm4@nowhere> | 2012-11-05 17:02:04 +0100 |
---|---|---|
committer | wm4 <wm4@nowhere> | 2012-11-12 20:06:14 +0100 |
commit | d4bdd0473d6f43132257c9fb3848d829755167a3 (patch) | |
tree | 8021c2f7da1841393c8c832105e20cd527826d6c /libao2/ao_portaudio.c | |
parent | bd48deba77bd5582c5829d6fe73a7d2571088aba (diff) | |
download | mpv-d4bdd0473d6f43132257c9fb3848d829755167a3.tar.bz2 mpv-d4bdd0473d6f43132257c9fb3848d829755167a3.tar.xz |
Rename directories, move files (step 1 of 2) (does not compile)
Tis drops the silly lib prefixes, and attempts to organize the tree in
a more logical way. Make the top-level directory less cluttered as
well.
Renames the following directories:
libaf -> audio/filter
libao2 -> audio/out
libvo -> video/out
libmpdemux -> demux
Split libmpcodecs:
vf* -> video/filter
vd*, dec_video.* -> video/decode
mp_image*, img_format*, ... -> video/
ad*, dec_audio.* -> audio/decode
libaf/format.* is moved to audio/ - this is similar to how mp_image.*
is located in video/.
Move most top-level .c/.h files to core. (talloc.c/.h is left on top-
level, because it's external.) Park some of the more annoying files
in compat/. Some of these are relicts from the time mplayer used
ffmpeg internals.
sub/ is not split, because it's too much of a mess (subtitle code is
mixed with OSD display and rendering).
Maybe the organization of core is not ideal: it mixes playback core
(like mplayer.c) and utility helpers (like bstr.c/h). Should the need
arise, the playback core will be moved somewhere else, while core
contains all helper and common code.
Diffstat (limited to 'libao2/ao_portaudio.c')
-rw-r--r-- | libao2/ao_portaudio.c | 431 |
1 files changed, 0 insertions, 431 deletions
diff --git a/libao2/ao_portaudio.c b/libao2/ao_portaudio.c deleted file mode 100644 index 36b08f8288..0000000000 --- a/libao2/ao_portaudio.c +++ /dev/null @@ -1,431 +0,0 @@ -/* - * This file is part of mplayer2. - * - * mplayer2 is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * mplayer2 is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with mplayer2. If not, see <http://www.gnu.org/licenses/>. - */ - -#include <stdlib.h> -#include <stdbool.h> -#include <string.h> -#include <stdlib.h> -#include <assert.h> -#include <pthread.h> - -#include <libavutil/common.h> -#include <portaudio.h> - -#include "config.h" -#include "subopt-helper.h" -#include "libaf/format.h" -#include "mp_msg.h" -#include "audio_out.h" - -struct priv { - PaStream *stream; - int framelen; - - pthread_mutex_t ring_mutex; - - // protected by ring_mutex - unsigned char *ring; - int ring_size; // max size of the ring - int read_pos; // points to first byte that can be read - int read_len; // number of bytes that can be read - double play_time; // time when last packet returned to PA is on speaker - // 0 is N/A (0 is not a valid PA time value) - int play_silence; // play this many bytes of silence, before real data - bool play_remaining;// play what's left in the buffer, then stop stream -}; - -struct format_map { - int mp_format; - PaSampleFormat pa_format; -}; - -static const struct format_map format_maps[] = { - // first entry is the default format - {AF_FORMAT_S16_NE, paInt16}, - {AF_FORMAT_S24_NE, paInt24}, - {AF_FORMAT_S32_NE, paInt32}, - {AF_FORMAT_S8, paInt8}, - {AF_FORMAT_U8, paUInt8}, - {AF_FORMAT_FLOAT_NE, paFloat32}, - {AF_FORMAT_UNKNOWN, 0} -}; - -static void print_help(void) -{ - mp_msg(MSGT_AO, MSGL_FATAL, - "\n-ao portaudio commandline help:\n" - "Example: mpv -ao portaudio:device=subdevice\n" - "\nOptions:\n" - " device=subdevice\n" - " Audio device PortAudio should use. Devices can be listed\n" - " with -ao portaudio:device=help\n" - " The subdevice can be passed as index, or as complete name.\n"); -} - -static bool check_pa_ret(int ret) -{ - if (ret < 0) { - mp_msg(MSGT_AO, MSGL_ERR, "[portaudio] %s\n", - Pa_GetErrorText(ret)); - if (ret == paUnanticipatedHostError) { - const PaHostErrorInfo* hosterr = Pa_GetLastHostErrorInfo(); - mp_msg(MSGT_AO, MSGL_ERR, "[portaudio] Host error: %s\n", - hosterr->errorText); - } - return false; - } - return true; -} - -// Amount of bytes that contain audio of the given duration, aligned to frames. -static int seconds_to_bytes(struct ao *ao, double duration_seconds) -{ - struct priv *priv = ao->priv; - - int bytes = duration_seconds * ao->bps; - if (bytes % priv->framelen) - bytes += priv->framelen - (bytes % priv->framelen); - return bytes; -} - -static int to_int(const char *s, int return_on_error) -{ - char *endptr; - int res = strtol(s, &endptr, 10); - return (s[0] && !endptr[0]) ? res : return_on_error; -} - -static int find_device(struct ao *ao, const char *name) -{ - int help = strcmp(name, "help") == 0; - int count = Pa_GetDeviceCount(); - check_pa_ret(count); - int found = paNoDevice; - int index = to_int(name, -1); - if (help) - mp_msg(MSGT_AO, MSGL_INFO, "PortAudio devices:\n"); - for (int n = 0; n < count; n++) { - const PaDeviceInfo* info = Pa_GetDeviceInfo(n); - if (help) { - if (info->maxOutputChannels < 1) - continue; - mp_msg(MSGT_AO, MSGL_INFO, " %d '%s', %d channels, latency: %.2f " - "ms, sample rate: %.0f\n", n, info->name, - info->maxOutputChannels, - info->defaultHighOutputLatency * 1000, - info->defaultSampleRate); - } - if (strcmp(name, info->name) == 0 || n == index) { - found = n; - break; - } - } - if (found == paNoDevice && !help) - mp_msg(MSGT_AO, MSGL_FATAL, "[portaudio] Device '%s' not found!\n", - name); - return found; -} - -static int ring_write(struct ao *ao, unsigned char *data, int len) -{ - struct priv *priv = ao->priv; - - int free = priv->ring_size - priv->read_len; - int write_pos = (priv->read_pos + priv->read_len) % priv->ring_size; - int write_len = FFMIN(len, free); - int len1 = FFMIN(priv->ring_size - write_pos, write_len); - int len2 = write_len - len1; - - memcpy(priv->ring + write_pos, data, len1); - memcpy(priv->ring, data + len1, len2); - - priv->read_len += write_len; - - return write_len; -} - -static int ring_read(struct ao *ao, unsigned char *data, int len) -{ - struct priv *priv = ao->priv; - - int read_len = FFMIN(len, priv->read_len); - int len1 = FFMIN(priv->ring_size - priv->read_pos, read_len); - int len2 = read_len - len1; - - memcpy(data, priv->ring + priv->read_pos, len1); - memcpy(data + len1, priv->ring, len2); - - priv->read_len -= read_len; - priv->read_pos = (priv->read_pos + read_len) % priv->ring_size; - - return read_len; -} - -static void fill_silence(unsigned char *ptr, int len) -{ - memset(ptr, 0, len); -} - -static int stream_callback(const void *input, - void *output_v, - unsigned long frameCount, - const PaStreamCallbackTimeInfo *timeInfo, - PaStreamCallbackFlags statusFlags, - void *userData) -{ - struct ao *ao = userData; - struct priv *priv = ao->priv; - int res = paContinue; - unsigned char *output = output_v; - int len_bytes = frameCount * priv->framelen; - - pthread_mutex_lock(&priv->ring_mutex); - - // NOTE: PA + ALSA in dmix mode seems to pretend that there is no latency - // (outputBufferDacTime == currentTime) - priv->play_time = timeInfo->outputBufferDacTime - + len_bytes / (float)ao->bps; - - if (priv->play_silence > 0) { - int bytes = FFMIN(priv->play_silence, len_bytes); - fill_silence(output, bytes); - priv->play_silence -= bytes; - len_bytes -= bytes; - output += bytes; - } - int read = ring_read(ao, output, len_bytes); - len_bytes -= read; - output += read; - - if (len_bytes > 0) { - if (priv->play_remaining) { - res = paComplete; - priv->play_remaining = false; - } else { - mp_msg(MSGT_AO, MSGL_ERR, "[portaudio] Buffer underflow!\n"); - } - fill_silence(output, len_bytes); - } - - pthread_mutex_unlock(&priv->ring_mutex); - - return res; -} - -static void uninit(struct ao *ao, bool cut_audio) -{ - struct priv *priv = ao->priv; - - if (priv->stream) { - if (!cut_audio && Pa_IsStreamActive(priv->stream) == 1) { - pthread_mutex_lock(&priv->ring_mutex); - - priv->play_remaining = true; - - pthread_mutex_unlock(&priv->ring_mutex); - - check_pa_ret(Pa_StopStream(priv->stream)); - } - check_pa_ret(Pa_CloseStream(priv->stream)); - } - - pthread_mutex_destroy(&priv->ring_mutex); - Pa_Terminate(); -} - -static int init(struct ao *ao, char *params) -{ - struct priv *priv = talloc_zero(ao, struct priv); - ao->priv = priv; - - if (!check_pa_ret(Pa_Initialize())) - return -1; - - pthread_mutex_init(&priv->ring_mutex, NULL); - - char *device = NULL; - const opt_t subopts[] = { - {"device", OPT_ARG_MSTRZ, &device, NULL}, - {NULL} - }; - if (subopt_parse(params, subopts) != 0) { - print_help(); - goto error_exit; - } - - int pa_device = Pa_GetDefaultOutputDevice(); - if (device) - pa_device = find_device(ao, device); - if (pa_device == paNoDevice) - goto error_exit; - - PaStreamParameters sp = { - .device = pa_device, - .channelCount = ao->channels, - .suggestedLatency - = Pa_GetDeviceInfo(pa_device)->defaultHighOutputLatency, - }; - - const struct format_map *fmt = format_maps; - while (fmt->pa_format) { - if (fmt->mp_format == ao->format) { - PaStreamParameters test = sp; - test.sampleFormat = fmt->pa_format; - if (Pa_IsFormatSupported(NULL, &test, ao->samplerate) == paNoError) - break; - } - fmt++; - } - if (!fmt->pa_format) { - mp_msg(MSGT_AO, MSGL_V, - "[portaudio] Unsupported format, using default.\n"); - fmt = format_maps; - } - - ao->format = fmt->mp_format; - sp.sampleFormat = fmt->pa_format; - priv->framelen = ao->channels * (af_fmt2bits(ao->format) / 8); - ao->bps = ao->samplerate * priv->framelen; - - if (!check_pa_ret(Pa_IsFormatSupported(NULL, &sp, ao->samplerate))) - goto error_exit; - if (!check_pa_ret(Pa_OpenStream(&priv->stream, NULL, &sp, ao->samplerate, - paFramesPerBufferUnspecified, paNoFlag, - stream_callback, ao))) - goto error_exit; - - priv->ring_size = seconds_to_bytes(ao, 0.5); - priv->ring = talloc_zero_size(priv, priv->ring_size); - - free(device); - return 0; - -error_exit: - uninit(ao, true); - free(device); - return -1; -} - -static int play(struct ao *ao, void *data, int len, int flags) -{ - struct priv *priv = ao->priv; - - pthread_mutex_lock(&priv->ring_mutex); - - int write_len = ring_write(ao, data, len); - if (flags & AOPLAY_FINAL_CHUNK) - priv->play_remaining = true; - - pthread_mutex_unlock(&priv->ring_mutex); - - if (Pa_IsStreamStopped(priv->stream) == 1) - check_pa_ret(Pa_StartStream(priv->stream)); - - return write_len; -} - -static int get_space(struct ao *ao) -{ - struct priv *priv = ao->priv; - - pthread_mutex_lock(&priv->ring_mutex); - - int free = priv->ring_size - priv->read_len; - - pthread_mutex_unlock(&priv->ring_mutex); - - return free; -} - -static float get_delay(struct ao *ao) -{ - struct priv *priv = ao->priv; - - double stream_time = Pa_GetStreamTime(priv->stream); - - pthread_mutex_lock(&priv->ring_mutex); - - float frame_time = priv->play_time ? priv->play_time - stream_time : 0; - float buffer_latency = (priv->read_len + priv->play_silence) - / (float)ao->bps; - - pthread_mutex_unlock(&priv->ring_mutex); - - return buffer_latency + frame_time; -} - -static void reset(struct ao *ao) -{ - struct priv *priv = ao->priv; - - if (Pa_IsStreamStopped(priv->stream) != 1) - check_pa_ret(Pa_AbortStream(priv->stream)); - - pthread_mutex_lock(&priv->ring_mutex); - - priv->read_len = 0; - priv->read_pos = 0; - priv->play_remaining = false; - priv->play_time = 0; - priv->play_silence = 0; - - pthread_mutex_unlock(&priv->ring_mutex); -} - -static void pause(struct ao *ao) -{ - struct priv *priv = ao->priv; - - check_pa_ret(Pa_AbortStream(priv->stream)); - - double stream_time = Pa_GetStreamTime(priv->stream); - - pthread_mutex_lock(&priv->ring_mutex); - - // When playback resumes, replace the lost audio (due to dropping the - // portaudio/driver/hardware internal buffers) with silence. - float frame_time = priv->play_time ? priv->play_time - stream_time : 0; - priv->play_silence += seconds_to_bytes(ao, FFMAX(frame_time, 0)); - priv->play_time = 0; - - pthread_mutex_unlock(&priv->ring_mutex); -} - -static void resume(struct ao *ao) -{ - struct priv *priv = ao->priv; - - check_pa_ret(Pa_StartStream(priv->stream)); -} - -const struct ao_driver audio_out_portaudio = { - .is_new = true, - .info = &(const struct ao_info) { - "PortAudio", - "portaudio", - "wm4", - "", - }, - .init = init, - .uninit = uninit, - .reset = reset, - .get_space = get_space, - .play = play, - .get_delay = get_delay, - .pause = pause, - .resume = resume, -}; |