|
26 | 26 |
|
27 | 27 | import javax.sound.sampled.AudioFileFormat; |
28 | 28 | import javax.sound.sampled.AudioFormat; |
| 29 | +import javax.sound.sampled.AudioInputStream; |
29 | 30 | import javax.sound.sampled.UnsupportedAudioFileException; |
30 | 31 | import java.io.*; |
31 | 32 | import java.net.MalformedURLException; |
@@ -326,6 +327,110 @@ public void testGetAudioFileFormatURL() throws IOException, UnsupportedAudioFile |
326 | 327 | } |
327 | 328 | } |
328 | 329 |
|
| 330 | + @Test |
| 331 | + public void testGetAudioFileFormatURLWithEmojis() throws IOException, UnsupportedAudioFileException { |
| 332 | + // first copy the file from resources to actual location in temp |
| 333 | + final String filename = "test.ogg"; |
| 334 | + final File file = File.createTempFile("testGetAudioFileFormatURLWithEmojis🔥", filename); |
| 335 | + extractFile(filename, file); |
| 336 | + try { |
| 337 | + final AudioFileFormat fileFormat = new FFAudioFileReader().getAudioFileFormat(file.toURI().toURL()); |
| 338 | + System.out.println(fileFormat); |
| 339 | + |
| 340 | + assertEquals("ogg", fileFormat.getType().getExtension()); |
| 341 | + assertEquals(file.length(), fileFormat.getByteLength()); |
| 342 | + assertEquals(NOT_SPECIFIED, fileFormat.getFrameLength()); |
| 343 | + |
| 344 | + final AudioFormat format = fileFormat.getFormat(); |
| 345 | + assertEquals(NOT_SPECIFIED, format.getFrameSize()); |
| 346 | + assertEquals(2, format.getChannels()); |
| 347 | + final Long duration = (Long)fileFormat.getProperty("duration"); |
| 348 | + assertNotNull(duration); |
| 349 | + assertEquals(3030204, (long)duration); |
| 350 | + assertEquals((float)NOT_SPECIFIED, format.getFrameRate(), 0.001f); |
| 351 | + final Integer bitrate = (Integer)format.getProperty("bitrate"); |
| 352 | + assertNotNull("Bitrate missing", bitrate); |
| 353 | + assertEquals(112000, (int) bitrate); |
| 354 | + } finally { |
| 355 | + file.delete(); |
| 356 | + } |
| 357 | + } |
| 358 | + |
| 359 | + @Test |
| 360 | + public void testGetAudioFileFormatFileWithEmojis() throws IOException, UnsupportedAudioFileException { |
| 361 | + // Tests that getAudioFileFormat(File) handles emoji in the file name. |
| 362 | + // This path goes through fileToURL(), which must keep emoji percent-encoded |
| 363 | + // so JNI's GetStringUTFChars does not produce CESU-8 (Modified UTF-8) bytes |
| 364 | + // that differ from the standard UTF-8 bytes used by the file system. |
| 365 | + final String filename = "test.ogg"; |
| 366 | + final File file = File.createTempFile("testGetAudioFileFormatFileWithEmojis🔥", filename); |
| 367 | + extractFile(filename, file); |
| 368 | + try { |
| 369 | + final AudioFileFormat fileFormat = new FFAudioFileReader().getAudioFileFormat(file); |
| 370 | + System.out.println(fileFormat); |
| 371 | + assertEquals("ogg", fileFormat.getType().getExtension()); |
| 372 | + assertEquals(2, fileFormat.getFormat().getChannels()); |
| 373 | + } finally { |
| 374 | + file.delete(); |
| 375 | + } |
| 376 | + } |
| 377 | + |
| 378 | + @Test |
| 379 | + public void testGetAudioInputStreamFileWithEmojis() throws IOException, UnsupportedAudioFileException { |
| 380 | + // Tests that getAudioInputStream(File) can open and read a file whose |
| 381 | + // name contains emoji. Exercises the FFURLInputStream.open() JNI call. |
| 382 | + final String filename = "test.ogg"; |
| 383 | + final File file = File.createTempFile("testGetAudioInputStreamFileWithEmojis🎵", filename); |
| 384 | + extractFile(filename, file); |
| 385 | + try { |
| 386 | + final AudioInputStream stream = new FFAudioFileReader().getAudioInputStream(file); |
| 387 | + try { |
| 388 | + final byte[] buf = new byte[1024]; |
| 389 | + assertTrue("Expected to read audio bytes from emoji-named file", stream.read(buf) > 0); |
| 390 | + } finally { |
| 391 | + stream.close(); |
| 392 | + } |
| 393 | + } finally { |
| 394 | + file.delete(); |
| 395 | + } |
| 396 | + } |
| 397 | + |
| 398 | + @Test |
| 399 | + public void testFileWithEmojiToURL() throws MalformedURLException { |
| 400 | + // fileToURL() must produce a valid file: URL for paths containing emoji. |
| 401 | + // The native code uses ff_jstring_to_utf8() (String.getBytes("UTF-8")) rather than |
| 402 | + // GetStringUTFChars so that supplementary characters like emoji are correctly encoded |
| 403 | + // as standard UTF-8 bytes — matching the bytes stored on disk — regardless of whether |
| 404 | + // the URL string contains the emoji as a raw character or percent-encoded. |
| 405 | + Assume.assumeTrue(File.separator.equals("/")); |
| 406 | + final File file = new File("/someDir/test🔥/name.ogg"); |
| 407 | + final URL url = FFAudioFileReader.fileToURL(file); |
| 408 | + assertTrue("URL must use file: protocol: " + url, url.toString().startsWith("file:")); |
| 409 | + // The emoji must be represented in the URL in some form (raw or percent-encoded). |
| 410 | + assertTrue("URL must contain emoji path component: " + url, |
| 411 | + url.toString().contains("test🔥") || url.toString().contains("%F0%9F%94%A5") || url.toString().contains("%f0%9f%94%a5")); |
| 412 | + // The path decoded from the URL must end with the original file name. |
| 413 | + assertTrue("Decoded path must contain original file name: " + url, |
| 414 | + url.getFile().contains("test") && url.getFile().contains("name.ogg")); |
| 415 | + } |
| 416 | + |
| 417 | + @Test |
| 418 | + public void testGetAudioFileFormatURLWithSpaces() throws IOException, UnsupportedAudioFileException { |
| 419 | + // Tests that getAudioFileFormat(URL) handles spaces in the file path. |
| 420 | + // file.toURI().toURL() encodes spaces as %20; urlToString() must decode |
| 421 | + // them before passing to FFmpeg, which does not percent-decode file: paths. |
| 422 | + final String filename = "test.ogg"; |
| 423 | + final File file = File.createTempFile("test with spaces", filename); |
| 424 | + extractFile(filename, file); |
| 425 | + try { |
| 426 | + final AudioFileFormat fileFormat = new FFAudioFileReader().getAudioFileFormat(file.toURI().toURL()); |
| 427 | + assertEquals("ogg", fileFormat.getType().getExtension()); |
| 428 | + assertEquals(2, fileFormat.getFormat().getChannels()); |
| 429 | + } finally { |
| 430 | + file.delete(); |
| 431 | + } |
| 432 | + } |
| 433 | + |
329 | 434 | @Test |
330 | 435 | public void testGetAudioFileFormatInputStream() throws IOException, UnsupportedAudioFileException { |
331 | 436 | // first copy the file from resources to actual location in temp |
|
0 commit comments