audio/internal/oboe: Bug fix: Guard the players by a mutex

Closes #1631
This commit is contained in:
Hajime Hoshi 2021-05-05 00:30:24 +09:00
parent ad86c297fb
commit 83c9015468

View File

@ -26,7 +26,10 @@ namespace {
class Player : public oboe::AudioStreamDataCallback { class Player : public oboe::AudioStreamDataCallback {
public: public:
static const char* Suspend() { static const char* Suspend() {
std::lock_guard<std::mutex> lock(GetPlayersMutex());
for (Player* player : GetPlayers()) { for (Player* player : GetPlayers()) {
// Close should be called rather than Pause for onPause.
// https://github.com/google/oboe/blob/master/docs/GettingStarted.md
if (const char* msg = player->Close(); msg) { if (const char* msg = player->Close(); msg) {
return msg; return msg;
} }
@ -35,6 +38,7 @@ public:
} }
static const char* Resume() { static const char* Resume() {
std::lock_guard<std::mutex> lock(GetPlayersMutex());
for (Player* player : GetPlayers()) { for (Player* player : GetPlayers()) {
if (const char* msg = player->Play(); msg) { if (const char* msg = player->Play(); msg) {
return msg; return msg;
@ -49,11 +53,10 @@ public:
bit_depth_in_bytes_{bit_depth_in_bytes}, bit_depth_in_bytes_{bit_depth_in_bytes},
go_player_{go_player} { go_player_{go_player} {
std::atomic_store(&volume_, volume); std::atomic_store(&volume_, volume);
{
std::lock_guard<std::mutex> lock(GetPlayersMutex());
GetPlayers().insert(this); GetPlayers().insert(this);
} }
~Player() {
GetPlayers().erase(this);
} }
void SetVolume(double volume) { void SetVolume(double volume) {
@ -66,7 +69,7 @@ public:
const size_t one_buffer_size = sample_rate_ * channel_num_ * bit_depth_in_bytes_ / 4 / bytes_per_sample * bytes_per_sample; const size_t one_buffer_size = sample_rate_ * channel_num_ * bit_depth_in_bytes_ / 4 / bytes_per_sample * bytes_per_sample;
const size_t max_buffer_size = one_buffer_size * 2; const size_t max_buffer_size = one_buffer_size * 2;
std::lock_guard<std::mutex> lock(lock_); std::lock_guard<std::mutex> lock(mutex_);
buf_.insert(buf_.end(), data, data + length); buf_.insert(buf_.end(), data, data + length);
} }
@ -123,8 +126,17 @@ public:
return nullptr; return nullptr;
} }
const char* CloseAndRemove() {
// Close and remove self from the players atomically.
// Otherwise, a removed player might be resumed at Resume unexpectedly.
std::lock_guard<std::mutex> lock(GetPlayersMutex());
const char* msg = Close();
GetPlayers().erase(this);
return msg;
}
int GetUnplayedBufferSize() { int GetUnplayedBufferSize() {
std::lock_guard<std::mutex> lock(lock_); std::lock_guard<std::mutex> lock(mutex_);
return buf_.size(); return buf_.size();
} }
@ -134,7 +146,7 @@ public:
{ {
// TODO: Do not use a lock in onAudioReady. // TODO: Do not use a lock in onAudioReady.
// https://google.github.io/oboe/reference/classoboe_1_1_audio_stream_data_callback.html#ad8a3a9f609df5fd3a5d885cbe1b2204d // https://google.github.io/oboe/reference/classoboe_1_1_audio_stream_data_callback.html#ad8a3a9f609df5fd3a5d885cbe1b2204d
std::lock_guard<std::mutex> lock(lock_); std::lock_guard<std::mutex> lock(mutex_);
size_t copy_bytes = std::min(num_bytes, buf_.size()); size_t copy_bytes = std::min(num_bytes, buf_.size());
std::copy(buf_.begin(), buf_.begin() + copy_bytes, buf.begin()); std::copy(buf_.begin(), buf_.begin() + copy_bytes, buf.begin());
buf_.erase(buf_.begin(), buf_.begin() + copy_bytes); buf_.erase(buf_.begin(), buf_.begin() + copy_bytes);
@ -160,6 +172,11 @@ private:
return players; return players;
} }
static std::mutex& GetPlayersMutex() {
static std::mutex mutex;
return mutex;
}
const int sample_rate_; const int sample_rate_;
const int channel_num_; const int channel_num_;
const int bit_depth_in_bytes_; const int bit_depth_in_bytes_;
@ -167,7 +184,7 @@ private:
std::atomic<double> volume_{1.0}; std::atomic<double> volume_{1.0};
std::vector<uint8_t> buf_; std::vector<uint8_t> buf_;
std::mutex lock_; std::mutex mutex_;
std::shared_ptr<oboe::AudioStream> stream_; std::shared_ptr<oboe::AudioStream> stream_;
}; };
@ -210,7 +227,7 @@ void Player_SetVolume(PlayerID audio_player, double volume) {
const char* Player_Close(PlayerID audio_player) { const char* Player_Close(PlayerID audio_player) {
Player* p = reinterpret_cast<Player*>(audio_player); Player* p = reinterpret_cast<Player*>(audio_player);
const char* msg = p->Close(); const char* msg = p->CloseAndRemove();
delete p; delete p;
return msg; return msg;
} }