|
OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2010 The Chromium 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 "chrome/renderer/audio_device.h" | |
6 | |
7 #include "chrome/common/render_messages_params.h" | |
8 #include "chrome/renderer/render_thread.h" | |
9 | |
10 scoped_refptr<AudioMessageFilter> AudioDevice::filter_; | |
11 | |
12 AudioDevice::AudioDevice(size_t buffer_size, | |
13 int channels, | |
14 double sample_rate, | |
15 RenderCallback* callback) | |
16 : buffer_size_(buffer_size), | |
17 channels_(channels), | |
18 sample_rate_(sample_rate), | |
19 callback_(callback), | |
20 stream_id_(0) { | |
21 audio_data_.reserve(channels); | |
scherkus (not reviewing)
2011/01/10 23:42:32
(thinking aloud) I wonder if it makes sense to mak
Chris Rogers
2011/01/11 23:01:02
I think for the simple case here it might not be n
| |
22 for (int i = 0; i < channels; ++i) { | |
23 float* channel_data = static_cast<float*>( | |
24 malloc(buffer_size * sizeof(float))); | |
scherkus (not reviewing)
2011/01/10 23:42:32
malloc is rarely used -- I'd just go for new float
Chris Rogers
2011/01/11 23:01:02
Done.
| |
25 audio_data_.push_back(channel_data); | |
26 } | |
27 } | |
28 | |
29 AudioDevice::~AudioDevice() { | |
30 Stop(); | |
31 for (int i = 0; i < channels_; ++i) | |
32 free(audio_data_[i]); | |
scherkus (not reviewing)
2011/01/10 23:42:32
and delete[] here
Chris Rogers
2011/01/11 23:01:02
Done.
| |
33 } | |
34 | |
35 bool AudioDevice::Start() { | |
neb
2011/01/10 23:11:57
For PPAPI, there was a requirement that all the au
Chris Rogers
2011/01/11 23:01:02
Andrew also asked the same question. The class is
| |
36 // Make sure we don't call Start() more than once. | |
37 DCHECK_EQ(0, stream_id_); | |
38 if (stream_id_) | |
39 return false; | |
40 | |
41 // Lazily create the message filter and share across AudioDevice instances. | |
42 if (!filter_.get()) { | |
scherkus (not reviewing)
2011/01/10 23:42:32
sanity check: are we sure there's no race conditio
Chris Rogers
2011/01/11 23:01:02
Yes, you're right. Unless the API contract is tha
| |
43 int routing_id; | |
44 RenderThread::current()->Send( | |
45 new ViewHostMsg_GenerateRoutingID(&routing_id)); | |
46 filter_ = new AudioMessageFilter(routing_id); | |
47 RenderThread::current()->AddFilter(filter_); | |
48 } | |
49 | |
50 stream_id_ = filter_->AddDelegate(this); | |
51 | |
52 ViewHostMsg_Audio_CreateStream_Params params; | |
53 params.params.format = AudioParameters::AUDIO_PCM_LINEAR; | |
54 params.params.channels = channels_; | |
55 params.params.sample_rate = sample_rate_; | |
56 params.params.bits_per_sample = 16; | |
57 params.params.samples_per_packet = buffer_size_; | |
58 | |
59 filter_->Send( | |
60 new ViewHostMsg_CreateAudioStream(0, stream_id_, params, true)); | |
61 | |
62 return true; | |
63 } | |
64 | |
65 bool AudioDevice::Stop() { | |
66 if (stream_id_) { | |
67 OnDestroy(); | |
68 return true; | |
69 } | |
70 return false; | |
71 } | |
72 | |
73 void AudioDevice::OnDestroy() { | |
74 // Make sure we don't call destroy more than once. | |
75 DCHECK_NE(0, stream_id_); | |
76 if (!stream_id_) | |
77 return; | |
78 | |
79 filter_->RemoveDelegate(stream_id_); | |
80 filter_->Send(new ViewHostMsg_CloseAudioStream(0, stream_id_)); | |
81 stream_id_ = 0; | |
82 if (audio_thread_.get()) { | |
83 socket_->Close(); | |
84 audio_thread_->Join(); | |
85 } | |
86 } | |
87 | |
88 void AudioDevice::OnRequestPacket(AudioBuffersState buffers_state) { | |
scherkus (not reviewing)
2011/01/10 23:42:32
is there any plan to implement these?
perhaps hav
Chris Rogers
2011/01/11 23:01:02
Done.
| |
89 } | |
90 | |
91 void AudioDevice::OnStateChanged( | |
92 const ViewMsg_AudioStreamState_Params& state) { | |
93 } | |
94 | |
95 void AudioDevice::OnCreated( | |
96 base::SharedMemoryHandle handle, uint32 length) { | |
97 } | |
98 | |
99 void AudioDevice::OnLowLatencyCreated( | |
100 base::SharedMemoryHandle handle, base::SyncSocket::Handle socket_handle, | |
scherkus (not reviewing)
2011/01/10 23:42:32
drop 2nd arg to next line
Chris Rogers
2011/01/11 23:01:02
Done.
| |
101 uint32 length) { | |
102 | |
103 #if defined(OS_WIN) | |
104 DCHECK(handle); | |
105 DCHECK(socket_handle); | |
106 #else | |
107 DCHECK_NE(-1, handle.fd); | |
scherkus (not reviewing)
2011/01/10 23:42:32
sanity check: is -1 the only possible bad value or
Chris Rogers
2011/01/11 23:01:02
This was taken from Neb's code, but yes, your chec
| |
108 DCHECK_NE(-1, socket_handle); | |
109 #endif | |
110 DCHECK(length); | |
111 DCHECK(!audio_thread_.get()); | |
112 | |
113 // TODO(crogers) : check that length is big enough for buffer_size_ | |
114 | |
115 shared_memory_.reset(new base::SharedMemory(handle, false)); | |
116 shared_memory_->Map(length); | |
117 | |
118 socket_.reset(new base::SyncSocket(socket_handle)); | |
119 // Allow the client to pre-populate the buffer. | |
120 FireRenderCallback(); | |
121 | |
122 // TODO(crogers) : we could optionally set the thread to high-priority | |
scherkus (not reviewing)
2011/01/10 23:42:32
nit: no space between ) and :
Chris Rogers
2011/01/11 23:01:02
Done.
| |
123 audio_thread_.reset( | |
124 new base::DelegateSimpleThread(this, "renderer_audio_thread")); | |
125 audio_thread_->Start(); | |
126 | |
127 filter_->Send(new ViewHostMsg_PlayAudioStream(0, stream_id_)); | |
128 } | |
129 | |
130 void AudioDevice::OnVolume(double volume) { | |
scherkus (not reviewing)
2011/01/10 23:42:32
ditto for this method
Chris Rogers
2011/01/11 23:01:02
Done.
| |
131 } | |
132 | |
133 // Our audio thread runs here. | |
134 void AudioDevice::Run() { | |
135 int pending_data; | |
136 while (sizeof(pending_data) == socket_->Receive(&pending_data, | |
137 sizeof(pending_data)) && | |
138 pending_data >= 0) { | |
scherkus (not reviewing)
2011/01/10 23:42:32
this should be aligned at (
Chris Rogers
2011/01/11 23:01:02
Done.
| |
139 FireRenderCallback(); | |
140 } | |
141 } | |
142 | |
143 void AudioDevice::FireRenderCallback() { | |
144 if (callback_) { | |
145 // For now, only handle stereo case. | |
146 DCHECK_EQ(2, channels_); | |
scherkus (not reviewing)
2011/01/10 23:42:32
instead of failing late perhaps this should get ch
Chris Rogers
2011/01/11 23:01:02
In looking over this code again, I don't think the
| |
147 | |
148 // Ask client to render audio. | |
149 callback_->render(audio_data_, buffer_size_); | |
scherkus (not reviewing)
2011/01/10 23:42:32
double-checking something just to be safe..
the h
Chris Rogers
2011/01/11 23:01:02
Actually, buffer_size_ is in sample-frames, so thi
| |
150 | |
151 // Interleave, scale, and clip to int16. | |
neb
2011/01/10 23:11:57
In PPAPI, we expect to provide different sample ty
scherkus (not reviewing)
2011/01/10 23:42:32
Is it worth converting everything to float at some
Chris Rogers
2011/01/11 23:01:02
I would be in favor of switching most of our code
Chris Rogers
2011/01/11 23:01:02
Currently the API requires the client provide the
| |
152 int16* output_buffer16 = static_cast<int16*>(shared_memory_data()); | |
scherkus (not reviewing)
2011/01/10 23:42:32
is there anything in media/audio/audio_util.h we c
Chris Rogers
2011/01/11 23:01:02
Sure, I made a more general function in audio_util
| |
153 const float kScale = 32768.0f; | |
154 for (int i = 0; i < channels_; ++i) { | |
155 float* channel_data = audio_data_[i]; | |
156 for (size_t j = 0; j < buffer_size_; ++j) { | |
157 float sample = kScale * channel_data[j]; | |
158 if (sample < -32768.0) | |
159 sample = -32768.0; | |
160 else if (sample > 32767.0) | |
161 sample = 32767.0; | |
162 | |
163 output_buffer16[j * channels_ + i] = static_cast<int16>(sample); | |
164 } | |
165 } | |
166 } | |
167 } | |
OLD | NEW |