2

I have an audio class with filePath (which is a link to audio file to AWS S3 file). Here's my function

fun download(audio: Audio) {
        val audioOutStream: OutputStream

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            val values = ContentValues()
            values.put(MediaStore.Audio.Media.DISPLAY_NAME, "${audio.title}.mp3")
            values.put(MediaStore.Audio.Media.MIME_TYPE, "audio/mpeg")
            values.put(
                MediaStore.Audio.Media.RELATIVE_PATH,
                "${Environment.DIRECTORY_MUSIC}/Soundy/"
            )
            val uri = context.contentResolver.insert(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, values)
            audioOutStream = context.contentResolver.openOutputStream(uri!!)!!
        } else {
            val audioPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC).toString() + "/Soundy/"
            val audio = File(audioPath, audio.title!!)
            audioOutStream = FileOutputStream(audio)
        }

        audioOutStream.close()
    }

It saves audio, but this file contains nothing (It's 0 bytes). How can I save file from Url using Mediastore? My android version is 11.

EDIT Changed my code to:

 fun download(audio: Audio) {
       val values = ContentValues()
        values.put(MediaStore.Audio.Media.DISPLAY_NAME, "${audio.title}.mp3")
        values.put(MediaStore.Audio.Media.MIME_TYPE, "audio/mpeg")
        values.put(
            MediaStore.Audio.Media.RELATIVE_PATH,
            "${Environment.DIRECTORY_MUSIC}/Soundy/"
        )
        val uri = context.contentResolver.insert(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, values)
        val audioOutStream = context.contentResolver.openOutputStream(uri!!)!!
        val request = Request.Builder().url(audio.filePath).build()
        val response = OkHttpClient().newCall(request).execute()
        val sink = Okio.buffer(Okio.sink(audioOutStream))
        sink.writeAll(response.body()!!.source())
        sink.close()
        audioOutStream.close()
    }

Still isn't working.

1 Answers1

0

That is because you do not do anything with audioOutStream, except to close it. If you want to write something, you need to write something. For example, you could use OkHttp to download the content and write it out. While that example shows writing to a File, Okio also offers a sink() extension function on OutputStream that you can use.

In other words, going back to your original code, you would have something like this:

fun download(audio: Audio) {
        val audioOutStream: OutputStream

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            val values = ContentValues()
            values.put(MediaStore.Audio.Media.DISPLAY_NAME, "${audio.title}.mp3")
            values.put(MediaStore.Audio.Media.MIME_TYPE, "audio/mpeg")
            values.put(
                MediaStore.Audio.Media.RELATIVE_PATH,
                "${Environment.DIRECTORY_MUSIC}/Soundy/"
            )
            val uri = context.contentResolver.insert(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, values)
            audioOutStream = context.contentResolver.openOutputStream(uri!!)!!
        } else {
            val audioPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC).toString() + "/Soundy/"
            val audio = File(audioPath, audio.title!!)
            audioOutStream = FileOutputStream(audio)
        }

        val request = Request.Builder().url(audio.filePath).build()
        val response = OkHttpClient().newCall(request).execute()
        val sink: BufferedSink = audioOutStream.sink().buffer()

        sink.writeAll(response.body()!!.source())
        sink.close()

        audioOutStream.close()
    }
CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • Can you please provide a code example? Just I'm not sure how to integrate it with audioOutStream. – Daniil Andreev Apr 25 '21 at 12:03
  • @DaniilAndreev: In Kotlin, it would be [this](https://stackoverflow.com/a/64020900/115145), except replacing `downloadedFile.sink().buffer()` with `audioOutStream.sink().buffer()`. – CommonsWare Apr 25 '21 at 12:05
  • @DaniilAndreev: Your added code should go after your `if`/`else`. Right now, you only use it in `else`. – CommonsWare Apr 25 '21 at 12:24
  • How can integrate it with Mediastore? – Daniil Andreev Apr 25 '21 at 12:31
  • @DaniilAndreev: It is [an extension function supplied by Okio](https://square.github.io/okio/2.x/okio/okio/sink.html) (which you get as a transitive dependency from OkHttp). You will need to add an `import` statement for it. If you are using Android Studio, there is probably a quick-fix to add that import statement. – CommonsWare Apr 25 '21 at 12:49
  • I've created an extension fun OutputStream.sink(): Sink, but now I get "Unresolved reference: buffer" and "Function 'sink' without a body must be abstract" – Daniil Andreev Apr 25 '21 at 12:55
  • @DaniilAndreev: That is not what I suggested. Add an `import` statement for the extension function supplied by Okio. That is just `import okio.sink`. – CommonsWare Apr 25 '21 at 12:58
  • "okio.sink" sink is not found – Daniil Andreev Apr 25 '21 at 13:18
  • I fixed it by implementation "com.squareup.okio:okio:2.3.0" – Daniil Andreev Apr 25 '21 at 13:28