OLD | NEW |
| (Empty) |
1 // Copyright (c) 2011 The Native Client Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "experimental/conways_life/audio/audio_player.h" | |
6 | |
7 #include <stdio.h> | |
8 #include <string.h> | |
9 #include <algorithm> | |
10 | |
11 #include "experimental/conways_life/audio/audio_source.h" | |
12 #include "experimental/conways_life/threading/scoped_mutex_lock.h" | |
13 #include "ppapi/c/pp_errors.h" | |
14 #include "ppapi/cpp/audio.h" | |
15 #include "ppapi/cpp/audio_config.h" | |
16 #include "ppapi/cpp/module.h" | |
17 | |
18 namespace audio { | |
19 | |
20 AudioPlayer::AudioPlayer(pp::Instance* instance) | |
21 : audio_source_(NULL), | |
22 playback_offset_(0), | |
23 pp_audio_(NULL), | |
24 instance_(instance), | |
25 factory_(this) { | |
26 pthread_mutex_init(&mutex_, NULL); | |
27 } | |
28 | |
29 AudioPlayer::~AudioPlayer() { | |
30 ClearAudioSource(); | |
31 ClearPepperAudio(); | |
32 pthread_mutex_destroy(&mutex_); | |
33 } | |
34 | |
35 void AudioPlayer::AssignAudioSource(AudioSource* source) { | |
36 threading::ScopedMutexLock scoped_mutex(&mutex_); | |
37 ClearPepperAudio(); | |
38 playback_offset_ = 0; | |
39 if (audio_source_ != source) { | |
40 ClearAudioSource(); | |
41 audio_source_ = source; | |
42 } | |
43 } | |
44 | |
45 void AudioPlayer::Play() { | |
46 assert(audio_source_ != NULL); // Forgot to assign a sound source? | |
47 pp::CompletionCallback cc = factory_.NewCallback(&AudioPlayer::InternalPlay); | |
48 pp::Module::Get()->core()->CallOnMainThread(0, cc, PP_OK); | |
49 } | |
50 | |
51 void AudioPlayer::Stop() { | |
52 pp::CompletionCallback cc = factory_.NewCallback(&AudioPlayer::InternalStop); | |
53 pp::Module::Get()->core()->CallOnMainThread(0, cc, PP_OK); | |
54 } | |
55 | |
56 bool AudioPlayer::IsReady() const { | |
57 return audio_source_ != NULL && audio_source_->IsReady(); | |
58 } | |
59 | |
60 void AudioPlayer::AudioCallback(void* sample_buffer, | |
61 uint32_t out_buffer_size, | |
62 void* user_data) { | |
63 AudioPlayer* player = reinterpret_cast<AudioPlayer*>(user_data); | |
64 char* out_buffer = reinterpret_cast<char*>(sample_buffer); | |
65 | |
66 // Copy the next chunk of samples from the audio source. | |
67 AudioSource* audio_source = player->audio_source_; | |
68 const char* src_buffer = audio_source->GetAudioData(); | |
69 uint32_t src_buffer_size = audio_source->GetAudioDataSize(); | |
70 uint32_t remaining_bytes = src_buffer_size - player->playback_offset_ + 1; | |
71 uint32_t copy_size = std::min(out_buffer_size, remaining_bytes); | |
72 | |
73 if (copy_size == 0) { | |
74 // No samples left; fill the buffer with 0s and stop the player. | |
75 ::memset(out_buffer, 0, out_buffer_size); | |
76 player->Stop(); | |
77 } else { | |
78 // Copy the next chunk of samples to the audio buffer; if it's not enough | |
79 // to fill the buffer add 0s. | |
80 const char* src_buffer_start = src_buffer + player->playback_offset_; | |
81 ::memcpy(out_buffer, src_buffer_start, copy_size); | |
82 if (copy_size < out_buffer_size) { | |
83 ::memset(out_buffer + copy_size, 0, out_buffer_size - copy_size); | |
84 } | |
85 player->playback_offset_ += copy_size; | |
86 } | |
87 } | |
88 | |
89 void AudioPlayer::InternalPlay(int32_t result) { | |
90 assert(pp::Module::Get()->core()->IsMainThread()); | |
91 threading::ScopedMutexLock scoped_mutex(&mutex_); | |
92 if (pp_audio_ == NULL && audio_source_->IsReady()) { | |
93 CreatePepperAudio(); | |
94 } | |
95 if (pp_audio_ != NULL) { | |
96 playback_offset_ = 0; | |
97 pp_audio_->StartPlayback(); | |
98 } | |
99 } | |
100 | |
101 void AudioPlayer::InternalStop(int32_t result) { | |
102 assert((pp::Module::Get()->core()->IsMainThread())); | |
103 threading::ScopedMutexLock scoped_mutex(&mutex_); | |
104 if (pp_audio_ != NULL) { | |
105 pp_audio_->StopPlayback(); | |
106 } | |
107 } | |
108 | |
109 void AudioPlayer::ClearAudioSource() { | |
110 if (audio_source_ != NULL) { | |
111 delete audio_source_; | |
112 audio_source_ = NULL; | |
113 } | |
114 } | |
115 | |
116 void AudioPlayer::ClearPepperAudio() { | |
117 if (pp_audio_ != NULL) { | |
118 delete pp_audio_; | |
119 pp_audio_ = NULL; | |
120 } | |
121 } | |
122 | |
123 bool AudioPlayer::CreatePepperAudio() { | |
124 assert(pp::Module::Get()->core()->IsMainThread()); | |
125 | |
126 // Create audio config per sound info. | |
127 PP_AudioSampleRate rate = (audio_source_->GetSampleRate() == 44100) ? | |
128 PP_AUDIOSAMPLERATE_44100 : PP_AUDIOSAMPLERATE_48000; | |
129 pp::AudioConfig config(instance_, rate, 4096); | |
130 if (config.is_null()) { | |
131 printf("Error: could not create audio config.\n"); | |
132 return false; | |
133 } | |
134 // Create audio object. | |
135 pp_audio_ = new pp::Audio(instance_, config, AudioCallback, this); | |
136 if (pp_audio_->is_null()) { | |
137 printf("Error: could not create audio player.\n"); | |
138 ClearPepperAudio(); | |
139 } | |
140 return true; | |
141 } | |
142 | |
143 } // namespace audio | |
OLD | NEW |