diff options
Diffstat (limited to 'drivers/alsa/audio_driver_alsa.cpp')
| -rw-r--r-- | drivers/alsa/audio_driver_alsa.cpp | 144 | 
1 files changed, 119 insertions, 25 deletions
| diff --git a/drivers/alsa/audio_driver_alsa.cpp b/drivers/alsa/audio_driver_alsa.cpp index b54a1ce0fc..1e17e72532 100644 --- a/drivers/alsa/audio_driver_alsa.cpp +++ b/drivers/alsa/audio_driver_alsa.cpp @@ -27,6 +27,7 @@  /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */  /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */  /*************************************************************************/ +  #include "audio_driver_alsa.h"  #ifdef ALSA_ENABLED @@ -36,19 +37,20 @@  #include <errno.h> -Error AudioDriverALSA::init() { - -	active = false; -	thread_exited = false; -	exit_thread = false; -	pcm_open = false; -	samples_in = NULL; -	samples_out = NULL; - +Error AudioDriverALSA::init_device() {  	mix_rate = GLOBAL_DEF("audio/mix_rate", DEFAULT_MIX_RATE);  	speaker_mode = SPEAKER_MODE_STEREO;  	channels = 2; +	// If there is a specified device check that it is really present +	if (device_name != "Default") { +		Array list = get_device_list(); +		if (list.find(device_name) == -1) { +			device_name = "Default"; +			new_device = "Default"; +		} +	} +  	int status;  	snd_pcm_hw_params_t *hwparams;  	snd_pcm_sw_params_t *swparams; @@ -64,7 +66,16 @@ Error AudioDriverALSA::init() {  	//6 chans - "plug:surround51"  	//4 chans - "plug:surround40"; -	status = snd_pcm_open(&pcm_handle, "default", SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK); +	if (device_name == "Default") { +		status = snd_pcm_open(&pcm_handle, "default", SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK); +	} else { +		String device = device_name; +		int pos = device.find(";"); +		if (pos != -1) { +			device = device.substr(0, pos); +		} +		status = snd_pcm_open(&pcm_handle, device.utf8().get_data(), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK); +	}  	ERR_FAIL_COND_V(status < 0, ERR_CANT_OPEN); @@ -128,15 +139,28 @@ Error AudioDriverALSA::init() {  	status = snd_pcm_sw_params(pcm_handle, swparams);  	CHECK_FAIL(status < 0); -	samples_in = memnew_arr(int32_t, period_size * channels); -	samples_out = memnew_arr(int16_t, period_size * channels); +	samples_in.resize(period_size * channels); +	samples_out.resize(period_size * channels);  	snd_pcm_nonblock(pcm_handle, 0); -	mutex = Mutex::create(); -	thread = Thread::create(AudioDriverALSA::thread_func, this); -  	return OK; +} + +Error AudioDriverALSA::init() { + +	active = false; +	thread_exited = false; +	exit_thread = false; +	pcm_open = false; + +	Error err = init_device(); +	if (err == OK) { +		mutex = Mutex::create(); +		thread = Thread::create(AudioDriverALSA::thread_func, this); +	} + +	return err;  };  void AudioDriverALSA::thread_func(void *p_udata) { @@ -151,7 +175,7 @@ void AudioDriverALSA::thread_func(void *p_udata) {  		} else {  			ad->lock(); -			ad->audio_server_process(ad->period_size, ad->samples_in); +			ad->audio_server_process(ad->period_size, ad->samples_in.ptrw());  			ad->unlock(); @@ -166,7 +190,7 @@ void AudioDriverALSA::thread_func(void *p_udata) {  		while (todo) {  			if (ad->exit_thread)  				break; -			uint8_t *src = (uint8_t *)ad->samples_out; +			uint8_t *src = (uint8_t *)ad->samples_out.ptr();  			int wrote = snd_pcm_writei(ad->pcm_handle, (void *)(src + (total * ad->channels)), todo);  			if (wrote < 0) { @@ -192,6 +216,26 @@ void AudioDriverALSA::thread_func(void *p_udata) {  			total += wrote;  			todo -= wrote;  		}; + +		// User selected a new device, finish the current one so we'll init the new device +		if (ad->device_name != ad->new_device) { +			ad->device_name = ad->new_device; +			ad->finish_device(); + +			Error err = ad->init_device(); +			if (err != OK) { +				ERR_PRINT("ALSA: init_device error"); +				ad->device_name = "Default"; +				ad->new_device = "Default"; + +				err = ad->init_device(); +				if (err != OK) { +					ad->active = false; +					ad->exit_thread = true; +					break; +				} +			} +		}  	};  	ad->thread_exited = true; @@ -212,6 +256,49 @@ AudioDriver::SpeakerMode AudioDriverALSA::get_speaker_mode() const {  	return speaker_mode;  }; +Array AudioDriverALSA::get_device_list() { + +	Array list; + +	list.push_back("Default"); + +	void **hints; + +	if (snd_device_name_hint(-1, "pcm", &hints) < 0) +		return list; + +	for (void **n = hints; *n != NULL; n++) { +		char *name = snd_device_name_get_hint(*n, "NAME"); +		char *desc = snd_device_name_get_hint(*n, "DESC"); + +		if (name != NULL && !strncmp(name, "plughw", 6)) { +			if (desc) { +				list.push_back(String(name) + ";" + String(desc)); +			} else { +				list.push_back(String(name)); +			} +		} + +		if (desc != NULL) +			free(desc); +		if (name != NULL) +			free(name); +	} +	snd_device_name_free_hint(hints); + +	return list; +} + +String AudioDriverALSA::get_device() { + +	return device_name; +} + +void AudioDriverALSA::set_device(String device) { + +	new_device = device; +} +  void AudioDriverALSA::lock() {  	if (!thread || !mutex) @@ -226,6 +313,14 @@ void AudioDriverALSA::unlock() {  	mutex->unlock();  }; +void AudioDriverALSA::finish_device() { + +	if (pcm_open) { +		snd_pcm_close(pcm_handle); +		pcm_open = NULL; +	} +} +  void AudioDriverALSA::finish() {  	if (!thread) @@ -234,17 +329,13 @@ void AudioDriverALSA::finish() {  	exit_thread = true;  	Thread::wait_to_finish(thread); -	if (pcm_open) -		snd_pcm_close(pcm_handle); - -	if (samples_in) { -		memdelete_arr(samples_in); -		memdelete_arr(samples_out); -	}; +	finish_device();  	memdelete(thread); -	if (mutex) +	if (mutex) {  		memdelete(mutex); +		mutex = NULL; +	}  	thread = NULL;  }; @@ -253,6 +344,9 @@ AudioDriverALSA::AudioDriverALSA() {  	mutex = NULL;  	thread = NULL;  	pcm_handle = NULL; + +	device_name = "Default"; +	new_device = "Default";  };  AudioDriverALSA::~AudioDriverALSA(){ |