add the 2.1-bootstrap dir to MONO_PATH when running smcs
[moon.git] / src / audio.cpp
blob9d33965bd864450337205527f3d7250c0e3c7bf9
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3 * audio.cpp:
5 * Contact:
6 * Moonlight List (moonlight-list@lists.ximian.com)
8 * Copyright 2008 Novell, Inc. (http://www.novell.com)
10 * See the LICENSE file included with the distribution for details.
13 #include <config.h>
15 #include <pthread.h>
17 #include "audio.h"
18 #include "audio-alsa.h"
19 #include "audio-pulse.h"
20 #include "pipeline.h"
21 #include "runtime.h"
22 #include "clock.h"
23 #include "debug.h"
24 #include "mediaplayer.h"
27 * AudioSource::AudioFrame
30 AudioSource::AudioFrame::AudioFrame (MediaFrame *frame)
32 this->frame = frame;
33 this->frame->ref ();
34 bytes_used = 0;
37 AudioSource::AudioFrame::~AudioFrame ()
39 frame->unref ();
43 * AudioSource
46 AudioSource::AudioSource (AudioPlayer *player, MediaPlayer *mplayer, AudioStream *stream)
47 : EventObject (Type::AUDIOSOURCE)
49 pthread_mutexattr_t attribs;
51 this->mplayer = mplayer;
52 this->mplayer->ref ();
53 this->stream = stream;
54 this->stream->ref ();
55 this->player = player;
57 stream->AddSafeHandler (IMediaStream::FirstFrameEnqueuedEvent, FirstFrameEnqueuedCallback, this, false);
59 current_frame = NULL;
61 state = AudioNone;
62 flags = (AudioFlags) 0;
64 balance = 0.0f;
65 volume = 1.0f;
66 muted = false;
68 last_write_pts = G_MAXUINT64;
69 last_current_pts = G_MAXUINT64;
71 channels = stream->GetOutputChannels ();
72 sample_rate = stream->GetOutputSampleRate ();
73 input_bytes_per_sample = stream->GetOutputBitsPerSample () / 8;
74 output_bytes_per_sample = input_bytes_per_sample;
76 pthread_mutexattr_init (&attribs);
77 pthread_mutexattr_settype (&attribs, PTHREAD_MUTEX_RECURSIVE);
78 pthread_mutex_init (&mutex, &attribs);
79 pthread_mutexattr_destroy (&attribs);
82 #ifdef DUMP_AUDIO
83 char *fname = g_strdup_printf ("/tmp/AudioSource-%iHz-%iChannels-%iBit.raw", sample_rate, channels, input_bytes_per_sample * 8);
84 dump_fd = fopen (fname, "w+");
85 printf ("AudioSource: Dumping pcm data to: %s, command line to play:\n", fname);
86 printf ("play -s -t raw -%i -c %i --rate %i %s\n", input_bytes_per_sample, channels, sample_rate, fname);
87 g_free (fname);
88 #endif
91 AudioSource::~AudioSource ()
93 pthread_mutex_destroy (&mutex);
95 #ifdef DUMP_AUDIO
96 fclose (dump_fd);
97 #endif
100 void
101 AudioSource::Dispose ()
103 if (stream) {
104 stream->RemoveAllHandlers (this);
105 stream->unref ();
106 stream = NULL;
109 if (mplayer) {
110 mplayer->unref ();
111 mplayer = NULL;
114 if (current_frame) {
115 delete current_frame;
116 current_frame = NULL;
119 EventObject::Dispose ();
122 void
123 AudioSource::Lock ()
125 pthread_mutex_lock (&mutex);
128 void
129 AudioSource::Unlock ()
131 pthread_mutex_unlock (&mutex);
134 AudioStream *
135 AudioSource::GetAudioStream ()
137 AudioStream *result;
138 Lock ();
139 result = stream;
140 Unlock ();
141 return result;
144 void
145 AudioSource::SetAudioStream (AudioStream *value)
147 Lock ();
148 if (stream)
149 stream->unref ();
150 stream = value;
151 if (stream)
152 stream->ref ();
153 Unlock ();
156 guint32
157 AudioSource::GetInputBytesPerFrame ()
159 /* No locking required, this can only be set during initialization */
160 return channels * input_bytes_per_sample;
163 guint32
164 AudioSource::GetInputBytesPerSample ()
166 /* No locking required, this can only be set during initialization */
167 return input_bytes_per_sample;
170 guint32
171 AudioSource::GetOutputBytesPerFrame ()
173 /* No locking required, this can only be set during initialization */
174 return channels * output_bytes_per_sample;
177 guint32
178 AudioSource::GetOutputBytesPerSample ()
180 /* No locking required, this can only be set during initialization */
181 return output_bytes_per_sample;
184 void
185 AudioSource::SetOutputBytesPerSample (guint32 value)
187 /* No locking required, this can only be set during initialization */
188 output_bytes_per_sample = value;
191 AudioStream *
192 AudioSource::GetStreamReffed ()
194 AudioStream *result;
195 Lock ();
196 result = stream;
197 if (result)
198 result->ref ();
199 Unlock ();
200 return result;
203 void
204 AudioSource::SetFlag (AudioFlags flag, bool value)
206 Lock ();
207 if (value) {
208 flags = (AudioFlags) (flag | flags);
209 } else {
210 flags = (AudioFlags) (~flag & flags);
212 LOG_AUDIO_EX ("AudioSource::SetFlag (%i = %s, %i), resulting flags: %i = %s\n", flag, GetFlagNames (flag), value, flags, GetFlagNames (flags));
213 Unlock ();
216 bool
217 AudioSource::GetFlag (AudioFlags flag)
219 return flags & flag;
222 #if DEBUG
223 char *
224 AudioSource::GetFlagNames (AudioFlags flags)
226 const char *v [5];
227 int i = 0;
228 v [0] = v [1] = v [2] = v [3] = v [4] = NULL;
230 if (flags & AudioInitialized)
231 v [i++] = "Initialized";
233 if (flags & AudioEOF)
234 v [i++] = "EOF";
236 if (flags & AudioWaiting)
237 v [i++] = "Waiting";
239 if (flags & AudioEnded)
240 v [i++] = "Ended";
242 return (char *) g_strjoinv (",", (gchar **) v);
245 #endif
247 const char *
248 AudioSource::GetStateName (AudioState state)
250 switch (state) {
251 case AudioNone: return "None";
252 case AudioPlaying: return "Playing";
253 case AudioPaused: return "Paused";
254 case AudioError: return "Error";
255 case AudioStopped: return "Stopped";
256 default: return "Unknown";
260 AudioState
261 AudioSource::GetState ()
263 AudioState result;
264 Lock ();
265 result = state;
266 Unlock ();
267 return result;
270 void
271 AudioSource::SetState (AudioState value)
273 AudioState old_state;
274 bool changed = false;
276 Lock ();
277 if (state != value) {
278 if (state == AudioError) {
279 LOG_AUDIO ("AudioSource::SetState (%s): Current state is Error, can't change that state\n", GetStateName (value));
280 } else {
281 old_state = state;
282 state = value;
283 changed = true;
284 if (value == AudioError)
285 mplayer->AudioFailed (this);
288 Unlock ();
290 LOG_AUDIO_EX ("AudioSource::SetState (%s), old state: %s, changed: %i\n", GetStateName (value), GetStateName (old_state), changed);
292 if (changed)
293 StateChanged (old_state);
296 double
297 AudioSource::GetBalance ()
299 double result;
300 Lock ();
301 result = balance;
302 Unlock ();
303 return result;
306 void
307 AudioSource::SetBalance (double value)
309 Lock ();
310 balance = value;
311 Unlock ();
314 double
315 AudioSource::GetVolume ()
317 double result;
318 Lock ();
319 result = volume;
320 Unlock ();
321 return result;
324 void
325 AudioSource::SetVolume (double value)
327 Lock ();
328 volume = value;
329 Unlock ();
332 bool
333 AudioSource::GetMuted ()
335 bool result;
336 Lock ();
337 result = muted;
338 Unlock ();
339 return result;
342 void
343 AudioSource::SetMuted (bool value)
345 Lock ();
346 muted = value;
347 Unlock ();
350 guint32
351 AudioSource::GetChannels ()
353 // This can only be set during initialization, so there's no need to lock here.
354 return channels;
357 guint32
358 AudioSource::GetSampleRate ()
360 // This can only be set during initialization, so there's no need to lock here.
361 return sample_rate;
364 bool
365 AudioSource::IsQueueEmpty ()
367 bool result;
368 AudioStream *stream;
370 LOG_AUDIO_EX ("AudioSource::IsQueueEmpty ().\n");
372 stream = GetStreamReffed ();
374 g_return_val_if_fail (stream != NULL, false);
376 result = stream->IsQueueEmpty ();
378 stream->unref ();
380 return result;
383 void
384 AudioSource::FirstFrameEnqueuedHandler (EventObject *sender, EventArgs *args)
386 LOG_AUDIO_EX ("AudioSource::FirstFrameEnqueuedHandler ().\n");
388 if (GetFlag (AudioWaiting)) {
389 SetFlag (AudioWaiting, false);
390 if (GetState () == AudioPlaying)
391 Play ();
395 guint64
396 AudioSource::GetDelay ()
398 return GetDelayInternal ();
401 guint64
402 AudioSource::GetCurrentPts ()
404 guint64 delay = 0;
405 guint64 current_pts = 0;
406 guint64 result = 0;
408 if (GetState () != AudioPlaying) {
409 result = last_current_pts;
410 } else {
411 Lock ();
412 current_pts = last_write_pts;
413 Unlock ();
415 delay = GetDelay ();
417 if (current_pts == G_MAXUINT64) {
418 result = current_pts;
419 } else if (delay == G_MAXUINT64 || GetState () != AudioPlaying) {
420 result = last_current_pts;
421 } else if (delay > current_pts) {
422 result = 0;
423 } else {
424 result = current_pts - delay;
428 last_current_pts = result;
430 LOG_AUDIO_EX ("AudioSource::GetCurrentPts (): %" G_GUINT64_FORMAT " ms, delay: %" G_GUINT64_FORMAT ", last_write_pts: %llu\n",
431 MilliSeconds_FromPts (result), MilliSeconds_FromPts (delay), MilliSeconds_FromPts (last_write_pts));
433 return result;
436 void
437 AudioSource::Stop ()
439 LOG_AUDIO ("AudioSource::Stop ()\n");
441 Lock ();
442 SetState (AudioStopped);
443 last_current_pts = G_MAXUINT64;
444 last_write_pts = G_MAXUINT64;
445 delete current_frame;
446 current_frame = NULL;
447 Unlock ();
448 Stopped ();
451 void
452 AudioSource::Play ()
454 LOG_AUDIO ("AudioSource::Play ()\n");
456 SetState (AudioPlaying);
457 SetFlag ((AudioFlags) (AudioEnded | AudioEOF | AudioWaiting), false);
458 Played ();
461 void
462 AudioSource::Pause ()
464 LOG_AUDIO ("AudioSource::Pause ()\n");
466 SetState (AudioPaused);
467 Paused ();
470 void
471 AudioSource::Underflowed ()
473 LOG_AUDIO ("AudioSource::Underflowed (), state: %s, flags: %s\n", GetStateName (GetState ()), GetFlagNames (flags));
475 SetCurrentDeployment (false);
477 if (GetState () == AudioPlaying) {
478 if (GetFlag (AudioEOF)) {
479 Stop ();
480 SetFlag (AudioEnded, true);
481 mplayer->AudioFinished ();
482 } else if (IsQueueEmpty ()) {
483 SetFlag (AudioWaiting, true);
484 mplayer->SetBufferUnderflow ();
489 bool
490 AudioSource::Initialize ()
492 bool result;
494 result = InitializeInternal ();
496 if (result) {
497 SetFlag (AudioInitialized, true);
498 } else {
499 SetFlag (AudioInitialized, false);
500 SetState (AudioError);
503 return result;
506 void
507 AudioSource::Close ()
509 CloseInternal ();
512 guint32
513 AudioSource::Write (void *dest, guint32 samples)
515 AudioData **data = (AudioData **) g_alloca (sizeof (AudioData *) * (channels + 1));
516 guint32 result = 0;
518 for (unsigned int i = 0; i < channels; i++)
519 data [i] = (AudioData *) g_malloc (sizeof (AudioData));
521 data [0]->dest = dest;
522 data [0]->distance = GetOutputBytesPerFrame ();
523 // Interleaved multi-channel audio data
524 for (unsigned int i = 1; i < channels; i++) {
525 data [i]->dest = ((char *) dest) + output_bytes_per_sample * i;
526 data [i]->distance = data [0]->distance;
528 data [channels] = NULL;
529 result = WriteFull (data, samples);
531 for (int i = 0; data [i] != NULL; i++) {
532 g_free (data [i]);
535 return result;
538 guint32
539 AudioSource::WriteFull (AudioData **channel_data, guint32 samples)
541 guint32 channels = GetChannels ();
542 gint32 *volumes = (gint32 *) g_alloca (sizeof (gint32) * channels);
543 gint32 volume;
544 double balance;
545 bool muted;
546 gint16 **write_ptr = (gint16 **) g_alloca (sizeof (gint16 *) * channels);
547 guint32 result = 0;
548 guint32 bytes_per_frame = input_bytes_per_sample * channels;
549 guint32 frames_to_write;
550 guint32 bytes_available;
551 guint32 bytes_written;
552 gint32 value;
553 guint64 last_frame_pts = 0; // The pts of the last frame which was used to write samples
554 guint64 last_frame_samples = 0; // Samples written from the last frame
556 SetCurrentDeployment (false);
558 // Validate input
559 if (channel_data == NULL) {
560 SetState (AudioError);
561 return 0;
563 for (guint32 i = 0; i < channels; i++) {
564 if (channel_data [i] == NULL) {
565 LOG_AUDIO ("AudioSource::WriteFull (%p, %u): channel data #%i is NULL\n", channel_data, samples, i );
566 SetState (AudioError);
567 return 0;
570 if (channel_data [channels] != NULL) {
571 SetState (AudioError);
572 return 0;
575 Lock ();
577 volume = this->volume * 8192;
578 balance = this->balance;
579 muted = false; //this->muted;
581 // Set the per-channel volume
582 if (channels > 2) {
583 // TODO: how does the balance work here?
584 // We probably need a channel map to figure out left and right
585 for (unsigned int i = 0; i < channels; i++) {
586 volumes [i] = muted ? 0.0 : volume;
588 } else if (channels == 2) {
589 if (muted) {
590 volumes [0] = volumes [1] = 0;
591 } else if (balance < 0.0) {
592 volumes [0] = volume;
593 volumes [1] = (1.0 + balance) * volume;
594 } else if (balance > 0.0) {
595 volumes [0] = (1.0 - balance) * volume;
596 volumes [1] = volume;
597 } else {
598 volumes [0] = volumes [1] = volume;
600 } else if (channels == 1) {
601 if (muted) {
602 volumes [0] = 0;
603 } else {
604 volumes [0] = volume;
606 } else {
607 SetState (AudioError);
608 goto cleanup;
611 for (guint32 i = 0; i < channels; i++)
612 write_ptr [i] = (gint16 *) channel_data [i]->dest;
614 while (GetState () == AudioPlaying) {
615 if (current_frame == NULL) {
616 MediaFrame *frame = stream->PopFrame ();
617 if (frame != NULL) {
618 current_frame = new AudioFrame (frame);
619 frame->unref ();
623 if (current_frame == NULL) {
624 if (stream->GetOutputEnded ()) {
625 LOG_AUDIO ("AudioSource::WriteFull (): No more data and reached the end.\n");
626 SetFlag (AudioWaiting, false);
627 SetFlag ((AudioFlags) (AudioEOF | AudioEnded), true);
628 } else {
629 LOG_AUDIO ("AudioSource::WriteFull (): No more data, starting to wait...\n");
630 if (!GetFlag (AudioEOF) && !GetFlag (AudioEnded)) {
631 SetFlag (AudioWaiting, true);
632 SetFlag ((AudioFlags) (AudioEOF | AudioEnded), false);
635 goto cleanup;
638 bytes_available = current_frame->frame->buflen - current_frame->bytes_used;
640 if (bytes_available < bytes_per_frame) {
641 LOG_AUDIO ("AudioSource::WriteFull (): incomplete packet, bytes_available: %u, buflen: %u, bytes_used: %u\n", bytes_available, current_frame->frame->buflen, current_frame->bytes_used);
642 delete current_frame;
643 current_frame = NULL;
644 continue;
647 frames_to_write = MIN (bytes_available / bytes_per_frame, samples - result);
648 bytes_written = frames_to_write * bytes_per_frame;
650 #ifdef DUMP_AUDIO
651 fwrite ((((char *) current_frame->frame->buffer) + current_frame->bytes_used), 1, bytes_written, dump_fd);
652 #endif
654 switch (this->input_bytes_per_sample) {
655 case 2: {
656 switch (this->output_bytes_per_sample) {
657 case 2: {
658 // 16bit audio -> 16bit audio
659 gint16 *read_ptr = (gint16 *) (((char *) current_frame->frame->buffer) + current_frame->bytes_used);
661 for (guint32 i = 0; i < frames_to_write; i++) {
662 for (guint32 channel = 0; channel < channels; channel++) {
663 value = ((*read_ptr) * volumes [channel]) >> 13;
664 *(write_ptr [channel]) = (gint16) CLAMP (value, -32768, 32767);
665 write_ptr [channel] = (gint16 *) (((char *) write_ptr [channel]) + channel_data [channel]->distance);
666 read_ptr++;
669 break;
671 default: // implement others as needed
672 LOG_AUDIO ("AudioSource::Write (): Invalid output_bytes_per_sample, expected 2, got: %i\n", this->output_bytes_per_sample);
673 break;
675 break;
677 case 3: {
678 switch (this->output_bytes_per_sample) {
679 case 2: {
680 // 24bit audio -> 16bit audio
681 gint16 *read_ptr = (gint16 *) (((char *) current_frame->frame->buffer) + current_frame->bytes_used);
683 for (guint32 i = 0; i < frames_to_write; i++) {
684 for (guint32 channel = 0; channel < channels; channel++) {
685 read_ptr = (gint16 *) (((gint8 *) read_ptr) + 1); // +1 byte
686 value = *read_ptr;
687 value = (gint16) CLAMP (((value * volumes [channel]) >> 13), -32768, 32767);
688 *write_ptr [channel] = value;
689 write_ptr [channel] = (gint16 *) (((char *) write_ptr [channel]) + channel_data [channel]->distance);
690 read_ptr += 1; // +2 bytes
693 break;
695 // case 3: // 24bit audio -> 24bit audio, this is painful to both read and write.
696 case 4: {
697 // 24bit audio -> 32bit audio
698 gint32 *read_ptr = (gint32 *) (((char *) current_frame->frame->buffer) + current_frame->bytes_used);
700 for (guint32 i = 0; i < frames_to_write; i++) {
701 for (guint32 channel = 0; channel < channels; channel++) {
702 if (false && i > 0) {
703 // can overread before, mask out the upper bits.
704 value = * (gint32 *) (((gint8 *) read_ptr) - 1);
705 value &= 0xFFFFFF00;
706 } else {
707 // can't overread before, use byte pointers
708 value = 0;
709 ((guint8 *) &value) [1] = (((guint8 *) read_ptr) [0]);
710 ((guint8 *) &value) [2] = (((guint8 *) read_ptr) [1]);
711 ((guint8 *) &value) [3] = (((guint8 *) read_ptr) [2]);
713 // not sure how to calculate volume here, this shifts down 13 bits
714 // and then multiply with volume. This loses the lowest 5 bits of information
715 // from the 24 bit sample. Not quite sure how to do this with 32bit math without
716 // losing information though.
717 value = (value >> 13) * (volumes [channel]);
718 *((gint32 *) write_ptr [channel]) = value;
719 write_ptr [channel] = (gint16 *) (((char *) write_ptr [channel]) + channel_data [channel]->distance);
720 read_ptr = (gint32 *) (((gint8 *) read_ptr) + 3); // += input_bytes_per_sample;
723 break;
725 default: // implement others as needed
726 LOG_AUDIO ("AudioSource::Write (): Invalid output_bytes_per_sample, expected 2 or 4, got: %i\n", this->output_bytes_per_sample);
727 break;
729 break;
731 default:
732 LOG_AUDIO ("AudioSource::Write (): Invalid input_bytes_per_sample, can only be 2 or 3, but got: %i\n", this->input_bytes_per_sample);
733 SetState (AudioError);
734 break;
737 result += frames_to_write;
738 current_frame->bytes_used += bytes_written;
740 last_frame_samples = current_frame->bytes_used / GetInputBytesPerFrame ();
741 last_frame_pts = current_frame->frame->pts;
743 if (current_frame->bytes_used == current_frame->frame->buflen) {
744 // We used the entire packet
745 delete current_frame;
746 current_frame = NULL;
747 } else {
748 // There is still audio data left in the packet, just leave it.
751 if (result == samples) {
752 // We've written all we were requested to write
753 goto cleanup;
754 } else {
755 //printf ("AudioSource::WriteFull (): Written %u samples of %u requested samples, getting new packet (%i packets left)\n", result, samples, frames.Length ());
759 cleanup:
760 LOG_AUDIO_EX ("AudioSource::WriteFull (%p, %u): Wrote %u samples, current pts: %" G_GUINT64_FORMAT ", volume: %.2f\n", channel_data, samples, result, MilliSeconds_FromPts (GetCurrentPts ()), this->volume);
762 if (result > 0) {
763 last_write_pts = last_frame_pts + MilliSeconds_ToPts (last_frame_samples * 1000 / GetSampleRate ());
766 Unlock ();
768 return result;
772 * AudioListNode
775 AudioListNode::AudioListNode (AudioSource *source)
777 this->source = source;
778 this->source->ref ();
779 generation = 0;
782 AudioListNode::~AudioListNode ()
784 this->source->unref ();
788 * AudioSources
791 AudioSources::AudioSources ()
793 pthread_mutex_init (&mutex, NULL);
794 current_generation = 0;
797 AudioSources::~AudioSources ()
799 pthread_mutex_destroy (&mutex);
802 void
803 AudioSources::Lock ()
805 pthread_mutex_lock (&mutex);
808 void
809 AudioSources::Unlock ()
811 pthread_mutex_unlock (&mutex);
814 void
815 AudioSources::Add (AudioSource *source)
817 Lock ();
818 list.Append (new AudioListNode (source));
819 Unlock ();
822 bool
823 AudioSources::Remove (AudioSource *source)
825 AudioListNode *node;
826 bool result = false;
828 Lock ();
829 node = (AudioListNode *) list.First ();
830 while (node != NULL) {
831 if (node->source == source) {
832 result = true;
833 if (last_node == node)
834 last_node = (AudioListNode *) node->prev;
835 list.Remove (node);
836 source->unref ();
837 break;
839 node = (AudioListNode *) node->next;
841 last_node = NULL;
842 Unlock ();
844 return result;
847 void
848 AudioSources::StartEnumeration ()
850 Lock ();
851 current_generation++;
852 last_node = NULL;
853 Unlock ();
856 AudioSource *
857 AudioSources::GetNext (bool only_playing)
859 AudioListNode *node = NULL;
860 AudioSource *result = NULL;
862 Lock ();
864 // Check the last node returned from GetNext
865 if (last_node != NULL && last_node->next != NULL) {
866 node = (AudioListNode *) last_node->next;
867 if (node->generation != current_generation && (!only_playing || node->source->IsPlaying ()))
868 goto cleanup;
871 // Loop through all the nodes looking for a node not in the
872 // current generation.
873 node = (AudioListNode *) list.First ();
874 while (node != NULL && (node->generation == current_generation || (only_playing && !node->source->IsPlaying ()))) {
875 node = (AudioListNode *) node->next;
878 // Its possible that the loop has started but nothing is playing, which without this guard would
879 // return list.First () in an infinite loop while we're downloading / buffering.
880 // (due to the while loop above not clearing out the first value (list.First ()) if the condition is false and there's no other
881 // node which satifies the condition)
882 if (only_playing && node != NULL && !node->source->IsPlaying ())
883 node = NULL;
885 cleanup:
886 if (node) {
887 node->generation = current_generation;
888 last_node = node;
889 result = node->source;
890 result->SetCurrentDeployment (false);
891 result->ref ();
892 } else {
893 Deployment::SetCurrent (NULL, false);
896 Unlock ();
898 return result;
901 AudioSource *
902 AudioSources::GetHead ()
904 AudioSource *result = NULL;
905 AudioListNode *node;
907 Lock ();
909 node = (AudioListNode *) list.First ();
910 if (node != NULL) {
911 result = node->source;
912 result->SetCurrentDeployment (false);
913 result->ref ();
916 Unlock ();
918 return result;
921 #if DEBUG
923 AudioSources::Length ()
925 int result = 0;
927 Lock ();
928 result = list.Length ();
929 Unlock ();
931 return result;
933 #endif
936 * AudioPlayer
939 AudioPlayer * AudioPlayer::instance = NULL;
940 pthread_mutex_t AudioPlayer::instance_mutex = PTHREAD_MUTEX_INITIALIZER;
942 AudioSource *
943 AudioPlayer::Add (MediaPlayer *mplayer, AudioStream *stream)
945 AudioSource *result = NULL;
947 LOG_AUDIO ("AudioPlayer::Add (%p)\n", mplayer);
949 if (moonlight_flags & RUNTIME_INIT_DISABLE_AUDIO) {
950 LOG_AUDIO ("AudioPlayer: audio is disabled.\n");
951 return NULL;
954 pthread_mutex_lock (&instance_mutex);
955 if (instance == NULL)
956 instance = CreatePlayer ();
957 if (instance != NULL)
958 result = instance->AddImpl (mplayer, stream);
959 pthread_mutex_unlock (&instance_mutex);
961 return result;
964 void
965 AudioPlayer::Remove (AudioSource *source)
967 LOG_AUDIO ("AudioPlayer::Remove (%p)\n", source);
969 pthread_mutex_lock (&instance_mutex);
970 if (instance != NULL)
971 instance->RemoveImpl (source);
973 pthread_mutex_unlock (&instance_mutex);
976 void
977 AudioPlayer::Shutdown ()
979 AudioPlayer *player;
980 LOG_AUDIO ("AudioPlayer::Shutdown ()\n");
982 pthread_mutex_lock (&instance_mutex);
983 if (instance != NULL) {
984 player = instance;
985 instance = NULL;
986 player->ShutdownImpl ();
987 delete player;
989 pthread_mutex_unlock (&instance_mutex);
992 AudioPlayer *
993 AudioPlayer::CreatePlayer ()
995 bool overridden;
996 AudioPlayer *result = NULL;
998 // If any of the flags are specified, we disable all players
999 // and re-enable according to the flag.
1001 overridden = moonlight_flags & (RUNTIME_INIT_AUDIO_PULSE | RUNTIME_INIT_AUDIO_ALSA | RUNTIME_INIT_AUDIO_ALSA_MMAP | RUNTIME_INIT_AUDIO_ALSA_RW);
1003 #if INCLUDE_PULSEAUDIO
1004 if (result != NULL) {
1005 LOG_AUDIO ("AudioPlayer: Not checking for PulseAudio support, we already found support for another configuration.\n");
1006 } else if (overridden && !(moonlight_flags & RUNTIME_INIT_AUDIO_PULSE)) {
1007 LOG_AUDIO ("AudioPlayer: PulseAudio disabled with environment variable (MOONLIGHT_OVERRIDES)\n");
1008 } else if (!PulsePlayer::IsInstalled ()) {
1009 LOG_AUDIO ("AudioPlayer: PulseAudio is not installed or configured correctly.\n");
1010 } else {
1011 printf ("AudioPlayer: Using PulseAudio.\n");
1012 result = new PulsePlayer ();
1015 if (result != NULL) {
1016 if (!result->Initialize ()) {
1017 LOG_AUDIO ("AudioPlayer: Failed initialization.\n");
1018 result->ShutdownImpl ();
1019 delete result;
1020 result = NULL;
1021 } else {
1022 return result;
1025 #else
1026 LOG_AUDIO ("AudioPlayer: Built without support for pulseaudio.\n");
1027 #endif
1029 #if INCLUDE_ALSA
1030 if (result != NULL) {
1031 LOG_AUDIO ("AudioPlayer: Not checking for Alsa support, we already found support for another configuration.\n");
1032 } else if (overridden && !(moonlight_flags & (RUNTIME_INIT_AUDIO_ALSA | RUNTIME_INIT_AUDIO_ALSA_MMAP | RUNTIME_INIT_AUDIO_ALSA_RW))) {
1033 LOG_AUDIO ("AudioPlayer: Alsa disabled with environment variable (MOONLIGHT_OVERRIDES)\n");
1034 } else if (!AlsaPlayer::IsInstalled ()) {
1035 LOG_AUDIO ("AudioPlayer: Alsa is not installed or configured correctly.\n");
1036 } else {
1037 printf ("AudioPlayer: Using Alsa.\n");
1038 result = new AlsaPlayer ();
1041 if (result != NULL) {
1042 if (!result->Initialize ()) {
1043 LOG_AUDIO ("AudioPlayer: Failed initialization.\n");
1044 result->ShutdownImpl ();
1045 delete result;
1046 result = NULL;
1047 } else {
1048 return result;
1051 #else
1052 LOG_AUDIO ("AudioPlayer: Built without support for alsa.\n");
1053 #endif
1055 return result;
1058 AudioSource *
1059 AudioPlayer::AddImpl (MediaPlayer *mplayer, AudioStream *stream)
1061 AudioSource *result = CreateNode (mplayer, stream);
1063 if (result->Initialize ()) {
1064 sources.Add (result);
1065 AddInternal (result);
1066 } else {
1067 result->unref ();
1068 result = NULL;
1071 return result;
1074 void
1075 AudioPlayer::RemoveImpl (AudioSource *node)
1077 node->ref ();
1078 if (sources.Remove (node)) {
1079 RemoveInternal (node);
1080 node->Close ();
1082 node->unref ();
1085 void
1086 AudioPlayer::ShutdownImpl ()
1088 AudioSource *source;
1090 PrepareShutdownInternal ();
1092 // Remove all the sources.
1093 while ((source = sources.GetHead ()) != NULL) {
1094 RemoveImpl (source);
1095 source->unref ();
1098 FinishShutdownInternal ();