webrtc-sdk / webrtc

BSD 3-Clause "New" or "Revised" License
225 stars 89 forks source link

crash report #102

Open JiaoLiu opened 11 months ago

JiaoLiu commented 11 months ago
int32_t ObjCDesktopMediaList::UpdateSourceList(bool force_reload, bool get_thumbnail) {
  if (force_reload) {
    for (auto source : sources_) {
      [objcMediaList_ mediaSourceRemoved:source.get()];
    }
    sources_.clear();
  }

  webrtc::DesktopCapturer::SourceList new_sources;

  thread_->BlockingCall([this, &new_sources] {
    capturer_->GetSourceList(&new_sources);
  });

  typedef std::set<DesktopCapturer::SourceId> SourceSet;
  SourceSet new_source_set;
  for (size_t i = 0; i < new_sources.size(); ++i) {
    if (type_ == kScreen && new_sources[i].title.length() == 0) {
      new_sources[i].title = std::string("Screen " + std::to_string(i + 1));
    }
    new_source_set.insert(new_sources[i].id);
  }
  // Iterate through the old sources to find the removed sources.
  for (size_t i = 0; i < sources_.size(); ++i) {
    if (new_source_set.find(sources_[i]->id()) == new_source_set.end()) {
      [objcMediaList_ mediaSourceRemoved:(*(sources_.begin() + i)).get()];
      sources_.erase(sources_.begin() + i);
      --i;
    }
  }
  // Iterate through the new sources to find the added sources.
  if (new_sources.size() > sources_.size()) {
    SourceSet old_source_set;
    for (size_t i = 0; i < sources_.size(); ++i) {
      old_source_set.insert(sources_[i]->id());
    }
    for (size_t i = 0; i < new_sources.size(); ++i) {
      if (old_source_set.find(new_sources[i].id) == old_source_set.end()) {
        MediaSource *source = new MediaSource(this, new_sources[i], type_);
        sources_.insert(sources_.begin() + i, std::shared_ptr<MediaSource>(source));
        [objcMediaList_ mediaSourceAdded:source];
        GetThumbnail(source, true);
      }
    }
  }

  RTC_DCHECK_EQ(new_sources.size(), sources_.size());

  // Find the moved/changed sources.
  size_t pos = 0;
  while (pos < sources_.size()) {
    if (!(sources_[pos]->id() == new_sources[pos].id)) {
      // Find the source that should be moved to |pos|, starting from |pos + 1|
      // of |sources_|, because entries before |pos| should have been sorted.
      size_t old_pos = pos + 1;
      for (; old_pos < sources_.size(); ++old_pos) {
        if (sources_[old_pos]->id() == new_sources[pos].id) break;
      }
      RTC_DCHECK(sources_[old_pos]->id() == new_sources[pos].id);

      // Move the source from |old_pos| to |pos|.
      auto temp = sources_[old_pos];
      sources_.erase(sources_.begin() + old_pos);
      sources_.insert(sources_.begin() + pos, temp);
      //[objcMediaList_ mediaSourceMoved:old_pos newIndex:pos];
    }

    if (sources_[pos]->source.title != new_sources[pos].title) {
      sources_[pos]->source.title = new_sources[pos].title;
      [objcMediaList_ mediaSourceNameChanged:sources_[pos].get()];
    }
    ++pos;
  }

  if (get_thumbnail) {
    for (auto source : sources_) {
      GetThumbnail(source.get(), true);
    }
  }
  return sources_.size();
}

This method crashes when called simultaneously by multiple threads with force_reload = true. I suggest modifying the implementation to use a mutex lock to protect shared resources and ensure safe access in a multi-threaded environment. Here is the suggested modification:

int32_t ObjCDesktopMediaList::UpdateSourceList(bool force_reload, bool get_thumbnail) {
  std::lock_guard<std::mutex> lock(mutex_);

  if (force_reload) {
    for (auto source : sources_) {
      [objcMediaList_ mediaSourceRemoved:source.get()];
    }
    sources_.clear();
  }

  // CODE  ..

  return sources_.size();
}