Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

274 lines
7.4KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE 6 technical preview.
  4. Copyright (c) 2017 - ROLI Ltd.
  5. You may use this code under the terms of the GPL v3
  6. (see www.gnu.org/licenses).
  7. For this technical preview, this file is not subject to commercial licensing.
  8. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  9. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  10. DISCLAIMED.
  11. ==============================================================================
  12. */
  13. namespace juce
  14. {
  15. #if JUCE_CONTENT_SHARING
  16. //==============================================================================
  17. class ContentSharer::PrepareImagesThread : private Thread
  18. {
  19. public:
  20. PrepareImagesThread (ContentSharer& cs, const Array<Image>& imagesToUse,
  21. ImageFileFormat* imageFileFormatToUse)
  22. : Thread ("ContentSharer::PrepareImagesThread"),
  23. owner (cs),
  24. images (imagesToUse),
  25. imageFileFormat (imageFileFormatToUse == nullptr ? new PNGImageFormat()
  26. : imageFileFormatToUse),
  27. extension (imageFileFormat->getFormatName().toLowerCase())
  28. {
  29. startThread();
  30. }
  31. ~PrepareImagesThread() override
  32. {
  33. signalThreadShouldExit();
  34. waitForThreadToExit (10000);
  35. }
  36. private:
  37. void run() override
  38. {
  39. for (const auto& image : images)
  40. {
  41. if (threadShouldExit())
  42. return;
  43. File tempFile = File::createTempFile (extension);
  44. if (! tempFile.create().wasOk())
  45. break;
  46. std::unique_ptr<FileOutputStream> outputStream (tempFile.createOutputStream());
  47. if (outputStream == nullptr)
  48. break;
  49. if (imageFileFormat->writeImageToStream (image, *outputStream))
  50. owner.temporaryFiles.add (tempFile);
  51. }
  52. finish();
  53. }
  54. void finish()
  55. {
  56. MessageManager::callAsync ([this] () { owner.filesToSharePrepared(); });
  57. }
  58. ContentSharer& owner;
  59. const Array<Image> images;
  60. std::unique_ptr<ImageFileFormat> imageFileFormat;
  61. String extension;
  62. };
  63. //==============================================================================
  64. class ContentSharer::PrepareDataThread : private Thread
  65. {
  66. public:
  67. PrepareDataThread (ContentSharer& cs, const MemoryBlock& mb)
  68. : Thread ("ContentSharer::PrepareDataThread"),
  69. owner (cs),
  70. data (mb)
  71. {
  72. startThread();
  73. }
  74. ~PrepareDataThread() override
  75. {
  76. signalThreadShouldExit();
  77. waitForThreadToExit (10000);
  78. }
  79. private:
  80. void run() override
  81. {
  82. File tempFile = File::createTempFile ("data");
  83. if (tempFile.create().wasOk())
  84. {
  85. if (auto outputStream = std::unique_ptr<FileOutputStream> (tempFile.createOutputStream()))
  86. {
  87. size_t pos = 0;
  88. size_t totalSize = data.getSize();
  89. while (pos < totalSize)
  90. {
  91. if (threadShouldExit())
  92. return;
  93. size_t numToWrite = std::min ((size_t) 8192, totalSize - pos);
  94. outputStream->write (data.begin() + pos, numToWrite);
  95. pos += numToWrite;
  96. }
  97. owner.temporaryFiles.add (tempFile);
  98. }
  99. }
  100. finish();
  101. }
  102. void finish()
  103. {
  104. MessageManager::callAsync ([this] () { owner.filesToSharePrepared(); });
  105. }
  106. ContentSharer& owner;
  107. const MemoryBlock data;
  108. };
  109. #endif
  110. //==============================================================================
  111. JUCE_IMPLEMENT_SINGLETON (ContentSharer)
  112. ContentSharer::ContentSharer() {}
  113. ContentSharer::~ContentSharer() { clearSingletonInstance(); }
  114. void ContentSharer::shareFiles (const Array<URL>& files,
  115. std::function<void(bool, const String&)> callbackToUse)
  116. {
  117. #if JUCE_CONTENT_SHARING
  118. startNewShare (callbackToUse);
  119. pimpl->shareFiles (files);
  120. #else
  121. ignoreUnused (files);
  122. // Content sharing is not available on this platform!
  123. jassertfalse;
  124. if (callbackToUse)
  125. callbackToUse (false, "Content sharing is not available on this platform!");
  126. #endif
  127. }
  128. #if JUCE_CONTENT_SHARING
  129. void ContentSharer::startNewShare (std::function<void(bool, const String&)> callbackToUse)
  130. {
  131. // You should not start another sharing operation before the previous one is finished.
  132. // Forcibly stopping a previous sharing operation is rarely a good idea!
  133. jassert (pimpl == nullptr);
  134. pimpl.reset();
  135. prepareDataThread = nullptr;
  136. prepareImagesThread = nullptr;
  137. deleteTemporaryFiles();
  138. // You need to pass a valid callback.
  139. jassert (callbackToUse);
  140. callback = std::move (callbackToUse);
  141. pimpl.reset (createPimpl());
  142. }
  143. #endif
  144. void ContentSharer::shareText (const String& text,
  145. std::function<void(bool, const String&)> callbackToUse)
  146. {
  147. #if JUCE_CONTENT_SHARING
  148. startNewShare (callbackToUse);
  149. pimpl->shareText (text);
  150. #else
  151. ignoreUnused (text);
  152. // Content sharing is not available on this platform!
  153. jassertfalse;
  154. if (callbackToUse)
  155. callbackToUse (false, "Content sharing is not available on this platform!");
  156. #endif
  157. }
  158. void ContentSharer::shareImages (const Array<Image>& images,
  159. std::function<void(bool, const String&)> callbackToUse,
  160. ImageFileFormat* imageFileFormatToUse)
  161. {
  162. #if JUCE_CONTENT_SHARING
  163. startNewShare (callbackToUse);
  164. prepareImagesThread.reset (new PrepareImagesThread (*this, images, imageFileFormatToUse));
  165. #else
  166. ignoreUnused (images, imageFileFormatToUse);
  167. // Content sharing is not available on this platform!
  168. jassertfalse;
  169. if (callbackToUse)
  170. callbackToUse (false, "Content sharing is not available on this platform!");
  171. #endif
  172. }
  173. #if JUCE_CONTENT_SHARING
  174. void ContentSharer::filesToSharePrepared()
  175. {
  176. Array<URL> urls;
  177. for (const auto& tempFile : temporaryFiles)
  178. urls.add (URL (tempFile));
  179. prepareImagesThread = nullptr;
  180. prepareDataThread = nullptr;
  181. pimpl->shareFiles (urls);
  182. }
  183. #endif
  184. void ContentSharer::shareData (const MemoryBlock& mb,
  185. std::function<void(bool, const String&)> callbackToUse)
  186. {
  187. #if JUCE_CONTENT_SHARING
  188. startNewShare (callbackToUse);
  189. prepareDataThread.reset (new PrepareDataThread (*this, mb));
  190. #else
  191. ignoreUnused (mb);
  192. if (callbackToUse)
  193. callbackToUse (false, "Content sharing not available on this platform!");
  194. #endif
  195. }
  196. void ContentSharer::sharingFinished (bool succeeded, const String& errorDescription)
  197. {
  198. deleteTemporaryFiles();
  199. std::function<void(bool, String)> cb;
  200. std::swap (cb, callback);
  201. String error (errorDescription);
  202. #if JUCE_CONTENT_SHARING
  203. pimpl.reset();
  204. #endif
  205. if (cb)
  206. cb (succeeded, error);
  207. }
  208. void ContentSharer::deleteTemporaryFiles()
  209. {
  210. for (auto& f : temporaryFiles)
  211. f.deleteFile();
  212. temporaryFiles.clear();
  213. }
  214. } // namespace juce