📄 sdl_audio.cpp
字号:
// This file is part of Ambulant Player, www.ambulantplayer.org.//// Copyright (C) 2003-2007 Stichting CWI, // Kruislaan 413, 1098 SJ Amsterdam, The Netherlands.//// Ambulant Player is free software; you can redistribute it and/or modify// it under the terms of the GNU Lesser General Public License as published by// the Free Software Foundation; either version 2.1 of the License, or// (at your option) any later version.//// Ambulant Player 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 Lesser General Public License for more details.//// You should have received a copy of the GNU Lesser General Public License// along with Ambulant Player; if not, write to the Free Software// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA//#define AM_DBG#ifndef AM_DBG#define AM_DBG if(0)#endif#undef HAVE_ICONV#include "ambulant/gui/SDL/sdl_audio.h"#include "ambulant/net/posix_datasource.h"#include "ambulant/common/region_info.h"#include <stdlib.h>using namespace ambulant;//using namespace gui::sdl;extern "C" {void sdl_C_callback(void *userdata, Uint8 *stream, int len){ gui::sdl::sdl_audio_renderer::sdl_callback(stream, len);}}static voidadd_samples(short *outbuf, short *inbuf, int size, float *volumes, int volcount){ int i; int vol_index = 0; for(i=0; i<size; i++) { long value = (long)inbuf[i]; if (volcount) { value = (long)(value * volumes[vol_index]); if (++vol_index >= volcount) vol_index = 0; } value += (long)outbuf[i]; if (value > 0x7fff) value = 0x7fff; else if (value < -0x7fff) value = -0x7fff; outbuf[i] = (short)value; }}typedef lib::no_arg_callback<gui::sdl::sdl_audio_renderer> readdone_callback; // ************************************************************bool gui::sdl::sdl_audio_renderer::s_sdl_init = false;Uint16 gui::sdl::sdl_audio_renderer::s_sdl_format = AUDIO_S16SYS;net::audio_format gui::sdl::sdl_audio_renderer::s_ambulant_format = net::audio_format(44100, 2, 16);int gui::sdl::sdl_audio_renderer::s_buffer_size = 4096;int gui::sdl::sdl_audio_renderer::s_min_buffer_size_bytes = 2 * 4096 * 2 * 2; lib::critical_section gui::sdl::sdl_audio_renderer::s_static_lock; std::list<gui::sdl::sdl_audio_renderer *> gui::sdl::sdl_audio_renderer::s_renderers;intgui::sdl::sdl_audio_renderer::init(){ s_static_lock.enter(); if (s_sdl_init) { s_static_lock.leave(); return 0; } int err = 0; // XXXX Should check that s_ambulant_format and s_sdl_format match! // Step one - initialize the SDL library err = SDL_Init(SDL_INIT_AUDIO| SDL_INIT_NOPARACHUTE); if (err < 0) { lib::logger::get_logger()->trace("sdl_audio_renderer.init: SDL_Init failed: error %d", err); lib::logger::get_logger()->error(gettext("Cannot initialize SDL audio library")); s_static_lock.leave(); return err; } // Step three - open the mixer SDL_AudioSpec desired, obtained; (void) memset(&desired, 0, sizeof(SDL_AudioSpec)); (void) memset(&obtained, 0, sizeof(SDL_AudioSpec)); desired.freq = s_ambulant_format.samplerate; desired.format = s_sdl_format; desired.channels = s_ambulant_format.channels; desired.samples = s_buffer_size; desired.callback = sdl_C_callback; desired.userdata = NULL; err = SDL_OpenAudio(&desired, &obtained); if (err < 0) { lib::logger::get_logger()->trace("sdl_renderer_playable_ds.init: SDL_OpenAudio failed: error %d", err); lib::logger::get_logger()->error(gettext("Cannot open SDL audio output stream")); s_static_lock.leave(); return err; } s_ambulant_format.samplerate = obtained.freq; s_ambulant_format.channels = obtained.channels; if (obtained.format != s_sdl_format) { lib::logger::get_logger()->trace("sdl_renderer_playable_ds.init: SDL_OpenAudio could not support format 0x%x, returned 0x%x", s_sdl_format, obtained.format); lib::logger::get_logger()->error(gettext("Cannot open SDL audio output stream with required characteristics")); s_static_lock.leave(); return -1; } AM_DBG lib::logger::get_logger()->debug("sdl_audio_renderer.init: SDL init succes"); s_sdl_init = true; s_static_lock.leave(); return err;}voidgui::sdl::sdl_audio_renderer::register_renderer(sdl_audio_renderer *rnd){ s_static_lock.enter(); AM_DBG lib::logger::get_logger()->debug("sdl_audio_renderer::register_renderer(0x%x)", rnd); std::list<sdl_audio_renderer *>::iterator i; for( i=s_renderers.begin(); i != s_renderers.end(); i++) { if ((*i) == rnd) { AM_DBG lib::logger::get_logger()->debug("sdl_audio_renderer::register_renderer() already exists !"); s_static_lock.leave(); return; } } s_renderers.push_back(rnd); AM_DBG lib::logger::get_logger()->debug("sdl_audio_renderer::register_renderer: unpause SDL"); SDL_PauseAudio(0); s_static_lock.leave();}voidgui::sdl::sdl_audio_renderer::unregister_renderer(sdl_audio_renderer *rnd){ s_static_lock.enter(); AM_DBG lib::logger::get_logger()->debug("sdl_audio_renderer::unregister_renderer(0x%x)", rnd); std::list<sdl_audio_renderer *>::iterator i; for( i=s_renderers.begin(); i != s_renderers.end(); i++) { if ((*i) == rnd) { s_renderers.erase(i); break; } } if (s_renderers.size() == 0) { AM_DBG lib::logger::get_logger()->debug("sdl_audio_renderer::register_renderer: pause SDL"); SDL_PauseAudio(1); } s_static_lock.leave();}voidgui::sdl::sdl_audio_renderer::sdl_callback(Uint8 *stream, int len){ s_static_lock.enter(); std::list<sdl_audio_renderer *>::iterator first = s_renderers.begin(); if (s_renderers.size() == 1 && (*first)->m_volcount == 0 && ! ((*first)->m_intransition || (*first)->m_outtransition) ) { // Exactly one active stream, no volume/pan processing, // no transitions: use simple copy Uint8 *single_data; AM_DBG lib::logger::get_logger()->debug("sdl_audio_renderer::sdl_callback(0x%x, %d) [one stream] calling get_data()", (void*) stream, len); int single_len = (*first)->get_data(len, &single_data); assert(single_len <= len); if (single_len != 0) { assert(single_data); memcpy(stream, single_data, std::min(len, single_len)); } AM_DBG lib::logger::get_logger()->debug("sdl_audio_renderer::sdl_callback(0x%x, %d) [one stream] calling get_data_done(%d)", (void*) stream, len, single_len); (*first)->get_data_done(single_len); if (single_len < len) memset(stream+single_len, 0, (len-single_len)); } else { // No streams, or more than one: use an accumulation buffer memset(stream, 0, len); std::list<sdl_audio_renderer *>::iterator i; for (i=first; i != s_renderers.end(); i++) { Uint8 *next_data; AM_DBG lib::logger::get_logger()->debug("sdl_audio_renderer::sdl_callback(0x%x, %d))calling get_data() ", (void*) stream, len); int next_len = (*i)->get_data(len, &next_data); if (next_len) add_samples((short*)stream, (short*)next_data, std::min(len/2, next_len/2), (*i)->m_volumes, (*i)->m_volcount); AM_DBG lib::logger::get_logger()->debug("sdl_audio_renderer::sdl_callback(0x%x, %d))calling get_data_done(%d) ", (void*) stream, len, next_len); (*i)->get_data_done(next_len); } } s_static_lock.leave();}// ************************************************************gui::sdl::sdl_audio_renderer::sdl_audio_renderer( common::playable_notification *context, common::playable_notification::cookie_type cookie, const lib::node *node, lib::event_processor *evp, common::factories *factory): common::renderer_playable(context, cookie, node, evp), m_audio_src(NULL), m_is_playing(false), m_is_paused(false), m_read_ptr_called(false), m_volcount(0), m_intransition(NULL), m_outtransition(NULL), m_transition_engine(NULL){ AM_DBG lib::logger::get_logger()->debug("sdl_audio_renderer::sdl_audio_renderer() -> 0x%x", this); if (init() != 0) return; net::audio_format_choices supported(s_ambulant_format); net::url url = node->get_url("src"); _init_clip_begin_end(); m_audio_src = factory->get_datasource_factory()->new_audio_datasource(url, supported, m_clip_begin, m_clip_end); if (!m_audio_src) lib::logger::get_logger()->error(gettext("%s: cannot open audio file"), repr(url).c_str()); else if (!supported.contains(m_audio_src->get_audio_format())) { lib::logger::get_logger()->error(gettext("%s: audio format not supported"), repr(url).c_str()); m_audio_src->release(); m_audio_src = NULL; }}gui::sdl::sdl_audio_renderer::sdl_audio_renderer( common::playable_notification *context, common::playable_notification::cookie_type cookie, const lib::node *node, lib::event_processor *evp, common::factories* factory, net::audio_datasource *ds): common::renderer_playable(context, cookie, node, evp), m_audio_src(ds), m_is_playing(false), m_is_paused(false), m_read_ptr_called(false), m_intransition(NULL), m_outtransition(NULL), m_transition_engine(NULL){ net::audio_format_choices supported(s_ambulant_format); net::url url = node->get_url("src"); AM_DBG lib::logger::get_logger()->debug("sdl_audio_renderer::sdl_audio_renderer() this=(x%x), ds = 0x%x", (void*) this, (void*) ds); if (init() != 0) return; if (!m_audio_src) lib::logger::get_logger()->error(gettext("%s: cannot open"), repr(url).c_str()); // Ugly hack to get the resampler. if (m_audio_src) { net::audio_datasource *resample_ds = factory->get_datasource_factory()->new_audio_filter(url, supported, ds); AM_DBG lib::logger::get_logger ()->debug("sdl_audio_renderer::sdl_audio_renderer() (this =0x%x) got resample datasource 0x%x", (void *) this, resample_ds); if (resample_ds) { m_audio_src = resample_ds; AM_DBG lib::logger::get_logger()->debug("sdl_audio_renderer: opened resample datasource !"); } }}gui::sdl::sdl_audio_renderer::~sdl_audio_renderer(){ m_lock.enter(); AM_DBG lib::logger::get_logger()->debug("sdl_audio_renderer::~sdl_audio_renderer(0x%x) m_audio_src=0x%x", this, m_audio_src); if (m_is_playing) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -