OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "native_client/src/shared/ppapi_proxy/plugin_ppb_audio.h" | 5 #include "native_client/src/shared/ppapi_proxy/plugin_ppb_audio.h" |
6 | 6 |
7 #include <pthread.h> | 7 #include <pthread.h> |
8 #include <stdio.h> | 8 #include <stdio.h> |
9 #include <string.h> | 9 #include <string.h> |
10 #include <sys/errno.h> | 10 #include <sys/errno.h> |
(...skipping 12 matching lines...) Expand all Loading... |
23 #include "srpcgen/ppp_rpc.h" | 23 #include "srpcgen/ppp_rpc.h" |
24 | 24 |
25 namespace ppapi_proxy { | 25 namespace ppapi_proxy { |
26 namespace { | 26 namespace { |
27 | 27 |
28 // Round size up to next 64k; required for NaCl's version of mmap(). | 28 // Round size up to next 64k; required for NaCl's version of mmap(). |
29 size_t ceil64k(size_t n) { | 29 size_t ceil64k(size_t n) { |
30 return (n + 0xFFFF) & (~0xFFFF); | 30 return (n + 0xFFFF) & (~0xFFFF); |
31 } | 31 } |
32 | 32 |
| 33 // Hard coded values from PepperPlatformAudioOutputImpl. |
| 34 // TODO(???): PPAPI shouldn't hard code these values for all clients. |
| 35 enum { kChannels = 2, kBytesPerSample = 2 }; |
| 36 |
33 } // namespace | 37 } // namespace |
34 | 38 |
35 PluginAudio::PluginAudio() : | 39 PluginAudio::PluginAudio() : |
36 resource_(kInvalidResourceId), | 40 resource_(kInvalidResourceId), |
37 socket_(-1), | 41 socket_(-1), |
38 shm_(-1), | 42 shm_(-1), |
39 shm_size_(0), | 43 shm_size_(0), |
40 shm_buffer_(NULL), | 44 shm_buffer_(NULL), |
41 state_(AUDIO_INCOMPLETE), | 45 state_(AUDIO_INCOMPLETE), |
42 thread_id_(), | 46 thread_id_(), |
43 thread_active_(false), | 47 thread_active_(false), |
44 user_callback_(NULL), | 48 user_callback_(NULL), |
45 user_data_(NULL) { | 49 user_data_(NULL), |
| 50 audio_buffer_size_(0) { |
46 DebugPrintf("PluginAudio::PluginAudio\n"); | 51 DebugPrintf("PluginAudio::PluginAudio\n"); |
47 } | 52 } |
48 | 53 |
49 PluginAudio::~PluginAudio() { | 54 PluginAudio::~PluginAudio() { |
50 DebugPrintf("PluginAudio::~PluginAudio\n"); | 55 DebugPrintf("PluginAudio::~PluginAudio\n"); |
51 // Ensure audio thread is not active. | 56 // Ensure audio thread is not active. |
52 if (resource_ != kInvalidResourceId) | 57 if (resource_ != kInvalidResourceId) |
53 GetInterface()->StopPlayback(resource_); | 58 GetInterface()->StopPlayback(resource_); |
54 // Unmap the shared memory buffer, if present. | 59 // Unmap the shared memory buffer, if present. |
55 if (shm_buffer_) { | 60 if (shm_buffer_) { |
| 61 audio_bus_.reset(); |
| 62 audio_buffer_.reset(); |
56 munmap(shm_buffer_, | 63 munmap(shm_buffer_, |
57 ceil64k(media::TotalSharedMemorySizeInBytes(shm_size_))); | 64 ceil64k(media::TotalSharedMemorySizeInBytes(shm_size_))); |
58 shm_buffer_ = NULL; | 65 shm_buffer_ = NULL; |
59 shm_size_ = 0; | 66 shm_size_ = 0; |
| 67 audio_buffer_size_ = 0; |
60 } | 68 } |
61 // Close the handles. | 69 // Close the handles. |
62 if (shm_ != -1) { | 70 if (shm_ != -1) { |
63 close(shm_); | 71 close(shm_); |
64 shm_ = -1; | 72 shm_ = -1; |
65 } | 73 } |
66 if (socket_ != -1) { | 74 if (socket_ != -1) { |
67 close(socket_); | 75 close(socket_); |
68 socket_ = -1; | 76 socket_ = -1; |
69 } | 77 } |
(...skipping 10 matching lines...) Expand all Loading... |
80 PluginAudio* audio = static_cast<PluginAudio*>(self); | 88 PluginAudio* audio = static_cast<PluginAudio*>(self); |
81 DebugPrintf("PluginAudio::AudioThread: self=%p\n", self); | 89 DebugPrintf("PluginAudio::AudioThread: self=%p\n", self); |
82 while (true) { | 90 while (true) { |
83 int32_t sync_value; | 91 int32_t sync_value; |
84 // Block on socket read. | 92 // Block on socket read. |
85 ssize_t r = read(audio->socket_, &sync_value, sizeof(sync_value)); | 93 ssize_t r = read(audio->socket_, &sync_value, sizeof(sync_value)); |
86 // StopPlayback() will send a value of -1 over the sync_socket. | 94 // StopPlayback() will send a value of -1 over the sync_socket. |
87 if ((sizeof(sync_value) != r) || (-1 == sync_value)) | 95 if ((sizeof(sync_value) != r) || (-1 == sync_value)) |
88 break; | 96 break; |
89 // Invoke user callback, get next buffer of audio data. | 97 // Invoke user callback, get next buffer of audio data. |
90 audio->user_callback_(audio->shm_buffer_, | 98 audio->user_callback_(audio->audio_buffer_.get(), |
91 audio->shm_size_, | 99 audio->audio_buffer_size_, |
92 audio->user_data_); | 100 audio->user_data_); |
| 101 |
| 102 // Deinterleave the audio data into the shared memory as float. |
| 103 audio->audio_bus_->FromInterleaved( |
| 104 audio->audio_buffer_.get(), audio->audio_bus_->frames(), |
| 105 kBytesPerSample); |
| 106 |
93 // Signal audio backend by writing buffer length at end of buffer. | 107 // Signal audio backend by writing buffer length at end of buffer. |
94 // (Note: NaCl applications will always write the entire buffer.) | 108 // (Note: NaCl applications will always write the entire buffer.) |
95 media::SetActualDataSizeInBytes(audio->shm_buffer_, | 109 media::SetActualDataSizeInBytes(audio->shm_buffer_, |
96 audio->shm_size_, | 110 audio->shm_size_, |
97 audio->shm_size_); | 111 audio->shm_size_); |
98 } | 112 } |
99 } | 113 } |
100 | 114 |
101 void PluginAudio::StreamCreated(NaClSrpcImcDescType socket, | 115 void PluginAudio::StreamCreated(NaClSrpcImcDescType socket, |
102 NaClSrpcImcDescType shm, size_t shm_size) { | 116 NaClSrpcImcDescType shm, size_t shm_size) { |
103 DebugPrintf("PluginAudio::StreamCreated: shm=%"NACL_PRIu32"" | 117 DebugPrintf("PluginAudio::StreamCreated: shm=%"NACL_PRIu32"" |
104 " shm_size=%"NACL_PRIuS"\n", shm, shm_size); | 118 " shm_size=%"NACL_PRIuS"\n", shm, shm_size); |
105 socket_ = socket; | 119 socket_ = socket; |
106 shm_ = shm; | 120 shm_ = shm; |
107 shm_size_ = shm_size; | 121 shm_size_ = shm_size; |
108 shm_buffer_ = mmap(NULL, | 122 shm_buffer_ = mmap(NULL, |
109 ceil64k(media::TotalSharedMemorySizeInBytes(shm_size)), | 123 ceil64k(media::TotalSharedMemorySizeInBytes(shm_size)), |
110 PROT_READ | PROT_WRITE, | 124 PROT_READ | PROT_WRITE, |
111 MAP_SHARED, | 125 MAP_SHARED, |
112 shm, | 126 shm, |
113 0); | 127 0); |
114 if (MAP_FAILED != shm_buffer_) { | 128 if (MAP_FAILED != shm_buffer_) { |
| 129 // Deduce the frame count from the size using hard coded channel count. |
| 130 audio_bus_ = media::AudioBus::WrapMemory( |
| 131 kChannels, shm_size_ / (sizeof(float) * kChannels), shm_buffer_); |
| 132 // Setup integer audio buffer for user audio data. |
| 133 audio_buffer_size_ = |
| 134 audio_bus_->frames() * audio_bus_->channels() * kBytesPerSample; |
| 135 audio_buffer_.reset(new uint8_t[audio_buffer_size_]); |
| 136 |
115 if (state() == AUDIO_PENDING) { | 137 if (state() == AUDIO_PENDING) { |
116 StartAudioThread(); | 138 StartAudioThread(); |
117 } else { | 139 } else { |
118 set_state(AUDIO_READY); | 140 set_state(AUDIO_READY); |
119 } | 141 } |
120 } else { | 142 } else { |
121 shm_buffer_ = NULL; | 143 shm_buffer_ = NULL; |
122 } | 144 } |
123 } | 145 } |
124 | 146 |
125 bool PluginAudio::StartAudioThread() { | 147 bool PluginAudio::StartAudioThread() { |
126 // clear contents of shm buffer before spinning up audio thread | 148 // clear contents of shm buffer before spinning up audio thread |
127 DebugPrintf("PluginAudio::StartAudioThread\n"); | 149 DebugPrintf("PluginAudio::StartAudioThread\n"); |
128 memset(shm_buffer_, 0, shm_size_); | 150 memset(shm_buffer_, 0, shm_size_); |
| 151 memset(audio_buffer_.get(), 0, audio_buffer_size_); |
129 const struct PP_ThreadFunctions* thread_funcs = GetThreadCreator(); | 152 const struct PP_ThreadFunctions* thread_funcs = GetThreadCreator(); |
130 if (NULL == thread_funcs->thread_create || | 153 if (NULL == thread_funcs->thread_create || |
131 NULL == thread_funcs->thread_join) { | 154 NULL == thread_funcs->thread_join) { |
132 return false; | 155 return false; |
133 } | 156 } |
134 int ret = thread_funcs->thread_create(&thread_id_, AudioThread, this); | 157 int ret = thread_funcs->thread_create(&thread_id_, AudioThread, this); |
135 if (0 == ret) { | 158 if (0 == ret) { |
136 thread_active_ = true; | 159 thread_active_ = true; |
137 set_state(AUDIO_PLAYING); | 160 set_state(AUDIO_PLAYING); |
138 return true; | 161 return true; |
(...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
318 GetAs<ppapi_proxy::PluginAudio>(audio_resource); | 341 GetAs<ppapi_proxy::PluginAudio>(audio_resource); |
319 if (NULL == audio.get()) { | 342 if (NULL == audio.get()) { |
320 // Ignore if no audio_resource -> audio_instance mapping exists, | 343 // Ignore if no audio_resource -> audio_instance mapping exists, |
321 // the app may have shutdown audio before StreamCreated() invoked. | 344 // the app may have shutdown audio before StreamCreated() invoked. |
322 rpc->result = NACL_SRPC_RESULT_OK; | 345 rpc->result = NACL_SRPC_RESULT_OK; |
323 return; | 346 return; |
324 } | 347 } |
325 audio->StreamCreated(sync_socket, shm, shm_size); | 348 audio->StreamCreated(sync_socket, shm, shm_size); |
326 rpc->result = NACL_SRPC_RESULT_OK; | 349 rpc->result = NACL_SRPC_RESULT_OK; |
327 } | 350 } |
OLD | NEW |