Android

음성 파일 서버 업로드하기

그란. 2022. 1. 10. 12:25

음성파일 가져오기 

개념 : 파일을 byteArray로 만들어 서버에 전송 하려고한다.
- 당연하지만 만든다는건 변경한다는 의미가 아닌 copy의 의미 (단순히 읽는것임)


1. 파일로 만든다 
 File()  : URI도 가능하고 경로String도 가능

2. InputStream에 넣는다 ( FileInputStream )

3. 파일을 읽어서 byteArray형태로 가져온다

val fis = FileInputStream(File(speakingDirectory))
val byteArray = fil.readBytes()

코틀린 익스텐션 readBytes를 활용했는데

내부를 보면 Outstream도 만들어 주고, 알아서 처리해주니 너무 편리!!

public fun InputStream.readBytes(): ByteArray {
    val buffer = ByteArrayOutputStream(maxOf(DEFAULT_BUFFER_SIZE, this.available()))
    copyTo(buffer)
    return buffer.toByteArray()
}


public fun InputStream.copyTo(out: OutputStream, bufferSize: Int = DEFAULT_BUFFER_SIZE): Long {
    var bytesCopied: Long = 0
    val buffer = ByteArray(bufferSize)
    var bytes = read(buffer)
    while (bytes >= 0) {
        out.write(buffer, 0, bytes)
        bytesCopied += bytes
        bytes = read(buffer)
    }
    return bytesCopied
}

 

 

 

- API 인터페이스 

@Multipart
@POST(")
fun sendFile(
    @Part file: MultipartBody.Part
): Completable

@MultiPart 어노테이션, MultipartBody.Part 타입

 

 

bytesArray를  MutipartBody.Part 타입으로 변경 

sendFile(
	file = MultipartBody.Part.createFormData(
                name = "file",
                filename = "file.wav",
                body = bytes.toRequestBody(contentType = "audio/wav".toMediaTypeOrNull())
            )
)

 


ByteArray 재생하기

 

val path = File(fileDirectory)

val fileOutputStream = FileOutputStream(path).use{
	 it.write(bytes)
}

player = MediaPlayer()
    .apply {
        setDataSource(fileDirectory)
        prepare()
    }
player?.start()

파일들을 HEADER로부터 해당 파일의 타입을 정의할 수 있다 ( audio 인지 video인지 ) 

만약 이런 헤더가 없다면 단순 파일 ( 확장자 없는 흰 A4용지 아이콘 )이 된다.

 

단순히 녹음을 끝내고 생성한 File(directory) 에는 HEADER가 들어가 있지 않다. (단순 파일)

그래서 정의된 HEADER 를 임의로 추가해야 한다.

 

해당 헤더정보를 파일에 정해진 위치에 추가해야 한다. 


val header = getWavFileHeaderByteArray(...)
val randomAccessFile = RandomAccessFile(File(filePath), "rw").use{
	it.seek(0)
    	it.write(header)
}

private fun getWavFileHeaderByteArray(
    totalAudioLen: Long, totalDataLen: Long, longSampleRate: Long,
    channels: Int, byteRate: Long, bitsPerSample: Int
): ByteArray {
    val header = ByteArray(44)
    header[0] = 'R'.toByte()
    header[1] = 'I'.toByte()
    header[2] = 'F'.toByte()
    header[3] = 'F'.toByte()
    header[4] = (totalDataLen and 0xff).toByte()
    header[5] = (totalDataLen shr 8 and 0xff).toByte()
    header[6] = (totalDataLen shr 16 and 0xff).toByte()
    header[7] = (totalDataLen shr 24 and 0xff).toByte()
    header[8] = 'W'.toByte()
    header[9] = 'A'.toByte()
    header[10] = 'V'.toByte()
    header[11] = 'E'.toByte()
    header[12] = 'f'.toByte()
    header[13] = 'm'.toByte()
    header[14] = 't'.toByte()
    header[15] = ' '.toByte()
    header[16] = 16
    header[17] = 0
    header[18] = 0
    header[19] = 0
    header[20] = 1
    header[21] = 0
    header[22] = channels.toByte()
    header[23] = 0
    header[24] = (longSampleRate and 0xff).toByte()
    header[25] = (longSampleRate shr 8 and 0xff).toByte()
    header[26] = (longSampleRate shr 16 and 0xff).toByte()
    header[27] = (longSampleRate shr 24 and 0xff).toByte()
    header[28] = (byteRate and 0xff).toByte()
    header[29] = (byteRate shr 8 and 0xff).toByte()
    header[30] = (byteRate shr 16 and 0xff).toByte()
    header[31] = (byteRate shr 24 and 0xff).toByte()
    header[32] = (channels * (bitsPerSample / 8)).toByte()
    header[33] = 0
    header[34] = bitsPerSample.toByte()
    header[35] = 0
    header[36] = 'd'.toByte()
    header[37] = 'a'.toByte()
    header[38] = 't'.toByte()
    header[39] = 'a'.toByte()
    header[40] = (totalAudioLen and 0xff).toByte()
    header[41] = (totalAudioLen shr 8 and 0xff).toByte()
    header[42] = (totalAudioLen shr 16 and 0xff).toByte()
    header[43] = (totalAudioLen shr 24 and 0xff).toByte()
    return header
}

 

추가 ImageView의 이미지를 파일로 만들기 

ByteArrayOutputStream().use { bos ->
    (view as ImageView).drawable.toBitmap()
        .compress(CompressFormat.PNG, 0 /*ignored for PNG*/, bos)

    imageFile.outputStream().use{
        it.write(bos.toByteArray())
        it.flush()
    }
}

 

그 파일의 URI 가져오기

val imageUri =
    FileProvider.getUriForFile(
        this,
        "dev.hadrosaur.draganddropsample.images",
        imageFile
    )